From 53640f33362d8d6dc65db403e3b31a6776b49796 Mon Sep 17 00:00:00 2001 From: n-peugnet Date: Mon, 27 Sep 2021 19:55:57 +0200 Subject: add CLI with subcommands --- TODO.md | 7 +++--- main.go | 78 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++--------- repo.go | 7 ++++-- 3 files changed, 77 insertions(+), 15 deletions(-) diff --git a/TODO.md b/TODO.md index 0353b41..daa8120 100644 --- a/TODO.md +++ b/TODO.md @@ -17,7 +17,7 @@ priority 1 - [x] remove errored files from `fileList` - [ ] **TODO: Priority 3** add superblock logic. - [ ] **TODO: Priority 2** add version blocks or journal logic. -- [ ] command line with subcommands (like, hmm... git ? for instance). +- [x] command line with subcommands (like, hmm... git ? for instance). priority 2 ---------- @@ -48,6 +48,7 @@ priority 2 listing could be another solution but with this approach we would have to think about what other metadata we want to store - [ ] use a symlink aware Walk function (easy enough) +- [ ] add quick progress bar to CLI reunion 7/09 ------------ @@ -65,8 +66,8 @@ ideas 2. Implement the `fs` interface of Go? Not sure if this will be useful. -3. If we don't need to reduce read amplification we could compress all chunks if - it reduces the space used. +3. If we don't need to reduce read amplification we could compress all chunks + together if it reduces the space used. mystical bug 22/09 ------------------ diff --git a/main.go b/main.go index c0e55d8..cf208c9 100644 --- a/main.go +++ b/main.go @@ -8,32 +8,90 @@ import ( "github.com/n-peugnet/dna-backup/logger" ) +type command struct { + Flag *flag.FlagSet + Usage string + Help string + Run func([]string) error +} + const ( - usage = "usage: dna-backup [] [--] \n\noptions:\n" + name = "dna-backup" + baseUsage = " [] [--] " + commitUsage = "[] [--] " + commitHelp = "Create a new version of folder into repo " + restoreUsage = "[] [--] " + restoreHelp = "Restore the last version from repo into folder " ) var ( - logLevel int + logLevel int + commitCmd = flag.NewFlagSet("commit", flag.ExitOnError) + restoreCmd = flag.NewFlagSet("restore", flag.ExitOnError) + subcommands = map[string]command{ + commitCmd.Name(): {commitCmd, commitUsage, commitHelp, commitMain}, + restoreCmd.Name(): {restoreCmd, restoreUsage, restoreHelp, restoreMain}, + } ) func init() { - flag.IntVar(&logLevel, "v", 3, "log verbosity level (0-4)") + // init default help message + flag.Usage = func() { + fmt.Fprintf(flag.CommandLine.Output(), "usage: %s %s\n\ncommands:\n", name, baseUsage) + for _, s := range subcommands { + fmt.Printf(" %s %s\n", s.Flag.Name(), s.Help) + } + os.Exit(1) + } + // setup subcommands + for _, s := range subcommands { + s.Flag.IntVar(&logLevel, "v", 3, "log verbosity level (0-4)") + } } func main() { - flag.Usage = func() { - fmt.Fprintf(flag.CommandLine.Output(), usage) - flag.PrintDefaults() - } flag.Parse() - logger.Init(logLevel) - if len(flag.Args()) != 2 { + + args := flag.Args() + if len(args) < 1 { + flag.Usage() + } + cmd, exists := subcommands[args[0]] + if !exists { + fmt.Fprintf(flag.CommandLine.Output(), "error: unknown command %s\n\n", args[0]) flag.Usage() + } + cmd.Flag.Usage = func() { + fmt.Fprintf(cmd.Flag.Output(), "usage: %s %s %s\n\noptions:\n", name, cmd.Flag.Name(), cmd.Usage) + cmd.Flag.PrintDefaults() os.Exit(1) } - args := flag.Args() + cmd.Flag.Parse(args[1:]) + logger.Init(logLevel) + if err := cmd.Run(cmd.Flag.Args()); err != nil { + fmt.Fprintf(cmd.Flag.Output(), "error: %s\n\n", err) + cmd.Flag.Usage() + } +} + +func commitMain(args []string) error { + if len(args) != 2 { + return fmt.Errorf("wrong number of args") + } source := args[0] dest := args[1] repo := NewRepo(dest) repo.Commit(source) + return nil +} + +func restoreMain(args []string) error { + if len(args) != 2 { + return fmt.Errorf("wrong number args") + } + source := args[0] + dest := args[1] + repo := NewRepo(source) + repo.Restore(dest) + return nil } diff --git a/repo.go b/repo.go index 06524aa..d781b16 100644 --- a/repo.go +++ b/repo.go @@ -182,9 +182,12 @@ func (r *Repo) Commit(source string) { func (r *Repo) Restore(destination string) { versions := r.loadVersions() + logger.Info("loading previous file lists") r.loadFileLists(versions) + logger.Info("loading previous recipies") r.loadRecipes(versions) reader, writer := io.Pipe() + logger.Info("restoring latest version") go r.restoreStream(writer, r.recipe) bufReader := bufio.NewReaderSize(reader, r.chunkSize*2) for _, file := range r.files { @@ -353,7 +356,7 @@ func fileList2slice(l []File) (ret slice.Slice) { } func slice2fileList(s slice.Slice) (ret []File) { - ret = make([]File, len(s), len(s)) + ret = make([]File, len(s)) for i := range s { if f, ok := s[i].(File); ok { ret[i] = f @@ -721,7 +724,7 @@ func recipe2slice(r []Chunk) (ret slice.Slice) { } func slice2recipe(s slice.Slice) (ret []Chunk) { - ret = make([]Chunk, len(s), len(s)) + ret = make([]Chunk, len(s)) for i := range s { if c, ok := s[i].(Chunk); ok { ret[i] = c -- cgit v1.2.3