diff --git a/go.mod b/go.mod index 4c1816b3..df35749c 100644 --- a/go.mod +++ b/go.mod @@ -7,7 +7,7 @@ toolchain go1.23.4 require ( github.com/longhorn/go-common-libs v0.0.0-20241227132452-5a6ca245288a github.com/longhorn/longhorn-manager v1.7.2 - github.com/otiai10/copy v1.14.0 + github.com/otiai10/copy v1.14.1 github.com/pkg/errors v0.9.1 github.com/sirupsen/logrus v1.9.3 github.com/spf13/cobra v1.8.1 @@ -71,6 +71,7 @@ require ( github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f // indirect github.com/opencontainers/runc v1.1.14 // indirect github.com/opencontainers/runtime-spec v1.1.0 // indirect + github.com/otiai10/mint v1.6.3 // indirect github.com/peterbourgon/diskv v2.0.1+incompatible // indirect github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 // indirect github.com/robfig/cron v1.2.0 // indirect diff --git a/go.sum b/go.sum index 171283d5..00350187 100644 --- a/go.sum +++ b/go.sum @@ -134,10 +134,10 @@ github.com/opencontainers/runc v1.1.14 h1:rgSuzbmgz5DUJjeSnw337TxDbRuqjs6iqQck/2 github.com/opencontainers/runc v1.1.14/go.mod h1:E4C2z+7BxR7GHXp0hAY53mek+x49X1LjPNeMTfRGvOA= github.com/opencontainers/runtime-spec v1.1.0 h1:HHUyrt9mwHUjtasSbXSMvs4cyFxh+Bll4AjJ9odEGpg= github.com/opencontainers/runtime-spec v1.1.0/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= -github.com/otiai10/copy v1.14.0 h1:dCI/t1iTdYGtkvCuBG2BgR6KZa83PTclw4U5n2wAllU= -github.com/otiai10/copy v1.14.0/go.mod h1:ECfuL02W+/FkTWZWgQqXPWZgW9oeKCSQ5qVfSc4qc4w= -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/otiai10/copy v1.14.1 h1:5/7E6qsUMBaH5AnQ0sSLzzTg1oTECmcCmT6lvF45Na8= +github.com/otiai10/copy v1.14.1/go.mod h1:oQwrEDDOci3IM8dJF0d8+jnbfPDllW6vUjNc3DoZm9I= +github.com/otiai10/mint v1.6.3 h1:87qsV/aw1F5as1eH1zS/yqHY85ANKVMgkDrf9rcxbQs= +github.com/otiai10/mint v1.6.3/go.mod h1:MJm72SBthJjz8qhefc4z1PYEieWmy8Bku7CjcAqyUSM= github.com/peterbourgon/diskv v2.0.1+incompatible h1:UBdAOUP5p4RWqPBg048CAvpKN+vxiaj6gdUUzhl4XmI= github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= diff --git a/vendor/github.com/otiai10/copy/README.md b/vendor/github.com/otiai10/copy/README.md index 7c8b4e05..9f3dce74 100644 --- a/vendor/github.com/otiai10/copy/README.md +++ b/vendor/github.com/otiai10/copy/README.md @@ -10,6 +10,8 @@ [![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) +[![GopherJS](https://github.com/otiai10/copy/actions/workflows/gopherjs.yml/badge.svg)](https://github.com/otiai10/copy/actions/workflows/gopherjs.yml) +[![Go WASM](https://github.com/otiai10/copy/actions/workflows/wasm.yml/badge.svg)](https://github.com/otiai10/copy/actions/workflows/wasm.yml) `copy` copies directories recursively. @@ -47,6 +49,10 @@ type Options struct { // Skip can specify which files should be skipped Skip func(srcinfo os.FileInfo, src, dest string) (bool, error) + // RenameDestination can rename destination. + // If not set, nil, it does nothing. + RenameDestination func(src, dest string) (string, error) + // PermissionControl can control permission of // every entry. // When you want to add permission 0222, do like diff --git a/vendor/github.com/otiai10/copy/copy.go b/vendor/github.com/otiai10/copy/copy.go index 2979af93..f9787cd9 100644 --- a/vendor/github.com/otiai10/copy/copy.go +++ b/vendor/github.com/otiai10/copy/copy.go @@ -4,7 +4,6 @@ import ( "context" "io" "io/fs" - "io/ioutil" "os" "path/filepath" "time" @@ -47,6 +46,12 @@ func switchboard(src, dest string, info os.FileInfo, opt Options) (err error) { return onError(src, dest, err, opt) } + if opt.RenameDestination != nil { + if dest, err = opt.RenameDestination(src, dest); err != nil { + return onError(src, dest, err, opt) + } + } + switch { case info.Mode()&os.ModeSymlink != 0: err = onsymlink(src, dest, opt) @@ -167,28 +172,29 @@ func dcopy(srcdir, destdir string, info os.FileInfo, opt Options) (err error) { } defer chmodfunc(&err) - var contents []os.FileInfo + var entries []fs.DirEntry if opt.FS != nil { - entries, err := fs.ReadDir(opt.FS, srcdir) + 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 + } else { + entries, err = os.ReadDir(srcdir) + if err != nil { + if os.IsNotExist(err) { + return nil } - contents = append(contents, info) + return err } - } else { - contents, err = ioutil.ReadDir(srcdir) } - if err != nil { - if os.IsNotExist(err) { - return nil + contents := make([]fs.FileInfo, 0, len(entries)) + for _, e := range entries { + info, err := e.Info() + if err != nil { + return err } - return + contents = append(contents, info) } if yes, err := shouldCopyDirectoryConcurrent(opt, srcdir, destdir); err != nil { @@ -286,6 +292,10 @@ func onsymlink(src, dest string, opt Options) error { if err != nil { return err } + if !filepath.IsAbs(orig) { + // orig is a relative link: need to add src dir to orig + orig = filepath.Join(filepath.Dir(src), orig) + } info, err := os.Lstat(orig) if err != nil { return err @@ -301,18 +311,29 @@ func onsymlink(src, dest string, opt Options) error { // lcopy is for a symlink, // with just creating a new symlink by replicating src symlink. func lcopy(src, dest string) error { - src, err := os.Readlink(src) + orig, err := os.Readlink(src) + // @See https://github.com/otiai10/copy/issues/111 + // TODO: This might be controlled by Options in the future. if err != nil { - if os.IsNotExist(err) { - return nil + if os.IsNotExist(err) { // Copy symlink even if not existing + return os.Symlink(src, dest) } return err } - return os.Symlink(src, dest) + + // @See https://github.com/otiai10/copy/issues/132 + // TODO: Control by SymlinkExistsAction + if _, err := os.Lstat(dest); err == nil { + if err := os.Remove(dest); err != nil { + return err + } + } + + return os.Symlink(orig, dest) } // fclose ANYHOW closes file, -// with asiging error raised during Close, +// with assigning error raised during Close, // BUT respecting the error already reported. func fclose(f io.Closer, reported *error) { if err := f.Close(); *reported == nil { @@ -321,7 +342,7 @@ func fclose(f io.Closer, reported *error) { } // onError lets caller to handle errors -// occured when copying a file. +// occurred when copying a file. func onError(src, dest string, err error, opt Options) error { if opt.OnError == nil { return err diff --git a/vendor/github.com/otiai10/copy/copy_namedpipes.go b/vendor/github.com/otiai10/copy/copy_namedpipes.go index 615ddcd5..657fb381 100644 --- a/vendor/github.com/otiai10/copy/copy_namedpipes.go +++ b/vendor/github.com/otiai10/copy/copy_namedpipes.go @@ -1,5 +1,4 @@ //go:build !windows && !plan9 && !netbsd && !aix && !illumos && !solaris && !js -// +build !windows,!plan9,!netbsd,!aix,!illumos,!solaris,!js package copy diff --git a/vendor/github.com/otiai10/copy/copy_namedpipes_x.go b/vendor/github.com/otiai10/copy/copy_namedpipes_x.go index 38dd9dc7..da3d6f79 100644 --- a/vendor/github.com/otiai10/copy/copy_namedpipes_x.go +++ b/vendor/github.com/otiai10/copy/copy_namedpipes_x.go @@ -1,5 +1,4 @@ //go:build windows || plan9 || netbsd || aix || illumos || solaris || js -// +build windows plan9 netbsd aix illumos solaris js package copy diff --git a/vendor/github.com/otiai10/copy/fileinfo_go1.15.go b/vendor/github.com/otiai10/copy/fileinfo_go1.15.go deleted file mode 100644 index c0708eaf..00000000 --- a/vendor/github.com/otiai10/copy/fileinfo_go1.15.go +++ /dev/null @@ -1,17 +0,0 @@ -//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 deleted file mode 100644 index 01b3fd24..00000000 --- a/vendor/github.com/otiai10/copy/fileinfo_go1.16.go +++ /dev/null @@ -1,17 +0,0 @@ -//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 1fbfcb14..c1db48c8 100644 --- a/vendor/github.com/otiai10/copy/options.go +++ b/vendor/github.com/otiai10/copy/options.go @@ -24,6 +24,9 @@ type Options struct { // Skip can specify which files should be skipped Skip func(srcinfo os.FileInfo, src, dest string) (bool, error) + // RenameDestination can specify the destination file or dir name if needed to rename. + RenameDestination func(src, dest string) (string, error) + // Specials includes special files to be copied. default false. Specials bool diff --git a/vendor/github.com/otiai10/copy/permission_control.go b/vendor/github.com/otiai10/copy/permission_control.go index 97ae12d8..901a8451 100644 --- a/vendor/github.com/otiai10/copy/permission_control.go +++ b/vendor/github.com/otiai10/copy/permission_control.go @@ -1,6 +1,7 @@ package copy import ( + "io/fs" "os" ) @@ -11,11 +12,11 @@ const ( tmpPermissionForDirectory = os.FileMode(0755) ) -type PermissionControlFunc func(srcinfo fileInfo, dest string) (chmodfunc func(*error), err error) +type PermissionControlFunc func(srcinfo fs.FileInfo, dest string) (chmodfunc func(*error), err error) var ( AddPermission = func(perm os.FileMode) PermissionControlFunc { - return func(srcinfo fileInfo, dest string) (func(*error), error) { + return func(srcinfo fs.FileInfo, dest string) (func(*error), error) { orig := srcinfo.Mode() if srcinfo.IsDir() { if err := os.MkdirAll(dest, tmpPermissionForDirectory); err != nil { @@ -28,7 +29,7 @@ var ( } } PerservePermission PermissionControlFunc = AddPermission(0) - DoNothing PermissionControlFunc = func(srcinfo fileInfo, dest string) (func(*error), error) { + DoNothing PermissionControlFunc = func(srcinfo fs.FileInfo, dest string) (func(*error), error) { if srcinfo.IsDir() { if err := os.MkdirAll(dest, srcinfo.Mode()); err != nil { return func(*error) {}, err @@ -39,7 +40,7 @@ var ( ) // chmod ANYHOW changes file mode, -// with asiging error raised during Chmod, +// with assigning 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 { diff --git a/vendor/github.com/otiai10/copy/preserve_ltimes.go b/vendor/github.com/otiai10/copy/preserve_ltimes.go index cc006d37..6b6787b2 100644 --- a/vendor/github.com/otiai10/copy/preserve_ltimes.go +++ b/vendor/github.com/otiai10/copy/preserve_ltimes.go @@ -1,5 +1,4 @@ //go:build !windows && !plan9 && !js -// +build !windows,!plan9,!js package copy diff --git a/vendor/github.com/otiai10/copy/preserve_ltimes_x.go b/vendor/github.com/otiai10/copy/preserve_ltimes_x.go index 02aec40b..5ef234d5 100644 --- a/vendor/github.com/otiai10/copy/preserve_ltimes_x.go +++ b/vendor/github.com/otiai10/copy/preserve_ltimes_x.go @@ -1,5 +1,4 @@ //go:build windows || js || plan9 -// +build windows js plan9 package copy diff --git a/vendor/github.com/otiai10/copy/preserve_owner.go b/vendor/github.com/otiai10/copy/preserve_owner.go index 13ec4f57..bd129644 100644 --- a/vendor/github.com/otiai10/copy/preserve_owner.go +++ b/vendor/github.com/otiai10/copy/preserve_owner.go @@ -1,14 +1,14 @@ //go:build !windows && !plan9 -// +build !windows,!plan9 package copy import ( + "io/fs" "os" "syscall" ) -func preserveOwner(src, dest string, info fileInfo) (err error) { +func preserveOwner(src, dest string, info fs.FileInfo) (err error) { if info == nil { if info, err = os.Stat(src); err != nil { return err diff --git a/vendor/github.com/otiai10/copy/preserve_owner_x.go b/vendor/github.com/otiai10/copy/preserve_owner_x.go index 9d825740..1e8f1251 100644 --- a/vendor/github.com/otiai10/copy/preserve_owner_x.go +++ b/vendor/github.com/otiai10/copy/preserve_owner_x.go @@ -1,8 +1,9 @@ //go:build windows || plan9 -// +build windows plan9 package copy -func preserveOwner(src, dest string, info fileInfo) (err error) { +import "io/fs" + +func preserveOwner(src, dest string, info fs.FileInfo) (err error) { return nil } diff --git a/vendor/github.com/otiai10/copy/stat_times.go b/vendor/github.com/otiai10/copy/stat_times.go index 75f45f6e..49ea67c2 100644 --- a/vendor/github.com/otiai10/copy/stat_times.go +++ b/vendor/github.com/otiai10/copy/stat_times.go @@ -1,5 +1,4 @@ //go:build !windows && !darwin && !freebsd && !plan9 && !netbsd && !js -// +build !windows,!darwin,!freebsd,!plan9,!netbsd,!js // TODO: add more runtimes diff --git a/vendor/github.com/otiai10/copy/stat_times_darwin.go b/vendor/github.com/otiai10/copy/stat_times_darwin.go index d4c23d8e..935ce1d7 100644 --- a/vendor/github.com/otiai10/copy/stat_times_darwin.go +++ b/vendor/github.com/otiai10/copy/stat_times_darwin.go @@ -1,5 +1,4 @@ //go:build darwin -// +build darwin package copy diff --git a/vendor/github.com/otiai10/copy/stat_times_freebsd.go b/vendor/github.com/otiai10/copy/stat_times_freebsd.go index 5309334e..1deb1cc4 100644 --- a/vendor/github.com/otiai10/copy/stat_times_freebsd.go +++ b/vendor/github.com/otiai10/copy/stat_times_freebsd.go @@ -1,5 +1,4 @@ //go:build freebsd -// +build freebsd package copy diff --git a/vendor/github.com/otiai10/copy/stat_times_js.go b/vendor/github.com/otiai10/copy/stat_times_js.go index c645771c..a4b1e288 100644 --- a/vendor/github.com/otiai10/copy/stat_times_js.go +++ b/vendor/github.com/otiai10/copy/stat_times_js.go @@ -1,5 +1,4 @@ //go:build js -// +build js package copy diff --git a/vendor/github.com/otiai10/copy/stat_times_windows.go b/vendor/github.com/otiai10/copy/stat_times_windows.go index d6a84a76..babfe7d9 100644 --- a/vendor/github.com/otiai10/copy/stat_times_windows.go +++ b/vendor/github.com/otiai10/copy/stat_times_windows.go @@ -1,5 +1,4 @@ //go:build windows -// +build windows package copy diff --git a/vendor/github.com/otiai10/copy/stat_times_x.go b/vendor/github.com/otiai10/copy/stat_times_x.go index 886ddd3f..53da32e2 100644 --- a/vendor/github.com/otiai10/copy/stat_times_x.go +++ b/vendor/github.com/otiai10/copy/stat_times_x.go @@ -1,5 +1,4 @@ //go:build plan9 || netbsd -// +build plan9 netbsd package copy diff --git a/vendor/github.com/otiai10/copy/symlink_test_x.go b/vendor/github.com/otiai10/copy/symlink_test_x.go new file mode 100644 index 00000000..1f6bb1f4 --- /dev/null +++ b/vendor/github.com/otiai10/copy/symlink_test_x.go @@ -0,0 +1,45 @@ +//go:build windows || plan9 || netbsd || aix || illumos || solaris || js + +package copy + +import ( + "os" + "testing" + + . "github.com/otiai10/mint" +) + +func TestOptions_OnSymlink(t *testing.T) { + opt := Options{OnSymlink: func(string) SymlinkAction { return Deep }} + err := Copy("test/data/case03", "test/data.copy/case03.deep", opt) + Expect(t, err).ToBe(nil) + info, err := os.Lstat("test/data.copy/case03.deep/case01") + Expect(t, err).ToBe(nil) + Expect(t, info.Mode()&os.ModeSymlink).ToBe(os.FileMode(0)) + + opt = Options{OnSymlink: func(string) SymlinkAction { return Shallow }} + err = Copy("test/data/case03", "test/data.copy/case03.shallow", opt) + Expect(t, err).ToBe(nil) + info, err = os.Lstat("test/data.copy/case03.shallow/case01") + Expect(t, err).ToBe(nil) + Expect(t, info.Mode()&os.ModeSymlink).Not().ToBe(os.FileMode(0)) + + opt = Options{OnSymlink: func(string) SymlinkAction { return Skip }} + err = Copy("test/data/case03", "test/data.copy/case03.skip", opt) + Expect(t, err).ToBe(nil) + _, err = os.Stat("test/data.copy/case03.skip/case01") + Expect(t, os.IsNotExist(err)).ToBe(true) + + err = Copy("test/data/case03", "test/data.copy/case03.default") + Expect(t, err).ToBe(nil) + info, err = os.Lstat("test/data.copy/case03.default/case01") + Expect(t, err).ToBe(nil) + Expect(t, info.Mode()&os.ModeSymlink).Not().ToBe(os.FileMode(0)) + + opt = Options{OnSymlink: nil} + err = Copy("test/data/case03", "test/data.copy/case03.not-specified", opt) + Expect(t, err).ToBe(nil) + info, err = os.Lstat("test/data.copy/case03.not-specified/case01") + Expect(t, err).ToBe(nil) + Expect(t, info.Mode()&os.ModeSymlink).Not().ToBe(os.FileMode(0)) +} diff --git a/vendor/github.com/otiai10/copy/test_setup.go b/vendor/github.com/otiai10/copy/test_setup.go deleted file mode 100644 index 64a52927..00000000 --- a/vendor/github.com/otiai10/copy/test_setup.go +++ /dev/null @@ -1,20 +0,0 @@ -//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 deleted file mode 100644 index 4c35b144..00000000 --- a/vendor/github.com/otiai10/copy/test_setup_x.go +++ /dev/null @@ -1,17 +0,0 @@ -//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/github.com/otiai10/mint/.gitignore b/vendor/github.com/otiai10/mint/.gitignore new file mode 100644 index 00000000..6ae51791 --- /dev/null +++ b/vendor/github.com/otiai10/mint/.gitignore @@ -0,0 +1,2 @@ +coverage.txt +vendor diff --git a/vendor/github.com/otiai10/mint/LICENSE b/vendor/github.com/otiai10/mint/LICENSE new file mode 100644 index 00000000..a5bad7fc --- /dev/null +++ b/vendor/github.com/otiai10/mint/LICENSE @@ -0,0 +1,7 @@ +Copyright 2017 otiai10 (Hiromu OCHIAI) + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/vendor/github.com/otiai10/mint/README.md b/vendor/github.com/otiai10/mint/README.md new file mode 100644 index 00000000..06caae03 --- /dev/null +++ b/vendor/github.com/otiai10/mint/README.md @@ -0,0 +1,62 @@ +# mint + +[![Go](https://github.com/otiai10/mint/actions/workflows/go.yml/badge.svg)](https://github.com/otiai10/mint/actions/workflows/go.yml) +[![codecov](https://codecov.io/gh/otiai10/mint/branch/master/graph/badge.svg)](https://codecov.io/gh/otiai10/mint) +[![Go Report Card](https://goreportcard.com/badge/github.com/otiai10/mint)](https://goreportcard.com/report/github.com/otiai10/mint) +[![GoDoc](https://godoc.org/github.com/otiai10/mint?status.png)](https://godoc.org/github.com/otiai10/mint) +[![GitHub tag (latest SemVer)](https://img.shields.io/github/v/tag/otiai10/mint?sort=semver)](https://pkg.go.dev/github.com/otiai10/mint) +[![FOSSA Status](https://app.fossa.com/api/projects/git%2Bgithub.com%2Fotiai10%2Fmint.svg?type=shield)](https://app.fossa.com/projects/git%2Bgithub.com%2Fotiai10%2Fmint?ref=badge_shield) + +The very minimum assertion for Go. + +```go +package your_test + +import ( + "testing" + "pkg/your" + . "github.com/otiai10/mint" +) + +func TestFoo(t *testing.T) { + + foo := your.Foo() + Expect(t, foo).ToBe(1234) + Expect(t, foo).TypeOf("int") + Expect(t, foo).Not().ToBe(nil) + Expect(t, func() { yourFunc() }).Exit(1) + + // If assertion failed, exit 1 with message. + Expect(t, foo).ToBe("foobarbuz") + + // You can run assertions without os.Exit + res := Expect(t, foo).Dry().ToBe("bar") + // res.OK() == false + + // You can omit repeated `t`. + m := mint.Blend(t) + m.Expect(foo).ToBe(1234) +} +``` + +# features + +- Simple syntax +- Loosely coupled +- Plain implementation + +# tests +``` +go test ./... +``` + +# use cases + +Projects bellow use `mint` + +- [github.com/otiai10/gosseract](https://github.com/otiai10/gosseract/blob/master/all_test.go) +- [github.com/otiai10/marmoset](https://github.com/otiai10/marmoset/blob/master/all_test.go#L168-L190) + + +## License +[![FOSSA Status](https://app.fossa.com/api/projects/git%2Bgithub.com%2Fotiai10%2Fmint.svg?type=large)](https://app.fossa.com/projects/git%2Bgithub.com%2Fotiai10%2Fmint?ref=badge_large) \ No newline at end of file diff --git a/vendor/github.com/otiai10/mint/because.go b/vendor/github.com/otiai10/mint/because.go new file mode 100644 index 00000000..6d496cee --- /dev/null +++ b/vendor/github.com/otiai10/mint/because.go @@ -0,0 +1,15 @@ +package mint + +import "testing" + +// Because is context printer. +func Because(t *testing.T, context string, wrapper func(*testing.T)) { + Log(" Because ", context, "\n") + wrapper(t) +} + +// When is an alternative of `Because` +func When(t *testing.T, context string, wrapper func(*testing.T)) { + Log(" When ", context, "\n") + wrapper(t) +} diff --git a/vendor/github.com/otiai10/mint/comparer.go b/vendor/github.com/otiai10/mint/comparer.go new file mode 100644 index 00000000..d543eb6d --- /dev/null +++ b/vendor/github.com/otiai10/mint/comparer.go @@ -0,0 +1,53 @@ +package mint + +import ( + "fmt" + "reflect" +) + +func getComparer(a, b interface{}, deeply bool) Comparer { + if deeply { + return deepComparer{} + } + switch reflect.ValueOf(a).Kind() { + case reflect.Slice: + return sliceComparer{} + case reflect.Map: + return mapComparer{} + } + if b == nil { + return nilComparer{} + } + return defaultComparer{} +} + +type Comparer interface { + Compare(a, b interface{}) bool +} + +type defaultComparer struct{} + +func (c defaultComparer) Compare(a, b interface{}) bool { + return a == b +} + +type deepComparer struct{} + +func (c deepComparer) Compare(a, b interface{}) bool { + return reflect.DeepEqual(a, b) +} + +type mapComparer struct { + deepComparer +} + +type sliceComparer struct { + deepComparer +} + +type nilComparer struct { +} + +func (c nilComparer) Compare(a, _ interface{}) bool { + return fmt.Sprintf("%v", a) == fmt.Sprintf("%v", nil) +} diff --git a/vendor/github.com/otiai10/mint/exit.go b/vendor/github.com/otiai10/mint/exit.go new file mode 100644 index 00000000..fc64ac96 --- /dev/null +++ b/vendor/github.com/otiai10/mint/exit.go @@ -0,0 +1,41 @@ +//go:build !freebsd +// +build !freebsd + +package mint + +// On "freebsd/FreeBSD-10.4-STABLE" OS image, +// Go installed by `pkg install` might NOT have `syscall.Mprotect` +// causing such error: "bou.ke/monkey/replace_unix.go:13:10: undefined: syscall.Mprotect". +// See https://www.freebsd.org/cgi/man.cgi?sektion=2&query=mprotect +// TODO: Fix the image for https://github.com/otiai10/gosseract/blob/master/test/runtimes/freebsd.Vagrantfile#L4 +/* + * "bou.ke/monkey" + */ // FIXME: Now I remove this library because of LICENSE problem +// See https://github.com/otiai10/copy/issues/12 as well + +// Exit ... +func (testee *Testee) Exit(expectedCode int) MintResult { + + panic("`mint.Testee.Exit` method is temporarily deprecated.") + + /* + fun, ok := testee.actual.(func()) + if !ok { + panic("mint error: Exit only can be called for func type value") + } + + var actualCode int + patch := monkey.Patch(os.Exit, func(code int) { + actualCode = code + }) + fun() + patch.Unpatch() + + testee.actual = actualCode + if judge(actualCode, expectedCode, testee.not, testee.deeply) { + return testee.result + } + testee.expected = expectedCode + return testee.failed(failExitCode) + */ +} diff --git a/vendor/github.com/otiai10/mint/exit_freebsd.go b/vendor/github.com/otiai10/mint/exit_freebsd.go new file mode 100644 index 00000000..d5eed6cf --- /dev/null +++ b/vendor/github.com/otiai10/mint/exit_freebsd.go @@ -0,0 +1,10 @@ +//go:build freebsd +// +build freebsd + +package mint + +// Exit ... +func (testee *Testee) Exit(expectedCode int) MintResult { + panic("Exit method can NOT be used on FreeBSD, for now.") + return MintResult{ok: false} +} diff --git a/vendor/github.com/otiai10/mint/log.go b/vendor/github.com/otiai10/mint/log.go new file mode 100644 index 00000000..6aa8f8dc --- /dev/null +++ b/vendor/github.com/otiai10/mint/log.go @@ -0,0 +1,15 @@ +package mint + +import ( + "fmt" + "os" +) + +// Log only output if -v flag is given. +// This is because the standard "t.Testing.Log" method decorates +// its caller: runtime.Caller(3) automatically. +func Log(args ...interface{}) { + if isVerbose(os.Args) { + fmt.Print(args...) + } +} diff --git a/vendor/github.com/otiai10/mint/mint.go b/vendor/github.com/otiai10/mint/mint.go new file mode 100644 index 00000000..a37e3c1d --- /dev/null +++ b/vendor/github.com/otiai10/mint/mint.go @@ -0,0 +1,86 @@ +package mint + +import ( + "os" + "testing" +) + +// Mint (mint.Mint) is wrapper for *testing.T +// blending testing type to omit repeated `t`. +type Mint struct { + t *testing.T +} + +var ( + failToBe = 0 + failType = 1 + failIn = 2 + failToMatch = 3 + failExitCode = 4 + scolds = map[int]string{ + failToBe: "%s:%d\n\tExpected %sto be\t`%+v`\n\tBut actual\t`%+v`", + failType: "%s:%d\n\tExpected %stype\t`%+v`\n\tBut actual\t`%T`", + failIn: "%s:%d\n\tExpected %sis in\t`%v`\n\tbut it's not", + failToMatch: "%s:%d\n\tExpected %v to match\t`%s`\n\tBut actual\t`%+v`", + failExitCode: "%s:%d\n\tExpected %sto exit with code `%d`\n\tBut actual\t`%d`", + } +) +var ( + redB = "\033[1;31m" + reset = "\033[0m" + colorize = map[string]func(string) string{ + "red": func(v string) string { + return redB + v + reset + }, + } +) + +// Blend provides (blended) *mint.Mint. +// You can save writing "t" repeatedly. +func Blend(t *testing.T) *Mint { + return &Mint{ + t, + } +} + +// Expect provides "*Testee". +// The blended mint is merely a proxy to instantiate testee. +func (m *Mint) Expect(actual interface{}) *Testee { + return expect(m.t, actual) +} + +// Expect provides "*mint.Testee". +// It has assertion methods such as "ToBe". +func Expect(t *testing.T, actual interface{}) *Testee { + return expect(t, actual) +} + +func expect(t *testing.T, actual interface{}) *Testee { + return &Testee{t: t, actual: actual, verbose: isVerbose(os.Args), result: MintResult{ok: true}} +} + +// Require provides "*mint.Testee", +// which stops execution of goroutine when the assertion failed. +func Require(t *testing.T, actual interface{}) *Testee { + return require(t, actual) +} + +func require(t *testing.T, actual interface{}) *Testee { + return &Testee{t: t, actual: actual, verbose: isVerbose(os.Args), required: true, result: MintResult{ok: true}} +} + +func isVerbose(flags []string) bool { + for _, f := range flags { + if f == "-test.v=true" { + return true + } + } + return false +} +func judge(a, b interface{}, not, deeply bool) bool { + comparer := getComparer(a, b, deeply) + if not { + return !comparer.Compare(a, b) + } + return comparer.Compare(a, b) +} diff --git a/vendor/github.com/otiai10/mint/mocks.go b/vendor/github.com/otiai10/mint/mocks.go new file mode 100644 index 00000000..87feab49 --- /dev/null +++ b/vendor/github.com/otiai10/mint/mocks.go @@ -0,0 +1,30 @@ +package mint + +import ( + "bytes" + "io/ioutil" + "net/http" +) + +type HTTPClientMock struct { + HTTPError error + ResponseStatusCode int + ResponseBody string +} + +func (hcm *HTTPClientMock) Handle() (res *http.Response, err error, ok bool) { + if hcm.HTTPError != nil { + err = hcm.HTTPError + ok = true + } + res = new(http.Response) + if hcm.ResponseBody != "" { + res.Body = ioutil.NopCloser(bytes.NewBufferString(hcm.ResponseBody)) + ok = true + } + if hcm.ResponseStatusCode != 0 { + res.StatusCode = hcm.ResponseStatusCode + ok = true + } + return res, err, ok +} diff --git a/vendor/github.com/otiai10/mint/mquery/README.md b/vendor/github.com/otiai10/mint/mquery/README.md new file mode 100644 index 00000000..4992930d --- /dev/null +++ b/vendor/github.com/otiai10/mint/mquery/README.md @@ -0,0 +1,31 @@ +mquery +=== + +```go +import mquery + +var m = map[string]interface{}{ + "foo": "bar", + "hoge": map[string]interface{}{ + "name": "otiai10", + }, + "fuga": map[int]map[string]interface{}{ + 0: {"greet": "Hello"}, + 1: {"greet": "こんにちは"}, + }, + "langs": []string{"Go", "JavaScript", "English"}, + "baz": nil, + "required": false, +} + +func main() { + fmt.Println( + Query(m, "foo"), // "bar" + Query(m, "hoge.name"), // "otiai10" + Query(m, "fuga.0.greet"), // "Hello" + Query(m, "langs.2"), // "English" + Query(m, "required"), // false + Query(m, "baz.biz"), // nil + ) +} +``` \ No newline at end of file diff --git a/vendor/github.com/otiai10/mint/mquery/mquery.go b/vendor/github.com/otiai10/mint/mquery/mquery.go new file mode 100644 index 00000000..2a7ddbac --- /dev/null +++ b/vendor/github.com/otiai10/mint/mquery/mquery.go @@ -0,0 +1,72 @@ +package mquery + +import ( + "fmt" + "reflect" + "strconv" + "strings" +) + +func Query(m interface{}, q string) interface{} { + return query(m, strings.Split(q, ".")) +} + +func query(m interface{}, qs []string) interface{} { + t := reflect.TypeOf(m) + switch t.Kind() { + case reflect.Map: + return queryMap(m, t, qs) + case reflect.Slice: + return querySlice(m, t, qs) + default: + return m + } +} + +func queryMap(m interface{}, t reflect.Type, qs []string) interface{} { + if len(qs) == 0 { + return m + } + val := reflect.ValueOf(m) + if val.IsZero() { + return nil + } + switch t.Key().Kind() { + case reflect.String: + val := reflect.ValueOf(m).MapIndex(reflect.ValueOf(qs[0])) + if !val.IsValid() { + return nil + } + return query(val.Interface(), qs[1:]) + case reflect.Int: + i, err := strconv.Atoi(qs[0]) + if err != nil { + return fmt.Errorf("cannot access map with keyword: %s: %v", qs[0], err) + } + val := reflect.ValueOf(m).MapIndex(reflect.ValueOf(i)) + if !val.IsValid() { + return nil + } + return query(val.Interface(), qs[1:]) + } + return nil +} + +func querySlice(m interface{}, t reflect.Type, qs []string) interface{} { + if len(qs) == 0 { + return m + } + v := reflect.ValueOf(m) + if v.Len() == 0 { + return nil + } + i, err := strconv.Atoi(qs[0]) + if err != nil { + return fmt.Errorf("cannot access slice with keyword: %s: %v", qs[0], err) + } + if v.Len() <= i { + return nil + } + next := v.Index(i).Interface() + return query(next, qs[1:]) +} diff --git a/vendor/github.com/otiai10/mint/result.go b/vendor/github.com/otiai10/mint/result.go new file mode 100644 index 00000000..2ce38c05 --- /dev/null +++ b/vendor/github.com/otiai10/mint/result.go @@ -0,0 +1,23 @@ +package mint + +// MintResult provide the results of assertion +// for `Dry` option. +type MintResult struct { + ok bool + message string +} + +// OK returns whether result is ok or not. +func (r MintResult) OK() bool { + return r.ok +} + +// NG is the opposite alias for OK(). +func (r MintResult) NG() bool { + return !r.ok +} + +// Message returns failure message. +func (r MintResult) Message() string { + return r.message +} diff --git a/vendor/github.com/otiai10/mint/testee.go b/vendor/github.com/otiai10/mint/testee.go new file mode 100644 index 00000000..90537fc3 --- /dev/null +++ b/vendor/github.com/otiai10/mint/testee.go @@ -0,0 +1,145 @@ +package mint + +import ( + "fmt" + "path/filepath" + "reflect" + "regexp" + "runtime" + "testing" + + "github.com/otiai10/mint/mquery" +) + +// Testee is holder of interfaces which user want to assert +// and also has its result. +type Testee struct { + t *testing.T + actual interface{} + expected interface{} + dry bool + not bool + deeply bool + result MintResult + required bool + verbose bool + + // origin string // Only used when querying +} + +// Query queries the actual value with given query string. +func (testee *Testee) Query(query string) *Testee { + // testee.origin = fmt.Sprintf("%T", testee.actual) + testee.actual = mquery.Query(testee.actual, query) + return testee +} + +// ToBe can assert the testee to equal the parameter of this func. +// OS will exit with code 1, when the assertion fail. +// If you don't want to exit, see "Dry()". +func (testee *Testee) ToBe(expected interface{}) MintResult { + if judge(testee.actual, expected, testee.not, testee.deeply) { + return testee.result + } + testee.expected = expected + return testee.failed(failToBe) +} + +// Match can assert the testee to match with specified regular expression. +// It uses `regexp.MustCompile`, it's due to caller to make sure it's valid regexp. +// OS will exit with code 1, when the assertion fail. +// If you don't want to exit, see "Dry()". +func (testee *Testee) Match(expression string) MintResult { + exp := regexp.MustCompile(expression) + matched := exp.MatchString(fmt.Sprintf("%v", testee.actual)) + if judge(matched, true, testee.not, testee.deeply) { + return testee.result + } + testee.expected = expression + return testee.failed(failToMatch) +} + +// In can assert the testee is in given array. +func (testee *Testee) In(expecteds ...interface{}) MintResult { + for _, expected := range expecteds { + if judge(testee.actual, expected, testee.not, testee.deeply) { + return testee.result + } + } + testee.expected = expecteds + return testee.failed(failIn) +} + +// TypeOf can assert the type of testee to equal the parameter of this func. +// OS will exit with code 1, when the assertion fail. +// If you don't want to exit, see "Dry()". +func (testee *Testee) TypeOf(typeName string) MintResult { + if judge(reflect.TypeOf(testee.actual).String(), typeName, testee.not, testee.deeply) { + return testee.result + } + testee.expected = typeName + return testee.failed(failType) +} + +// Not makes following assertion conversed. +func (testee *Testee) Not() *Testee { + testee.not = true + return testee +} + +// Dry makes the testee NOT to call "Fail()". +// Use this if you want to fail test in a purpose. +func (testee *Testee) Dry() *Testee { + testee.dry = true + return testee +} + +// Deeply makes following assertions use `reflect.DeepEqual`. +// You had better use this to compare reference type objects. +func (testee *Testee) Deeply() *Testee { + testee.deeply = true + return testee +} + +func (testee *Testee) failed(failure int) MintResult { + message := testee.toText(failure) + testee.result.ok = false + testee.result.message = message + if !testee.dry { + fmt.Println(colorize["red"](message)) + if testee.required { + testee.t.FailNow() + } else { + testee.t.Fail() + } + } + return testee.result +} + +func (testee *Testee) toText(fail int) string { + not := "" + if testee.not { + not = "NOT " + } + _, file, line, _ := runtime.Caller(3) + // if testee.origin != "" { + // testee.origin = fmt.Sprintf("(queried from %s)", testee.origin) + // } + return fmt.Sprintf( + scolds[fail], + filepath.Base(file), line, + not, + testee.expected, + testee.actual, + ) +} + +// Log only output if -v flag is given. +// This is because the standard "t.Testing.Log" method decorates +// its caller: runtime.Caller(3) automatically. +func (testee *Testee) Log(args ...interface{}) { + if !testee.verbose { + return + } + fmt.Print(args...) +} diff --git a/vendor/modules.txt b/vendor/modules.txt index 5fac5b02..e3c66beb 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -205,9 +205,13 @@ github.com/opencontainers/runc/libcontainer/userns # github.com/opencontainers/runtime-spec v1.1.0 ## explicit github.com/opencontainers/runtime-spec/specs-go -# github.com/otiai10/copy v1.14.0 +# github.com/otiai10/copy v1.14.1 ## explicit; go 1.18 github.com/otiai10/copy +# github.com/otiai10/mint v1.6.3 +## explicit; go 1.18 +github.com/otiai10/mint +github.com/otiai10/mint/mquery # github.com/peterbourgon/diskv v2.0.1+incompatible ## explicit github.com/peterbourgon/diskv