12 Commits

9 changed files with 224 additions and 15 deletions

View File

@@ -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,

26
api/resources.go Normal file
View File

@@ -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
}

View File

@@ -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

View File

@@ -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
}

View File

@@ -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
}
}

57
cmd/itctl/resources.go Normal file
View File

@@ -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
View File

@@ -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-20221025193634-0ad671d3f550
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
View File

@@ -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-20221025193634-0ad671d3f550 h1:GScKSLy9KI83+au3mV9w6koiYRap/uYNarRoUleou4k=
go.arsenm.dev/infinitime v0.0.0-20221025193634-0ad671d3f550/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=

View File

@@ -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