forked from Elara6331/itd
Compare commits
16 Commits
Author | SHA1 | Date |
---|---|---|
Elara | 03f3968fe1 | |
Elara | dea92c6404 | |
Elara | 006f245c10 | |
Elara | d232340edd | |
Elara | c6458720e9 | |
Elara | 1e072a3540 | |
Elara | f639fef992 | |
Elara | 2d0db1dcf1 | |
Elara | 4efa4380c4 | |
Elara | fca64afbf3 | |
Elara | cf24c5ace8 | |
Elara | a25b2e3e62 | |
Elara | 2d0b64d92f | |
Elara | 5efafe9be7 | |
Elara | 6f87980d4b | |
Elara | 851f1975d6 |
|
@ -1,8 +1,5 @@
|
|||
# This is an example .goreleaser.yml file with some sensible defaults.
|
||||
# Make sure to check the documentation at https://goreleaser.com
|
||||
before:
|
||||
hooks:
|
||||
# You may remove this if you don't use go modules.
|
||||
- go mod tidy
|
||||
builds:
|
||||
- id: itd
|
||||
|
|
34
README.md
34
README.md
|
@ -4,8 +4,8 @@
|
|||
`itd` is a daemon that uses my infinitime [library](https://go.arsenm.dev/infinitime) to interact with the [PineTime](https://www.pine64.org/pinetime/) running [InfiniTime](https://infinitime.io).
|
||||
|
||||
[![Build status](https://ci.appveyor.com/api/projects/status/01qpwa2bn7c7fdi2?svg=true)](https://ci.appveyor.com/project/moussaelianarsen/itd-7t6ko)
|
||||
[![Binary downloads](https://img.shields.io/badge/download-binary-orange)](https://minio.arsenm.dev/minio/itd/)
|
||||
[![AUR package](https://img.shields.io/aur/version/itd-git?label=itd-git&logo=archlinux)](https://aur.archlinux.org/packages/itd-git/)
|
||||
[![itd-git AUR package](https://img.shields.io/aur/version/itd-git?label=itd-git&logo=archlinux)](https://aur.archlinux.org/packages/itd-git/)
|
||||
[![itd-bin AUR package](https://img.shields.io/aur/version/itd-bin?label=itd-bin&logo=archlinux)](https://aur.archlinux.org/packages/itd-bin/)
|
||||
|
||||
---
|
||||
|
||||
|
@ -24,6 +24,36 @@
|
|||
|
||||
---
|
||||
|
||||
### Installation
|
||||
|
||||
Since ITD 0.0.7, packages are built and uploaded whenever a new release is created.
|
||||
|
||||
#### Arch Linux
|
||||
|
||||
Use the `itd-bin` or `itd-git` AUR packages.
|
||||
|
||||
#### Debian/Ubuntu
|
||||
|
||||
- Go to the [latest release](https://gitea.arsenm.dev/Arsen6331/itd/releases/latest) and download the `.deb` package for your CPU architecture. You can find your architecture by running `uname -m` in the terminal.
|
||||
- Run `sudo apt install <package>`, replacing `<package>` with the path to the downloaded file. Note: relative paths must begin with `./`.
|
||||
- Example: `sudo apt install ~/Downloads/itd-0.0.7-linux-aarch64.deb`
|
||||
|
||||
#### Fedora
|
||||
|
||||
- Go to the [latest release](https://gitea.arsenm.dev/Arsen6331/itd/releases/latest) and download the `.rpm` package for your CPU architecture. You can find your architecture by running `uname -m` in the terminal.
|
||||
- Run `sudo dnf install <package>`, replacing `<package>` with the path to the downloaded file.
|
||||
- Example: `sudo dnf install ~/Downloads/itd-0.0.7-linux-aarch64.rpm`
|
||||
|
||||
#### Alpine (and postmarketOS)
|
||||
|
||||
- Go to the [latest release](https://gitea.arsenm.dev/Arsen6331/itd/releases/latest) and download the `.apk` package for your CPU architecture. You can find your architecture by running `uname -m` in the terminal.
|
||||
- Run `sudo apk add --allow-untrusted <package>`, replacing `<package>` with the path to the downloaded file.
|
||||
- Example: `sudo apk add --allow-untrusted ~/Downloads/itd-0.0.7-linux-aarch64.apk`
|
||||
|
||||
Note: `--allow-untrusted` is required because ITD isn't part of a repository, and therefore is not signed.
|
||||
|
||||
---
|
||||
|
||||
### Socket
|
||||
|
||||
This daemon creates a UNIX socket at `/tmp/itd/socket`. It allows you to directly control the daemon and, by extension, the connected watch.
|
||||
|
|
20
api/fs.go
20
api/fs.go
|
@ -2,6 +2,16 @@ package api
|
|||
|
||||
import "context"
|
||||
|
||||
func (c *Client) RemoveAll(ctx context.Context, paths ...string) error {
|
||||
return c.client.Call(
|
||||
ctx,
|
||||
"FS",
|
||||
"RemoveAll",
|
||||
paths,
|
||||
nil,
|
||||
)
|
||||
}
|
||||
|
||||
func (c *Client) Remove(ctx context.Context, paths ...string) error {
|
||||
return c.client.Call(
|
||||
ctx,
|
||||
|
@ -22,6 +32,16 @@ func (c *Client) Rename(ctx context.Context, old, new string) error {
|
|||
)
|
||||
}
|
||||
|
||||
func (c *Client) MkdirAll(ctx context.Context, paths ...string) error {
|
||||
return c.client.Call(
|
||||
ctx,
|
||||
"FS",
|
||||
"MkdirAll",
|
||||
paths,
|
||||
nil,
|
||||
)
|
||||
}
|
||||
|
||||
func (c *Client) Mkdir(ctx context.Context, paths ...string) error {
|
||||
return c.client.Call(
|
||||
ctx,
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
package api
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"go.arsenm.dev/infinitime"
|
||||
)
|
||||
|
||||
// LoadResources loads resources onto the watch from the given
|
||||
// file path to the resources zip
|
||||
func (c *Client) LoadResources(ctx context.Context, path string) (<-chan infinitime.ResourceLoadProgress, error) {
|
||||
progCh := make(chan infinitime.ResourceLoadProgress)
|
||||
|
||||
err := c.client.Call(
|
||||
ctx,
|
||||
"FS",
|
||||
"LoadResources",
|
||||
path,
|
||||
progCh,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return progCh, nil
|
||||
}
|
|
@ -6,11 +6,26 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/cheggaaa/pb/v3"
|
||||
"github.com/rs/zerolog/log"
|
||||
"github.com/urfave/cli/v2"
|
||||
"go.arsenm.dev/itd/api"
|
||||
)
|
||||
|
||||
func fwUpgrade(c *cli.Context) error {
|
||||
resources := c.String("resources")
|
||||
if resources != "" {
|
||||
absRes, err := filepath.Abs(resources)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = resLoad(c.Context, []string{absRes})
|
||||
if err != nil {
|
||||
log.Error().Msg("Resource loading has returned an error. This can happen if your current version of InfiniTime doesn't support BLE FS. Try updating without resource loading, and then load them after using the `itctl res load` command.")
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
start := time.Now()
|
||||
|
||||
var upgType api.UpgradeType
|
||||
|
|
|
@ -34,7 +34,12 @@ func fsMkdir(c *cli.Context) error {
|
|||
return cli.Exit("Command mkdir requires one or more arguments", 1)
|
||||
}
|
||||
|
||||
err := client.Mkdir(c.Context, c.Args().Slice()...)
|
||||
var err error
|
||||
if c.Bool("parents") {
|
||||
err = client.MkdirAll(c.Context, c.Args().Slice()...)
|
||||
} else {
|
||||
err = client.Mkdir(c.Context, c.Args().Slice()...)
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -109,7 +114,12 @@ func fsRemove(c *cli.Context) error {
|
|||
return cli.Exit("Command remove requires one or more arguments", 1)
|
||||
}
|
||||
|
||||
err := client.Remove(c.Context, c.Args().Slice()...)
|
||||
var err error
|
||||
if c.Bool("recursive") {
|
||||
err = client.RemoveAll(c.Context, c.Args().Slice()...)
|
||||
} else {
|
||||
err = client.Remove(c.Context, c.Args().Slice()...)
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"time"
|
||||
"context"
|
||||
"os"
|
||||
"os/signal"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/rs/zerolog"
|
||||
"github.com/rs/zerolog/log"
|
||||
|
@ -24,17 +24,17 @@ func main() {
|
|||
syscall.SIGINT,
|
||||
syscall.SIGTERM,
|
||||
)
|
||||
|
||||
|
||||
// This goroutine ensures that itctl will exit
|
||||
// at most 200ms after the user sends SIGINT/SIGTERM.
|
||||
go func() {
|
||||
<-ctx.Done()
|
||||
time.Sleep(200*time.Millisecond)
|
||||
time.Sleep(200 * time.Millisecond)
|
||||
os.Exit(0)
|
||||
}()
|
||||
|
||||
app := cli.App{
|
||||
Name: "itctl",
|
||||
Name: "itctl",
|
||||
HideHelpCommand: true,
|
||||
Flags: []cli.Flag{
|
||||
&cli.StringFlag{
|
||||
|
@ -46,10 +46,23 @@ func main() {
|
|||
},
|
||||
Commands: []*cli.Command{
|
||||
{
|
||||
Name: "help",
|
||||
Name: "help",
|
||||
ArgsUsage: "<command>",
|
||||
Usage: "Display help screen for a command",
|
||||
Action: helpCmd,
|
||||
Usage: "Display help screen for a command",
|
||||
Action: helpCmd,
|
||||
},
|
||||
{
|
||||
Name: "resources",
|
||||
Aliases: []string{"res"},
|
||||
Usage: "Handle InfiniTime resource loading",
|
||||
Subcommands: []*cli.Command{
|
||||
{
|
||||
Name: "load",
|
||||
ArgsUsage: "<path>",
|
||||
Usage: "Load an InifiniTime resources package",
|
||||
Action: resourcesLoad,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "filesystem",
|
||||
|
@ -64,6 +77,13 @@ func main() {
|
|||
Action: fsList,
|
||||
},
|
||||
{
|
||||
Flags: []cli.Flag{
|
||||
&cli.BoolFlag{
|
||||
Name: "parents",
|
||||
Aliases: []string{"p"},
|
||||
Usage: "Make parent directories if needed, no error if already existing",
|
||||
},
|
||||
},
|
||||
Name: "mkdir",
|
||||
ArgsUsage: "<paths...>",
|
||||
Usage: "Create new directories",
|
||||
|
@ -84,6 +104,13 @@ func main() {
|
|||
Action: fsRead,
|
||||
},
|
||||
{
|
||||
Flags: []cli.Flag{
|
||||
&cli.BoolFlag{
|
||||
Name: "recursive",
|
||||
Aliases: []string{"r", "R"},
|
||||
Usage: "Remove directories and their contents recursively",
|
||||
},
|
||||
},
|
||||
Name: "remove",
|
||||
ArgsUsage: "<paths...>",
|
||||
Aliases: []string{"rm"},
|
||||
|
@ -116,6 +143,11 @@ func main() {
|
|||
Aliases: []string{"f"},
|
||||
Usage: "Path to firmware image (.bin file)",
|
||||
},
|
||||
&cli.PathFlag{
|
||||
Name: "resources",
|
||||
Aliases: []string{"r"},
|
||||
Usage: "Path to resources file (.zip file)",
|
||||
},
|
||||
&cli.PathFlag{
|
||||
Name: "archive",
|
||||
Aliases: []string{"a"},
|
||||
|
@ -284,4 +316,4 @@ func isHelpCmd() bool {
|
|||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,57 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/cheggaaa/pb/v3"
|
||||
"github.com/urfave/cli/v2"
|
||||
"go.arsenm.dev/infinitime"
|
||||
)
|
||||
|
||||
func resourcesLoad(c *cli.Context) error {
|
||||
return resLoad(c.Context, c.Args().Slice())
|
||||
}
|
||||
|
||||
func resLoad(ctx context.Context, args []string) error {
|
||||
if len(args) == 0 {
|
||||
return cli.Exit("Command load requires one argument.", 1)
|
||||
}
|
||||
|
||||
// Create progress bar templates
|
||||
rmTmpl := `Removing {{string . "filename"}}`
|
||||
upTmpl := `Uploading {{string . "filename"}} {{counters . }} B {{bar . "|" "-" (cycle .) " " "|"}} {{percent . }} {{rtime . "%s"}}`
|
||||
// Start full bar at 0 total
|
||||
bar := pb.ProgressBarTemplate(rmTmpl).Start(0)
|
||||
|
||||
path, err := filepath.Abs(args[0])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
progCh, err := client.LoadResources(ctx, path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for evt := range progCh {
|
||||
if evt.Err != nil {
|
||||
return evt.Err
|
||||
}
|
||||
|
||||
if evt.Operation == infinitime.ResourceOperationRemoveObsolete {
|
||||
bar.SetTemplateString(rmTmpl)
|
||||
bar.Set("filename", evt.Name)
|
||||
} else {
|
||||
bar.SetTemplateString(upTmpl)
|
||||
bar.Set("filename", evt.Name)
|
||||
|
||||
bar.SetTotal(evt.Total)
|
||||
bar.SetCurrent(evt.Sent)
|
||||
}
|
||||
}
|
||||
|
||||
bar.Finish()
|
||||
|
||||
return nil
|
||||
}
|
4
go.mod
4
go.mod
|
@ -15,7 +15,7 @@ require (
|
|||
github.com/mozillazg/go-pinyin v0.19.0
|
||||
github.com/rs/zerolog v1.26.1
|
||||
github.com/urfave/cli/v2 v2.3.0
|
||||
go.arsenm.dev/infinitime v0.0.0-20220819210252-d199fba93c2f
|
||||
go.arsenm.dev/infinitime v0.0.0-20221020084115-54fdd19bec3c
|
||||
go.arsenm.dev/lrpc v0.0.0-20220513001344-3bcc01fdb6a0
|
||||
golang.org/x/text v0.3.7
|
||||
modernc.org/sqlite v1.17.2
|
||||
|
@ -38,7 +38,7 @@ require (
|
|||
github.com/gopherjs/gopherjs v1.17.2 // indirect
|
||||
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect
|
||||
github.com/mattn/go-colorable v0.1.8 // indirect
|
||||
github.com/mattn/go-runewidth v0.0.12 // indirect
|
||||
github.com/mattn/go-runewidth v0.0.13 // indirect
|
||||
github.com/mitchellh/copystructure v1.2.0 // indirect
|
||||
github.com/mitchellh/mapstructure v1.5.0 // indirect
|
||||
github.com/mitchellh/reflectwalk v1.0.2 // indirect
|
||||
|
|
7
go.sum
7
go.sum
|
@ -270,8 +270,9 @@ github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNx
|
|||
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
||||
github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y=
|
||||
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
|
||||
github.com/mattn/go-runewidth v0.0.12 h1:Y41i/hVW3Pgwr8gV+J23B9YEY0zxjptBuCWEaxmAOow=
|
||||
github.com/mattn/go-runewidth v0.0.12/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk=
|
||||
github.com/mattn/go-runewidth v0.0.13 h1:lTGmDsbAYt5DmK6OnoV7EuIF1wEIFAcxld6ypU4OSgU=
|
||||
github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
|
||||
github.com/mattn/go-sqlite3 v1.14.12 h1:TJ1bhYJPV44phC+IMu1u2K/i5RriLTPe+yc68XDJ1Z0=
|
||||
github.com/mattn/go-sqlite3 v1.14.12/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
|
||||
github.com/metal3d/fyne-x v0.0.0-20220508095732-177117e583fb h1:+fP6ENsbd+BUOmD/kSjNtrOmi2vgJ/JfWDSWjTKmTVY=
|
||||
|
@ -396,8 +397,8 @@ github.com/yuin/goldmark v1.3.8/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1
|
|||
github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||
github.com/yuin/goldmark v1.4.4 h1:zNWRjYUW32G9KirMXYHQHVNFkXvMI7LpgNW2AgYAoIs=
|
||||
github.com/yuin/goldmark v1.4.4/go.mod h1:rmuwmfZ0+bvzB24eSC//bk1R1Zp3hM0OXYv/G2LIilg=
|
||||
go.arsenm.dev/infinitime v0.0.0-20220819210252-d199fba93c2f h1:Np0ZNlgVC5D9NOilN14HJ1mSXM8vl2LYGfK0fZOYUbY=
|
||||
go.arsenm.dev/infinitime v0.0.0-20220819210252-d199fba93c2f/go.mod h1:K3NJ6fyPv5qqHUedB3MccKOE0whJMJZ80l/yTzzTrgc=
|
||||
go.arsenm.dev/infinitime v0.0.0-20221020084115-54fdd19bec3c h1:1YnQeP7BSjbpF7umNKNee4BU7rad6zcjYMhff2smjrY=
|
||||
go.arsenm.dev/infinitime v0.0.0-20221020084115-54fdd19bec3c/go.mod h1:K3NJ6fyPv5qqHUedB3MccKOE0whJMJZ80l/yTzzTrgc=
|
||||
go.arsenm.dev/lrpc v0.0.0-20220513001344-3bcc01fdb6a0 h1:1K96g1eww+77GeGchwMhd0NTrs7Mk/Hc3M3ItW5NbG4=
|
||||
go.arsenm.dev/lrpc v0.0.0-20220513001344-3bcc01fdb6a0/go.mod h1:goK9z735lfXmqlDxu9qN7FS8t0HJHN3PjyDtCToUY4w=
|
||||
go.etcd.io/etcd/api/v3 v3.5.0/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs=
|
||||
|
|
48
socket.go
48
socket.go
|
@ -293,6 +293,17 @@ type FS struct {
|
|||
fs *blefs.FS
|
||||
}
|
||||
|
||||
func (fs *FS) RemoveAll(_ *server.Context, paths []string) error {
|
||||
fs.updateFS()
|
||||
for _, path := range paths {
|
||||
err := fs.fs.RemoveAll(path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (fs *FS) Remove(_ *server.Context, paths []string) error {
|
||||
fs.updateFS()
|
||||
for _, path := range paths {
|
||||
|
@ -309,6 +320,17 @@ func (fs *FS) Rename(_ *server.Context, paths [2]string) error {
|
|||
return fs.fs.Rename(paths[0], paths[1])
|
||||
}
|
||||
|
||||
func (fs *FS) MkdirAll(_ *server.Context, paths []string) error {
|
||||
fs.updateFS()
|
||||
for _, path := range paths {
|
||||
err := fs.fs.MkdirAll(path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (fs *FS) Mkdir(_ *server.Context, paths []string) error {
|
||||
fs.updateFS()
|
||||
for _, path := range paths {
|
||||
|
@ -424,6 +446,32 @@ func (fs *FS) Download(ctx *server.Context, paths [2]string) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (fs *FS) LoadResources(ctx *server.Context, path string) error {
|
||||
resFl, err := os.Open(path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
progCh, err := infinitime.LoadResources(resFl, fs.fs)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
ch, err := ctx.MakeChannel()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
go func() {
|
||||
for evt := range progCh {
|
||||
ch <- evt
|
||||
}
|
||||
close(ch)
|
||||
}()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (fs *FS) updateFS() {
|
||||
if fs.fs == nil || updateFS {
|
||||
// Get new FS
|
||||
|
|
Loading…
Reference in New Issue