From b1ac5a476159b02db42a1022f1ec81ff4441a2d9 Mon Sep 17 00:00:00 2001 From: Steve Kuznetsov Date: Wed, 20 Sep 2023 08:40:12 -0400 Subject: [PATCH] cmd: add a utility to copy catalog content (#3036) Signed-off-by: Steve Kuznetsov --- Dockerfile | 1 + Makefile | 5 +- cmd/copy-content/main.go | 38 +++ go.mod | 2 +- go.sum | 10 +- vendor/github.com/otiai10/copy/.gitignore | 8 +- vendor/github.com/otiai10/copy/README.md | 102 +++++++- vendor/github.com/otiai10/copy/copy.go | 226 +++++++++++++----- .../otiai10/copy/copy_namedpipes.go | 18 ++ .../otiai10/copy/copy_namedpipes_x.go | 15 ++ .../otiai10/copy/fileinfo_go1.15.go | 17 ++ .../otiai10/copy/fileinfo_go1.16.go | 17 ++ vendor/github.com/otiai10/copy/options.go | 113 ++++++++- .../otiai10/copy/permission_control.go | 48 ++++ .../otiai10/copy/preserve_ltimes.go | 20 ++ .../otiai10/copy/preserve_ltimes_x.go | 8 + .../github.com/otiai10/copy/preserve_owner.go | 23 ++ .../otiai10/copy/preserve_owner_x.go | 8 + .../github.com/otiai10/copy/preserve_times.go | 11 + vendor/github.com/otiai10/copy/stat_times.go | 22 ++ .../otiai10/copy/stat_times_darwin.go | 20 ++ .../otiai10/copy/stat_times_freebsd.go | 20 ++ .../github.com/otiai10/copy/stat_times_js.go | 20 ++ .../otiai10/copy/stat_times_windows.go | 19 ++ .../github.com/otiai10/copy/stat_times_x.go | 18 ++ .../copy/test/data/case18/assets/README.md | 1 + vendor/github.com/otiai10/copy/test_setup.go | 20 ++ .../github.com/otiai10/copy/test_setup_x.go | 17 ++ vendor/modules.txt | 4 +- 29 files changed, 764 insertions(+), 87 deletions(-) create mode 100644 cmd/copy-content/main.go create mode 100644 vendor/github.com/otiai10/copy/copy_namedpipes.go create mode 100644 vendor/github.com/otiai10/copy/copy_namedpipes_x.go create mode 100644 vendor/github.com/otiai10/copy/fileinfo_go1.15.go create mode 100644 vendor/github.com/otiai10/copy/fileinfo_go1.16.go create mode 100644 vendor/github.com/otiai10/copy/permission_control.go create mode 100644 vendor/github.com/otiai10/copy/preserve_ltimes.go create mode 100644 vendor/github.com/otiai10/copy/preserve_ltimes_x.go create mode 100644 vendor/github.com/otiai10/copy/preserve_owner.go create mode 100644 vendor/github.com/otiai10/copy/preserve_owner_x.go create mode 100644 vendor/github.com/otiai10/copy/preserve_times.go create mode 100644 vendor/github.com/otiai10/copy/stat_times.go create mode 100644 vendor/github.com/otiai10/copy/stat_times_darwin.go create mode 100644 vendor/github.com/otiai10/copy/stat_times_freebsd.go create mode 100644 vendor/github.com/otiai10/copy/stat_times_js.go create mode 100644 vendor/github.com/otiai10/copy/stat_times_windows.go create mode 100644 vendor/github.com/otiai10/copy/stat_times_x.go create mode 100644 vendor/github.com/otiai10/copy/test/data/case18/assets/README.md create mode 100644 vendor/github.com/otiai10/copy/test_setup.go create mode 100644 vendor/github.com/otiai10/copy/test_setup_x.go diff --git a/Dockerfile b/Dockerfile index 2a92bcc63d..1ed3c19c3d 100644 --- a/Dockerfile +++ b/Dockerfile @@ -33,6 +33,7 @@ COPY --from=builder /build/bin/olm /bin/olm COPY --from=builder /build/bin/catalog /bin/catalog COPY --from=builder /build/bin/package-server /bin/package-server COPY --from=builder /build/bin/cpb /bin/cpb +COPY --from=builder /build/bin/copy-content /bin/copy-content USER 1001 EXPOSE 8080 EXPOSE 5443 diff --git a/Makefile b/Makefile index 708bfcd3bd..06df094021 100644 --- a/Makefile +++ b/Makefile @@ -97,11 +97,14 @@ bin/wait: FORCE build-util-linux: arch_flags=GOOS=linux GOARCH=$(ARCH) build-util-linux: build-util -build-util: bin/cpb +build-util: bin/cpb bin/copy-content bin/cpb: FORCE CGO_ENABLED=0 $(arch_flags) go build -buildvcs=false $(MOD_FLAGS) -ldflags '-extldflags "-static"' -o $@ ./util/cpb +bin/copy-content: FORCE + CGO_ENABLED=0 $(arch_flags) go build -buildvcs=false $(MOD_FLAGS) -ldflags '-extldflags "-static"' -o $@ ./cmd/copy-content + $(CMDS): version_flags=-ldflags "-X $(PKG)/pkg/version.GitCommit=$(GIT_COMMIT) -X $(PKG)/pkg/version.OLMVersion=`cat OLM_VERSION`" $(CMDS): $(arch_flags) go $(build_cmd) $(MOD_FLAGS) $(version_flags) -tags $(BUILD_TAGS) -o bin/$(shell basename $@) $@ diff --git a/cmd/copy-content/main.go b/cmd/copy-content/main.go new file mode 100644 index 0000000000..dc70a7dd52 --- /dev/null +++ b/cmd/copy-content/main.go @@ -0,0 +1,38 @@ +package main + +import ( + "flag" + "fmt" + "os" + + "github.com/otiai10/copy" +) + +func main() { + catalogSource := flag.String("catalog.from", "", "Path to catalog contents to copy.") + catalogDestination := flag.String("catalog.to", "", "Path to where catalog contents should be copied.") + cacheSource := flag.String("cache.from", "", "Path to cache contents to copy.") + cacheDestination := flag.String("cache.to", "", "Path to where cache contents should be copied.") + + for flagName, value := range map[string]*string{ + "catalog.from": catalogSource, + "catalog.to": catalogDestination, + "cache.from": cacheSource, + "cache.to": cacheDestination, + } { + if value == nil || *value == "" { + fmt.Printf("--%s is required", flagName) + os.Exit(1) + } + } + + for from, to := range map[string]string{ + *catalogSource: *catalogDestination, + *cacheSource: *cacheDestination, + } { + if err := copy.Copy(from, to); err != nil { + fmt.Printf("failed to copy %s to %s: %s\n", from, to, err) + os.Exit(1) + } + } +} diff --git a/go.mod b/go.mod index d6dbbc8a1f..17bf8f1223 100644 --- a/go.mod +++ b/go.mod @@ -27,7 +27,7 @@ require ( github.com/openshift/client-go v0.0.0-20220525160904-9e1acff93e4a github.com/operator-framework/api v0.17.8-0.20230908201838-28c6773d2b74 github.com/operator-framework/operator-registry v1.29.0 - github.com/otiai10/copy v1.2.0 + github.com/otiai10/copy v1.12.0 github.com/pkg/errors v0.9.1 github.com/prometheus/client_golang v1.15.1 github.com/prometheus/client_model v0.4.0 diff --git a/go.sum b/go.sum index 03144ef466..cf844ef4a1 100644 --- a/go.sum +++ b/go.sum @@ -608,13 +608,9 @@ github.com/operator-framework/api v0.17.8-0.20230908201838-28c6773d2b74 h1:BNzxQ github.com/operator-framework/api v0.17.8-0.20230908201838-28c6773d2b74/go.mod h1:Wbg136l1Po6zqG2QcTN1QZ8dbT4BQvNlQDM9tmQYvz0= github.com/operator-framework/operator-registry v1.29.0 h1:HMmVTiuOAGoHLzYqR9Lr2QSOqbVzA50++ojNl2mu9f4= github.com/operator-framework/operator-registry v1.29.0/go.mod h1:4rVQu/cOuCtVt3JzKsAmwyq2lsiu9uPaH9nYNfnqj9o= -github.com/otiai10/copy v1.2.0 h1:HvG945u96iNadPoG2/Ja2+AUJeW5YuFQMixq9yirC+k= -github.com/otiai10/copy v1.2.0/go.mod h1:rrF5dJ5F0t/EWSYODDu4j9/vEeYHMkc8jt0zJChqQWw= -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 h1:BCmzIS3n71sGfHB5NMNDB3lHYPz8fWSkCAErHed//qc= -github.com/otiai10/mint v1.3.1/go.mod h1:/yxELlJQ0ufhjUwhshSj+wFjZ78CnZ48/1wtmBH1OTc= +github.com/otiai10/copy v1.12.0 h1:cLMgSQnXBs1eehF0Wy/FAGsgDTDmAqFR7rQylBb1nDY= +github.com/otiai10/copy v1.12.0/go.mod h1:rSaLseMUsZFFbsFGc7wCJnnkTAvdc5L6VWxPE4308Ww= +github.com/otiai10/mint v1.5.1 h1:XaPLeE+9vGbuyEHem1JNk3bYc7KKqyI/na0/mLd/Kks= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pbnjay/strptime v0.0.0-20140226051138-5c05b0d668c9 h1:4lfz0keanz7/gAlvJ7lAe9zmE08HXxifBZJC0AdeGKo= github.com/pbnjay/strptime v0.0.0-20140226051138-5c05b0d668c9/go.mod h1:6Hr+C/olSdkdL3z68MlyXWzwhvwmwN7KuUFXGb3PoOk= diff --git a/vendor/github.com/otiai10/copy/.gitignore b/vendor/github.com/otiai10/copy/.gitignore index 5b5ae0a524..a793485586 100644 --- a/vendor/github.com/otiai10/copy/.gitignore +++ b/vendor/github.com/otiai10/copy/.gitignore @@ -1,3 +1,9 @@ -testdata.copy +test/data.copy +test/owned-by-root coverage.txt vendor +.vagrant +.idea/ + +# Test Specific +test/data/case16/large.file diff --git a/vendor/github.com/otiai10/copy/README.md b/vendor/github.com/otiai10/copy/README.md index 5ad7c57ca9..1cc8fc8c82 100644 --- a/vendor/github.com/otiai10/copy/README.md +++ b/vendor/github.com/otiai10/copy/README.md @@ -1,14 +1,108 @@ # copy +[![Go Reference](https://pkg.go.dev/badge/github.com/otiai10/copy.svg)](https://pkg.go.dev/github.com/otiai10/copy) [![Actions Status](https://github.com/otiai10/copy/workflows/Go/badge.svg)](https://github.com/otiai10/copy/actions) -[![codecov](https://codecov.io/gh/otiai10/copy/branch/master/graph/badge.svg)](https://codecov.io/gh/otiai10/copy) -[![GoDoc](https://godoc.org/github.com/otiai10/copy?status.svg)](https://godoc.org/github.com/otiai10/copy) +[![codecov](https://codecov.io/gh/otiai10/copy/branch/main/graph/badge.svg)](https://codecov.io/gh/otiai10/copy) +[![License: MIT](https://img.shields.io/badge/License-MIT-green.svg)](https://github.com/otiai10/copy/blob/main/LICENSE) +[![FOSSA Status](https://app.fossa.com/api/projects/git%2Bgithub.com%2Fotiai10%2Fcopy.svg?type=shield)](https://app.fossa.com/projects/git%2Bgithub.com%2Fotiai10%2Fcopy?ref=badge_shield) +[![CodeQL](https://github.com/otiai10/copy/actions/workflows/codeql-analysis.yml/badge.svg)](https://github.com/otiai10/copy/actions/workflows/codeql-analysis.yml) [![Go Report Card](https://goreportcard.com/badge/github.com/otiai10/copy)](https://goreportcard.com/report/github.com/otiai10/copy) +[![GitHub tag (latest SemVer)](https://img.shields.io/github/v/tag/otiai10/copy?sort=semver)](https://pkg.go.dev/github.com/otiai10/copy) +[![Docker Test](https://github.com/otiai10/copy/actions/workflows/docker-test.yml/badge.svg)](https://github.com/otiai10/copy/actions/workflows/docker-test.yml) +[![Vagrant Test](https://github.com/otiai10/copy/actions/workflows/vagrant-test.yml/badge.svg)](https://github.com/otiai10/copy/actions/workflows/vagrant-test.yml) `copy` copies directories recursively. -Example: +# 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 + +```go +// Options specifies optional actions on copying. +type Options struct { + + // OnSymlink can specify what to do on symlink + OnSymlink func(src string) SymlinkAction + + // OnDirExists can specify what to do when there is a directory already existing in destination. + OnDirExists func(src, dest string) DirExistsAction + + // OnError can let users decide how to handle errors (e.g., you can suppress specific error). + OnError func(src, dest, string, err error) error + + // 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 + // (in case crash happens, for example), + // at the expense of some performance penalty + Sync bool + + // Preserve the atime and the mtime of the entries + // On linux we can preserve only up to 1 millisecond accuracy + PreserveTimes bool + + // Preserve the uid and the gid of all entries. + PreserveOwner bool + + // The byte size of the buffer to use for copying files. + // If zero, the internal default buffer of 32KB is used. + // 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 io.Reader) io.Reader + + // If given, copy.Copy refers to this fs.FS instead of the OS filesystem. + // e.g., You can use embed.FS to copy files from embedded filesystem. + FS fs.FS +} +``` + +```go +// For example... +opt := Options{ + Skip: func(info os.FileInfo, src, dest string) (bool, error) { + return strings.HasSuffix(src, ".git"), nil + }, +} +err := Copy("your/directory", "your/directory.copy", opt) ``` + +# Issues + +- https://github.com/otiai10/copy/issues + + +## License +[![FOSSA Status](https://app.fossa.com/api/projects/git%2Bgithub.com%2Fotiai10%2Fcopy.svg?type=large)](https://app.fossa.com/projects/git%2Bgithub.com%2Fotiai10%2Fcopy?ref=badge_large) \ No newline at end of file diff --git a/vendor/github.com/otiai10/copy/copy.go b/vendor/github.com/otiai10/copy/copy.go index 0ff0e5b258..085db78249 100644 --- a/vendor/github.com/otiai10/copy/copy.go +++ b/vendor/github.com/otiai10/copy/copy.go @@ -2,50 +2,69 @@ package copy import ( "io" + "io/fs" "io/ioutil" "os" "path/filepath" + "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 + Ctime time.Time +} // 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...) + if opt.FS != nil { + info, err := fs.Stat(opt.FS, src) + if err != nil { + return onError(src, dest, err, opt) + } + return switchboard(src, dest, info, opt) + } info, err := os.Lstat(src) if err != nil { - return err + return onError(src, dest, err, opt) } - return switchboard(src, dest, info, assure(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) error { +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: - return onsymlink(src, dest, info, opt) + err = onsymlink(src, dest, opt) case info.IsDir(): - return dcopy(src, dest, info, opt) + err = dcopy(src, dest, info, opt) + case info.Mode()&os.ModeNamedPipe != 0: + err = pcopy(dest, info) default: - return fcopy(src, dest, info, opt) + err = fcopy(src, dest, info, opt) } + + return onError(src, dest, err, opt) } -// copy decide if this src should be copied or not. +// 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 copy(src, dest string, info os.FileInfo, opt Options) error { - skip, err := opt.Skip(src) - if err != nil { - return err - } - if skip { - return nil +func copyNextOrSkip(src, dest string, info os.FileInfo, opt Options) error { + 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) } @@ -55,6 +74,20 @@ func copy(src, dest string, info os.FileInfo, opt Options) error { // and file permission. func fcopy(src, dest string, info os.FileInfo, opt Options) (err error) { + var readcloser io.ReadCloser + if opt.FS != nil { + readcloser, err = opt.FS.Open(src) + } else { + readcloser, err = os.Open(src) + } + if err != nil { + if os.IsNotExist(err) { + return nil + } + return + } + defer fclose(readcloser, &err) + if err = os.MkdirAll(filepath.Dir(dest), os.ModePerm); err != nil { return } @@ -65,24 +98,47 @@ 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 + chmodfunc, err := opt.PermissionControl(info, dest) + if err != nil { + return err } + chmodfunc(&err) - s, err := os.Open(src) - if err != nil { - return + var buf []byte = nil + var w io.Writer = f + var r io.Reader = readcloser + + if opt.WrapReader != nil { + r = opt.WrapReader(r) } - defer fclose(s, &err) - if _, err = io.Copy(f, s); err != nil { - return + if opt.CopyBufferSize != 0 { + buf = make([]byte, opt.CopyBufferSize) + // Disable using `ReadFrom` by io.CopyBuffer. + // See https://github.com/otiai10/copy/pull/60#discussion_r627320811 for more details. + w = struct{ io.Writer }{f} + // r = struct{ io.Reader }{s} + } + + if _, err = io.CopyBuffer(w, r, buf); err != nil { + return err } if opt.Sync { err = f.Sync() } + if opt.PreserveOwner { + if err := preserveOwner(src, dest, info); err != nil { + return err + } + } + if opt.PreserveTimes { + if err := preserveTimes(info, dest); err != nil { + return err + } + } + return } @@ -90,48 +146,104 @@ 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) { - - originalMode := info.Mode() + 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. - if err = os.MkdirAll(destdir, tmpPermissionForDirectory); err != nil { - return + chmodfunc, err := opt.PermissionControl(info, destdir) + if err != nil { + return err + } + defer chmodfunc(&err) + + var contents []os.FileInfo + if opt.FS != nil { + entries, err := fs.ReadDir(opt.FS, srcdir) + if err != nil { + return err + } + for _, e := range entries { + info, err := e.Info() + if err != nil { + return err + } + contents = append(contents, info) + } + } else { + contents, err = ioutil.ReadDir(srcdir) } - // Recover dir mode with original one. - defer chmod(destdir, originalMode|opt.AddPermission, &err) - contents, err := ioutil.ReadDir(srcdir) if err != nil { + if os.IsNotExist(err) { + return nil + } return } for _, content := range contents { cs, cd := filepath.Join(srcdir, content.Name()), filepath.Join(destdir, content.Name()) - if err = copy(cs, cd, content, opt); err != nil { + if err = copyNextOrSkip(cs, cd, content, opt); err != nil { // If any error, exit immediately return } } + if opt.PreserveTimes { + if err := preserveTimes(info, destdir); err != nil { + return err + } + } + + if opt.PreserveOwner { + if err := preserveOwner(srcdir, destdir, info); err != nil { + return err + } + } + return } -func onsymlink(src, dest string, info os.FileInfo, opt Options) error { +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 { return err } - info, err = os.Lstat(orig) + info, err := os.Lstat(orig) if err != nil { return err } - return copy(orig, dest, info, opt) + return copyNextOrSkip(orig, dest, info, opt) case Skip: fallthrough default: @@ -144,6 +256,9 @@ func onsymlink(src, dest string, info os.FileInfo, 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) @@ -152,33 +267,18 @@ func lcopy(src, dest string) error { // fclose ANYHOW closes file, // with asiging error raised during Close, // BUT respecting the error already reported. -func fclose(f *os.File, reported *error) { +func fclose(f io.Closer, reported *error) { if err := f.Close(); *reported == nil { *reported = err } } -// 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(opts ...Options) Options { - if len(opts) == 0 { - return getDefaultOptions() - } - defopt := getDefaultOptions() - if opts[0].OnSymlink == nil { - opts[0].OnSymlink = defopt.OnSymlink - } - if opts[0].Skip == nil { - opts[0].Skip = defopt.Skip - } - return opts[0] + return opt.OnError(src, dest, err) } diff --git a/vendor/github.com/otiai10/copy/copy_namedpipes.go b/vendor/github.com/otiai10/copy/copy_namedpipes.go new file mode 100644 index 0000000000..615ddcd554 --- /dev/null +++ b/vendor/github.com/otiai10/copy/copy_namedpipes.go @@ -0,0 +1,18 @@ +//go:build !windows && !plan9 && !netbsd && !aix && !illumos && !solaris && !js +// +build !windows,!plan9,!netbsd,!aix,!illumos,!solaris,!js + +package copy + +import ( + "os" + "path/filepath" + "syscall" +) + +// pcopy is for just named pipes +func pcopy(dest string, info os.FileInfo) error { + if err := os.MkdirAll(filepath.Dir(dest), os.ModePerm); err != nil { + return err + } + return syscall.Mkfifo(dest, uint32(info.Mode())) +} diff --git a/vendor/github.com/otiai10/copy/copy_namedpipes_x.go b/vendor/github.com/otiai10/copy/copy_namedpipes_x.go new file mode 100644 index 0000000000..38dd9dc724 --- /dev/null +++ b/vendor/github.com/otiai10/copy/copy_namedpipes_x.go @@ -0,0 +1,15 @@ +//go:build windows || plan9 || netbsd || aix || illumos || solaris || js +// +build windows plan9 netbsd aix illumos solaris js + +package copy + +import ( + "os" +) + +// TODO: check plan9 netbsd aix illumos solaris in future + +// pcopy is for just named pipes. Windows doesn't support them +func pcopy(dest string, info os.FileInfo) error { + return nil +} diff --git a/vendor/github.com/otiai10/copy/fileinfo_go1.15.go b/vendor/github.com/otiai10/copy/fileinfo_go1.15.go new file mode 100644 index 0000000000..c0708eaf11 --- /dev/null +++ b/vendor/github.com/otiai10/copy/fileinfo_go1.15.go @@ -0,0 +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() os.FileMode // file mode bits + // ModTime() time.Time // modification time + IsDir() bool // abbreviation for Mode().IsDir() + Sys() interface{} // underlying data source (can return nil) +} diff --git a/vendor/github.com/otiai10/copy/fileinfo_go1.16.go b/vendor/github.com/otiai10/copy/fileinfo_go1.16.go new file mode 100644 index 0000000000..01b3fd2499 --- /dev/null +++ b/vendor/github.com/otiai10/copy/fileinfo_go1.16.go @@ -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) +} diff --git a/vendor/github.com/otiai10/copy/options.go b/vendor/github.com/otiai10/copy/options.go index 21504cd1f0..1b4e508332 100644 --- a/vendor/github.com/otiai10/copy/options.go +++ b/vendor/github.com/otiai10/copy/options.go @@ -1,21 +1,74 @@ package copy -import "os" +import ( + "io" + "io/fs" + "os" +) // Options specifies optional actions on copying. type Options struct { + // OnSymlink can specify what to do on symlink OnSymlink func(src string) SymlinkAction + + // 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), // at the expense of some performance penalty Sync bool + + // Preserve the atime and the mtime of the entries. + // On linux we can preserve only up to 1 millisecond accuracy. + PreserveTimes bool + + // Preserve the uid and the gid of all entries. + PreserveOwner bool + + // The byte size of the buffer to use for copying files. + // If zero, the internal default buffer of 32KB is used. + // 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 io.Reader) io.Reader + + // If given, copy.Copy refers to this fs.FS instead of the OS filesystem. + // e.g., You can use embed.FS to copy files from embedded filesystem. + FS fs.FS + + intent struct { + src string + dest string + } } // SymlinkAction represents what to do on symlink. @@ -30,17 +83,61 @@ const ( Skip ) +// DirExistsAction represents what to do on dest dir. +type DirExistsAction int + +const ( + // Merge preserves or overwrites existing files under the dir (default behavior). + Merge DirExistsAction = iota + // Replace deletes all contents under the dir and copy src files. + Replace + // Untouchable does nothing for the dir, and leaves it as it is. + Untouchable +) + // getDefaultOptions provides default options, // which would be modified by usage-side. -func getDefaultOptions() Options { +func getDefaultOptions(src, dest string) Options { return Options{ OnSymlink: func(string) SymlinkAction { return Shallow // Do shallow copy }, - Skip: func(string) (bool, error) { - return false, nil // Don't skip - }, - AddPermission: 0, // Add nothing - Sync: false, // Do not sync + 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] } diff --git a/vendor/github.com/otiai10/copy/permission_control.go b/vendor/github.com/otiai10/copy/permission_control.go new file mode 100644 index 0000000000..97ae12d8e0 --- /dev/null +++ b/vendor/github.com/otiai10/copy/permission_control.go @@ -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 + } +} diff --git a/vendor/github.com/otiai10/copy/preserve_ltimes.go b/vendor/github.com/otiai10/copy/preserve_ltimes.go new file mode 100644 index 0000000000..cc006d3750 --- /dev/null +++ b/vendor/github.com/otiai10/copy/preserve_ltimes.go @@ -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()), + }) +} diff --git a/vendor/github.com/otiai10/copy/preserve_ltimes_x.go b/vendor/github.com/otiai10/copy/preserve_ltimes_x.go new file mode 100644 index 0000000000..02aec40be6 --- /dev/null +++ b/vendor/github.com/otiai10/copy/preserve_ltimes_x.go @@ -0,0 +1,8 @@ +//go:build windows || js || plan9 +// +build windows js plan9 + +package copy + +func preserveLtimes(src, dest string) error { + return nil // Unsupported +} diff --git a/vendor/github.com/otiai10/copy/preserve_owner.go b/vendor/github.com/otiai10/copy/preserve_owner.go new file mode 100644 index 0000000000..13ec4f5793 --- /dev/null +++ b/vendor/github.com/otiai10/copy/preserve_owner.go @@ -0,0 +1,23 @@ +//go:build !windows && !plan9 +// +build !windows,!plan9 + +package copy + +import ( + "os" + "syscall" +) + +func preserveOwner(src, dest string, info fileInfo) (err error) { + if info == nil { + if info, err = os.Stat(src); err != nil { + return err + } + } + if stat, ok := info.Sys().(*syscall.Stat_t); ok { + if err := os.Chown(dest, int(stat.Uid), int(stat.Gid)); err != nil { + return err + } + } + return nil +} diff --git a/vendor/github.com/otiai10/copy/preserve_owner_x.go b/vendor/github.com/otiai10/copy/preserve_owner_x.go new file mode 100644 index 0000000000..9d8257400b --- /dev/null +++ b/vendor/github.com/otiai10/copy/preserve_owner_x.go @@ -0,0 +1,8 @@ +//go:build windows || plan9 +// +build windows plan9 + +package copy + +func preserveOwner(src, dest string, info fileInfo) (err error) { + return nil +} diff --git a/vendor/github.com/otiai10/copy/preserve_times.go b/vendor/github.com/otiai10/copy/preserve_times.go new file mode 100644 index 0000000000..d89b128980 --- /dev/null +++ b/vendor/github.com/otiai10/copy/preserve_times.go @@ -0,0 +1,11 @@ +package copy + +import "os" + +func preserveTimes(srcinfo os.FileInfo, dest string) error { + spec := getTimeSpec(srcinfo) + if err := os.Chtimes(dest, spec.Atime, spec.Mtime); err != nil { + return err + } + return nil +} diff --git a/vendor/github.com/otiai10/copy/stat_times.go b/vendor/github.com/otiai10/copy/stat_times.go new file mode 100644 index 0000000000..75f45f6e29 --- /dev/null +++ b/vendor/github.com/otiai10/copy/stat_times.go @@ -0,0 +1,22 @@ +//go:build !windows && !darwin && !freebsd && !plan9 && !netbsd && !js +// +build !windows,!darwin,!freebsd,!plan9,!netbsd,!js + +// TODO: add more runtimes + +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.Atim.Sec), int64(stat.Atim.Nsec)), + Ctime: time.Unix(int64(stat.Ctim.Sec), int64(stat.Ctim.Nsec)), + } + return times +} diff --git a/vendor/github.com/otiai10/copy/stat_times_darwin.go b/vendor/github.com/otiai10/copy/stat_times_darwin.go new file mode 100644 index 0000000000..d4c23d8ef2 --- /dev/null +++ b/vendor/github.com/otiai10/copy/stat_times_darwin.go @@ -0,0 +1,20 @@ +//go:build darwin +// +build darwin + +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(stat.Atimespec.Sec, stat.Atimespec.Nsec), + Ctime: time.Unix(stat.Ctimespec.Sec, stat.Ctimespec.Nsec), + } + return times +} diff --git a/vendor/github.com/otiai10/copy/stat_times_freebsd.go b/vendor/github.com/otiai10/copy/stat_times_freebsd.go new file mode 100644 index 0000000000..5309334ef9 --- /dev/null +++ b/vendor/github.com/otiai10/copy/stat_times_freebsd.go @@ -0,0 +1,20 @@ +//go:build freebsd +// +build freebsd + +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.Atimespec.Sec), int64(stat.Atimespec.Nsec)), + Ctime: time.Unix(int64(stat.Ctimespec.Sec), int64(stat.Ctimespec.Nsec)), + } + return times +} diff --git a/vendor/github.com/otiai10/copy/stat_times_js.go b/vendor/github.com/otiai10/copy/stat_times_js.go new file mode 100644 index 0000000000..c645771cab --- /dev/null +++ b/vendor/github.com/otiai10/copy/stat_times_js.go @@ -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 +} diff --git a/vendor/github.com/otiai10/copy/stat_times_windows.go b/vendor/github.com/otiai10/copy/stat_times_windows.go new file mode 100644 index 0000000000..d6a84a7693 --- /dev/null +++ b/vendor/github.com/otiai10/copy/stat_times_windows.go @@ -0,0 +1,19 @@ +//go:build windows +// +build windows + +package copy + +import ( + "os" + "syscall" + "time" +) + +func getTimeSpec(info os.FileInfo) timespec { + stat := info.Sys().(*syscall.Win32FileAttributeData) + return timespec{ + Mtime: time.Unix(0, stat.LastWriteTime.Nanoseconds()), + Atime: time.Unix(0, stat.LastAccessTime.Nanoseconds()), + Ctime: time.Unix(0, stat.CreationTime.Nanoseconds()), + } +} diff --git a/vendor/github.com/otiai10/copy/stat_times_x.go b/vendor/github.com/otiai10/copy/stat_times_x.go new file mode 100644 index 0000000000..886ddd3fd0 --- /dev/null +++ b/vendor/github.com/otiai10/copy/stat_times_x.go @@ -0,0 +1,18 @@ +//go:build plan9 || netbsd +// +build plan9 netbsd + +package copy + +import ( + "os" +) + +// TODO: check plan9 netbsd in future +func getTimeSpec(info os.FileInfo) timespec { + times := timespec{ + Mtime: info.ModTime(), + Atime: info.ModTime(), + Ctime: info.ModTime(), + } + return times +} diff --git a/vendor/github.com/otiai10/copy/test/data/case18/assets/README.md b/vendor/github.com/otiai10/copy/test/data/case18/assets/README.md new file mode 100644 index 0000000000..5570c7ff58 --- /dev/null +++ b/vendor/github.com/otiai10/copy/test/data/case18/assets/README.md @@ -0,0 +1 @@ +# Hello \ No newline at end of file diff --git a/vendor/github.com/otiai10/copy/test_setup.go b/vendor/github.com/otiai10/copy/test_setup.go new file mode 100644 index 0000000000..64a5292788 --- /dev/null +++ b/vendor/github.com/otiai10/copy/test_setup.go @@ -0,0 +1,20 @@ +//go:build !windows && !plan9 && !netbsd && !aix && !illumos && !solaris && !js +// +build !windows,!plan9,!netbsd,!aix,!illumos,!solaris,!js + +package copy + +import ( + "os" + "syscall" + "testing" +) + +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", 0o555) + os.Chmod("test/data/case07/file_0444", 0o444) + syscall.Mkfifo("test/data/case11/foo/bar", 0o555) + Copy("test/data/case18/assets", "test/data/case18/assets.backup") +} diff --git a/vendor/github.com/otiai10/copy/test_setup_x.go b/vendor/github.com/otiai10/copy/test_setup_x.go new file mode 100644 index 0000000000..4c35b144b1 --- /dev/null +++ b/vendor/github.com/otiai10/copy/test_setup_x.go @@ -0,0 +1,17 @@ +//go:build windows || plan9 || netbsd || aix || illumos || solaris || js +// +build windows plan9 netbsd aix illumos solaris js + +package copy + +import ( + "os" + "testing" +) + +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) +} diff --git a/vendor/modules.txt b/vendor/modules.txt index 019fa048ad..5ea7de72e5 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -688,8 +688,8 @@ github.com/operator-framework/operator-registry/pkg/registry github.com/operator-framework/operator-registry/pkg/server github.com/operator-framework/operator-registry/pkg/sqlite github.com/operator-framework/operator-registry/pkg/sqlite/migrations -# github.com/otiai10/copy v1.2.0 -## explicit; go 1.12 +# github.com/otiai10/copy v1.12.0 +## explicit; go 1.18 github.com/otiai10/copy # github.com/pbnjay/strptime v0.0.0-20140226051138-5c05b0d668c9 ## explicit