Repository: otiai10/copy
Pull request #92 (2022-10-26 06:37:05)

[Breaking Change] Skip now accepts FileInfo
Close #40

codecov-commenter: # [Codecov](https://codecov.io/gh/otiai10/copy/pull/92?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Hiromu+OCHIAI) Report
> Merging [#92](https://codecov.io/gh/otiai10/copy/pull/92?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Hiromu+OCHIAI) (46aa855) into [main](https://codecov.io/gh/otiai10/copy/commit/d69252f9c80a2f1e76a8174c142ab4f726412db7?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Hiromu+OCHIAI) (d69252f) will **decrease** coverage by `0.26%`.
> The diff coverage is `100.00%`.

```diff
@@            Coverage Diff             @@
##             main      #92      +/-   ##
==========================================
- Coverage   77.19%   76.92%   -0.27%     
==========================================
  Files           9        9              
  Lines         171      169       -2     
==========================================
- Hits          132      130       -2     
  Misses         19       19              
  Partials       20       20              
```


| [Impacted Files](https://codecov.io/gh/otiai10/copy/pull/92?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Hiromu+OCHIAI) | Coverage Δ | |
|---|---|---|
| [options.go](https://codecov.io/gh/otiai10/copy/pull/92/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Hiromu+OCHIAI#diff-b3B0aW9ucy5nbw==) | `83.33% <ø> (-2.39%)` | :arrow_down: |
| [copy.go](https://codecov.io/gh/otiai10/copy/pull/92/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Hiromu+OCHIAI#diff-Y29weS5nbw==) | `76.69% <100.00%> (+0.22%)` | :arrow_up: |

Help us with your feedback. Take ten seconds to tell us [how you rate us](https://about.codecov.io/nps?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Hiromu+OCHIAI). Have a feature suggestion? [Share it here.](https://app.codecov.io/gh/feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Hiromu+OCHIAI)


Patch:
diff --git a/README.md b/README.md
index 9335dc2..32edfd8 100644
--- a/README.md
+++ b/README.md
@@ -42,7 +42,7 @@ type Options struct {
 	OnDirExists func(src, dest string) DirExistsAction
 
 	// Skip can specify which files should be skipped
-	Skip func(src string) (bool, error)
+	Skip func(srcinfo os.FileInfo, src, dest string) (bool, error)
 
 	// PermissionControl can control permission of
 	// every entry.
@@ -80,7 +80,7 @@ type Options struct {
 ```go
 // For example...
 opt := Options{
-	Skip: func(src string) (bool, error) {
+	Skip: func(info os.FileInfo, src, dest string) (bool, error) {
 		return strings.HasSuffix(src, ".git"), nil
 	},
 }
diff --git a/copy.go b/copy.go
index 556c2b6..60643dd 100644
--- a/copy.go
+++ b/copy.go
@@ -49,12 +49,14 @@ func switchboard(src, dest string, info os.FileInfo, opt Options) (err error) {
 // Because this "copy" could be called recursively,
 // "info" MUST be given here, NOT nil.
 func copyNextOrSkip(src, dest string, info os.FileInfo, opt Options) error {
-	skip, err := opt.Skip(src)
-	if err != nil {
-		return err
-	}
-	if skip {
-		return nil
+	if opt.Skip != nil {
+		skip, err := opt.Skip(info, src, dest)
+		if err != nil {
+			return err
+		}
+		if skip {
+			return nil
+		}
 	}
 	return switchboard(src, dest, info, opt)
 }
@@ -129,18 +131,10 @@ func fcopy(src, dest string, info os.FileInfo, opt Options) (err error) {
 // and pass everything to "copy" recursively.
 func dcopy(srcdir, destdir string, info os.FileInfo, opt Options) (err error) {
 
-	_, err = os.Stat(destdir)
-	if err == nil && opt.OnDirExists != nil && destdir != opt.intent.dest {
-		switch opt.OnDirExists(srcdir, destdir) {
-		case Replace:
-			if err := os.RemoveAll(destdir); err != nil {
-				return err
-			}
-		case Untouchable:
-			return nil
-		} // case "Merge" is default behaviour. Go through.
-	} else if err != nil && !os.IsNotExist(err) {
-		return err // Unwelcome error type...!
+	if skip, err := onDirExists(opt, srcdir, destdir); err != nil {
+		return err
+	} else if skip {
+		return nil
 	}
 
 	// Make dest dir with 0755 so that everything writable.
@@ -179,6 +173,23 @@ func dcopy(srcdir, destdir string, info os.FileInfo, opt Options) (err error) {
 	return
 }
 
+func onDirExists(opt Options, srcdir, destdir string) (bool, error) {
+	_, err := os.Stat(destdir)
+	if err == nil && opt.OnDirExists != nil && destdir != opt.intent.dest {
+		switch opt.OnDirExists(srcdir, destdir) {
+		case Replace:
+			if err := os.RemoveAll(destdir); err != nil {
+				return false, err
+			}
+		case Untouchable:
+			return true, nil
+		} // case "Merge" is default behaviour. Go through.
+	} else if err != nil && !os.IsNotExist(err) {
+		return true, err // Unwelcome error type...!
+	}
+	return false, nil
+}
+
 func onsymlink(src, dest string, opt Options) error {
 	switch opt.OnSymlink(src) {
 	case Shallow:
diff --git a/options.go b/options.go
index a020e7a..bd18d56 100644
--- a/options.go
+++ b/options.go
@@ -15,7 +15,7 @@ type Options struct {
 	OnDirExists func(src, dest string) DirExistsAction
 
 	// Skip can specify which files should be skipped
-	Skip func(src string) (bool, error)
+	Skip func(srcinfo os.FileInfo, src, dest string) (bool, error)
 
 	// Specials includes special files to be copied. default false.
 	Specials bool
@@ -94,10 +94,8 @@ func getDefaultOptions(src, dest string) Options {
 		OnSymlink: func(string) SymlinkAction {
 			return Shallow // Do shallow copy
 		},
-		OnDirExists: nil, // Default behavior is "Merge".
-		Skip: func(string) (bool, error) {
-			return false, nil // Don't skip
-		},
+		OnDirExists:       nil,                // Default behavior is "Merge".
+		Skip:              nil,                // Do not skip anything
 		AddPermission:     0,                  // Add nothing
 		PermissionControl: PerservePermission, // Just preserve permission
 		Sync:              false,              // Do not sync


Test patch:
diff --git a/all_test.go b/all_test.go
index 214647c..910570a 100644
--- a/all_test.go
+++ b/all_test.go
@@ -152,7 +152,7 @@ func TestOptions_OnSymlink(t *testing.T) {
 }
 
 func TestOptions_Skip(t *testing.T) {
-	opt := Options{Skip: func(src string) (bool, error) {
+	opt := Options{Skip: func(info os.FileInfo, src, dest string) (bool, error) {
 		switch {
 		case strings.HasSuffix(src, "_skip"):
 			return true, nil
@@ -186,7 +186,7 @@ func TestOptions_Skip(t *testing.T) {
 
 	Because(t, "if Skip func returns error, Copy should be interrupted", func(t *testing.T) {
 		errInsideSkipFunc := errors.New("Something wrong inside Skip")
-		opt := Options{Skip: func(src string) (bool, error) {
+		opt := Options{Skip: func(info os.FileInfo, src, dest string) (bool, error) {
 			return false, errInsideSkipFunc
 		}}
 		err := Copy("test/data/case06", "test/data.copy/case06.01", opt)
@@ -357,9 +357,9 @@ func TestOptions_CopyRateLimit(t *testing.T) {
 
 	start := time.Now()
 	err = Copy("test/data/case16", "test/data.copy/case16", opt)
-	elasped := time.Since(start)
+	elapsed := time.Since(start)
 	Expect(t, err).ToBe(nil)
-	Expect(t, elasped > 5*time.Second).ToBe(true)
+	Expect(t, elapsed > 5*time.Second).ToBe(true)
 }
 
 type SleepyReader struct {
diff --git a/example_test.go b/example_test.go
index 88cc590..d097857 100644
--- a/example_test.go
+++ b/example_test.go
@@ -24,7 +24,7 @@ func ExampleOptions() {
 		"test/data/example",
 		"test/data.copy/example_with_options",
 		Options{
-			Skip: func(src string) (bool, error) {
+			Skip: func(info os.FileInfo, src, dest string) (bool, error) {
 				return strings.HasSuffix(src, ".git-like"), nil
 			},
 			OnSymlink: func(src string) SymlinkAction {