From 257b309b08dc20a72d2964063fccae0621f89085 Mon Sep 17 00:00:00 2001 From: plastikfan Date: Fri, 18 Aug 2023 18:06:02 +0100 Subject: [PATCH] feat(command): implement root command (#27) --- .vscode/launch.json | 10 +++- go.sum | 2 - src/app/command/bootstrap.go | 33 +++++++++--- src/app/command/root-cmd_test.go | 2 +- src/app/command/shrink-cmd.go | 21 +------- src/app/magick/enter-root.go | 90 ++++++++++++++++++++++++++++++++ src/app/magick/enter-shrink.go | 37 ++++--------- src/app/magick/entry-base.go | 38 ++++++++++++++ src/app/magick/image-defs.go | 2 +- 9 files changed, 178 insertions(+), 57 deletions(-) create mode 100644 src/app/magick/enter-root.go create mode 100644 src/app/magick/entry-base.go diff --git a/.vscode/launch.json b/.vscode/launch.json index 0d1185b..4f91ec9 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -4,12 +4,20 @@ // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 "version": "0.2.0", "configurations": [ + { + "name": "Launch file", + "type": "go", + "request": "launch", + "mode": "debug", + "program": "${file}" + }, { "name": "Launch Package", "type": "go", "request": "launch", "mode": "auto", - "program": "${fileDirname}" + "program": "${fileDirname}", + "args": ["shrink", "~/music/"] } ] } \ No newline at end of file diff --git a/go.sum b/go.sum index 77b97af..afd9ec4 100644 --- a/go.sum +++ b/go.sum @@ -190,8 +190,6 @@ github.com/samber/lo v1.38.1 h1:j2XEAqXKb09Am4ebOg31SpvzUTTs6EN3VfgeLUhPdXM= github.com/samber/lo v1.38.1/go.mod h1:+m/ZKRl6ClXCE2Lgf3MsQlWfh4bn1bz6CXEOxnEXnEA= github.com/snivilised/cobrass v0.3.0 h1:ByvHGg59ctNl+OD+qCINC6vl0QtUNtZjR1ChX3V9+hg= github.com/snivilised/cobrass v0.3.0/go.mod h1:5pf0tiAz1mWb7h+QDm/CJtukO3HXPQoKjQKhUnyX980= -github.com/snivilised/extendio v0.1.16 h1:pMu1ZFKDZwRl/DB2QHL9jH02JaZMm0ax+ZZ3AZxLUUU= -github.com/snivilised/extendio v0.1.16/go.mod h1:SO4udqtdfNl/KTLG9GF8kHxoMiIhnvN/9xlqkCCC6VY= github.com/snivilised/extendio v0.1.20 h1:pEnWUHFBVf62EaDWyG2dYsJdwiyWCs/GN8pQBlBd4G4= github.com/snivilised/extendio v0.1.20/go.mod h1:60Q6KRprh4qD7+aDXdlnKkXSgcmwsEV91OPO7j2CaEI= github.com/spf13/afero v1.9.5 h1:stMpOSZFs//0Lv29HduCmli3GUfpFoF3Y1Q/aXj/wVM= diff --git a/src/app/command/bootstrap.go b/src/app/command/bootstrap.go index e09fe5a..9fcd87b 100644 --- a/src/app/command/bootstrap.go +++ b/src/app/command/bootstrap.go @@ -15,6 +15,7 @@ import ( "github.com/snivilised/cobrass/src/assistant" ci18n "github.com/snivilised/cobrass/src/assistant/i18n" xi18n "github.com/snivilised/extendio/i18n" + "github.com/snivilised/extendio/xfs/utils" "github.com/snivilised/pixa/src/app/magick" "github.com/snivilised/pixa/src/i18n" ) @@ -33,6 +34,20 @@ func (j *Jabber) Scan() language.Tag { return language.MustParse(lang) } +func validatePositionalArgs(cmd *cobra.Command, args []string) error { + if err := cobra.ExactArgs(1)(cmd, args); err != nil { + return err + } + + directory := magick.ResolvePath(args[0]) + + if !utils.Exists(directory) { + return xi18n.NewPathNotFoundError("shrink directory", directory) + } + + return nil +} + // Bootstrap represents construct that performs start up of the cli // without resorting to the use of Go's init() mechanism and minimal // use of package global variables. @@ -48,18 +63,22 @@ func (b *Bootstrap) Root() *cobra.Command { // ---> co.configFile = "~/pixa.yml" }) - // all these string literals here should be made translate-able - // - b.container = assistant.NewCobraContainer( &cobra.Command{ Use: "main", Short: xi18n.Text(i18n.RootCmdShortDescTemplData{}), Long: xi18n.Text(i18n.RootCmdLongDescTemplData{}), Version: fmt.Sprintf("'%v'", Version), - // Uncomment the following line if your bare application - // has an action associated with it: - // Run: func(cmd *cobra.Command, args []string) { }, + RunE: func(cmd *cobra.Command, args []string) error { + fmt.Printf(" ===> 🌷🌷🌷 Root Command...\n") + + rps := b.container.MustGetParamSet(RootPsName).(magick.RootParameterSetPtr) //nolint:errcheck // is Must call + rps.Native.Directory = magick.ResolvePath(args[0]) + + // ---> execute root core + // + return magick.EnterRoot(rps) + }, }, ) @@ -277,5 +296,7 @@ func (b *Bootstrap) buildRootCommand(container *assistant.CobraContainer) { rootCommand.MarkFlagsMutuallyExclusive("files-rx", "files-gb") rootCommand.MarkFlagsMutuallyExclusive("folder-rx", "folder-gb") + rootCommand.Args = validatePositionalArgs + container.MustRegisterParamSet(RootPsName, paramSet) } diff --git a/src/app/command/root-cmd_test.go b/src/app/command/root-cmd_test.go index 7147bab..b007850 100644 --- a/src/app/command/root-cmd_test.go +++ b/src/app/command/root-cmd_test.go @@ -26,7 +26,7 @@ var _ = Describe("RootCmd", Ordered, func() { Detector: &DetectorStub{}, } tester := helpers.CommandTester{ - Args: []string{}, + Args: []string{"./"}, Root: bootstrap.Root(), } _, err := tester.Execute() diff --git a/src/app/command/shrink-cmd.go b/src/app/command/shrink-cmd.go index a4a14de..6504bdd 100644 --- a/src/app/command/shrink-cmd.go +++ b/src/app/command/shrink-cmd.go @@ -2,7 +2,6 @@ package command import ( "fmt" - "path/filepath" "strings" "github.com/snivilised/cobrass/src/assistant" @@ -96,14 +95,10 @@ func buildShrinkCommand(container *assistant.CobraContainer) *cobra.Command { fmt.Printf("💠 Blur defined with value: '%v'\n", cmd.Flag("sampling-factor").Value) } - ps.Native.Directory = args[0] - if absolute, absErr := filepath.Abs(args[0]); absErr == nil { - ps.Native.Directory = absolute - } - // Get inherited parameters // rps := container.MustGetParamSet(RootPsName).(magick.RootParameterSetPtr) //nolint:errcheck // is Must call + rps.Native.Directory = magick.ResolvePath(args[0]) // ---> execute application core with the parameter set (native) // @@ -264,19 +259,7 @@ func buildShrinkCommand(container *assistant.CobraContainer) *cobra.Command { container.MustRegisterRootedCommand(shrinkCommand) container.MustRegisterParamSet(shrinkPsName, paramSet) - shrinkCommand.Args = func(cmd *cobra.Command, args []string) error { - if err := cobra.ExactArgs(1)(cmd, args); err != nil { - return err - } - - directory := args[0] - - if !utils.Exists(directory) { - return xi18n.NewPathNotFoundError("shrink directory", directory) - } - - return nil - } + shrinkCommand.Args = validatePositionalArgs return shrinkCommand } diff --git a/src/app/magick/enter-root.go b/src/app/magick/enter-root.go new file mode 100644 index 0000000..9631f39 --- /dev/null +++ b/src/app/magick/enter-root.go @@ -0,0 +1,90 @@ +package magick + +import ( + "fmt" + "io/fs" + "path/filepath" + + "github.com/samber/lo" + "github.com/snivilised/cobrass/src/assistant" + "github.com/snivilised/extendio/xfs/nav" +) + +type RootEntry struct { + EntryBase + + rps *assistant.ParamSet[RootParameterSet] + files []string +} + +func (e *RootEntry) ConfigureOptions(o *nav.TraverseOptions) { + o.Notify.OnBegin = func(_ *nav.NavigationState) { + fmt.Printf("===> 🛡️ beginning traversal ...\n") + } + o.Notify.OnEnd = func(result *nav.TraverseResult) { + fmt.Printf("===> 🚩 finished traversal - folders '%v'\n", + result.Metrics.Count(nav.MetricNoFoldersInvokedEn), + ) + } + o.Callback = nav.LabelledTraverseCallback{ + Label: "Root Entry Callback", + Fn: func(item *nav.TraverseItem) error { + depth := item.Extension.Depth + indicator := lo.Ternary(len(item.Children) > 0, "☀️", "🌊") + + lo.ForEach(item.Children, func(de fs.DirEntry, index int) { + fullPath := filepath.Join(item.Path, de.Name()) + e.files = append(e.files, fullPath) + }) + + fmt.Printf( + "---> %v ROOT-CALLBACK: (depth:%v, files:%v) '%v'\n", + indicator, + depth, len(item.Children), + item.Path, + ) + + return nil + }, + } + o.Store.Subscription = nav.SubscribeFoldersWithFiles + o.Store.DoExtend = true + e.EntryBase.ConfigureOptions(o) +} + +func GetRootTraverseOptionsFunc(entry *RootEntry) func(o *nav.TraverseOptions) { + // make this a generic? + // + return func(o *nav.TraverseOptions) { + entry.ConfigureOptions(o) + } +} + +func EnterRoot( + rps *assistant.ParamSet[RootParameterSet], +) error { + fmt.Printf("---> 🦠🦠🦠 Directory: '%v'\n", rps.Native.Directory) + + entry := &RootEntry{ + rps: rps, + } + session := &nav.PrimarySession{ + Path: rps.Native.Directory, + OptionFn: GetRootTraverseOptionsFunc(entry), + } + result, err := session.Init().Run() + + lo.ForEach(entry.files, func(f string, _ int) { + fmt.Printf(" ===> 🔆 candidate file: '%v'\n", f) + }) + + no := result.Metrics.Count(nav.MetricNoChildFilesFoundEn) + summary := fmt.Sprintf("files: %v", no) + message := lo.Ternary(err == nil, + fmt.Sprintf("navigation completed (%v) ✔️", summary), + fmt.Sprintf("error occurred during navigation (%v)❌\n", err), + ) + fmt.Println(message) + + return err +} diff --git a/src/app/magick/enter-shrink.go b/src/app/magick/enter-shrink.go index 1761114..711905e 100644 --- a/src/app/magick/enter-shrink.go +++ b/src/app/magick/enter-shrink.go @@ -10,20 +10,6 @@ import ( "github.com/snivilised/extendio/xfs/nav" ) -type EntryBase struct { - session nav.TraverseSession -} - -func (e *EntryBase) ConfigureOptions(o *nav.TraverseOptions) { - o.Store.FilterDefs = &nav.FilterDefinitions{ - Children: nav.CompoundFilterDef{ - Type: nav.FilterTypeRegexEn, - Description: "Image types supported by pixa", - Pattern: "\\.(jpe?g|png|gif)$", - }, - } -} - type ShrinkEntry struct { EntryBase @@ -67,15 +53,11 @@ func (e *ShrinkEntry) ConfigureOptions(o *nav.TraverseOptions) { e.EntryBase.ConfigureOptions(o) } -func Configure(entry *ShrinkEntry, o *nav.TraverseOptions) { - entry.ConfigureOptions(o) -} - -func GetTraverseOptionsFunc(entry *ShrinkEntry) func(o *nav.TraverseOptions) { +func GetShrinkTraverseOptionsFunc(entry *ShrinkEntry) func(o *nav.TraverseOptions) { // make this a generic? // return func(o *nav.TraverseOptions) { - Configure(entry, o) + entry.ConfigureOptions(o) } } @@ -83,23 +65,24 @@ func EnterShrink( rps *assistant.ParamSet[RootParameterSet], ps *assistant.ParamSet[ShrinkParameterSet], ) error { - fmt.Printf("---> 🦠🦠🦠 Directory: '%v'\n", ps.Native.Directory) + fmt.Printf("---> 🦠🦠🦠 Directory: '%v'\n", rps.Native.Directory) entry := &ShrinkEntry{ rps: rps, ps: ps, } session := &nav.PrimarySession{ - Path: ps.Native.Directory, - OptionFn: GetTraverseOptionsFunc(entry), + Path: rps.Native.Directory, + OptionFn: GetShrinkTraverseOptionsFunc(entry), } - _, err := session.Init().Run() + result, err := session.Init().Run() - lo.ForEach(entry.jobs, func(i string, index int) { - fmt.Printf(" ===> ✨ job: '%v'\n", i) + lo.ForEach(entry.jobs, func(j string, _ int) { + fmt.Printf(" ===> ✨ job: '%v'\n", j) }) - summary := fmt.Sprintf("files: %v", len(entry.jobs)) + no := result.Metrics.Count(nav.MetricNoChildFilesFoundEn) + summary := fmt.Sprintf("files: %v, count: %v", len(entry.jobs), no) message := lo.Ternary(err == nil, fmt.Sprintf("navigation completed (%v) ✔️", summary), fmt.Sprintf("error occurred during navigation (%v)❌\n", err), diff --git a/src/app/magick/entry-base.go b/src/app/magick/entry-base.go new file mode 100644 index 0000000..89e5ecd --- /dev/null +++ b/src/app/magick/entry-base.go @@ -0,0 +1,38 @@ +package magick + +import ( + "os" + "path/filepath" + + "github.com/snivilised/extendio/xfs/nav" +) + +type EntryBase struct { + session nav.TraverseSession +} + +func (e *EntryBase) ConfigureOptions(o *nav.TraverseOptions) { + o.Store.FilterDefs = &nav.FilterDefinitions{ + Children: nav.CompoundFilterDef{ + Type: nav.FilterTypeRegexEn, + Description: "Image types supported by pixa", + Pattern: "\\.(jpe?g|png|gif)$", + }, + } +} + +func ResolvePath(path string) string { + result := path + + if result[0] == '~' { + if h, err := os.UserHomeDir(); err == nil { + result = filepath.Join(h, result[1:]) + } + } else { + if absolute, absErr := filepath.Abs(path); absErr == nil { + result = absolute + } + } + + return result +} diff --git a/src/app/magick/image-defs.go b/src/app/magick/image-defs.go index 1c0a6d3..3004977 100644 --- a/src/app/magick/image-defs.go +++ b/src/app/magick/image-defs.go @@ -8,6 +8,7 @@ import ( type RootParameterSet struct { GeneralParameters FilterParameters + Directory string Viper bool ConfigFile string Language string @@ -92,7 +93,6 @@ type CoreParameters struct { type ShrinkParameterSet struct { CoreParameters // - Directory string MirrorPath string ModeEn assistant.EnumValue[ModeEnum] }