Skip to content

Commit

Permalink
Merge pull request #19 from otiai10/feature/skip
Browse files Browse the repository at this point in the history
Feature/skip
  • Loading branch information
otiai10 committed Mar 6, 2020
2 parents 9530851 + 99ee8e8 commit b5d0589
Show file tree
Hide file tree
Showing 6 changed files with 55 additions and 9 deletions.
20 changes: 19 additions & 1 deletion all_test.go
Expand Up @@ -3,6 +3,7 @@ package copy
import (
"os"
"path/filepath"
"strings"
"testing"

. "github.com/otiai10/mint"
Expand Down Expand Up @@ -114,7 +115,7 @@ func TestCopy(t *testing.T) {
})

When(t, "try to copy READ-not-allowed source", func(t *testing.T) {
err := Copy("testdata/case06", "testdata.copy/case06")
err := Copy("testdata/doesNotExist", "testdata.copy/doesNotExist")
Expect(t, err).Not().ToBe(nil)
})

Expand All @@ -138,4 +139,21 @@ func TestCopy(t *testing.T) {
err = os.Chmod(dest, 0755)
Expect(t, err).ToBe(nil)
})

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/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)
})
}
34 changes: 26 additions & 8 deletions copy.go
Expand Up @@ -16,21 +16,26 @@ 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 {
opt = append(opt, DefaultOptions)
info, err := os.Lstat(src)
if err != nil {
return err
}
return copy(src, dest, 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, info os.FileInfo, opt Options) error {

if opt.Skip(src) {
return nil
}

if info.Mode()&os.ModeSymlink != 0 {
return onsymlink(src, dest, info, opt)
}

if info.IsDir() {
return dcopy(src, dest, info, opt)
}
Expand Down Expand Up @@ -98,10 +103,6 @@ func dcopy(srcdir, destdir string, info os.FileInfo, opt Options) (err error) {

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 Down Expand Up @@ -133,17 +134,34 @@ func lcopy(src, dest string) error {
}

// fclose ANYHOW closes file,
// with asiging error occured BUT respecting the error already reported.
// with asiging error raised during Close,
// BUT respecting the error already reported.
func fclose(f *os.File, reported *error) {
if err := f.Close(); *reported == nil {
*reported = err
}
}

// chmod ANYHOW changes file mode,
// with asiging error occured BUT respecting the error already reported.
// with asiging error raised during Chmod,
// BUT respecting the error already reported.
func chmod(dir string, mode os.FileMode, reported *error) {
if err := os.Chmod(dir, mode); *reported == nil {
*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
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
@@ -0,0 +1,3 @@
# Case 06

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

0 comments on commit b5d0589

Please sign in to comment.