diff --git a/internal/plugin/config.go b/internal/plugin/config.go index ce2536de..86e919aa 100644 --- a/internal/plugin/config.go +++ b/internal/plugin/config.go @@ -1,8 +1,11 @@ package plugin import ( + "fmt" + "strings" "time" + "github.com/bmatcuk/doublestar" "github.com/meltwater/drone-cache/storage/backend/azure" "github.com/meltwater/drone-cache/storage/backend/filesystem" "github.com/meltwater/drone-cache/storage/backend/gcs" @@ -38,3 +41,25 @@ type Config struct { Azure azure.Config GCS gcs.Config } + +func (c *Config) HandleMount() error { + mountLen := len(c.Mount) + if mountLen > 0 { + for i, mount := range c.Mount { + if strings.Contains(mount, "**") { + // Remove the glob from the original mount list + c.Mount[i] = c.Mount[mountLen-1] + c.Mount = c.Mount[:mountLen-1] + + globMounts, err := doublestar.Glob(mount) + if err != nil { + return fmt.Errorf("glob handle mount error <%s>, %w", mount, err) + } + + c.Mount = append(c.Mount, globMounts...) + } + } + } + + return nil +} diff --git a/internal/plugin/config_test.go b/internal/plugin/config_test.go new file mode 100644 index 00000000..aacd8092 --- /dev/null +++ b/internal/plugin/config_test.go @@ -0,0 +1,94 @@ +package plugin + +import ( + "fmt" + "os" + "reflect" + "strings" + "testing" + "time" + + "github.com/meltwater/drone-cache/archive" + "github.com/meltwater/drone-cache/test" +) + +const ( + testRoot = "testdata" + defaultStorageOperationTimeout = 5 * time.Second +) + +func TestHandleMount(t *testing.T) { + test.Ok(t, os.Mkdir(testRoot, 0755)) + t.Cleanup(func() { + os.RemoveAll(testRoot) + }) + cases := []struct { + name string + mounts []string + expectedMounts []string + makeFiles func() + }{ + { + name: "handle-mount-single", + mounts: []string{"test/single"}, + expectedMounts: []string{"test/single"}, + makeFiles: func() {}, + }, + { + name: "handle-mount-nested", + mounts: []string{"test/a", "test/b"}, + expectedMounts: []string{"test/a", "test/b"}, + makeFiles: func() {}, + }, + { + name: "handle-mount-glob-empty", + mounts: []string{"test/**", "test/b"}, + expectedMounts: []string{"test/b"}, + makeFiles: func() {}, + }, + { + name: "handle-mount-glob-notempty", + mounts: []string{fmt.Sprintf("%s/%s", testRoot, "test/**")}, + expectedMounts: []string{ + fmt.Sprintf("%s/%s", testRoot, "test/nestedA"), + fmt.Sprintf("%s/%s", testRoot, "test/nestedB"), + }, + makeFiles: func() { + // Make test directories for glob to work properly + os.MkdirAll(fmt.Sprintf("%s/%s", testRoot, "test/nestedA"), 0755) + os.MkdirAll(fmt.Sprintf("%s/%s", testRoot, "test/nestedB"), 0755) + }, + }, + } + + for _, tc := range cases { + c := defaultConfig() + c.Mount = tc.mounts + + tc.makeFiles() + test.Ok(t, c.HandleMount()) + + test.Assert(t, reflect.DeepEqual(c.Mount, tc.expectedMounts), + "expected mount differs from handled mount result:\nexpected: %v\ngot:%v", tc.expectedMounts, c.Mount) + } +} + +// Config plugin configuration + +func defaultConfig() *Config { + return &Config{ + CompressionLevel: archive.DefaultCompressionLevel, + StorageOperationTimeout: defaultStorageOperationTimeout, + Override: true, + } +} + +func containsGlob(a []string) bool { + for _, v := range a { + if strings.Contains(v, "**") { + return true + } + } + + return false +} diff --git a/internal/plugin/plugin.go b/internal/plugin/plugin.go index cfbd65c2..8835f848 100644 --- a/internal/plugin/plugin.go +++ b/internal/plugin/plugin.go @@ -6,9 +6,7 @@ import ( "fmt" "os" "path/filepath" - "strings" - "github.com/bmatcuk/doublestar" "github.com/go-kit/log" "github.com/go-kit/log/level" "github.com/meltwater/drone-cache/archive" @@ -123,21 +121,8 @@ func (p *Plugin) Exec() error { // nolint: funlen,cyclop ) // 4. Glob match mounts if doublestar paths exist - for i, mount := range p.Config.Mount { - if strings.Contains(mount, "**") { - mountLen := len(p.Config.Mount) - - // Remove the glob from the original mount list - p.Config.Mount[i] = p.Config.Mount[mountLen-1] - p.Config.Mount = p.Config.Mount[:mountLen-1] - - globMounts, err := doublestar.Glob(mount) - if err != nil { - return fmt.Errorf("glob mount error <%s>, %w", mount, err) - } - - p.Config.Mount = append(p.Config.Mount, globMounts...) - } + if err = p.Config.HandleMount(); err != nil { + return fmt.Errorf("exec handle mount call, %w", err) } // 5. Select mode diff --git a/internal/plugin/plugin_test.go b/internal/plugin/plugin_test.go index 9bd0006b..a8498698 100644 --- a/internal/plugin/plugin_test.go +++ b/internal/plugin/plugin_test.go @@ -149,7 +149,9 @@ func TestPlugin(t *testing.T) { c := defaultConfig() setup(t, c, name) paths := tc.mount(tc.name) - mount(c, paths...) + c = mount(c, paths...) + test.Ok(t, c.HandleMount()) + cacheKey(c, tc.cacheKey) format(c, f) @@ -168,7 +170,7 @@ func TestPlugin(t *testing.T) { restoreRoot, cleanup := test.CreateTempDir(t, sanitize(name), testRootMoved) t.Cleanup(cleanup) - for _, p := range paths { + for _, p := range c.Mount { rel, err := filepath.Rel(testRootMounted, p) test.Ok(t, err) dst := filepath.Join(restoreRoot, rel) @@ -189,7 +191,7 @@ func TestPlugin(t *testing.T) { } // Compare - test.EqualDirs(t, restoreRoot, testRootMounted, paths) + test.EqualDirs(t, restoreRoot, testRootMounted, c.Mount) }) } } @@ -220,6 +222,7 @@ func restore(c *Config) *Config { func mount(c *Config, mount ...string) *Config { c.Mount = mount + return c } @@ -321,25 +324,21 @@ func exampleFileTreeWithSymlinks(t *testing.T, name string, content []byte) []st func exampleNestedFileTreeWithGlob(t *testing.T, name string, content []byte) []string { name = sanitize(name) - name1 := fmt.Sprintf("%s1", name) - dir, cleanup := test.CreateTempDir(t, name, testRootMounted) - t.Cleanup(cleanup) + dir, dirClean := test.CreateTempFilesInDir(t, name, content, testRootMounted) + t.Cleanup(dirClean) - nestedDir, nestedDirClean := test.CreateTempDir(t, name, dir) + _, nestedDirClean := test.CreateTempFilesInDir(t, name, content, dir) t.Cleanup(nestedDirClean) - nestedFile, nestedFileClean := test.CreateTempFile(t, name, content, nestedDir) - t.Cleanup(nestedFileClean) - - nestedDir1, nestedDirClean1 := test.CreateTempDir(t, name1, dir) + _, nestedDirClean1 := test.CreateTempFilesInDir(t, name, content, dir) t.Cleanup(nestedDirClean1) - _, nestedFileClean1 := test.CreateTempFile(t, name1, content, nestedDir1) - t.Cleanup(nestedFileClean1) + file, fileClean := test.CreateTempFile(t, name, content, dir) + t.Cleanup(fileClean) - globPath := fmt.Sprintf("%s/**/%s", testRootMounted, nestedDir1) - return []string{nestedDir, nestedFile, globPath} + globPath := fmt.Sprintf("%s/**/", testRootMounted) + return []string{file, globPath} } // Setup