chore(deps): bump github.com/otiai10/copy from 1.7.0 to 1.11.0 (#2523)
Bumps [github.com/otiai10/copy](https://github.com/otiai10/copy) from 1.7.0 to 1.11.0. - [Release notes](https://github.com/otiai10/copy/releases) - [Commits](https://github.com/otiai10/copy/compare/v1.7.0...v1.11.0) --- updated-dependencies: - dependency-name: github.com/otiai10/copy dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
This commit is contained in:
parent
b4f3885a92
commit
74b2b6c9ef
2
go.mod
2
go.mod
|
|
@ -20,7 +20,7 @@ require (
|
|||
github.com/karrick/godirwalk v1.16.1
|
||||
github.com/minio/highwayhash v1.0.2
|
||||
github.com/moby/buildkit v0.11.4
|
||||
github.com/otiai10/copy v1.7.0
|
||||
github.com/otiai10/copy v1.11.0
|
||||
github.com/pkg/errors v0.9.1
|
||||
github.com/sirupsen/logrus v1.9.0
|
||||
github.com/spf13/afero v1.9.5
|
||||
|
|
|
|||
8
go.sum
8
go.sum
|
|
@ -2104,14 +2104,14 @@ github.com/openzipkin/zipkin-go v0.1.1/go.mod h1:NtoC/o8u3JlF1lSlyPNswIbeQH9bJTm
|
|||
github.com/openzipkin/zipkin-go v0.1.3/go.mod h1:NtoC/o8u3JlF1lSlyPNswIbeQH9bJTmOf0Erfk+hxe8=
|
||||
github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw=
|
||||
github.com/otiai10/copy v1.2.0/go.mod h1:rrF5dJ5F0t/EWSYODDu4j9/vEeYHMkc8jt0zJChqQWw=
|
||||
github.com/otiai10/copy v1.7.0 h1:hVoPiN+t+7d2nzzwMiDHPSOogsWAStewq3TwU05+clE=
|
||||
github.com/otiai10/copy v1.7.0/go.mod h1:rmRl6QPdJj6EiUqXQ/4Nn2lLXoNQjFCQbbNrxgc/t3U=
|
||||
github.com/otiai10/copy v1.11.0 h1:OKBD80J/mLBrwnzXqGtFCzprFSGioo30JcmR4APsNwc=
|
||||
github.com/otiai10/copy v1.11.0/go.mod h1:rSaLseMUsZFFbsFGc7wCJnnkTAvdc5L6VWxPE4308Ww=
|
||||
github.com/otiai10/curr v0.0.0-20150429015615-9b4961190c95/go.mod h1:9qAhocn7zKJG+0mI8eUu6xqkFDYS2kb2saOteoSB3cE=
|
||||
github.com/otiai10/curr v1.0.0/go.mod h1:LskTG5wDwr8Rs+nNQ+1LlxRjAtTZZjtJW4rMXl6j4vs=
|
||||
github.com/otiai10/mint v1.3.0/go.mod h1:F5AjcsTsWUqX+Na9fpHb52P8pcRX2CI6A3ctIT91xUo=
|
||||
github.com/otiai10/mint v1.3.1/go.mod h1:/yxELlJQ0ufhjUwhshSj+wFjZ78CnZ48/1wtmBH1OTc=
|
||||
github.com/otiai10/mint v1.3.3 h1:7JgpsBaN0uMkyju4tbYHu0mnM55hNKVYLsXmwr15NQI=
|
||||
github.com/otiai10/mint v1.3.3/go.mod h1:/yxELlJQ0ufhjUwhshSj+wFjZ78CnZ48/1wtmBH1OTc=
|
||||
github.com/otiai10/mint v1.5.1 h1:XaPLeE+9vGbuyEHem1JNk3bYc7KKqyI/na0/mLd/Kks=
|
||||
github.com/otiai10/mint v1.5.1/go.mod h1:MJm72SBthJjz8qhefc4z1PYEieWmy8Bku7CjcAqyUSM=
|
||||
github.com/package-url/packageurl-go v0.1.1-0.20220428063043-89078438f170/go.mod h1:uQd4a7Rh3ZsVg5j0lNyAfyxIeGde9yrlhjF78GzeW0c=
|
||||
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
|
||||
github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k=
|
||||
|
|
|
|||
|
|
@ -1,5 +1,9 @@
|
|||
test/data.copy
|
||||
test/owned-by-root
|
||||
coverage.txt
|
||||
vendor
|
||||
.vagrant
|
||||
.idea/
|
||||
|
||||
# Test Specific
|
||||
test/data/case16/large.file
|
||||
|
|
|
|||
|
|
@ -16,7 +16,17 @@
|
|||
# Example Usage
|
||||
|
||||
```go
|
||||
err := Copy("your/directory", "your/directory.copy")
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
cp "github.com/otiai10/copy"
|
||||
)
|
||||
|
||||
func main() {
|
||||
err := cp.Copy("your/src", "your/dest")
|
||||
fmt.Println(err) // nil
|
||||
}
|
||||
```
|
||||
|
||||
# Advanced Usage
|
||||
|
|
@ -31,12 +41,24 @@ type Options struct {
|
|||
// OnDirExists can specify what to do when there is a directory already existing in destination.
|
||||
OnDirExists func(src, dest string) DirExistsAction
|
||||
|
||||
// Skip can specify which files should be skipped
|
||||
Skip func(src string) (bool, error)
|
||||
// OnError can let users decide how to handle errors (e.g., you can suppress specific error).
|
||||
OnError func(src, dest, string, err error) error
|
||||
|
||||
// AddPermission to every entry,
|
||||
// NO MORE THAN 0777
|
||||
AddPermission os.FileMode
|
||||
// Skip can specify which files should be skipped
|
||||
Skip func(srcinfo os.FileInfo, src, dest string) (bool, error)
|
||||
|
||||
// PermissionControl can control permission of
|
||||
// every entry.
|
||||
// When you want to add permission 0222, do like
|
||||
//
|
||||
// PermissionControl = AddPermission(0222)
|
||||
//
|
||||
// or if you even don't want to touch permission,
|
||||
//
|
||||
// PermissionControl = DoNothing
|
||||
//
|
||||
// By default, PermissionControl = PreservePermission
|
||||
PermissionControl PermissionControlFunc
|
||||
|
||||
// Sync file after copy.
|
||||
// Useful in case when file must be on the disk
|
||||
|
|
@ -61,7 +83,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
|
||||
},
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,13 +8,6 @@ import (
|
|||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
// tmpPermissionForDirectory makes the destination directory writable,
|
||||
// so that stuff can be copied recursively even if any original directory is NOT writable.
|
||||
// See https://github.com/otiai10/copy/pull/9 for more information.
|
||||
tmpPermissionForDirectory = os.FileMode(0755)
|
||||
)
|
||||
|
||||
type timespec struct {
|
||||
Mtime time.Time
|
||||
Atime time.Time
|
||||
|
|
@ -22,17 +15,22 @@ type timespec struct {
|
|||
}
|
||||
|
||||
// Copy copies src to dest, doesn't matter if src is a directory or a file.
|
||||
func Copy(src, dest string, opt ...Options) error {
|
||||
func Copy(src, dest string, opts ...Options) error {
|
||||
opt := assureOptions(src, dest, opts...)
|
||||
info, err := os.Lstat(src)
|
||||
if err != nil {
|
||||
return err
|
||||
return onError(src, dest, err, opt)
|
||||
}
|
||||
return switchboard(src, dest, info, assure(src, dest, opt...))
|
||||
return switchboard(src, dest, info, opt)
|
||||
}
|
||||
|
||||
// switchboard switches proper copy functions regarding file type, etc...
|
||||
// If there would be anything else here, add a case to this switchboard.
|
||||
func switchboard(src, dest string, info os.FileInfo, opt Options) (err error) {
|
||||
if info.Mode()&os.ModeDevice != 0 && !opt.Specials {
|
||||
return onError(src, dest, err, opt)
|
||||
}
|
||||
|
||||
switch {
|
||||
case info.Mode()&os.ModeSymlink != 0:
|
||||
err = onsymlink(src, dest, opt)
|
||||
|
|
@ -44,19 +42,21 @@ func switchboard(src, dest string, info os.FileInfo, opt Options) (err error) {
|
|||
err = fcopy(src, dest, info, opt)
|
||||
}
|
||||
|
||||
return err
|
||||
return onError(src, dest, err, opt)
|
||||
}
|
||||
|
||||
// copyNextOrSkip decide if this src should be copied or not.
|
||||
// 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)
|
||||
}
|
||||
|
|
@ -65,6 +65,14 @@ func copyNextOrSkip(src, dest string, info os.FileInfo, opt Options) error {
|
|||
// with considering existence of parent directory
|
||||
// and file permission.
|
||||
func fcopy(src, dest string, info os.FileInfo, opt Options) (err error) {
|
||||
s, err := os.Open(src)
|
||||
if err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
return nil
|
||||
}
|
||||
return
|
||||
}
|
||||
defer fclose(s, &err)
|
||||
|
||||
if err = os.MkdirAll(filepath.Dir(dest), os.ModePerm); err != nil {
|
||||
return
|
||||
|
|
@ -76,19 +84,20 @@ func fcopy(src, dest string, info os.FileInfo, opt Options) (err error) {
|
|||
}
|
||||
defer fclose(f, &err)
|
||||
|
||||
if err = os.Chmod(f.Name(), info.Mode()|opt.AddPermission); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
s, err := os.Open(src)
|
||||
chmodfunc, err := opt.PermissionControl(info, dest)
|
||||
if err != nil {
|
||||
return
|
||||
return err
|
||||
}
|
||||
defer fclose(s, &err)
|
||||
chmodfunc(&err)
|
||||
|
||||
var buf []byte = nil
|
||||
var w io.Writer = f
|
||||
// var r io.Reader = s
|
||||
var r io.Reader = s
|
||||
|
||||
if opt.WrapReader != nil {
|
||||
r = opt.WrapReader(s)
|
||||
}
|
||||
|
||||
if opt.CopyBufferSize != 0 {
|
||||
buf = make([]byte, opt.CopyBufferSize)
|
||||
// Disable using `ReadFrom` by io.CopyBuffer.
|
||||
|
|
@ -96,7 +105,8 @@ func fcopy(src, dest string, info os.FileInfo, opt Options) (err error) {
|
|||
w = struct{ io.Writer }{f}
|
||||
// r = struct{ io.Reader }{s}
|
||||
}
|
||||
if _, err = io.CopyBuffer(w, s, buf); err != nil {
|
||||
|
||||
if _, err = io.CopyBuffer(w, r, buf); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
|
@ -122,32 +132,24 @@ func fcopy(src, dest string, info os.FileInfo, opt Options) (err error) {
|
|||
// with scanning contents inside the directory
|
||||
// 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
|
||||
}
|
||||
|
||||
originalMode := info.Mode()
|
||||
|
||||
// Make dest dir with 0755 so that everything writable.
|
||||
if err = os.MkdirAll(destdir, tmpPermissionForDirectory); err != nil {
|
||||
return
|
||||
chmodfunc, err := opt.PermissionControl(info, destdir)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// Recover dir mode with original one.
|
||||
defer chmod(destdir, originalMode|opt.AddPermission, &err)
|
||||
defer chmodfunc(&err)
|
||||
|
||||
contents, err := ioutil.ReadDir(srcdir)
|
||||
if err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
return nil
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
|
|
@ -175,10 +177,33 @@ 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:
|
||||
return lcopy(src, dest)
|
||||
if err := lcopy(src, dest); err != nil {
|
||||
return err
|
||||
}
|
||||
if opt.PreserveTimes {
|
||||
return preserveLtimes(src, dest)
|
||||
}
|
||||
return nil
|
||||
case Deep:
|
||||
orig, err := os.Readlink(src)
|
||||
if err != nil {
|
||||
|
|
@ -201,6 +226,9 @@ func onsymlink(src, dest string, opt Options) error {
|
|||
func lcopy(src, dest string) error {
|
||||
src, err := os.Readlink(src)
|
||||
if err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
return nil
|
||||
}
|
||||
return err
|
||||
}
|
||||
return os.Symlink(src, dest)
|
||||
|
|
@ -215,29 +243,12 @@ func fclose(f *os.File, reported *error) {
|
|||
}
|
||||
}
|
||||
|
||||
// chmod ANYHOW changes file mode,
|
||||
// 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
|
||||
// onError lets caller to handle errors
|
||||
// occured when copying a file.
|
||||
func onError(src, dest string, err error, opt Options) error {
|
||||
if opt.OnError == nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// assure Options struct, should be called only once.
|
||||
// All optional values MUST NOT BE nil/zero after assured.
|
||||
func assure(src, dest string, opts ...Options) Options {
|
||||
defopt := getDefaultOptions(src, dest)
|
||||
if len(opts) == 0 {
|
||||
return defopt
|
||||
}
|
||||
if opts[0].OnSymlink == nil {
|
||||
opts[0].OnSymlink = defopt.OnSymlink
|
||||
}
|
||||
if opts[0].Skip == nil {
|
||||
opts[0].Skip = defopt.Skip
|
||||
}
|
||||
opts[0].intent.src = defopt.intent.src
|
||||
opts[0].intent.dest = defopt.intent.dest
|
||||
return opts[0]
|
||||
return opt.OnError(src, dest, err)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
// +build !windows,!plan9,!netbsd,!aix,!illumos,!solaris
|
||||
//go:build !windows && !plan9 && !netbsd && !aix && !illumos && !solaris && !js
|
||||
// +build !windows,!plan9,!netbsd,!aix,!illumos,!solaris,!js
|
||||
|
||||
package copy
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
// +build windows plan9 netbsd aix illumos solaris
|
||||
//go:build windows || plan9 || netbsd || aix || illumos || solaris || js
|
||||
// +build windows plan9 netbsd aix illumos solaris js
|
||||
|
||||
package copy
|
||||
|
||||
|
|
|
|||
|
|
@ -1,12 +1,17 @@
|
|||
//go:build !go1.16
|
||||
// +build !go1.16
|
||||
|
||||
package copy
|
||||
|
||||
import "os"
|
||||
|
||||
// This is a cloned definition of os.FileInfo (go1.15) or fs.FileInfo (go1.16~)
|
||||
// A FileInfo describes a file and is returned by Stat.
|
||||
type fileInfo interface {
|
||||
// Name() string // base name of the file
|
||||
// Size() int64 // length in bytes for regular files; system-dependent for others
|
||||
// Mode() FileMode // file mode bits
|
||||
Mode() os.FileMode // file mode bits
|
||||
// ModTime() time.Time // modification time
|
||||
// IsDir() bool // abbreviation for Mode().IsDir()
|
||||
IsDir() bool // abbreviation for Mode().IsDir()
|
||||
Sys() interface{} // underlying data source (can return nil)
|
||||
}
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
//go:build go1.16
|
||||
// +build go1.16
|
||||
|
||||
package copy
|
||||
|
||||
import "io/fs"
|
||||
|
||||
// This is a cloned definition of os.FileInfo (go1.15) or fs.FileInfo (go1.16~)
|
||||
// A FileInfo describes a file and is returned by Stat.
|
||||
type fileInfo interface {
|
||||
// Name() string // base name of the file
|
||||
// Size() int64 // length in bytes for regular files; system-dependent for others
|
||||
Mode() fs.FileMode // file mode bits
|
||||
// ModTime() time.Time // modification time
|
||||
IsDir() bool // abbreviation for Mode().IsDir()
|
||||
Sys() interface{} // underlying data source (can return nil)
|
||||
}
|
||||
|
|
@ -1,6 +1,9 @@
|
|||
package copy
|
||||
|
||||
import "os"
|
||||
import (
|
||||
"io"
|
||||
"os"
|
||||
)
|
||||
|
||||
// Options specifies optional actions on copying.
|
||||
type Options struct {
|
||||
|
|
@ -11,13 +14,29 @@ type Options struct {
|
|||
// OnDirExists can specify what to do when there is a directory already existing in destination.
|
||||
OnDirExists func(src, dest string) DirExistsAction
|
||||
|
||||
// OnErr lets called decide whether or not to continue on particular copy error.
|
||||
OnError func(src, dest string, err error) error
|
||||
|
||||
// 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
|
||||
|
||||
// AddPermission to every entities,
|
||||
// NO MORE THAN 0777
|
||||
// @OBSOLETE
|
||||
// Use `PermissionControl = AddPermission(perm)` instead
|
||||
AddPermission os.FileMode
|
||||
|
||||
// PermissionControl can preserve or even add permission to
|
||||
// every entries, for example
|
||||
//
|
||||
// opt.PermissionControl = AddPermission(0222)
|
||||
//
|
||||
// See permission_control.go for more detail.
|
||||
PermissionControl PermissionControlFunc
|
||||
|
||||
// Sync file after copy.
|
||||
// Useful in case when file must be on the disk
|
||||
// (in case crash happens, for example),
|
||||
|
|
@ -36,6 +55,11 @@ type Options struct {
|
|||
// See https://golang.org/pkg/io/#CopyBuffer for more information.
|
||||
CopyBufferSize uint
|
||||
|
||||
// If you want to add some limitation on reading src file,
|
||||
// you can wrap the src and provide new reader,
|
||||
// such as `RateLimitReader` in the test case.
|
||||
WrapReader func(src *os.File) io.Reader
|
||||
|
||||
intent struct {
|
||||
src string
|
||||
dest string
|
||||
|
|
@ -73,17 +97,42 @@ 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
|
||||
},
|
||||
AddPermission: 0, // Add nothing
|
||||
Sync: false, // Do not sync
|
||||
PreserveTimes: false, // Do not preserve the modification time
|
||||
CopyBufferSize: 0, // Do not specify, use default bufsize (32*1024)
|
||||
OnDirExists: nil, // Default behavior is "Merge".
|
||||
OnError: nil, // Default is "accept error"
|
||||
Skip: nil, // Do not skip anything
|
||||
AddPermission: 0, // Add nothing
|
||||
PermissionControl: PerservePermission, // Just preserve permission
|
||||
Sync: false, // Do not sync
|
||||
Specials: false, // Do not copy special files
|
||||
PreserveTimes: false, // Do not preserve the modification time
|
||||
CopyBufferSize: 0, // Do not specify, use default bufsize (32*1024)
|
||||
WrapReader: nil, // Do not wrap src files, use them as they are.
|
||||
intent: struct {
|
||||
src string
|
||||
dest string
|
||||
}{src, dest},
|
||||
}
|
||||
}
|
||||
|
||||
// assureOptions struct, should be called only once.
|
||||
// All optional values MUST NOT BE nil/zero after assured.
|
||||
func assureOptions(src, dest string, opts ...Options) Options {
|
||||
defopt := getDefaultOptions(src, dest)
|
||||
if len(opts) == 0 {
|
||||
return defopt
|
||||
}
|
||||
if opts[0].OnSymlink == nil {
|
||||
opts[0].OnSymlink = defopt.OnSymlink
|
||||
}
|
||||
if opts[0].Skip == nil {
|
||||
opts[0].Skip = defopt.Skip
|
||||
}
|
||||
if opts[0].AddPermission > 0 {
|
||||
opts[0].PermissionControl = AddPermission(opts[0].AddPermission)
|
||||
} else if opts[0].PermissionControl == nil {
|
||||
opts[0].PermissionControl = PerservePermission
|
||||
}
|
||||
opts[0].intent.src = defopt.intent.src
|
||||
opts[0].intent.dest = defopt.intent.dest
|
||||
return opts[0]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,48 @@
|
|||
package copy
|
||||
|
||||
import (
|
||||
"os"
|
||||
)
|
||||
|
||||
const (
|
||||
// tmpPermissionForDirectory makes the destination directory writable,
|
||||
// so that stuff can be copied recursively even if any original directory is NOT writable.
|
||||
// See https://github.com/otiai10/copy/pull/9 for more information.
|
||||
tmpPermissionForDirectory = os.FileMode(0755)
|
||||
)
|
||||
|
||||
type PermissionControlFunc func(srcinfo fileInfo, dest string) (chmodfunc func(*error), err error)
|
||||
|
||||
var (
|
||||
AddPermission = func(perm os.FileMode) PermissionControlFunc {
|
||||
return func(srcinfo fileInfo, dest string) (func(*error), error) {
|
||||
orig := srcinfo.Mode()
|
||||
if srcinfo.IsDir() {
|
||||
if err := os.MkdirAll(dest, tmpPermissionForDirectory); err != nil {
|
||||
return func(*error) {}, err
|
||||
}
|
||||
}
|
||||
return func(err *error) {
|
||||
chmod(dest, orig|perm, err)
|
||||
}, nil
|
||||
}
|
||||
}
|
||||
PerservePermission PermissionControlFunc = AddPermission(0)
|
||||
DoNothing PermissionControlFunc = func(srcinfo fileInfo, dest string) (func(*error), error) {
|
||||
if srcinfo.IsDir() {
|
||||
if err := os.MkdirAll(dest, srcinfo.Mode()); err != nil {
|
||||
return func(*error) {}, err
|
||||
}
|
||||
}
|
||||
return func(*error) {}, nil
|
||||
}
|
||||
)
|
||||
|
||||
// chmod ANYHOW changes file mode,
|
||||
// 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
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
//go:build !windows && !plan9 && !js
|
||||
// +build !windows,!plan9,!js
|
||||
|
||||
package copy
|
||||
|
||||
import (
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
func preserveLtimes(src, dest string) error {
|
||||
info := new(unix.Stat_t)
|
||||
if err := unix.Lstat(src, info); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return unix.Lutimes(dest, []unix.Timeval{
|
||||
unix.NsecToTimeval(info.Atim.Nano()),
|
||||
unix.NsecToTimeval(info.Mtim.Nano()),
|
||||
})
|
||||
}
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
//go:build windows || js || plan9
|
||||
// +build windows js plan9
|
||||
|
||||
package copy
|
||||
|
||||
func preserveLtimes(src, dest string) error {
|
||||
return nil // Unsupported
|
||||
}
|
||||
|
|
@ -1,4 +1,5 @@
|
|||
//+build !windows
|
||||
//go:build !windows && !plan9
|
||||
// +build !windows,!plan9
|
||||
|
||||
package copy
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
//+build windows
|
||||
//go:build windows || plan9
|
||||
// +build windows plan9
|
||||
|
||||
package copy
|
||||
|
||||
|
|
@ -1,4 +1,5 @@
|
|||
// +build !windows,!darwin,!freebsd,!plan9,!netbsd
|
||||
//go:build !windows && !darwin && !freebsd && !plan9 && !netbsd && !js
|
||||
// +build !windows,!darwin,!freebsd,!plan9,!netbsd,!js
|
||||
|
||||
// TODO: add more runtimes
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
//go:build darwin
|
||||
// +build darwin
|
||||
|
||||
package copy
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
//go:build freebsd
|
||||
// +build freebsd
|
||||
|
||||
package copy
|
||||
|
|
|
|||
|
|
@ -0,0 +1,20 @@
|
|||
//go:build js
|
||||
// +build js
|
||||
|
||||
package copy
|
||||
|
||||
import (
|
||||
"os"
|
||||
"syscall"
|
||||
"time"
|
||||
)
|
||||
|
||||
func getTimeSpec(info os.FileInfo) timespec {
|
||||
stat := info.Sys().(*syscall.Stat_t)
|
||||
times := timespec{
|
||||
Mtime: info.ModTime(),
|
||||
Atime: time.Unix(int64(stat.Atime), int64(stat.AtimeNsec)),
|
||||
Ctime: time.Unix(int64(stat.Ctime), int64(stat.CtimeNsec)),
|
||||
}
|
||||
return times
|
||||
}
|
||||
|
|
@ -1,3 +1,4 @@
|
|||
//go:build windows
|
||||
// +build windows
|
||||
|
||||
package copy
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
//go:build plan9 || netbsd
|
||||
// +build plan9 netbsd
|
||||
|
||||
package copy
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
// +build !windows,!plan9,!netbsd,!aix,!illumos,!solaris
|
||||
//go:build !windows && !plan9 && !netbsd && !aix && !illumos && !solaris && !js
|
||||
// +build !windows,!plan9,!netbsd,!aix,!illumos,!solaris,!js
|
||||
|
||||
package copy
|
||||
|
||||
|
|
@ -9,9 +10,10 @@ import (
|
|||
)
|
||||
|
||||
func setup(m *testing.M) {
|
||||
os.RemoveAll("test/data.copy")
|
||||
os.MkdirAll("test/data.copy", os.ModePerm)
|
||||
os.Symlink("test/data/case01", "test/data/case03/case01")
|
||||
os.Chmod("test/data/case07/dir_0555", 0555)
|
||||
os.Chmod("test/data/case07/file_0444", 0444)
|
||||
syscall.Mkfifo("test/data/case11/foo/bar", 0555)
|
||||
os.Chmod("test/data/case07/dir_0555", 0o555)
|
||||
os.Chmod("test/data/case07/file_0444", 0o444)
|
||||
syscall.Mkfifo("test/data/case11/foo/bar", 0o555)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
// +build windows plan9 netbsd aix illumos solaris
|
||||
//go:build windows || plan9 || netbsd || aix || illumos || solaris || js
|
||||
// +build windows plan9 netbsd aix illumos solaris js
|
||||
|
||||
package copy
|
||||
|
||||
|
|
|
|||
|
|
@ -696,8 +696,8 @@ github.com/opencontainers/runtime-spec/specs-go
|
|||
github.com/opencontainers/selinux/go-selinux
|
||||
github.com/opencontainers/selinux/go-selinux/label
|
||||
github.com/opencontainers/selinux/pkg/pwalkdir
|
||||
# github.com/otiai10/copy v1.7.0
|
||||
## explicit; go 1.14
|
||||
# github.com/otiai10/copy v1.11.0
|
||||
## explicit; go 1.18
|
||||
github.com/otiai10/copy
|
||||
# github.com/pkg/errors v0.9.1
|
||||
## explicit
|
||||
|
|
|
|||
Loading…
Reference in New Issue