From df82c8dce9a54f33e2642c1c3567437645fbb33a Mon Sep 17 00:00:00 2001 From: Hiromu OCHIAI Date: Fri, 6 Mar 2020 13:50:29 +0200 Subject: [PATCH] Use Options to pass which files to be skipped --- all_test.go | 18 +++++++-- copy.go | 46 +++++++++++------------ options.go | 5 +++ testdata/case06/README.md | 3 ++ testdata/case06/caseFilesToSkip/README.md | 0 testdata/case06/dir_skip/README.md | 1 + testdata/case06/file_skip | 1 + 7 files changed, 47 insertions(+), 27 deletions(-) delete mode 100644 testdata/case06/caseFilesToSkip/README.md create mode 100644 testdata/case06/dir_skip/README.md create mode 100644 testdata/case06/file_skip diff --git a/all_test.go b/all_test.go index 444ef82..cd91b80 100644 --- a/all_test.go +++ b/all_test.go @@ -3,6 +3,7 @@ package copy import ( "os" "path/filepath" + "strings" "testing" . "github.com/otiai10/mint" @@ -139,11 +140,20 @@ func TestCopy(t *testing.T) { Expect(t, err).ToBe(nil) }) - When(t, "try to copy a directory with subdirectories to skip", func(t *testing.T) { - err := CopyButSkipSome("testdata/case06", "testdata.copy/case06", []string{"testdata/case06/caseFilesToSkip"}) + When(t, "Options.Skip provided", func(t *testing.T) { + opt := Options{Skip: func(src string) bool { return strings.HasSuffix(src, "_skip") }} + err := Copy("testdata/case06", "testdata.copy/case06", opt) Expect(t, err).ToBe(nil) - info, err := os.Stat("./testdata.copy/case06/caseFilesToSkip/README.md") - Expect(t, err).Not().ToBe(nil) + info, err := os.Stat("./testdata.copy/case06/dir_skip") + Expect(t, info).ToBe(nil) + Expect(t, os.IsNotExist(err)).ToBe(true) + + info, err = os.Stat("./testdata.copy/case06/file_skip") Expect(t, info).ToBe(nil) + Expect(t, os.IsNotExist(err)).ToBe(true) + + info, err = os.Stat("./testdata.copy/case06/README.md") + Expect(t, info).Not().ToBe(nil) + Expect(t, err).ToBe(nil) }) } diff --git a/copy.go b/copy.go index ec1baf8..eea5f80 100644 --- a/copy.go +++ b/copy.go @@ -16,30 +16,19 @@ const ( // Copy copies src to dest, doesn't matter if src is a directory or a file func Copy(src, dest string, opt ...Options) error { - return CopyButSkipSome(src, dest, nil, opt...) -} - -// Copy copies src to dest, doesn't matter if src is a directory or a file. -func CopyButSkipSome(src, dest string, toSkip []string, opt ...Options) error { - toSkipMap := make(map[string]struct{}) - for i := 0; i < len(toSkip); i++ { - toSkipMap[filepath.FromSlash(toSkip[i])] = struct{}{} - } - - opt = append(opt, DefaultOptions) info, err := os.Lstat(src) if err != nil { return err } - - return copy(src, dest, toSkipMap, info, opt[0]) + return copy(src, dest, info, assure(opt...)) } // copy dispatches copy-funcs according to the mode. // Because this "copy" could be called recursively, // "info" MUST be given here, NOT nil. -func copy(src, dest string, toSkip map[string]struct{}, info os.FileInfo, opt Options) error { - if _, isToSkip := toSkip[src]; isToSkip { +func copy(src, dest string, info os.FileInfo, opt Options) error { + + if opt.Skip(src) { return nil } @@ -48,7 +37,7 @@ func copy(src, dest string, toSkip map[string]struct{}, info os.FileInfo, opt Op } if info.IsDir() { - return dcopy(src, dest, toSkip, info, opt) + return dcopy(src, dest, info, opt) } return fcopy(src, dest, info) } @@ -85,7 +74,7 @@ func fcopy(src, dest string, info os.FileInfo) (err error) { // dcopy is for a directory, // with scanning contents inside the directory // and pass everything to "copy" recursively. -func dcopy(srcdir, destdir string, toSkip map[string]struct{}, info os.FileInfo, opt Options) (err error) { +func dcopy(srcdir, destdir string, info os.FileInfo, opt Options) (err error) { originalMode := info.Mode() @@ -103,7 +92,7 @@ func dcopy(srcdir, destdir string, toSkip map[string]struct{}, info os.FileInfo, for _, content := range contents { cs, cd := filepath.Join(srcdir, content.Name()), filepath.Join(destdir, content.Name()) - if err := copy(cs, cd, toSkip, content, opt); err != nil { + if err := copy(cs, cd, content, opt); err != nil { // If any error, exit immediately return err } @@ -114,10 +103,6 @@ func dcopy(srcdir, destdir string, toSkip map[string]struct{}, info os.FileInfo, func onsymlink(src, dest string, info os.FileInfo, opt Options) error { - if opt.OnSymlink == nil { - opt.OnSymlink = DefaultOptions.OnSymlink - } - switch opt.OnSymlink(src) { case Shallow: return lcopy(src, dest) @@ -130,7 +115,7 @@ func onsymlink(src, dest string, info os.FileInfo, opt Options) error { if err != nil { return err } - return copy(orig, dest, nil, info, opt) + return copy(orig, dest, info, opt) case Skip: fallthrough default: @@ -163,3 +148,18 @@ func chmod(dir string, mode os.FileMode, reported *error) { *reported = err } } + +// assure Options struct, should be called only once. +// All optional values MUST NOT BE nil/zero after assured. +func assure(opts ...Options) Options { + if len(opts) == 0 { + return DefaultOptions + } + if opts[0].OnSymlink == nil { + opts[0].OnSymlink = DefaultOptions.OnSymlink + } + if opts[0].Skip == nil { + opts[0].Skip = DefaultOptions.Skip + } + return opts[0] +} diff --git a/options.go b/options.go index 4053a3f..f51cdfb 100644 --- a/options.go +++ b/options.go @@ -4,6 +4,8 @@ package copy type Options struct { // OnSymlink can specify what to do on symlink OnSymlink func(p string) SymlinkAction + // Skip can specify which files should be skipped + Skip func(src string) bool } // SymlinkAction represents what to do on symlink. @@ -23,4 +25,7 @@ var DefaultOptions = Options{ OnSymlink: func(string) SymlinkAction { return Shallow }, + Skip: func(string) bool { + return false + }, } diff --git a/testdata/case06/README.md b/testdata/case06/README.md index e69de29..461e401 100644 --- a/testdata/case06/README.md +++ b/testdata/case06/README.md @@ -0,0 +1,3 @@ +# Case 06 + +When `Options.Skip` is provided and returns `true`, src files should be skipped. \ No newline at end of file diff --git a/testdata/case06/caseFilesToSkip/README.md b/testdata/case06/caseFilesToSkip/README.md deleted file mode 100644 index e69de29..0000000 diff --git a/testdata/case06/dir_skip/README.md b/testdata/case06/dir_skip/README.md new file mode 100644 index 0000000..5ab2f8a --- /dev/null +++ b/testdata/case06/dir_skip/README.md @@ -0,0 +1 @@ +Hello \ No newline at end of file diff --git a/testdata/case06/file_skip b/testdata/case06/file_skip new file mode 100644 index 0000000..5ab2f8a --- /dev/null +++ b/testdata/case06/file_skip @@ -0,0 +1 @@ +Hello \ No newline at end of file