Skip to content

Commit

Permalink
Use Options to pass which files to be skipped
Browse files Browse the repository at this point in the history
  • Loading branch information
otiai10 committed Mar 6, 2020
1 parent cc1cc34 commit df82c8d
Show file tree
Hide file tree
Showing 7 changed files with 47 additions and 27 deletions.
18 changes: 14 additions & 4 deletions all_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package copy
import (
"os"
"path/filepath"
"strings"
"testing"

. "github.com/otiai10/mint"
Expand Down Expand Up @@ -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)
})
}
46 changes: 23 additions & 23 deletions copy.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
}

Expand All @@ -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)
}
Expand Down Expand Up @@ -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()

Expand All @@ -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
}
Expand All @@ -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)
Expand All @@ -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:
Expand Down Expand Up @@ -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]
}
5 changes: 5 additions & 0 deletions options.go
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -23,4 +25,7 @@ var DefaultOptions = Options{
OnSymlink: func(string) SymlinkAction {
return Shallow
},
Skip: func(string) bool {
return false
},
}
3 changes: 3 additions & 0 deletions testdata/case06/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Case 06

When `Options.Skip` is provided and returns `true`, src files should be skipped.
Empty file.
1 change: 1 addition & 0 deletions testdata/case06/dir_skip/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Hello
1 change: 1 addition & 0 deletions testdata/case06/file_skip
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Hello

0 comments on commit df82c8d

Please sign in to comment.