diff --git a/.vscode/settings.json b/.vscode/settings.json index e6882f2..02266ae 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -74,6 +74,7 @@ "plog", "prealloc", "promptui", + "randemoji", "repotoken", "samber", "sidewalk", diff --git a/src/app/proxy/enter-shrink.go b/src/app/proxy/enter-shrink.go index a4b0631..853de93 100644 --- a/src/app/proxy/enter-shrink.go +++ b/src/app/proxy/enter-shrink.go @@ -148,7 +148,7 @@ func (e *ShrinkEntry) run() (result *nav.TraverseResult, err error) { e.PrincipalOptionsFn, runnerWith, resumption, - e.Inputs.Root.PreviewFam.Native.DryRun, + e.Inputs, )) return result, err @@ -169,13 +169,25 @@ func EnterShrink( err error ) + schemes := params.Inputs.Root.Configs.Schemes + selectedScheme := params.Inputs.Root.ProfileFam.Native.Scheme + scheme, _ := schemes.Scheme(selectedScheme) + noProfiles := lo.TernaryF(scheme == nil, + func() uint { + return 1 + }, + func() uint { + return uint(len(scheme.Profiles())) + }, + ) finder := filing.NewFinder(&filing.NewFinderInfo{ Advanced: params.Inputs.Root.Configs.Advanced, - Schemes: params.Inputs.Root.Configs.Schemes, - Scheme: params.Inputs.Root.ProfileFam.Native.Scheme, + Schemes: schemes, + Scheme: selectedScheme, OutputPath: params.Inputs.ParamSet.Native.OutputPath, TrashPath: params.Inputs.ParamSet.Native.TrashPath, Observer: params.Inputs.Root.Observers.PathFinder, + Arity: noProfiles, }) fileManager := filing.NewManager(params.Vfs, finder, params.Inputs.Root.PreviewFam.Native.DryRun, diff --git a/src/app/proxy/filing/file-manager.go b/src/app/proxy/filing/file-manager.go index c5e14f5..8df1035 100644 --- a/src/app/proxy/filing/file-manager.go +++ b/src/app/proxy/filing/file-manager.go @@ -38,7 +38,7 @@ func (fm *FileManager) Finder() common.PathFinder { func (fm *FileManager) Create(path string, overwrite bool) error { if fm.Vfs.FileExists(path) && !overwrite { - return os.ErrExist + return errors.Wrapf(os.ErrExist, "could not create file at path: '%v'", path) } file, err := fm.Vfs.Create(path) diff --git a/src/app/proxy/filing/path-finder.go b/src/app/proxy/filing/path-finder.go index fc0d5fd..4b1b4e0 100644 --- a/src/app/proxy/filing/path-finder.go +++ b/src/app/proxy/filing/path-finder.go @@ -18,6 +18,7 @@ type NewFinderInfo struct { OutputPath string TrashPath string Observer common.PathFinder + Arity uint } func NewFinder( @@ -179,7 +180,7 @@ func (f *PathFinder) init(info *NewFinderInfo) { // When the user specifies an alternative location for the results to be sent to // with the --output flag, then the input is no longer transparent, as the user has // to go to the output location to see the result. - f.transparentInput = info.OutputPath == "" + f.transparentInput = info.OutputPath == "" && info.Arity == 1 journal := info.Advanced.JournalLabel() diff --git a/src/app/proxy/filing/path-finder_test.go b/src/app/proxy/filing/path-finder_test.go index 61b7eaf..82e9c73 100644 --- a/src/app/proxy/filing/path-finder_test.go +++ b/src/app/proxy/filing/path-finder_test.go @@ -7,6 +7,7 @@ import ( . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" + "github.com/samber/lo" "github.com/snivilised/extendio/xfs/nav" "github.com/snivilised/pixa/src/app/cfg" @@ -14,22 +15,20 @@ import ( "github.com/snivilised/pixa/src/app/proxy/filing" ) -type supplements struct { +type reasons struct { folder string file string } -type reasons = supplements - type asserter func(folder, file string, pi *common.PathInfo, statics *common.StaticInfo, entry *pfTE) type pfTE struct { given string should string - reasons supplements + reasons reasons scheme string profile string - supplements supplements + supplement string output string trash string cuddle bool @@ -95,12 +94,22 @@ var _ = Describe("PathFinder", Ordered, func() { DescribeTable("core", func(entry *pfTE) { + scheme, _ := schemes.Scheme(entry.scheme) + noProfiles := lo.TernaryF(scheme == nil, + func() uint { + return 1 + }, + func() uint { + return uint(len(scheme.Profiles())) + }, + ) finder := filing.NewFinder(&filing.NewFinderInfo{ Advanced: advanced, Schemes: schemes, Scheme: entry.scheme, OutputPath: entry.output, TrashPath: entry.trash, + Arity: noProfiles, }) origin := filepath.Join("foo", "sessions", "scan01") @@ -147,13 +156,11 @@ var _ = Describe("PathFinder", Ordered, func() { folder: "transparency, result should take place of input in same folder", file: "file should be moved out of the way and not cuddled", }, - profile: "blur", - supplements: supplements{ - folder: filepath.Join("$TRASH$", "blur"), - }, + profile: "blur", + supplement: filepath.Join("$TRASH$", "blur"), actionTransfer: true, assert: func(folder, file string, pi *common.PathInfo, statics *common.StaticInfo, entry *pfTE) { - Expect(folder).To(Equal(filepath.Join(pi.Origin, entry.supplements.folder)), because(entry.reasons.folder)) + Expect(folder).To(Equal(filepath.Join(pi.Origin, entry.supplement)), because(entry.reasons.folder)) Expect(file).To(Equal(pi.Item.Extension.Name), because(entry.reasons.file)) }, }), @@ -179,16 +186,14 @@ var _ = Describe("PathFinder", Ordered, func() { folder: "not modify folder to enable cuddle", file: "cuddled file needs to be disambiguated from the input", }, - profile: "blur", - supplements: supplements{ - file: fmt.Sprintf("%v.%v", "$TRASH$", "blur"), - }, + profile: "blur", + supplement: fmt.Sprintf("%v.%v", "$TRASH$", "blur"), actionTransfer: true, cuddle: true, assert: func(folder, file string, pi *common.PathInfo, statics *common.StaticInfo, entry *pfTE) { Expect(folder).To(Equal(pi.Origin), because(entry.reasons.folder)) supplemented := filing.SupplementFilename( - pi.Item.Extension.Name, entry.supplements.file, statics, + pi.Item.Extension.Name, entry.supplement, statics, ) Expect(file).To(Equal(supplemented), because(entry.reasons.file, file)) }, @@ -217,14 +222,12 @@ var _ = Describe("PathFinder", Ordered, func() { folder: "transparency, result should take place of input in same folder", file: "file should be moved out of the way and not cuddled", }, - scheme: "blur-sf", - profile: "blur", - supplements: supplements{ - folder: filepath.Join("$TRASH$", "blur-sf", "blur"), - }, + scheme: "blur-sf", + profile: "blur", + supplement: filepath.Join("$TRASH$", "blur-sf", "blur"), actionTransfer: true, assert: func(folder, file string, pi *common.PathInfo, statics *common.StaticInfo, entry *pfTE) { - Expect(folder).To(Equal(filepath.Join(pi.Origin, entry.supplements.folder)), because(entry.reasons.folder)) + Expect(folder).To(Equal(filepath.Join(pi.Origin, entry.supplement)), because(entry.reasons.folder)) Expect(file).To(Equal(pi.Item.Extension.Name), because(entry.reasons.file)) }, }), @@ -238,14 +241,12 @@ var _ = Describe("PathFinder", Ordered, func() { folder: "transparency, result should take place of input in same folder", file: "file should be moved out of the way and not cuddled", }, - scheme: "blur-sf", - profile: "sf", - supplements: supplements{ - folder: filepath.Join("$TRASH$", "blur-sf", "sf"), - }, + scheme: "blur-sf", + profile: "sf", + supplement: filepath.Join("$TRASH$", "blur-sf", "sf"), actionTransfer: true, assert: func(folder, file string, pi *common.PathInfo, statics *common.StaticInfo, entry *pfTE) { - Expect(folder).To(Equal(filepath.Join(pi.Origin, entry.supplements.folder)), because(entry.reasons.folder)) + Expect(folder).To(Equal(filepath.Join(pi.Origin, entry.supplement)), because(entry.reasons.folder)) Expect(file).To(Equal(pi.Item.Extension.Name), because(entry.reasons.file)) }, }), @@ -259,18 +260,15 @@ var _ = Describe("PathFinder", Ordered, func() { folder: "not modify folder to enable cuddle", file: "cuddled file needs to be disambiguated from the input", }, - scheme: "blur-sf", - profile: "blur", - supplements: supplements{ - folder: "", - file: "$TRASH$.blur-sf.blur", - }, + scheme: "blur-sf", + profile: "blur", + supplement: "$TRASH$.blur-sf.blur", actionTransfer: true, cuddle: true, assert: func(folder, file string, pi *common.PathInfo, statics *common.StaticInfo, entry *pfTE) { Expect(folder).To(Equal(pi.Origin), because(entry.reasons.folder)) supplemented := filing.SupplementFilename( - pi.Item.Extension.Name, entry.supplements.file, statics, + pi.Item.Extension.Name, entry.supplement, statics, ) Expect(file).To(Equal(supplemented), because(entry.reasons.file, file)) }, @@ -285,18 +283,15 @@ var _ = Describe("PathFinder", Ordered, func() { folder: "not modify folder to enable cuddle", file: "cuddled file needs to be disambiguated from the input", }, - scheme: "blur-sf", - profile: "sf", - supplements: supplements{ - folder: "", - file: "$TRASH$.blur-sf.sf", - }, + scheme: "blur-sf", + profile: "sf", + supplement: "$TRASH$.blur-sf.sf", actionTransfer: true, cuddle: true, assert: func(folder, file string, pi *common.PathInfo, statics *common.StaticInfo, entry *pfTE) { Expect(folder).To(Equal(pi.Origin), because(entry.reasons.folder)) supplemented := filing.SupplementFilename( - pi.Item.Extension.Name, entry.supplements.file, statics, + pi.Item.Extension.Name, entry.supplement, statics, ) Expect(file).To(Equal(supplemented), because(entry.reasons.file)) }, @@ -312,12 +307,10 @@ var _ = Describe("PathFinder", Ordered, func() { folder: "transparency, result should take place of input in same folder", file: "file should be moved out of the way and not cuddled", }, - supplements: supplements{ - folder: filepath.Join("$TRASH$", "ADHOC"), - }, + supplement: filepath.Join("$TRASH$", "ADHOC"), actionTransfer: true, assert: func(folder, file string, pi *common.PathInfo, statics *common.StaticInfo, entry *pfTE) { - Expect(folder).To(Equal(filepath.Join(pi.Origin, entry.supplements.folder)), because(entry.reasons.folder)) + Expect(folder).To(Equal(filepath.Join(pi.Origin, entry.supplement)), because(entry.reasons.folder)) Expect(file).To(Equal(pi.Item.Extension.Name), because(entry.reasons.file)) }, }), @@ -345,14 +338,12 @@ var _ = Describe("PathFinder", Ordered, func() { folder: "transparency, result should take place of input in same folder", file: "file should be moved out of the way and not cuddled", }, - profile: "blur", - trash: filepath.Join("foo", "sessions", "scan01", "rubbish"), - supplements: supplements{ - folder: filepath.Join("$TRASH$", "blur"), - }, + profile: "blur", + trash: filepath.Join("foo", "sessions", "scan01", "rubbish"), + supplement: filepath.Join("$TRASH$", "blur"), actionTransfer: true, assert: func(folder, file string, pi *common.PathInfo, statics *common.StaticInfo, entry *pfTE) { - Expect(folder).To(Equal(filepath.Join(entry.trash, entry.supplements.folder)), because(entry.reasons.folder, folder)) + Expect(folder).To(Equal(filepath.Join(entry.trash, entry.supplement)), because(entry.reasons.folder, folder)) Expect(file).To(Equal(pi.Item.Extension.Name), because(entry.reasons.file)) }, }), @@ -381,15 +372,13 @@ var _ = Describe("PathFinder", Ordered, func() { folder: "transparency, result should take place of input in same folder", file: "file should be moved out of the way", }, - scheme: "blur-sf", - profile: "blur", - trash: filepath.Join("foo", "sessions", "scan01", "rubbish"), - supplements: supplements{ - folder: filepath.Join("rubbish", "$TRASH$", "blur-sf", "blur"), - }, + scheme: "blur-sf", + profile: "blur", + trash: filepath.Join("foo", "sessions", "scan01", "rubbish"), + supplement: filepath.Join("rubbish", "$TRASH$", "blur-sf", "blur"), actionTransfer: true, assert: func(folder, file string, pi *common.PathInfo, statics *common.StaticInfo, entry *pfTE) { - Expect(folder).To(Equal(filepath.Join(pi.Origin, entry.supplements.folder)), because(entry.reasons.folder)) + Expect(folder).To(Equal(filepath.Join(pi.Origin, entry.supplement)), because(entry.reasons.folder)) Expect(file).To(Equal(pi.Item.Extension.Name), because(entry.reasons.file)) }, }), @@ -403,15 +392,13 @@ var _ = Describe("PathFinder", Ordered, func() { folder: "transparency, result should take place of input in same folder", file: "file should be moved out of the way", }, - scheme: "blur-sf", - profile: "sf", - trash: filepath.Join("foo", "sessions", "scan01", "rubbish"), - supplements: supplements{ - folder: filepath.Join("rubbish", "$TRASH$", "blur-sf", "sf"), - }, + scheme: "blur-sf", + profile: "sf", + trash: filepath.Join("foo", "sessions", "scan01", "rubbish"), + supplement: filepath.Join("rubbish", "$TRASH$", "blur-sf", "sf"), actionTransfer: true, assert: func(folder, file string, pi *common.PathInfo, statics *common.StaticInfo, entry *pfTE) { - Expect(folder).To(Equal(filepath.Join(pi.Origin, entry.supplements.folder)), because(entry.reasons.folder)) + Expect(folder).To(Equal(filepath.Join(pi.Origin, entry.supplement)), because(entry.reasons.folder)) Expect(file).To(Equal(pi.Item.Extension.Name), because(entry.reasons.file)) }, }), @@ -427,11 +414,9 @@ var _ = Describe("PathFinder", Ordered, func() { folder: "no transfer required", file: "input file left alone", }, - profile: "blur", - output: filepath.Join("foo", "sessions", "scan01", "results"), - supplements: supplements{ - folder: filepath.Join("$TRASH$", "blur"), - }, + profile: "blur", + output: filepath.Join("foo", "sessions", "scan01", "results"), + supplement: filepath.Join("$TRASH$", "blur"), actionTransfer: true, assert: func(folder, file string, pi *common.PathInfo, statics *common.StaticInfo, entry *pfTE) { Expect(folder).To(BeEmpty(), because(entry.reasons.folder, folder)) @@ -446,14 +431,12 @@ var _ = Describe("PathFinder", Ordered, func() { folder: "result should be send to supplemented output folder", file: "filename only needs to match input filename because the folder is supplemented", }, - profile: "blur", - output: filepath.Join("foo", "sessions", "scan01", "results"), - supplements: supplements{ - folder: "blur", - }, + profile: "blur", + output: filepath.Join("foo", "sessions", "scan01", "results"), + supplement: "blur", assert: func(folder, file string, pi *common.PathInfo, statics *common.StaticInfo, entry *pfTE) { supplemented := filing.SupplementFolder( - entry.output, entry.supplements.folder, + entry.output, entry.supplement, ) Expect(folder).To(Equal(supplemented), because(entry.reasons.folder, folder)) Expect(file).To(Equal(pi.Item.Extension.Name), because(entry.reasons.file)) @@ -469,12 +452,9 @@ var _ = Describe("PathFinder", Ordered, func() { folder: "no transfer required", file: "input file left alone", }, - scheme: "blur-sf", - profile: "blur", - output: filepath.Join("foo", "sessions", "scan01", "results"), - supplements: supplements{ - folder: filepath.Join("rubbish", "$TRASH$", "blur-sf", "blur"), - }, + scheme: "blur-sf", + profile: "blur", + output: filepath.Join("foo", "sessions", "scan01", "results"), actionTransfer: true, assert: func(folder, file string, pi *common.PathInfo, statics *common.StaticInfo, entry *pfTE) { Expect(folder).To(BeEmpty(), because(entry.reasons.folder)) @@ -491,12 +471,9 @@ var _ = Describe("PathFinder", Ordered, func() { folder: "no transfer required", file: "input file left alone", }, - scheme: "blur-sf", - profile: "sf", - output: filepath.Join("foo", "sessions", "scan01", "results"), - supplements: supplements{ - folder: filepath.Join("rubbish", "$TRASH$", "blur-sf", "sf"), - }, + scheme: "blur-sf", + profile: "sf", + output: filepath.Join("foo", "sessions", "scan01", "results"), actionTransfer: true, assert: func(folder, file string, pi *common.PathInfo, statics *common.StaticInfo, entry *pfTE) { Expect(folder).To(BeEmpty(), because(entry.reasons.folder)) @@ -529,13 +506,11 @@ var _ = Describe("PathFinder", Ordered, func() { folder: "result should be send to supplemented output folder", file: "filename only needs to match input filename because the folder is supplemented", }, - output: filepath.Join("foo", "sessions", "scan01", "results"), - supplements: supplements{ - folder: "ADHOC", - }, + output: filepath.Join("foo", "sessions", "scan01", "results"), + supplement: "ADHOC", assert: func(folder, file string, pi *common.PathInfo, statics *common.StaticInfo, entry *pfTE) { supplemented := filing.SupplementFolder( - entry.output, entry.supplements.folder, + entry.output, entry.supplement, ) Expect(folder).To(Equal(supplemented), because(entry.reasons.folder)) Expect(file).To(Equal(pi.Item.Extension.Name), because(entry.reasons.file)) diff --git a/src/app/proxy/user/interaction.go b/src/app/proxy/user/interaction.go index 9d295ab..08fca23 100644 --- a/src/app/proxy/user/interaction.go +++ b/src/app/proxy/user/interaction.go @@ -72,7 +72,7 @@ func (u *interaction) navigate(ci common.ClientTraverseInfo, return result, err } -func randomEmoji() string { +func randemoji() string { return string(emojis[rand.Intn(len(emojis))]) //nolint:gosec // foo } diff --git a/src/app/proxy/user/model.go b/src/app/proxy/user/model.go index 6d0afc2..4f138c5 100644 --- a/src/app/proxy/user/model.go +++ b/src/app/proxy/user/model.go @@ -12,6 +12,8 @@ import ( "github.com/snivilised/pixa/src/app/proxy/common" ) +type actionType string + type JobDescription struct { Scheme string Profile string @@ -27,6 +29,7 @@ type Summary struct { } type model struct { + inputs *common.ShrinkCommandInputs executable string status string workload uint @@ -117,7 +120,7 @@ func (m *model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { m.latest.Destination = msg.Destination m.latest.Scheme = msg.Scheme m.latest.Profile = msg.Profile - m.latest.emoji = randomEmoji() + m.latest.emoji = randemoji() m.latest.err = msg.Err m.status = "🚀 progressing" @@ -173,27 +176,45 @@ func (m *model) View() string { executable := fmt.Sprintf("%v %v", common.Definitions.Pixa.Emoji, m.executable) scheme := lo.Ternary(m.latest.Scheme != "", m.latest.Scheme, "[NONE]") profile := lo.Ternary(m.latest.Profile != "", m.latest.Profile, "[NONE]") - info := fmt.Sprintf("scheme: '%v', profile: '%v'", scheme, profile) + executing := lo.TernaryF(m.di.IsDryRun(), + func() string { + return "⛔ dry with" + }, + func() string { + return "🌀 go using" + }, + ) + wpf := m.inputs.Root.WorkerPoolFam.Native + cpus := lo.TernaryF(wpf.NoWorkers > 1 || wpf.CPU, + func() string { + return fmt.Sprintf("%v CPUs", fmt.Sprintf("%v", wpf.CPU)) + }, + func() string { + return "single CPU" + }, + ) + + action := fmt.Sprintf("%v %v", executing, cpus) + info := fmt.Sprintf("action: '%v', scheme: '%v', profile: '%v'", action, scheme, profile) bc := bodyContent{ source: m.latest.Source, destination: m.latest.Destination, emoji: m.latest.emoji, } - dry := lo.Ternary(m.di.IsDryRun(), "⛔", "🌀") e := lo.Ternary(m.latest.err != nil, fmt.Sprintf("💥 %v", m.latest.err), "💫 ok", ) latestView := fmt.Sprintf( ` - - %v status(%v) %v: %v + - %v status(%v): %v --> info: %v %v --> error: %v --> progress: %v of %v `, - m.spinner.View(), executable, dry, m.status, + m.spinner.View(), executable, m.status, info, bc.view(), e, diff --git a/src/app/proxy/user/ui-linear.go b/src/app/proxy/user/ui-linear.go index 0814f66..16cda5d 100644 --- a/src/app/proxy/user/ui-linear.go +++ b/src/app/proxy/user/ui-linear.go @@ -25,7 +25,7 @@ func (ui *linearUI) Traverse(di common.DriverTraverseInfo) (*nav.TraverseResult, // we could simple call Next, then call the principal, but we // could change the meaning of next which automatically calls principal // - with := clearResumeFromWith(di.RunWith()) + with := di.RunWith() if _, err := ui.navigate(di, clearResumeFromWith(with)); err != nil { return nil, errors.Wrap(err, "shrink look-ahead phase failed") @@ -42,7 +42,7 @@ func (ui *linearUI) Tick(msg *common.ProgressMsg) { bc := bodyContent{ source: msg.Source, destination: msg.Destination, - emoji: randomEmoji(), + emoji: randemoji(), } fmt.Printf( diff --git a/src/app/proxy/user/ui-textual.go b/src/app/proxy/user/ui-textual.go index e208e76..cd832ef 100644 --- a/src/app/proxy/user/ui-textual.go +++ b/src/app/proxy/user/ui-textual.go @@ -33,6 +33,7 @@ func (ui *textualUI) Decorate(target *nav.LabelledTraverseCallback) *nav.Labelle func (ui *textualUI) Traverse(di common.DriverTraverseInfo, ) (*nav.TraverseResult, error) { ui.m = &model{ + inputs: ui.inputs, executable: ui.inputs.Root.Configs.Advanced.Executable().Symbol(), status: "🔎 discovering ...", latest: JobDescription{ diff --git a/src/app/proxy/user/walk-info.go b/src/app/proxy/user/walk-info.go index ba95977..b69214c 100644 --- a/src/app/proxy/user/walk-info.go +++ b/src/app/proxy/user/walk-info.go @@ -11,14 +11,14 @@ type walkInfo struct { activeOptionsFn nav.TraverseOptionFn with nav.CreateNewRunnerWith resumption *nav.Resumption - dryRun bool + inputs *common.ShrinkCommandInputs } func NewWalkInfo(discoverOptionsFn nav.TraverseOptionFn, principalOptionsFn nav.TraverseOptionFn, with nav.CreateNewRunnerWith, resumption *nav.Resumption, - dryRun bool, + inputs *common.ShrinkCommandInputs, ) common.DriverTraverseInfo { return &walkInfo{ discoverOptionsFn: discoverOptionsFn, @@ -26,7 +26,7 @@ func NewWalkInfo(discoverOptionsFn nav.TraverseOptionFn, activeOptionsFn: discoverOptionsFn, with: with, resumption: resumption, - dryRun: dryRun, + inputs: inputs, } } @@ -43,7 +43,7 @@ func (wi *walkInfo) Resumption() *nav.Resumption { } func (wi *walkInfo) IsDryRun() bool { - return wi.dryRun + return wi.inputs.Root.PreviewFam.Native.DryRun } func (wi *walkInfo) Next() {