diff --git a/.vscode/settings.json b/.vscode/settings.json index bce455e..a4eeef9 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -4,10 +4,13 @@ "--fast" ], "cSpell.words": [ + "beezledub", "bodyclose", "chardata", "clif", "cmds", + "cmock", + "cmocks", "cobrass", "cubiest", "deadcode", @@ -19,6 +22,7 @@ "errcheck", "exportloopref", "extendio", + "faydeaudeau", "fieldalignment", "GOARCH", "goconst", diff --git a/src/app/command/shrink-cmd.go b/src/app/command/shrink-cmd.go index 2e0d2ac..01513e5 100644 --- a/src/app/command/shrink-cmd.go +++ b/src/app/command/shrink-cmd.go @@ -107,6 +107,9 @@ func (b *Bootstrap) buildShrinkCommand(container *assistant.CobraContainer) *cob shrinkPS.Native.ThirdPartySet.KnownBy, ) + // changed is incorrect; it only contains the third party args, + // all the native args are being omitted + shrinkPS.Native.ThirdPartySet.LongChangedCL = changed fmt.Printf("%v %v Running shrink, with options: '%v', args: '%v'\n", diff --git a/src/app/proxy/enter-shrink.go b/src/app/proxy/enter-shrink.go index 9aada2d..2700c02 100644 --- a/src/app/proxy/enter-shrink.go +++ b/src/app/proxy/enter-shrink.go @@ -102,9 +102,11 @@ func (e *ShrinkEntry) PrincipalOptionsFn(o *nav.TraverseOptions) { func (e *ShrinkEntry) createFinder() *PathFinder { finder := &PathFinder{ + Scheme: e.Inputs.Root.ProfileFam.Native.Scheme, + Profile: e.Inputs.Root.ProfileFam.Native.Profile, behaviours: strategies{ - output: inlineOutputStrategy{}, - deletion: inlineDeletionStrategy{}, + output: &inlineOutputStrategy{}, + deletion: &inlineDeletionStrategy{}, }, } diff --git a/src/app/proxy/execution-step.go b/src/app/proxy/execution-step.go index 4d4be90..2dfecdb 100644 --- a/src/app/proxy/execution-step.go +++ b/src/app/proxy/execution-step.go @@ -6,7 +6,7 @@ import ( // Step type Step interface { - Run() error + Run(*SharedRunnerInfo) error } // Sequence @@ -19,16 +19,16 @@ type Sequence []Step type magickStep struct { shared *SharedRunnerInfo thirdPartyCL clif.ThirdPartyCommandLine + scheme string + profile string sourcePath string outputPath string journalPath string } // Run -func (s *magickStep) Run() error { +func (s *magickStep) Run(*SharedRunnerInfo) error { positional := []string{s.sourcePath} - err := s.shared.program.Execute(clif.Expand(positional, s.thirdPartyCL)...) - - return err + return s.shared.program.Execute(clif.Expand(positional, s.thirdPartyCL, s.outputPath)...) } diff --git a/src/app/proxy/file-manager.go b/src/app/proxy/file-manager.go index 3286d47..521e078 100644 --- a/src/app/proxy/file-manager.go +++ b/src/app/proxy/file-manager.go @@ -1,28 +1,59 @@ package proxy import ( + "fmt" + "os" + "path/filepath" + "github.com/pkg/errors" + "github.com/snivilised/extendio/xfs/nav" "github.com/snivilised/extendio/xfs/storage" ) +const ( + beezledub = os.FileMode(0o666) +) + +// FileManager knows how to translate requests into invocations on the file +// system and nothing else. type FileManager struct { vfs storage.VirtualFS finder *PathFinder } -func (fm *FileManager) setup(source string) error { - // prepare: move existing file out of the way - +// Setup prepares for operation by moving existing file out of the way, +// if applicable. +func (fm *FileManager) Setup(item *nav.TraverseItem) error { // https://pkg.go.dev/os#Rename LinkError may result // // this might not be right. it may be that we want to leave the // original alone and create other outputs; in this scenario // we don't want to rename/move the source... // - destination := fm.finder.Destination(source) + from := &destinationInfo{ + item: item, + origin: item.Parent.Path, + transparent: true, // might come from a flag + } + + if folder, file := fm.finder.Destination(from); folder != "" { + if err := fm.vfs.MkdirAll(folder, beezledub); err != nil { + return errors.Wrapf(err, "could not create parent setup for '%v'", item.Path) + } + + destination := filepath.Join(folder, file) + + if !fm.vfs.FileExists(item.Path) { + return fmt.Errorf("source file: '%v' does not exist", item.Path) + } + + if fm.vfs.FileExists(destination) { + return fmt.Errorf("destination file: '%v' already exists", destination) + } - if err := fm.vfs.Rename(source, destination); err != nil { - return errors.Wrapf(err, "could not complete setup for '%v'", source) + if err := fm.vfs.Rename(item.Path, destination); err != nil { + return errors.Wrapf(err, "could not complete setup for '%v'", item.Path) + } } return nil @@ -40,7 +71,7 @@ func (fm *FileManager) delete(target string) error { return nil } -func (fm *FileManager) tidy() error { +func (fm *FileManager) Tidy() error { // invoke deletions // delete journal file // diff --git a/src/app/proxy/path-finder.go b/src/app/proxy/path-finder.go index 8a1c896..088f7ef 100644 --- a/src/app/proxy/path-finder.go +++ b/src/app/proxy/path-finder.go @@ -2,8 +2,65 @@ package proxy import ( "path/filepath" + "strings" + + "github.com/samber/lo" + "github.com/snivilised/extendio/xfs/nav" +) + +const ( + inlineDestinationTempl = "" +) + +type ( + templateSegments []string + pfTemplatesCollection map[string]templateSegments + pfFieldValues map[string]string ) +var ( + pfTemplates pfTemplatesCollection +) + +func init() { + pfTemplates = pfTemplatesCollection{ + // we probably have to come up with better key names... + // + "setup-inline-dest-folder": templateSegments{ + "${{OUTPUT-ROOT}}", + "${{ITEM-SUB-PATH}}", + "${{TRASH-LABEL}}", + }, + + "setup-inline-dest-file-original-ext": templateSegments{ + "${{ITEM-NAME-ORIG-EXT}}", + }, + } +} + +// expand returns a string as a result of joining the segments +func (tc pfTemplatesCollection) expand(segments ...string) string { + return filepath.Join(segments...) +} + +// evaluate returns a string representing a file system path from a +// template string containing place-holders and field values +func (tc pfTemplatesCollection) evaluate( + sourceTemplate string, + placeHolders templateSegments, + values pfFieldValues, +) string { + const ( + quantity = 1 + ) + + return lo.Reduce(placeHolders, func(acc, field string, _ int) string { + return strings.Replace(acc, field, values[field], quantity) + }, + sourceTemplate, + ) +} + // INLINE-MODE: EJECT | INLINE (should we call this a strategy? // they do the same thing but create a different output structure => OutputStrategy) // @@ -39,7 +96,7 @@ then we revert to the default which is eject(transparent) -- then other flags could adjust the transparent mode if --eject not specified, then ous=inline; des=inline -but if can be adjusted by --output , --trash +but it can be adjusted by --output , --trash -- perhaps we have a transparency mode, ie perform renames such that the new generated @@ -66,9 +123,12 @@ type strategies struct { } type PathFinder struct { - // is this item.Path or item.Path's parent folder? + Scheme string + Profile string + // Origin is the parent of the item (item.Parent) // Origin string + // only the step knows this, so this should be the parent of the output // for scheme, this would include scheme/profile // for profile, this should include profile @@ -78,8 +138,11 @@ type PathFinder struct { // perhaps represented as a slice so it can be joined with filepath.Join // // if Output Path is set, then use this as the output, but also - // create the intermediate paths in order to implement mirroring - // + // create the intermediate paths in order to implement mirroring. + // It is the output as indicated by --output. If not set, then it is + // derived: + // - sampling: (inline) -- item.parent; => item.parent/SHRINK/ + // - full: (inline) -- item.parent Output string // I think this depends on the mode (tidy/preserve) @@ -88,12 +151,100 @@ type PathFinder struct { behaviours strategies } -func (f *PathFinder) Destination(source string) string { - // may be we also return a bool that indicates weather a rename - // should be implemented or not. this depends on the appropriate - // strategy. Or if we dont need to rename, we return an empty string; - // this is the preferred solution. - return filepath.Join(f.Output, source) +type staticInfo struct { + trashLabel string + legacyLabel string +} + +type destinationInfo struct { + item *nav.TraverseItem + origin string // in:item.Parent.Path, ej:eject-path(output???) + // statics *staticInfo + transparent bool + // + // transparent=true should be the default scenario. This means + // that any changes that occur leave the file system in a state + // where nothing appears to have changed except that files have + // been modified, without name changes. This of course doesn't + // include items that end up in TRASH and can be manually deleted + // by the user. The purpose of this is to by default require + // the least amount of post-processing clean-up from the user. + // + // In sampling mode, transparent may mean something different + // because multiple files could be created for each input file. + // So, in this scenario, the original file should stay in-tact + // and the result(s) should be created into the supplementary + // location. + // + // In full mode, transparent means the input file is moved + // to a trash location. The output takes the name of the original + // file, so that by the end of processing, the resultant file + // takes the place of the source file, leaving the file system + // in a state that was the same before processing occurred. + // + // So what happens in non transparent scenario? The source file + // remains unchanged, so the user has to look at another location + // to get the result. It uses the SHRINK label to create the + // output filename; but note, we only use the SHRINK label in + // scenarios where there is a potential for a filename clash if + // the output file is in the same location as the input file + // because we want to create the least amount of friction as + // possible. This only occurs when in adhoc mode (no profile + // or scheme) +} + +// Destination returns the location of what should be used +// for the specified source path; ie when the program runs, it uses +// a source file and requires the destination location. The source +// and destination may not be n the same folder, so the source's name +// is extracted from the source path and attached to the output +// folder. +// +// should return empty string if no move is required +func (f *PathFinder) Destination(info *destinationInfo) (destinationFolder, destinationFile string) { + // TODO: we still need to get the rest of the mirror sub-path + // .///TRASH///<.item.Name>..ext + // legacyLabel := "LEGACY" + trashLabel := "TRASH" + + // this does not take into account transparent, without modification; + // ie what happens if we don;t want any supplemented paths? + + to := lo.TernaryF(f.Output != "", + func() string { + return f.Output // eject + }, + func() string { + return info.origin // inline + }, + ) + + destinationFolder = func() string { + templateFolderSegments := pfTemplates["setup-inline-dest-folder"] + templateFolderPath := pfTemplates.expand(filepath.Join(templateFolderSegments...)) + folder := pfTemplates.evaluate(templateFolderPath, templateFolderSegments, pfFieldValues{ + "${{OUTPUT-ROOT}}": to, + "${{ITEM-SUB-PATH}}": info.item.Extension.SubPath, + "${{TRASH-LABEL}}": trashLabel, + }) + folder = filepath.Clean(folder) + + return folder + }() + + destinationFile = func() string { + templateFileSegments := pfTemplates["setup-inline-dest-file-original-ext"] + templateFilePath := pfTemplates.expand(filepath.Join(templateFileSegments...)) + + file := pfTemplates.evaluate(templateFilePath, templateFileSegments, pfFieldValues{ + "${{ITEM-NAME-ORIG-EXT}}": info.item.Extension.Name, + }) + file = filepath.Clean(file) + + return file + }() + + return destinationFolder, destinationFile } /* diff --git a/src/app/proxy/runner-base.go b/src/app/proxy/runner-base.go index 490f7ab..015e094 100644 --- a/src/app/proxy/runner-base.go +++ b/src/app/proxy/runner-base.go @@ -1,7 +1,6 @@ package proxy import ( - "github.com/pkg/errors" "github.com/snivilised/cobrass" "github.com/snivilised/cobrass/src/clif" "github.com/snivilised/extendio/collections" @@ -27,6 +26,7 @@ func (r *baseRunner) profileSequence( shared: r.shared, thirdPartyCL: cl, sourcePath: itemPath, + profile: name, // outputPath: , // journalPath: , } @@ -38,15 +38,17 @@ func (r *baseRunner) schemeSequence( name, itemPath string, ) Sequence { changed := r.shared.Inputs.ParamSet.Native.ThirdPartySet.LongChangedCL - scheme, _ := r.shared.sampler.Scheme(name) // scheme already validated - sequence := make(Sequence, 0, len(scheme.Profiles)) + schemeCfg, _ := r.shared.sampler.Scheme(name) // scheme already validated + sequence := make(Sequence, 0, len(schemeCfg.Profiles)) - for _, currentProfileName := range scheme.Profiles { - cl := r.composeProfileCL(currentProfileName, changed) + for _, current := range schemeCfg.Profiles { + cl := r.composeProfileCL(current, changed) step := &magickStep{ shared: r.shared, thirdPartyCL: cl, sourcePath: itemPath, + scheme: name, + profile: current, // outputPath: , // journalPath: , } @@ -93,28 +95,7 @@ func (r *baseRunner) Run(item *nav.TraverseItem, sequence Sequence) error { iterator := collections.ForwardRunIt[Step, error](sequence, zero) each := func(s Step) error { - // TODO: need to decide a proper policy for cleaning up - // in the presence of an error. Do we allow the journal - // file to remain in place? What happens if there is a timeout? - // There are a few more things to decide about error handling. - // Perhaps we have an error policy including one that implements - // a retry. - if err := r.shared.fileManager.setup(item.Path); err != nil { - return err - } - - err := s.Run() - te := r.shared.fileManager.tidy() - - switch { - case (err != nil) && (te != nil): - return errors.Wrap(err, te.Error()) - - case (err != nil): - return err - } - - return te + return s.Run(r.shared) } while := func(_ Step, err error) bool { if resultErr == nil { @@ -127,9 +108,20 @@ func (r *baseRunner) Run(item *nav.TraverseItem, sequence Sequence) error { return err == nil } + // TODO: need to decide a proper policy for cleaning up + // in the presence of an error. Do we allow the journal + // file to remain in place? What happens if there is a timeout? + // There are a few more things to decide about error handling. + // Perhaps we have an error policy including one that implements + // a retry. + // + if err := r.shared.fileManager.Setup(item); err != nil { + return err + } + iterator.RunAll(each, while) - return resultErr + return r.shared.fileManager.Tidy() } func (r *baseRunner) Reset() { diff --git a/src/app/proxy/runner-sampler_test.go b/src/app/proxy/runner-sampler_test.go index 3f635ed..277c7e2 100644 --- a/src/app/proxy/runner-sampler_test.go +++ b/src/app/proxy/runner-sampler_test.go @@ -2,12 +2,14 @@ package proxy_test import ( "fmt" + "os" "path/filepath" . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" "github.com/snivilised/cobrass/src/assistant/configuration" ci18n "github.com/snivilised/cobrass/src/assistant/i18n" + cmocks "github.com/snivilised/cobrass/src/assistant/mocks" "github.com/snivilised/cobrass/src/clif" xi18n "github.com/snivilised/extendio/i18n" "github.com/snivilised/extendio/xfs/storage" @@ -23,8 +25,11 @@ import ( ) const ( - silent = false - verbose = true + silent = true + verbose = false + faydeaudeau = os.FileMode(0o777) + beezledub = os.FileMode(0o666) + backyardWorldsPlanet9Scan01 = "nasa/exo/Backyard Worlds - Planet 9/sessions/scan-01" ) var ( @@ -33,32 +38,32 @@ var ( _ proxy.ProfilesConfigReader = &proxy.MsProfilesConfigReader{} _ proxy.SamplerConfigReader = &proxy.MsSamplerConfigReader{} - expectedDarkEnergyExplorersScan01First2 []string - expectedDarkEnergyExplorersScan01First4 []string - expectedDarkEnergyExplorersScan01First6 []string + backyardWorldsPlanet9Scan01First2 []string + backyardWorldsPlanet9Scan01First4 []string + backyardWorldsPlanet9Scan01First6 []string ) func init() { - expectedDarkEnergyExplorersScan01First2 = []string{ - "01_Dark-Energy-Explorers_s01.jpg", - "02_Dark-Energy-Explorers_s01.jpg", + backyardWorldsPlanet9Scan01First2 = []string{ + "01_Backyard-Worlds-Planet-9_s01.jpg", + "02_Backyard-Worlds-Planet-9_s01.jpg", } - expectedDarkEnergyExplorersScan01First4 = expectedDarkEnergyExplorersScan01First2 - expectedDarkEnergyExplorersScan01First4 = append( - expectedDarkEnergyExplorersScan01First4, + backyardWorldsPlanet9Scan01First4 = backyardWorldsPlanet9Scan01First2 + backyardWorldsPlanet9Scan01First4 = append( + backyardWorldsPlanet9Scan01First4, []string{ - "03_Dark-Energy-Explorers_s01.jpg", - "04_Dark-Energy-Explorers_s01.jpg", + "03_Backyard-Worlds-Planet-9_s01.jpg", + "04_Backyard-Worlds-Planet-9_s01.jpg", }..., ) - expectedDarkEnergyExplorersScan01First6 = expectedDarkEnergyExplorersScan01First4 - expectedDarkEnergyExplorersScan01First6 = append( - expectedDarkEnergyExplorersScan01First6, + backyardWorldsPlanet9Scan01First6 = backyardWorldsPlanet9Scan01First4 + backyardWorldsPlanet9Scan01First6 = append( + backyardWorldsPlanet9Scan01First6, []string{ - "05_Dark-Energy-Explorers_s01.jpg", - "06_Dark-Energy-Explorers_s01.jpg", + "05_Backyard-Worlds-Planet-9_s01.jpg", + "06_Backyard-Worlds-Planet-9_s01.jpg", }..., ) } @@ -84,28 +89,52 @@ var _ = Describe("SamplerRunner", Ordered, func() { configPath string root string config configuration.ViperConfig - nfs storage.VirtualFS + vfs storage.VirtualFS ctrl *gomock.Controller mockProfilesReader *mocks.MockProfilesConfigReader mockSamplerReader *mocks.MockSamplerConfigReader + mockViperConfig *cmocks.MockViperConfig ) + Context("filepath", func() { + XIt("check how a single / path behaves in a join", func() { + path := "/home/virgin" + mid := "///" + appendage := "foo/${{bar}}" + result := filepath.Join(path, mid, appendage) + fmt.Printf("===> 🌀🌀🌀 RESULT: '%v'\n", result) + }) + }) + BeforeAll(func() { - nfs = storage.UseNativeFS() repo = helpers.Repo(filepath.Join("..", "..", "..")) - l10nPath = helpers.Path(repo, filepath.Join("test", "data", "l10n")) - Expect(matchers.AsDirectory(l10nPath)).To(matchers.ExistInFS(nfs)) - configPath = filepath.Join(repo, "test", "data", "configuration") - Expect(matchers.AsDirectory(configPath)).To(matchers.ExistInFS(nfs)) - - root = helpers.Scientist(nfs, "nasa-scientist-index.xml", verbose) - Expect(matchers.AsDirectory(root)).To(matchers.ExistInFS(nfs)) }) BeforeEach(func() { + vfs = storage.UseMemFS() + root = helpers.Scientist(vfs, "nasa-scientist-index.xml", silent) + Expect(matchers.AsDirectory(root)).To(matchers.ExistInFS(vfs)) + + ctrl = gomock.NewController(GinkgoT()) viper.Reset() + mockViperConfig = cmocks.NewMockViperConfig(ctrl) + mockViperConfig.EXPECT().ReadInConfig().DoAndReturn( + func() error { + return nil + }, + ).AnyTimes() + + // create a dummy config file in vfs + // + _ = vfs.MkdirAll(configPath, beezledub) + if _, err := vfs.Create(filepath.Join(configPath, helpers.PixaConfigTestFilename)); err != nil { + Fail(fmt.Sprintf("🔥 can't create dummy config (err: '%v')", err)) + } + + Expect(matchers.AsDirectory(configPath)).To(matchers.ExistInFS(vfs)) + config = &configuration.GlobalViperConfig{} config.SetConfigType(helpers.PixaConfigType) @@ -135,7 +164,6 @@ var _ = Describe("SamplerRunner", Ordered, func() { Fail(err.Error()) } - ctrl = gomock.NewController(GinkgoT()) mockProfilesReader = mocks.NewMockProfilesConfigReader(ctrl) mockSamplerReader = mocks.NewMockSamplerConfigReader(ctrl) }) @@ -148,7 +176,7 @@ var _ = Describe("SamplerRunner", Ordered, func() { func(entry *samplerTE) { mockProfilesReader.EXPECT().Read(config).DoAndReturn( func(viper configuration.ViperConfig) (proxy.ProfilesConfig, error) { - config := &proxy.MsProfilesConfig{ + stub := &proxy.MsProfilesConfig{ Profiles: proxy.ProfilesConfigMap{ "blur": clif.ChangedFlagsMap{ "strip": "true", @@ -170,13 +198,13 @@ var _ = Describe("SamplerRunner", Ordered, func() { }, } - return config, nil + return stub, nil }, ).AnyTimes() mockSamplerReader.EXPECT().Read(config).DoAndReturn( func(viper configuration.ViperConfig) (proxy.SamplerConfig, error) { - return &proxy.MsSamplerConfig{ + stub := &proxy.MsSamplerConfig{ Files: 2, Folders: 1, Schemes: proxy.MsSamplerSchemesConfig{ @@ -190,7 +218,9 @@ var _ = Describe("SamplerRunner", Ordered, func() { Profiles: []string{"adaptive", "blur"}, }, }, - }, nil + } + + return stub, nil }, ).AnyTimes() @@ -200,12 +230,14 @@ var _ = Describe("SamplerRunner", Ordered, func() { "--dry-run", "--mode", "tidy", } + args := options + args = append(args, entry.args...) bootstrap := command.Bootstrap{ - Vfs: nfs, + Vfs: vfs, } tester := helpers.CommandTester{ - Args: append(options, entry.args...), + Args: args, Root: bootstrap.Root(func(co *command.ConfigureOptionsInfo) { co.Detector = &helpers.DetectorStub{} co.Program = &helpers.ExecutorStub{ @@ -223,7 +255,7 @@ var _ = Describe("SamplerRunner", Ordered, func() { _, err := tester.Execute() Expect(err).Error().To(BeNil(), - fmt.Sprintf("should pass validation due to all flag being valid (%v)", err), + fmt.Sprintf("execution result non nil (%v)", err), ) // eventually, we should assert on files created in the virtual @@ -240,16 +272,16 @@ var _ = Describe("SamplerRunner", Ordered, func() { runnerTE: runnerTE{ given: "profile", should: "sample(first) with glob filter using the defined profile", - relative: "nasa/interstellar/Dark Energy Explorers/sessions/scan-01", + relative: backyardWorldsPlanet9Scan01, args: []string{ "--sample", "--no-files", "4", - "--files-gb", "*Energy-Explorers*", + "--files-gb", "*Backyard Worlds*", "--profile", "adaptive", "--gaussian-blur", "0.51", "--interlace", "line", }, - expected: expectedDarkEnergyExplorersScan01First4, + expected: backyardWorldsPlanet9Scan01First4, }, }), @@ -257,7 +289,7 @@ var _ = Describe("SamplerRunner", Ordered, func() { runnerTE: runnerTE{ given: "profile", should: "sample(last) with glob filter using the defined profile", - relative: "nasa/interstellar/Dark Energy Explorers/sessions/scan-01", + relative: backyardWorldsPlanet9Scan01, args: []string{ "--sample", "--last", @@ -265,7 +297,7 @@ var _ = Describe("SamplerRunner", Ordered, func() { "--files-gb", "*Energy-Explorers*", "--profile", "adaptive", }, - expected: expectedDarkEnergyExplorersScan01First4, + expected: backyardWorldsPlanet9Scan01First4, }, }), @@ -273,13 +305,13 @@ var _ = Describe("SamplerRunner", Ordered, func() { runnerTE: runnerTE{ given: "profile without no-files in args", should: "sample(first) with glob filter, using no-files from config", - relative: "nasa/interstellar/Dark Energy Explorers/sessions/scan-01", + relative: backyardWorldsPlanet9Scan01, args: []string{ "--sample", "--files-gb", "*Energy-Explorers*", "--profile", "adaptive", }, - expected: expectedDarkEnergyExplorersScan01First2, + expected: backyardWorldsPlanet9Scan01First2, }, }), @@ -287,7 +319,7 @@ var _ = Describe("SamplerRunner", Ordered, func() { runnerTE: runnerTE{ given: "profile", should: "sample with regex filter using the defined profile", - relative: "nasa/interstellar/Dark Energy Explorers/sessions/scan-01", + relative: backyardWorldsPlanet9Scan01, args: []string{ "--strip", "--interlace", "plane", "--quality", "85", "--profile", "adaptive", }, @@ -305,11 +337,11 @@ var _ = Describe("SamplerRunner", Ordered, func() { runnerTE: runnerTE{ given: "scheme", should: "sample all profiles in the scheme", - relative: "nasa/interstellar/Dark Energy Explorers/sessions/scan-01", + relative: backyardWorldsPlanet9Scan01, args: []string{ "--strip", "--interlace", "plane", "--quality", "85", "--scheme", "blur-sf", }, - expected: expectedDarkEnergyExplorersScan01First6, + expected: backyardWorldsPlanet9Scan01First6, }, }), ) diff --git a/src/app/proxy/strategy-output.go b/src/app/proxy/strategy-output.go index a867343..3bf6374 100644 --- a/src/app/proxy/strategy-output.go +++ b/src/app/proxy/strategy-output.go @@ -1,10 +1,32 @@ package proxy +// the strategies look like they don't do much, so all this +// abstraction feels like overkill. instead the path finder +// could make a one calculation of destination path depending +// on strategy, using s simple func closure, eg we could +// funcs such as inlineDestination and ejectDestination() of +// the form func(source string) string. (rename this file +// strategy-funcs) + type outputStrategy interface { + // Destination fills in the gap between the root and the destination + Destination(source string) string } type inlineOutputStrategy struct { } +func (s *inlineOutputStrategy) Destination(source string) string { + _ = source + // .//TRASH///destination/<.item.Name>..ext + return "" +} + type ejectOutputStrategy struct { } + +func (s *ejectOutputStrategy) Destination(source string) string { + _ = source + // .//TRASH///destination + return "" +} diff --git a/test/data/configuration/pixa-test.yml b/test/data/configuration/pixa-test.yml index f10d03d..ed9487b 100644 --- a/test/data/configuration/pixa-test.yml +++ b/test/data/configuration/pixa-test.yml @@ -29,4 +29,5 @@ advanced: external-program-execution-retry: 0 legacy-file-dot-suffix: LEGACY journal-file-dot-suffix: JOURNAL - trash-folder: TRASH + trash-label: TRASH + shrink-label: SHRINK