diff --git a/changes/20230724173139.feature b/changes/20230724173139.feature new file mode 100644 index 0000000000..b550a8619a --- /dev/null +++ b/changes/20230724173139.feature @@ -0,0 +1 @@ +:sparkles: `[errortest]` Added utilities to check the error description diff --git a/changes/20230724173259.bugfix b/changes/20230724173259.bugfix new file mode 100644 index 0000000000..967db3b0c7 --- /dev/null +++ b/changes/20230724173259.bugfix @@ -0,0 +1 @@ +:recycle: `[filesystem]` Use `afero.ReadOnlyFS` rather than our own implementation when exposing `embed.FS` diff --git a/changes/20230728174153.feature b/changes/20230728174153.feature new file mode 100644 index 0000000000..7bf48aa688 --- /dev/null +++ b/changes/20230728174153.feature @@ -0,0 +1 @@ +:sparkles: `[filesystem]` Added zipFS to enable filesystem utilities on zip files diff --git a/changes/20230731170709.feature b/changes/20230731170709.feature new file mode 100644 index 0000000000..79d2c0a206 --- /dev/null +++ b/changes/20230731170709.feature @@ -0,0 +1 @@ +:sparkles: Added module `[resource]` to define generic utilities regarding resource management diff --git a/utils/commonerrors/errortest/testing.go b/utils/commonerrors/errortest/testing.go index c63d6b537c..8ab1e7cb6c 100644 --- a/utils/commonerrors/errortest/testing.go +++ b/utils/commonerrors/errortest/testing.go @@ -18,6 +18,15 @@ func AssertError(t *testing.T, err error, expectedErrors ...error) bool { return assert.Fail(t, fmt.Sprintf("Failed error assertion:\n actual: %v\n expected: %+v", err, expectedErrors)) } +// AssertErrorDescription asserts that the error description corresponds to one of the `expectedErrorDescriptions` +// This is a wrapper for commonerrors.CorrespondTo. +func AssertErrorDescription(t *testing.T, err error, expectedErrorDescriptions ...string) bool { + if commonerrors.CorrespondTo(err, expectedErrorDescriptions...) { + return true + } + return assert.Fail(t, fmt.Sprintf("Failed error description assertion:\n actual: %v\n expected: %+v", err, expectedErrorDescriptions)) +} + // RequireError requires that the error is matching one of the `expectedErrors` // This is a wrapper for commonerrors.Any. func RequireError(t *testing.T, err error, expectedErrors ...error) { @@ -27,3 +36,13 @@ func RequireError(t *testing.T, err error, expectedErrors ...error) { } t.FailNow() } + +// RequireErrorDescription requires that the error description corresponds to one of the `expectedErrorDescriptions` +// This is a wrapper for commonerrors.CorrespondTo. +func RequireErrorDescription(t *testing.T, err error, expectedErrorDescriptions ...string) { + t.Helper() + if commonerrors.CorrespondTo(err, expectedErrorDescriptions...) { + return + } + t.FailNow() +} diff --git a/utils/commonerrors/errortest/testing_test.go b/utils/commonerrors/errortest/testing_test.go index 49213f4c48..41fb44681c 100644 --- a/utils/commonerrors/errortest/testing_test.go +++ b/utils/commonerrors/errortest/testing_test.go @@ -10,6 +10,14 @@ func TestAssertError(t *testing.T) { AssertError(t, commonerrors.ErrUndefined, commonerrors.ErrNotFound, commonerrors.ErrMarshalling, commonerrors.ErrUndefined) } +func TestAssertErrorDescription(t *testing.T) { + AssertErrorDescription(t, commonerrors.ErrUndefined, "undefined", "not found") +} + func TestRequireError(t *testing.T) { RequireError(t, commonerrors.ErrUndefined, commonerrors.ErrNotFound, commonerrors.ErrMarshalling, commonerrors.ErrUndefined) } + +func TestRequireErrorContent(t *testing.T) { + RequireErrorDescription(t, commonerrors.ErrUndefined, "undefined", "not found") +} diff --git a/utils/filesystem/embedfs.go b/utils/filesystem/embedfs.go index a771af251d..b7c16b5c2b 100644 --- a/utils/filesystem/embedfs.go +++ b/utils/filesystem/embedfs.go @@ -3,31 +3,17 @@ package filesystem import ( "embed" "fmt" - "os" "github.com/spf13/afero" "github.com/ARM-software/golang-utils/utils/commonerrors" ) -type embedFsAdapter struct { - afero.Fs -} - -func (e *embedFsAdapter) OpenFile(name string, flag int, _ os.FileMode) (afero.File, error) { - if flag != os.O_RDONLY { - return nil, fmt.Errorf("%w: embed.FS is readonly", commonerrors.ErrUnsupported) - } - return e.Open(name) -} - func newEmbedFSAdapter(fs *embed.FS) (afero.Fs, error) { if fs == nil { return nil, fmt.Errorf("%w: missing filesystem", commonerrors.ErrUndefined) } - return &embedFsAdapter{ - Fs: afero.FromIOFS{ - FS: *fs, - }, - }, nil + return afero.NewReadOnlyFs(afero.FromIOFS{ + FS: *fs, + }), nil } diff --git a/utils/filesystem/embedfs_test.go b/utils/filesystem/embedfs_test.go index 1e83d6788d..bb0ce74d2f 100644 --- a/utils/filesystem/embedfs_test.go +++ b/utils/filesystem/embedfs_test.go @@ -137,7 +137,7 @@ func Test_embed_not_supported(t *testing.T) { require.NoError(t, err) _, err = efs.TempDir("testdata", "aaaa") - assert.True(t, commonerrors.CorrespondTo(err, "permission denied")) + errortest.AssertErrorDescription(t, err, "operation not permitted") f, err := efs.OpenFile("testdata/embed/test.txt", os.O_RDWR, os.FileMode(0600)) defer func() { @@ -146,10 +146,10 @@ func Test_embed_not_supported(t *testing.T) { } }() require.Error(t, err) - errortest.AssertError(t, err, commonerrors.ErrUnsupported) + errortest.AssertErrorDescription(t, err, "operation not permitted") err = efs.Chmod("testdata/embed/test.txt", os.FileMode(0600)) require.Error(t, err) - assert.True(t, commonerrors.CorrespondTo(err, "permission denied")) + errortest.AssertErrorDescription(t, err, "operation not permitted") } diff --git a/utils/filesystem/files.go b/utils/filesystem/files.go index cccefc6c8b..b7e35c83b6 100644 --- a/utils/filesystem/files.go +++ b/utils/filesystem/files.go @@ -25,6 +25,7 @@ import ( "github.com/ARM-software/golang-utils/utils/parallelisation" "github.com/ARM-software/golang-utils/utils/platform" "github.com/ARM-software/golang-utils/utils/reflection" + "github.com/ARM-software/golang-utils/utils/resource" "github.com/ARM-software/golang-utils/utils/safeio" ) @@ -64,13 +65,28 @@ func IdentityPathConverterFunc(path string) string { } type VFS struct { + resourceInUse resource.ICloseableResource vfs afero.Fs fsType FilesystemType pathConverter func(path string) string } +// NewVirtualFileSystem returns a virtual filesystem similarly to NewCloseableVirtualFileSystem func NewVirtualFileSystem(vfs afero.Fs, fsType FilesystemType, pathConverter func(path string) string) FS { + return NewCloseableVirtualFileSystem(vfs, fsType, nil, "", pathConverter) +} + +// NewCloseableVirtualFileSystem returns a virtual filesystem which requires closing after use. +// It is a wrapper over afero.FS virtual filesystem and tends to define common filesystem utilities as the ones available in posix. +func NewCloseableVirtualFileSystem(vfs afero.Fs, fsType FilesystemType, resourceInUse io.Closer, resourceInUseDescription string, pathConverter func(path string) string) ICloseableFS { + var resourceInUseByFs resource.ICloseableResource + if resourceInUse == nil { + resourceInUseByFs = resource.NewNonCloseableResource() + } else { + resourceInUseByFs = resource.NewCloseableResource(resourceInUse, resourceInUseDescription) + } return &VFS{ + resourceInUse: resourceInUseByFs, vfs: vfs, fsType: fsType, pathConverter: pathConverter, @@ -85,6 +101,14 @@ func GetType() FilesystemType { return globalFileSystem.GetType() } +// checkWhetherUnderlyingResourceIsClosed checks whether the filesystem is in a working state when relying on a ICloseableResource. +func (fs *VFS) checkWhetherUnderlyingResourceIsClosed() error { + if fs.resourceInUse.IsClosed() { + return fmt.Errorf("%w: the resource this filesystem is based on [%v] has been closed", commonerrors.ErrCondition, fs.resourceInUse.String()) + } + return nil +} + // Walk walks https://golang.org/pkg/path/filepath/#WalkDir func (fs *VFS) Walk(root string, fn filepath.WalkFunc) error { return fs.WalkWithContext(context.Background(), root, fn) @@ -95,6 +119,11 @@ func (fs *VFS) WalkWithContext(ctx context.Context, root string, fn filepath.Wal } func (fs *VFS) WalkWithContextAndExclusionPatterns(ctx context.Context, root string, fn filepath.WalkFunc, exclusionPatterns ...string) (err error) { + err = fs.checkWhetherUnderlyingResourceIsClosed() + if err != nil { + return + } + root = filepath.Join(root, string(fs.PathSeparator())) exclusionRegex, err := NewExclusionRegexList(fs.PathSeparator(), exclusionPatterns...) if err != nil { return @@ -118,6 +147,10 @@ func (fs *VFS) WalkWithContextAndExclusionPatterns(ctx context.Context, root str // walks recursively descends path, calling fn. func (fs *VFS) walk(ctx context.Context, path string, info os.FileInfo, exclusions []*regexp.Regexp, fn filepath.WalkFunc) (err error) { + err = fs.checkWhetherUnderlyingResourceIsClosed() + if err != nil { + return + } err = parallelisation.DetermineContextError(ctx) if err != nil { return @@ -187,7 +220,8 @@ func CurrentDirectory() (string, error) { return globalFileSystem.CurrentDirectory() } func (fs *VFS) CurrentDirectory() (string, error) { - return os.Getwd() + current, err := os.Getwd() + return fs.ConvertFilePath(current), err } func Lstat(name string) (fileInfo os.FileInfo, err error) { @@ -195,6 +229,10 @@ func Lstat(name string) (fileInfo os.FileInfo, err error) { } func (fs *VFS) Lstat(name string) (fileInfo os.FileInfo, err error) { + err = fs.checkWhetherUnderlyingResourceIsClosed() + if err != nil { + return + } if correctobj, ok := fs.vfs.(interface { LstatIfPossible(string) (os.FileInfo, bool, error) }); ok { @@ -216,6 +254,10 @@ func GenericOpen(name string) (File, error) { return globalFileSystem.GenericOpen(name) } func (fs *VFS) GenericOpen(name string) (File, error) { + err := fs.checkWhetherUnderlyingResourceIsClosed() + if err != nil { + return nil, err + } return convertFile(func() (afero.File, error) { return fs.vfs.Open(name) }, func() error { return nil }) } @@ -224,6 +266,10 @@ func OpenFile(name string, flag int, perm os.FileMode) (File, error) { } func (fs *VFS) OpenFile(name string, flag int, perm os.FileMode) (File, error) { + err := fs.checkWhetherUnderlyingResourceIsClosed() + if err != nil { + return nil, err + } return convertFile(func() (afero.File, error) { return fs.vfs.OpenFile(name, flag, perm) }, func() error { return nil }) } @@ -231,6 +277,10 @@ func CreateFile(name string) (File, error) { return globalFileSystem.CreateFile(name) } func (fs *VFS) CreateFile(name string) (File, error) { + err := fs.checkWhetherUnderlyingResourceIsClosed() + if err != nil { + return nil, err + } return convertFile(func() (afero.File, error) { return fs.vfs.Create(name) }, func() error { return nil }) } @@ -263,6 +313,10 @@ func (fs *VFS) ReadFileWithContextAndLimits(ctx context.Context, filename string } func (fs *VFS) readFileWithContextAndLimits(ctx context.Context, filename string, limits ILimits) (content []byte, err error) { + err = fs.checkWhetherUnderlyingResourceIsClosed() + if err != nil { + return + } err = parallelisation.DetermineContextError(ctx) if err != nil { return @@ -288,6 +342,10 @@ func ReadFileContent(ctx context.Context, file File) ([]byte, error) { } func (fs *VFS) ReadFileContent(ctx context.Context, file File, limits ILimits) (content []byte, err error) { + err = fs.checkWhetherUnderlyingResourceIsClosed() + if err != nil { + return + } err = parallelisation.DetermineContextError(ctx) if err != nil { return @@ -332,6 +390,10 @@ func (fs *VFS) WriteFile(filename string, data []byte, perm os.FileMode) error { } func (fs *VFS) WriteFileWithContext(ctx context.Context, filename string, data []byte, perm os.FileMode) (err error) { + err = fs.checkWhetherUnderlyingResourceIsClosed() + if err != nil { + return + } reader := bytes.NewReader(data) n, err := fs.WriteToFile(ctx, filename, reader, perm) if err != nil { @@ -344,6 +406,10 @@ func (fs *VFS) WriteFileWithContext(ctx context.Context, filename string, data [ } func (fs *VFS) WriteToFile(ctx context.Context, filename string, reader io.Reader, perm os.FileMode) (written int64, err error) { + err = fs.checkWhetherUnderlyingResourceIsClosed() + if err != nil { + return + } err = parallelisation.DetermineContextError(ctx) if err != nil { return @@ -378,6 +444,10 @@ func Stat(name string) (os.FileInfo, error) { } func (fs *VFS) Stat(name string) (os.FileInfo, error) { + err := fs.checkWhetherUnderlyingResourceIsClosed() + if err != nil { + return nil, err + } return fs.vfs.Stat(name) } @@ -394,6 +464,10 @@ func TempDir(dir string, prefix string) (name string, err error) { } func (fs *VFS) TempDir(dir string, prefix string) (name string, err error) { + err = fs.checkWhetherUnderlyingResourceIsClosed() + if err != nil { + return + } return afero.TempDir(fs.vfs, dir, prefix) } @@ -408,6 +482,10 @@ func TempFile(dir string, pattern string) (f File, err error) { return globalFileSystem.TempFile(dir, pattern) } func (fs *VFS) TempFile(dir string, prefix string) (f File, err error) { + err = fs.checkWhetherUnderlyingResourceIsClosed() + if err != nil { + return + } file, err := afero.TempFile(fs.vfs, dir, prefix) if err != nil { return @@ -435,6 +513,10 @@ func (fs *VFS) CleanDirWithContext(ctx context.Context, dir string) error { return fs.CleanDirWithContextAndExclusionPatterns(ctx, dir) } func (fs *VFS) CleanDirWithContextAndExclusionPatterns(ctx context.Context, dir string, exclusionPatterns ...string) (err error) { + err = fs.checkWhetherUnderlyingResourceIsClosed() + if err != nil { + return + } err = parallelisation.DetermineContextError(ctx) if err != nil { return @@ -461,6 +543,10 @@ func (fs *VFS) CleanDirWithContextAndExclusionPatterns(ctx context.Context, dir } func (fs *VFS) removeFileWithContext(ctx context.Context, dir, f string) (err error) { + err = fs.checkWhetherUnderlyingResourceIsClosed() + if err != nil { + return + } err = parallelisation.DetermineContextError(ctx) if err != nil { return @@ -518,6 +604,10 @@ func (fs *VFS) RemoveWithContext(ctx context.Context, dir string) error { return fs.RemoveWithContextAndExclusionPatterns(ctx, dir) } func (fs *VFS) RemoveWithContextAndExclusionPatterns(ctx context.Context, dir string, exclusionPatterns ...string) (err error) { + err = fs.checkWhetherUnderlyingResourceIsClosed() + if err != nil { + return + } if dir == "" { return } @@ -560,6 +650,10 @@ func IsFile(path string) (result bool, err error) { return globalFileSystem.IsFile(path) } func (fs *VFS) IsFile(path string) (result bool, err error) { + err = fs.checkWhetherUnderlyingResourceIsClosed() + if err != nil { + return + } if !fs.Exists(path) { return } @@ -579,6 +673,10 @@ func IsRegularFile(fi os.FileInfo) bool { } func (fs *VFS) IsLink(path string) (result bool, err error) { + err = fs.checkWhetherUnderlyingResourceIsClosed() + if err != nil { + return + } if !fs.Exists(path) { return } @@ -602,7 +700,12 @@ func IsDir(path string) (result bool, err error) { return globalFileSystem.IsDir(path) } func (fs *VFS) IsDir(path string) (result bool, err error) { + err = fs.checkWhetherUnderlyingResourceIsClosed() + if err != nil { + return + } if !fs.Exists(path) { + err = fmt.Errorf("%w: path [%v]", commonerrors.ErrNotFound, path) return } fi, err := fs.Stat(path) @@ -625,6 +728,10 @@ func IsEmpty(name string) (empty bool, err error) { return globalFileSystem.IsEmpty(name) } func (fs *VFS) IsEmpty(name string) (empty bool, err error) { + err = fs.checkWhetherUnderlyingResourceIsClosed() + if err != nil { + return + } if !fs.Exists(name) { empty = true return @@ -649,6 +756,10 @@ func (fs *VFS) isFileEmpty(name string) (empty bool, err error) { } func (fs *VFS) isDirEmpty(name string) (empty bool, err error) { + err = fs.checkWhetherUnderlyingResourceIsClosed() + if err != nil { + return + } f, err := fs.vfs.Open(name) if err != nil { return @@ -677,6 +788,10 @@ func (fs *VFS) MkDir(dir string) (err error) { } func (fs *VFS) MkDirAll(dir string, perm os.FileMode) (err error) { + err = fs.checkWhetherUnderlyingResourceIsClosed() + if err != nil { + return + } if dir == "" { return fmt.Errorf("missing path: %w", commonerrors.ErrUndefined) } @@ -696,6 +811,10 @@ func FindAll(dir string, extensions ...string) (files []string, err error) { return globalFileSystem.FindAll(dir, extensions...) } func (fs *VFS) FindAll(dir string, extensions ...string) (files []string, err error) { + err = fs.checkWhetherUnderlyingResourceIsClosed() + if err != nil { + return + } files = []string{} if !fs.Exists(dir) { return @@ -710,6 +829,10 @@ func (fs *VFS) FindAll(dir string, extensions ...string) (files []string, err er return } func (fs *VFS) findAllOfExtension(dir string, ext string) (files []string, err error) { + err = fs.checkWhetherUnderlyingResourceIsClosed() + if err != nil { + return + } files, err = doublestar.GlobOS(fs, filepath.Join(dir, "**", fmt.Sprintf("*.%v", strings.TrimPrefix(ext, ".")))) if commonerrors.Any(err, doublestar.ErrBadPattern) { err = fmt.Errorf("%w: %v", commonerrors.ErrInvalid, err.Error()) @@ -717,15 +840,29 @@ func (fs *VFS) findAllOfExtension(dir string, ext string) (files []string, err e return } -func (fs *VFS) Chmod(name string, mode os.FileMode) error { - return fs.vfs.Chmod(name, mode) +func (fs *VFS) Chmod(name string, mode os.FileMode) (err error) { + err = fs.checkWhetherUnderlyingResourceIsClosed() + if err != nil { + return + } + err = fs.vfs.Chmod(name, mode) + return } -func (fs *VFS) Chtimes(name string, atime time.Time, mtime time.Time) error { - return fs.vfs.Chtimes(name, atime, mtime) +func (fs *VFS) Chtimes(name string, atime time.Time, mtime time.Time) (err error) { + err = fs.checkWhetherUnderlyingResourceIsClosed() + if err != nil { + return + } + err = fs.vfs.Chtimes(name, atime, mtime) + return } func (fs *VFS) Chown(name string, uid, gid int) (err error) { + err = fs.checkWhetherUnderlyingResourceIsClosed() + if err != nil { + return + } if correctobj, ok := fs.vfs.(interface { ChownIfPossible(string, int, int) error }); ok { @@ -737,6 +874,10 @@ func (fs *VFS) Chown(name string, uid, gid int) (err error) { } func (fs *VFS) FetchOwners(name string) (uid, gid int, err error) { + err = fs.checkWhetherUnderlyingResourceIsClosed() + if err != nil { + return + } stat, err := fs.Stat(name) if err != nil { return @@ -754,6 +895,10 @@ func (fs *VFS) FetchOwners(name string) (uid, gid int, err error) { } func (fs *VFS) Link(oldname, newname string) (err error) { + err = fs.checkWhetherUnderlyingResourceIsClosed() + if err != nil { + return + } if correctobj, ok := fs.vfs.(interface { LinkIfPossible(string, string) error }); ok { @@ -765,6 +910,10 @@ func (fs *VFS) Link(oldname, newname string) (err error) { } func (fs *VFS) Readlink(name string) (value string, err error) { + err = fs.checkWhetherUnderlyingResourceIsClosed() + if err != nil { + return + } if correctobj, ok := fs.vfs.(interface { ReadlinkIfPossible(string) (string, error) }); ok { @@ -776,6 +925,10 @@ func (fs *VFS) Readlink(name string) (value string, err error) { } func (fs *VFS) Symlink(oldname string, newname string) (err error) { + err = fs.checkWhetherUnderlyingResourceIsClosed() + if err != nil { + return + } if correctobj, ok := fs.vfs.(interface { SymlinkIfPossible(string, string) error }); ok { @@ -794,6 +947,10 @@ func (fs *VFS) Ls(dir string) (names []string, err error) { } func (fs *VFS) LsWithExclusionPatterns(dir string, exclusionPatterns ...string) (names []string, err error) { + err = fs.checkWhetherUnderlyingResourceIsClosed() + if err != nil { + return + } regexes, err := NewExclusionRegexList(fs.PathSeparator(), exclusionPatterns...) if err != nil { return nil, err @@ -823,6 +980,10 @@ func LsWithExclusionPatterns(fs FS, dir string, regexes []*regexp.Regexp) (names } func (fs *VFS) LsFromOpenedDirectory(dir File) ([]string, error) { + err := fs.checkWhetherUnderlyingResourceIsClosed() + if err != nil { + return nil, err + } if dir == nil { return nil, fmt.Errorf("%w: nil directory", commonerrors.ErrUndefined) } @@ -830,6 +991,10 @@ func (fs *VFS) LsFromOpenedDirectory(dir File) ([]string, error) { } func (fs *VFS) Lls(dir string) (files []os.FileInfo, err error) { + err = fs.checkWhetherUnderlyingResourceIsClosed() + if err != nil { + return + } if isDir, err := fs.IsDir(dir); !isDir || err != nil { err = fmt.Errorf("path [%v] is not a directory: %w", dir, commonerrors.ErrInvalid) return nil, err @@ -844,6 +1009,10 @@ func (fs *VFS) Lls(dir string) (files []os.FileInfo, err error) { } func (fs *VFS) LlsFromOpenedDirectory(dir File) ([]os.FileInfo, error) { + err := fs.checkWhetherUnderlyingResourceIsClosed() + if err != nil { + return nil, err + } if dir == nil { return nil, fmt.Errorf("%w: nil directory", commonerrors.ErrUndefined) } @@ -851,6 +1020,10 @@ func (fs *VFS) LlsFromOpenedDirectory(dir File) ([]os.FileInfo, error) { } func (fs *VFS) ConvertToAbsolutePath(rootPath string, paths ...string) ([]string, error) { + err := fs.checkWhetherUnderlyingResourceIsClosed() + if err != nil { + return nil, err + } basepath := fs.ConvertFilePath(rootPath) converted := make([]string, 0, len(paths)) for i := range paths { @@ -867,6 +1040,10 @@ func (fs *VFS) ConvertToAbsolutePath(rootPath string, paths ...string) ([]string } func (fs *VFS) ConvertToRelativePath(rootPath string, paths ...string) ([]string, error) { + err := fs.checkWhetherUnderlyingResourceIsClosed() + if err != nil { + return nil, err + } basepath := fs.ConvertFilePath(rootPath) converted := make([]string, 0, len(paths)) for i := range paths { @@ -889,6 +1066,10 @@ func (fs *VFS) Move(src string, dest string) error { } func (fs *VFS) MoveWithContext(ctx context.Context, src string, dest string) (err error) { + err = fs.checkWhetherUnderlyingResourceIsClosed() + if err != nil { + return + } err = parallelisation.DetermineContextError(ctx) if err != nil { return @@ -922,6 +1103,10 @@ func (fs *VFS) MoveWithContext(ctx context.Context, src string, dest string) (er } func (fs *VFS) moveFolder(ctx context.Context, src string, dest string) (err error) { + err = fs.checkWhetherUnderlyingResourceIsClosed() + if err != nil { + return + } err = parallelisation.DetermineContextError(ctx) if err != nil { return @@ -958,10 +1143,14 @@ func IsPathNotExist(err error) bool { if err == nil { return false } - return os.IsNotExist(err) || commonerrors.Any(err, ErrPathNotExist) + return os.IsNotExist(err) || commonerrors.Any(err, ErrPathNotExist) || commonerrors.CorrespondTo(err, ErrPathNotExist.Error()) } func (fs *VFS) moveFile(ctx context.Context, src string, dest string) (err error) { + err = fs.checkWhetherUnderlyingResourceIsClosed() + if err != nil { + return + } err = parallelisation.DetermineContextError(ctx) if err != nil { return @@ -985,6 +1174,10 @@ func (fs *VFS) FileHash(hashAlgo string, path string) (string, error) { } func (fs *VFS) FileHashWithContext(ctx context.Context, hashAlgo string, path string) (hash string, err error) { + err = fs.checkWhetherUnderlyingResourceIsClosed() + if err != nil { + return + } hasher, err := NewFileHash(hashAlgo) if err != nil { return @@ -1015,6 +1208,10 @@ func CopyToFileWithContext(ctx context.Context, srcFile, destFile string) error } func (fs *VFS) CopyToFileWithContext(ctx context.Context, src string, dest string) (err error) { + err = fs.checkWhetherUnderlyingResourceIsClosed() + if err != nil { + return + } isFile, err := fs.IsFile(src) if err != nil { return @@ -1055,6 +1252,10 @@ func CopyToDirectoryWithContext(ctx context.Context, src, destDirectory string) } func (fs *VFS) CopyToDirectoryWithContext(ctx context.Context, src, destDirectory string) (err error) { + err = fs.checkWhetherUnderlyingResourceIsClosed() + if err != nil { + return + } err = fs.MkDir(destDirectory) if err != nil { return @@ -1231,6 +1432,10 @@ func copyFileBetweenFSWithExclusionPatternsWithExclusionRegexes(ctx context.Cont } func (fs *VFS) DiskUsage(name string) (usage DiskUsage, err error) { + err = fs.checkWhetherUnderlyingResourceIsClosed() + if err != nil { + return + } realPath := fs.pathConverter(name) du, err := disk.Usage(realPath) if err != nil { @@ -1274,6 +1479,10 @@ func (fs *VFS) SubDirectoriesWithContext(ctx context.Context, directory string) return fs.SubDirectoriesWithContextAndExclusionPatterns(ctx, directory, "^[.].*$") } func (fs *VFS) SubDirectoriesWithContextAndExclusionPatterns(ctx context.Context, directory string, exclusionPatterns ...string) (directories []string, err error) { + err = fs.checkWhetherUnderlyingResourceIsClosed() + if err != nil { + return + } err = parallelisation.DetermineContextError(ctx) if err != nil { return @@ -1314,6 +1523,10 @@ func (fs *VFS) ListDirTreeWithContext(ctx context.Context, dirPath string, list return fs.ListDirTreeWithContextAndExclusionPatterns(ctx, dirPath, list) } func (fs *VFS) ListDirTreeWithContextAndExclusionPatterns(ctx context.Context, dirPath string, list *[]string, exclusionPatterns ...string) (err error) { + err = fs.checkWhetherUnderlyingResourceIsClosed() + if err != nil { + return + } regexes, err := NewExclusionRegexList(fs.PathSeparator(), exclusionPatterns...) if err != nil { return @@ -1369,6 +1582,10 @@ func (fs *VFS) GarbageCollectWithContext(ctx context.Context, root string, durat } func (fs *VFS) garbageCollectFile(ctx context.Context, durationSinceLastAccess time.Duration, path string) (err error) { + err = fs.checkWhetherUnderlyingResourceIsClosed() + if err != nil { + return + } err = parallelisation.DetermineContextError(ctx) if err != nil { return @@ -1385,6 +1602,10 @@ func (fs *VFS) garbageCollectFile(ctx context.Context, durationSinceLastAccess t } func (fs *VFS) garbageCollect(ctx context.Context, durationSinceLastAccess time.Duration, path string, deletePath bool) (err error) { + err = fs.checkWhetherUnderlyingResourceIsClosed() + if err != nil { + return + } err = parallelisation.DetermineContextError(ctx) if err != nil { return @@ -1399,6 +1620,10 @@ func (fs *VFS) garbageCollect(ctx context.Context, durationSinceLastAccess time. } func (fs *VFS) garbageCollectDir(ctx context.Context, durationSinceLastAccess time.Duration, path string, deletePath bool) (err error) { + err = fs.checkWhetherUnderlyingResourceIsClosed() + if err != nil { + return + } err = parallelisation.DetermineContextError(ctx) if err != nil { return @@ -1433,6 +1658,10 @@ func (fs *VFS) garbageCollectDir(ctx context.Context, durationSinceLastAccess ti return } +func (fs *VFS) Close() error { + return fs.resourceInUse.Close() +} + type extendedFile struct { afero.File onCloseCallBack func() error diff --git a/utils/filesystem/files_test.go b/utils/filesystem/files_test.go index 6f8931fac4..97e0e8412f 100644 --- a/utils/filesystem/files_test.go +++ b/utils/filesystem/files_test.go @@ -30,6 +30,17 @@ import ( sizeUnits "github.com/ARM-software/golang-utils/utils/units/size" ) +func TestCurrentDirectory(t *testing.T) { + for _, fsType := range FileSystemTypes { + t.Run(fmt.Sprintf("%v_for_fs_%v", t.Name(), fsType), func(t *testing.T) { + fs := NewFs(fsType) + current, err := fs.CurrentDirectory() + require.NoError(t, err) + assert.NotEmpty(t, current) + }) + } +} + func TestExists(t *testing.T) { for _, fsType := range FileSystemTypes { t.Run(fmt.Sprintf("%v_for_fs_%v", t.Name(), fsType), func(t *testing.T) { diff --git a/utils/filesystem/filesystem.go b/utils/filesystem/filesystem.go index ff02a0852f..7e393b2fdb 100644 --- a/utils/filesystem/filesystem.go +++ b/utils/filesystem/filesystem.go @@ -7,6 +7,7 @@ package filesystem import ( "embed" + "fmt" "os" "github.com/spf13/afero" @@ -21,6 +22,7 @@ const ( InMemoryFS Embed Custom + ZipFS ) var ( @@ -43,6 +45,23 @@ func NewEmbedFileSystem(fs *embed.FS) (FS, error) { return NewVirtualFileSystem(wrapped, Embed, IdentityPathConverterFunc), nil } +// NewZipFileSystem returns a filesystem over the contents of a .zip file. +// Warning: After use of the filesystem, it is crucial to close the zip file (zipFile) which has been opened from source for the entirety of the filesystem use session. +// fs corresponds to the filesystem to use to find the zip file. +func NewZipFileSystem(fs FS, source string, limits ILimits) (zipFs ICloseableFS, zipFile File, err error) { + wrapped, zipFile, err := newZipFSAdapterFromFilePath(fs, source, limits) + if err != nil { + return + } + zipFs = NewCloseableVirtualFileSystem(wrapped, ZipFS, zipFile, fmt.Sprintf(".zip file `%v`", source), IdentityPathConverterFunc) + return +} + +// NewZipFileSystemFromStandardFileSystem returns a zip filesystem similar to NewZipFileSystem but assumes the zip file described by source can be found on the standard file system. +func NewZipFileSystemFromStandardFileSystem(source string, limits ILimits) (ICloseableFS, File, error) { + return NewZipFileSystem(NewStandardFileSystem(), source, limits) +} + func NewFs(fsType FilesystemType) FS { switch fsType { case StandardFS: diff --git a/utils/filesystem/interfaces.go b/utils/filesystem/interfaces.go index d07f5b8012..2330434408 100644 --- a/utils/filesystem/interfaces.go +++ b/utils/filesystem/interfaces.go @@ -17,7 +17,7 @@ import ( "github.com/ARM-software/golang-utils/utils/config" ) -//go:generate mockgen -destination=../mocks/mock_$GOPACKAGE.go -package=mocks github.com/ARM-software/golang-utils/utils/$GOPACKAGE IFileHash,Chowner,Linker,File,DiskUsage,FileTimeInfo,ILock,ILimits,FS +//go:generate mockgen -destination=../mocks/mock_$GOPACKAGE.go -package=mocks github.com/ARM-software/golang-utils/utils/$GOPACKAGE IFileHash,Chowner,Linker,File,DiskUsage,FileTimeInfo,ILock,ILimits,FS,ICloseableFS // IFileHash defines a file hash. // For reference. @@ -303,3 +303,9 @@ type FS interface { // IsZipWithContext states whether a file is a zip file or not. Since the process can take some time (i.e type detection with sniffers such as http.DetectContentType), it is controlled by a context. IsZipWithContext(ctx context.Context, filepath string) (bool, error) } + +// ICloseableFS is a filesystem which utilises resources which must be closed when it is no longer used, such as open files. The close method is invoked to release resources that the object is holding. +type ICloseableFS interface { + FS + io.Closer +} diff --git a/utils/filesystem/testdata/t.zip b/utils/filesystem/testdata/t.zip new file mode 100644 index 0000000000..99e39a7d2d Binary files /dev/null and b/utils/filesystem/testdata/t.zip differ diff --git a/utils/filesystem/zip.go b/utils/filesystem/zip.go index e8fcfe7c62..c55eb9b3e2 100644 --- a/utils/filesystem/zip.go +++ b/utils/filesystem/zip.go @@ -203,16 +203,15 @@ func (fs *VFS) UnzipWithContextAndLimits(ctx context.Context, source string, des return } -func (fs *VFS) unzip(ctx context.Context, source string, destination string, limits ILimits, currentDepth int64) (fileList []string, fileOnDiskCount uint64, sizeOnDisk uint64, err error) { - if limits == nil { - err = fmt.Errorf("%w: missing file system limits", commonerrors.ErrUndefined) +func newZipReader(fs FS, source string, limits ILimits, currentDepth int64) (zipReader *zip.Reader, file File, err error) { + if fs == nil { + err = fmt.Errorf("%w: missing file system", commonerrors.ErrUndefined) return } - err = parallelisation.DetermineContextError(ctx) - if err != nil { + if limits == nil { + err = fmt.Errorf("%w: missing file system limits", commonerrors.ErrUndefined) return } - if limits.Apply() && limits.GetMaxDepth() >= 0 && currentDepth > limits.GetMaxDepth() { err = fmt.Errorf("%w: depth [%v] of zip file [%v] is beyond allowed limits (max: %v)", commonerrors.ErrTooLarge, currentDepth, source, limits.GetMaxDepth()) return @@ -223,20 +222,14 @@ func (fs *VFS) unzip(ctx context.Context, source string, destination string, lim return } - fileCounter := atomic.NewUint64(0) - - // List of file paths to return - totalSizeOnDisk := atomic.NewUint64(0) - info, err := fs.Lstat(source) if err != nil { return } - f, err := fs.GenericOpen(source) + file, err = fs.GenericOpen(source) if err != nil { return } - defer func() { _ = f.Close() }() zipFileSize := info.Size() @@ -245,9 +238,31 @@ func (fs *VFS) unzip(ctx context.Context, source string, destination string, lim return } - zipReader, err := zip.NewReader(f, zipFileSize) + zipReader, err = zip.NewReader(file, zipFileSize) + err = convertZipError(err) + + return +} + +func (fs *VFS) unzip(ctx context.Context, source string, destination string, limits ILimits, currentDepth int64) (fileList []string, fileOnDiskCount uint64, sizeOnDisk uint64, err error) { + + err = parallelisation.DetermineContextError(ctx) + if err != nil { + return + } + + fileCounter := atomic.NewUint64(0) + + // List of file paths to return + totalSizeOnDisk := atomic.NewUint64(0) + + zipReader, f, err := newZipReader(fs, source, limits, currentDepth) + defer func() { + if f != nil { + _ = f.Close() + } + }() if err != nil { - err = convertZipError(err) return } @@ -507,6 +522,9 @@ func (fs *VFS) IsZipWithContext(ctx context.Context, path string) (ok bool, err } func convertZipError(err error) error { + if err == nil { + return nil + } err = commonerrors.ConvertContextError(err) if commonerrors.Any(err, zip.ErrFormat, zip.ErrChecksum) { return fmt.Errorf("%w: %v", commonerrors.ErrInvalid, err.Error()) diff --git a/utils/filesystem/zipfs.go b/utils/filesystem/zipfs.go new file mode 100644 index 0000000000..f3187daf53 --- /dev/null +++ b/utils/filesystem/zipfs.go @@ -0,0 +1,35 @@ +package filesystem + +import ( + "archive/zip" + "fmt" + + "github.com/spf13/afero" + "github.com/spf13/afero/zipfs" + + "github.com/ARM-software/golang-utils/utils/commonerrors" +) + +func newZipFSAdapterFromReader(reader *zip.Reader) (afero.Fs, error) { + if reader == nil { + return nil, fmt.Errorf("%w: missing reader", commonerrors.ErrUndefined) + } + return afero.NewReadOnlyFs(zipfs.New(reader)), nil +} + +func newZipFSAdapterFromFilePath(fs FS, zipFilePath string, limits ILimits) (zipFs afero.Fs, zipFile File, err error) { + if fs == nil { + err = fmt.Errorf("%w: missing filesystem to use for finding the zip file", commonerrors.ErrUndefined) + return + } + zipReader, zipFile, err := newZipReader(fs, zipFilePath, limits, 0) + if err != nil && zipFile != nil { + subErr := zipFile.Close() + if subErr == nil { + zipFile = nil + } + return + } + zipFs, err = newZipFSAdapterFromReader(zipReader) + return +} diff --git a/utils/filesystem/zipfs_test.go b/utils/filesystem/zipfs_test.go new file mode 100644 index 0000000000..71a7054bbc --- /dev/null +++ b/utils/filesystem/zipfs_test.go @@ -0,0 +1,258 @@ +package filesystem + +import ( + "io" + "io/fs" + "os" + "path/filepath" + "sort" + "testing" + + "github.com/bxcodec/faker/v3" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "github.com/ARM-software/golang-utils/utils/commonerrors/errortest" +) + +const zipTestFileContent = "Test names:\r\nGeorge\r\nGeoffrey\r\nGonzo" + +var ( + aferoTestZipContentTree = []string{ + string(globalFileSystem.PathSeparator()), + filepath.Join("/", "sub"), + filepath.Join("/", "sub", "testDir2"), + filepath.Join("/", "sub", "testDir2", "testFile"), + filepath.Join("/", "testDir1"), + filepath.Join("/", "testDir1", "testFile"), + filepath.Join("/", "testFile"), + } +) + +func Test_zipFs_Close(t *testing.T) { + fs, zipFile, err := NewZipFileSystemFromStandardFileSystem(filepath.Join("testdata", "testunzip.zip"), NoLimits()) + require.NoError(t, err) + defer func() { + if zipFile != nil { + _ = zipFile.Close() + } + }() + require.NotNil(t, zipFile) + _, err = fs.Stat("testunzip/test.txt") + assert.NoError(t, err) + require.NoError(t, fs.Close()) + _, err = fs.Stat("testunzip/test.txt") + errortest.AssertErrorDescription(t, err, "closed") + require.NoError(t, fs.Close()) + require.NoError(t, fs.Close()) +} + +func Test_zipFs_Exists(t *testing.T) { + fs, _, err := NewZipFileSystemFromStandardFileSystem(filepath.Join("testdata", "testunzip.zip"), NoLimits()) + require.NoError(t, err) + defer func() { _ = fs.Close() }() + + assert.False(t, fs.Exists(faker.DomainName())) + // FIXME: enable when issue in afero is fixed https://github.com/spf13/afero/issues/395 + // assert.True(t, fs.Exists(string(filepath.Separator))) + // assert.True(t, fs.Exists("/")) + assert.True(t, fs.Exists("testunzip/test.txt")) + assert.True(t, fs.Exists("testunzip/child.zip")) + assert.True(t, fs.Exists("testunzip/ไป ไหน มา.txt")) + require.NoError(t, fs.Close()) +} + +func Test_zipFs_Exists_usingAferoTestZip(t *testing.T) { + // using afero test zip file + fs, _, err := NewZipFileSystemFromStandardFileSystem(filepath.Join("testdata", "t.zip"), NoLimits()) + require.NoError(t, err) + defer func() { _ = fs.Close() }() + + assert.False(t, fs.Exists(faker.DomainName())) + assert.True(t, fs.Exists(string(filepath.Separator))) + assert.True(t, fs.Exists("/")) + + assert.True(t, fs.Exists("testDir1")) + assert.True(t, fs.Exists("testFile")) + assert.True(t, fs.Exists("testDir1/testFile")) + require.NoError(t, fs.Close()) +} + +func Test_zipFS_FileInfo(t *testing.T) { + fs, _, err := NewZipFileSystemFromStandardFileSystem(filepath.Join("testdata", "testunzip.zip"), NoLimits()) + require.NoError(t, err) + defer func() { _ = fs.Close() }() + + zfile, err := fs.Stat("/") + require.NoError(t, err) + assert.Equal(t, string(filepath.Separator), zfile.Name()) + assert.True(t, zfile.IsDir()) + assert.Zero(t, zfile.Size()) + + zfile, err = fs.Stat("testunzip/test.txt") + require.NoError(t, err) + assert.Equal(t, "test.txt", zfile.Name()) + assert.False(t, zfile.IsDir()) + assert.NotZero(t, zfile.Size()) + + require.NoError(t, fs.Close()) +} + +func Test_zipFs_Browsing(t *testing.T) { + fs, _, err := NewZipFileSystemFromStandardFileSystem(filepath.Join("testdata", "testunzip.zip"), NoLimits()) + require.NoError(t, err) + defer func() { _ = fs.Close() }() + + empty, err := fs.IsEmpty(faker.DomainName()) + require.NoError(t, err) + assert.True(t, empty) + empty, err = fs.IsEmpty("testunzip/test.txt") + require.NoError(t, err) + assert.False(t, empty) + empty, err = fs.IsEmpty("testunzip/child.zip") + require.NoError(t, err) + assert.False(t, empty) + empty, err = fs.IsEmpty("testunzip/ไป ไหน มา.txt") + require.NoError(t, err) + assert.True(t, empty) + require.NoError(t, fs.Close()) +} + +func Test_zipFs_Browsing_usingAferoTestZip(t *testing.T) { + zipFs, _, err := NewZipFileSystemFromStandardFileSystem(filepath.Join("testdata", "t.zip"), NoLimits()) + require.NoError(t, err) + defer func() { _ = zipFs.Close() }() + + // Warning: this assumes the walk function is executed in the same goroutine and not concurrently. + // If not, this list should be created with some thread access protection in place. + pathList := []string{} + + var wFunc = func(path string, info fs.FileInfo, err error) error { + pathList = append(pathList, path) + return nil + } + + require.NoError(t, zipFs.Walk("/", wFunc)) + require.NoError(t, zipFs.Close()) + + sort.Strings(pathList) + sort.Strings(aferoTestZipContentTree) + assert.Equal(t, aferoTestZipContentTree, pathList) +} + +func Test_zipFs_LS(t *testing.T) { + fs, _, err := NewZipFileSystemFromStandardFileSystem(filepath.Join("testdata", "t.zip"), NoLimits()) + require.NoError(t, err) + defer func() { _ = fs.Close() }() + + files, err := fs.Ls("/") + require.NoError(t, err) + assert.NotZero(t, files) + assert.Contains(t, files, "testFile") + + files, err = fs.Ls("sub/") + require.NoError(t, err) + assert.NotZero(t, files) + assert.Contains(t, files, "testDir2") + require.NoError(t, fs.Close()) +} + +func Test_zipFs_itemType(t *testing.T) { + fs, _, err := NewZipFileSystemFromStandardFileSystem(filepath.Join("testdata", "testunzip.zip"), NoLimits()) + require.NoError(t, err) + defer func() { _ = fs.Close() }() + + isFile, err := fs.IsFile("unzip") + require.NoError(t, err) + assert.False(t, isFile) + // FIXME: Enable when issue in afero is fixed https://github.com/spf13/afero/issues/395 + // isDir, err := fs.IsDir("unzip") + // require.NoError(t, err) + // assert.True(t, isDir) + isFile, err = fs.IsFile("testunzip/test.txt") + require.NoError(t, err) + assert.True(t, isFile) + isDir, err := fs.IsDir("testunzip/test.txt") + require.NoError(t, err) + assert.False(t, isDir) + require.NoError(t, fs.Close()) +} + +func Test_zipFs_itemType_usingAferoTestZip(t *testing.T) { + fs, _, err := NewZipFileSystemFromStandardFileSystem(filepath.Join("testdata", "t.zip"), NoLimits()) + require.NoError(t, err) + defer func() { _ = fs.Close() }() + + isFile, err := fs.IsFile("testDir1") + require.NoError(t, err) + assert.False(t, isFile) + isDir, err := fs.IsDir("testDir1") + require.NoError(t, err) + assert.True(t, isDir) + isFile, err = fs.IsFile("testDir1/testFile") + require.NoError(t, err) + assert.True(t, isFile) + isDir, err = fs.IsDir("testDir1/testFile") + require.NoError(t, err) + assert.False(t, isDir) + require.NoError(t, fs.Close()) +} + +func Test_zipFs_Read(t *testing.T) { + fs, _, err := NewZipFileSystemFromStandardFileSystem(filepath.Join("testdata", "testunzip.zip"), NoLimits()) + require.NoError(t, err) + defer func() { _ = fs.Close() }() + + t.Run("using file opening", func(t *testing.T) { + f, err := fs.GenericOpen("testunzip/test.txt") + require.NoError(t, err) + defer func() { _ = f.Close() }() + c, err := io.ReadAll(f) + require.NoError(t, err) + assert.Equal(t, zipTestFileContent, string(c)) + require.NoError(t, f.Close()) + }) + + t.Run("using file opening 2", func(t *testing.T) { + f, err := fs.OpenFile("testunzip/test.txt", os.O_RDONLY, os.FileMode(0600)) + require.NoError(t, err) + defer func() { _ = f.Close() }() + c, err := io.ReadAll(f) + require.NoError(t, err) + assert.Equal(t, zipTestFileContent, string(c)) + require.NoError(t, f.Close()) + }) + + t.Run("using file read", func(t *testing.T) { + c, err := fs.ReadFile("testunzip/test.txt") + require.NoError(t, err) + assert.Equal(t, zipTestFileContent, string(c)) + }) + + require.NoError(t, fs.Close()) +} + +func Test_zipFs_not_supported(t *testing.T) { + fs, _, err := NewZipFileSystemFromStandardFileSystem(filepath.Join("testdata", "testunzip.zip"), NoLimits()) + require.NoError(t, err) + defer func() { _ = fs.Close() }() + + _, err = fs.TempDir("testdata", "aaaa") + errortest.AssertErrorDescription(t, err, "operation not permitted") + + f, err := fs.OpenFile("testunzip/test.txt", os.O_RDWR, os.FileMode(0600)) + defer func() { + if f != nil { + _ = f.Close() + } + }() + require.Error(t, err) + errortest.AssertErrorDescription(t, err, "operation not permitted") + + err = fs.Chmod("testunzip/test.txt", os.FileMode(0600)) + require.Error(t, err) + errortest.AssertErrorDescription(t, err, "operation not permitted") + + require.NoError(t, fs.Close()) + +} diff --git a/utils/mocks/mock_filesystem.go b/utils/mocks/mock_filesystem.go index 24e4287e8f..b94c8f16f3 100644 --- a/utils/mocks/mock_filesystem.go +++ b/utils/mocks/mock_filesystem.go @@ -1,5 +1,5 @@ // Code generated by MockGen. DO NOT EDIT. -// Source: github.com/ARM-software/golang-utils/utils/filesystem (interfaces: IFileHash,Chowner,Linker,File,DiskUsage,FileTimeInfo,ILock,ILimits,FS) +// Source: github.com/ARM-software/golang-utils/utils/filesystem (interfaces: IFileHash,Chowner,Linker,File,DiskUsage,FileTimeInfo,ILock,ILimits,FS,ICloseableFS) // Package mocks is a generated GoMock package. package mocks @@ -12,10 +12,9 @@ import ( reflect "reflect" time "time" + filesystem "github.com/ARM-software/golang-utils/utils/filesystem" doublestar "github.com/bmatcuk/doublestar/v3" gomock "github.com/golang/mock/gomock" - - filesystem "github.com/ARM-software/golang-utils/utils/filesystem" ) // MockIFileHash is a mock of IFileHash interface. @@ -2260,3 +2259,1363 @@ func (mr *MockFSMockRecorder) ZipWithContextAndLimitsAndExclusionPatterns(arg0, varargs := append([]interface{}{arg0, arg1, arg2, arg3}, arg4...) return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ZipWithContextAndLimitsAndExclusionPatterns", reflect.TypeOf((*MockFS)(nil).ZipWithContextAndLimitsAndExclusionPatterns), varargs...) } + +// MockICloseableFS is a mock of ICloseableFS interface. +type MockICloseableFS struct { + ctrl *gomock.Controller + recorder *MockICloseableFSMockRecorder +} + +// MockICloseableFSMockRecorder is the mock recorder for MockICloseableFS. +type MockICloseableFSMockRecorder struct { + mock *MockICloseableFS +} + +// NewMockICloseableFS creates a new mock instance. +func NewMockICloseableFS(ctrl *gomock.Controller) *MockICloseableFS { + mock := &MockICloseableFS{ctrl: ctrl} + mock.recorder = &MockICloseableFSMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockICloseableFS) EXPECT() *MockICloseableFSMockRecorder { + return m.recorder +} + +// Chmod mocks base method. +func (m *MockICloseableFS) Chmod(arg0 string, arg1 fs.FileMode) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Chmod", arg0, arg1) + ret0, _ := ret[0].(error) + return ret0 +} + +// Chmod indicates an expected call of Chmod. +func (mr *MockICloseableFSMockRecorder) Chmod(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Chmod", reflect.TypeOf((*MockICloseableFS)(nil).Chmod), arg0, arg1) +} + +// Chown mocks base method. +func (m *MockICloseableFS) Chown(arg0 string, arg1, arg2 int) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Chown", arg0, arg1, arg2) + ret0, _ := ret[0].(error) + return ret0 +} + +// Chown indicates an expected call of Chown. +func (mr *MockICloseableFSMockRecorder) Chown(arg0, arg1, arg2 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Chown", reflect.TypeOf((*MockICloseableFS)(nil).Chown), arg0, arg1, arg2) +} + +// Chtimes mocks base method. +func (m *MockICloseableFS) Chtimes(arg0 string, arg1, arg2 time.Time) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Chtimes", arg0, arg1, arg2) + ret0, _ := ret[0].(error) + return ret0 +} + +// Chtimes indicates an expected call of Chtimes. +func (mr *MockICloseableFSMockRecorder) Chtimes(arg0, arg1, arg2 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Chtimes", reflect.TypeOf((*MockICloseableFS)(nil).Chtimes), arg0, arg1, arg2) +} + +// CleanDir mocks base method. +func (m *MockICloseableFS) CleanDir(arg0 string) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "CleanDir", arg0) + ret0, _ := ret[0].(error) + return ret0 +} + +// CleanDir indicates an expected call of CleanDir. +func (mr *MockICloseableFSMockRecorder) CleanDir(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CleanDir", reflect.TypeOf((*MockICloseableFS)(nil).CleanDir), arg0) +} + +// CleanDirWithContext mocks base method. +func (m *MockICloseableFS) CleanDirWithContext(arg0 context.Context, arg1 string) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "CleanDirWithContext", arg0, arg1) + ret0, _ := ret[0].(error) + return ret0 +} + +// CleanDirWithContext indicates an expected call of CleanDirWithContext. +func (mr *MockICloseableFSMockRecorder) CleanDirWithContext(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CleanDirWithContext", reflect.TypeOf((*MockICloseableFS)(nil).CleanDirWithContext), arg0, arg1) +} + +// CleanDirWithContextAndExclusionPatterns mocks base method. +func (m *MockICloseableFS) CleanDirWithContextAndExclusionPatterns(arg0 context.Context, arg1 string, arg2 ...string) error { + m.ctrl.T.Helper() + varargs := []interface{}{arg0, arg1} + for _, a := range arg2 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "CleanDirWithContextAndExclusionPatterns", varargs...) + ret0, _ := ret[0].(error) + return ret0 +} + +// CleanDirWithContextAndExclusionPatterns indicates an expected call of CleanDirWithContextAndExclusionPatterns. +func (mr *MockICloseableFSMockRecorder) CleanDirWithContextAndExclusionPatterns(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]interface{}{arg0, arg1}, arg2...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CleanDirWithContextAndExclusionPatterns", reflect.TypeOf((*MockICloseableFS)(nil).CleanDirWithContextAndExclusionPatterns), varargs...) +} + +// Close mocks base method. +func (m *MockICloseableFS) Close() error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Close") + ret0, _ := ret[0].(error) + return ret0 +} + +// Close indicates an expected call of Close. +func (mr *MockICloseableFSMockRecorder) Close() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Close", reflect.TypeOf((*MockICloseableFS)(nil).Close)) +} + +// ConvertFilePath mocks base method. +func (m *MockICloseableFS) ConvertFilePath(arg0 string) string { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ConvertFilePath", arg0) + ret0, _ := ret[0].(string) + return ret0 +} + +// ConvertFilePath indicates an expected call of ConvertFilePath. +func (mr *MockICloseableFSMockRecorder) ConvertFilePath(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ConvertFilePath", reflect.TypeOf((*MockICloseableFS)(nil).ConvertFilePath), arg0) +} + +// ConvertToAbsolutePath mocks base method. +func (m *MockICloseableFS) ConvertToAbsolutePath(arg0 string, arg1 ...string) ([]string, error) { + m.ctrl.T.Helper() + varargs := []interface{}{arg0} + for _, a := range arg1 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "ConvertToAbsolutePath", varargs...) + ret0, _ := ret[0].([]string) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// ConvertToAbsolutePath indicates an expected call of ConvertToAbsolutePath. +func (mr *MockICloseableFSMockRecorder) ConvertToAbsolutePath(arg0 interface{}, arg1 ...interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]interface{}{arg0}, arg1...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ConvertToAbsolutePath", reflect.TypeOf((*MockICloseableFS)(nil).ConvertToAbsolutePath), varargs...) +} + +// ConvertToRelativePath mocks base method. +func (m *MockICloseableFS) ConvertToRelativePath(arg0 string, arg1 ...string) ([]string, error) { + m.ctrl.T.Helper() + varargs := []interface{}{arg0} + for _, a := range arg1 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "ConvertToRelativePath", varargs...) + ret0, _ := ret[0].([]string) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// ConvertToRelativePath indicates an expected call of ConvertToRelativePath. +func (mr *MockICloseableFSMockRecorder) ConvertToRelativePath(arg0 interface{}, arg1 ...interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]interface{}{arg0}, arg1...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ConvertToRelativePath", reflect.TypeOf((*MockICloseableFS)(nil).ConvertToRelativePath), varargs...) +} + +// Copy mocks base method. +func (m *MockICloseableFS) Copy(arg0, arg1 string) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Copy", arg0, arg1) + ret0, _ := ret[0].(error) + return ret0 +} + +// Copy indicates an expected call of Copy. +func (mr *MockICloseableFSMockRecorder) Copy(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Copy", reflect.TypeOf((*MockICloseableFS)(nil).Copy), arg0, arg1) +} + +// CopyToDirectory mocks base method. +func (m *MockICloseableFS) CopyToDirectory(arg0, arg1 string) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "CopyToDirectory", arg0, arg1) + ret0, _ := ret[0].(error) + return ret0 +} + +// CopyToDirectory indicates an expected call of CopyToDirectory. +func (mr *MockICloseableFSMockRecorder) CopyToDirectory(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CopyToDirectory", reflect.TypeOf((*MockICloseableFS)(nil).CopyToDirectory), arg0, arg1) +} + +// CopyToDirectoryWithContext mocks base method. +func (m *MockICloseableFS) CopyToDirectoryWithContext(arg0 context.Context, arg1, arg2 string) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "CopyToDirectoryWithContext", arg0, arg1, arg2) + ret0, _ := ret[0].(error) + return ret0 +} + +// CopyToDirectoryWithContext indicates an expected call of CopyToDirectoryWithContext. +func (mr *MockICloseableFSMockRecorder) CopyToDirectoryWithContext(arg0, arg1, arg2 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CopyToDirectoryWithContext", reflect.TypeOf((*MockICloseableFS)(nil).CopyToDirectoryWithContext), arg0, arg1, arg2) +} + +// CopyToFile mocks base method. +func (m *MockICloseableFS) CopyToFile(arg0, arg1 string) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "CopyToFile", arg0, arg1) + ret0, _ := ret[0].(error) + return ret0 +} + +// CopyToFile indicates an expected call of CopyToFile. +func (mr *MockICloseableFSMockRecorder) CopyToFile(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CopyToFile", reflect.TypeOf((*MockICloseableFS)(nil).CopyToFile), arg0, arg1) +} + +// CopyToFileWithContext mocks base method. +func (m *MockICloseableFS) CopyToFileWithContext(arg0 context.Context, arg1, arg2 string) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "CopyToFileWithContext", arg0, arg1, arg2) + ret0, _ := ret[0].(error) + return ret0 +} + +// CopyToFileWithContext indicates an expected call of CopyToFileWithContext. +func (mr *MockICloseableFSMockRecorder) CopyToFileWithContext(arg0, arg1, arg2 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CopyToFileWithContext", reflect.TypeOf((*MockICloseableFS)(nil).CopyToFileWithContext), arg0, arg1, arg2) +} + +// CopyWithContext mocks base method. +func (m *MockICloseableFS) CopyWithContext(arg0 context.Context, arg1, arg2 string) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "CopyWithContext", arg0, arg1, arg2) + ret0, _ := ret[0].(error) + return ret0 +} + +// CopyWithContext indicates an expected call of CopyWithContext. +func (mr *MockICloseableFSMockRecorder) CopyWithContext(arg0, arg1, arg2 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CopyWithContext", reflect.TypeOf((*MockICloseableFS)(nil).CopyWithContext), arg0, arg1, arg2) +} + +// CopyWithContextAndExclusionPatterns mocks base method. +func (m *MockICloseableFS) CopyWithContextAndExclusionPatterns(arg0 context.Context, arg1, arg2 string, arg3 ...string) error { + m.ctrl.T.Helper() + varargs := []interface{}{arg0, arg1, arg2} + for _, a := range arg3 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "CopyWithContextAndExclusionPatterns", varargs...) + ret0, _ := ret[0].(error) + return ret0 +} + +// CopyWithContextAndExclusionPatterns indicates an expected call of CopyWithContextAndExclusionPatterns. +func (mr *MockICloseableFSMockRecorder) CopyWithContextAndExclusionPatterns(arg0, arg1, arg2 interface{}, arg3 ...interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]interface{}{arg0, arg1, arg2}, arg3...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CopyWithContextAndExclusionPatterns", reflect.TypeOf((*MockICloseableFS)(nil).CopyWithContextAndExclusionPatterns), varargs...) +} + +// CreateFile mocks base method. +func (m *MockICloseableFS) CreateFile(arg0 string) (filesystem.File, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "CreateFile", arg0) + ret0, _ := ret[0].(filesystem.File) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// CreateFile indicates an expected call of CreateFile. +func (mr *MockICloseableFSMockRecorder) CreateFile(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateFile", reflect.TypeOf((*MockICloseableFS)(nil).CreateFile), arg0) +} + +// CurrentDirectory mocks base method. +func (m *MockICloseableFS) CurrentDirectory() (string, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "CurrentDirectory") + ret0, _ := ret[0].(string) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// CurrentDirectory indicates an expected call of CurrentDirectory. +func (mr *MockICloseableFSMockRecorder) CurrentDirectory() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CurrentDirectory", reflect.TypeOf((*MockICloseableFS)(nil).CurrentDirectory)) +} + +// DiskUsage mocks base method. +func (m *MockICloseableFS) DiskUsage(arg0 string) (filesystem.DiskUsage, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DiskUsage", arg0) + ret0, _ := ret[0].(filesystem.DiskUsage) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// DiskUsage indicates an expected call of DiskUsage. +func (mr *MockICloseableFSMockRecorder) DiskUsage(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DiskUsage", reflect.TypeOf((*MockICloseableFS)(nil).DiskUsage), arg0) +} + +// ExcludeAll mocks base method. +func (m *MockICloseableFS) ExcludeAll(arg0 []string, arg1 ...string) ([]string, error) { + m.ctrl.T.Helper() + varargs := []interface{}{arg0} + for _, a := range arg1 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "ExcludeAll", varargs...) + ret0, _ := ret[0].([]string) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// ExcludeAll indicates an expected call of ExcludeAll. +func (mr *MockICloseableFSMockRecorder) ExcludeAll(arg0 interface{}, arg1 ...interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]interface{}{arg0}, arg1...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ExcludeAll", reflect.TypeOf((*MockICloseableFS)(nil).ExcludeAll), varargs...) +} + +// Exists mocks base method. +func (m *MockICloseableFS) Exists(arg0 string) bool { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Exists", arg0) + ret0, _ := ret[0].(bool) + return ret0 +} + +// Exists indicates an expected call of Exists. +func (mr *MockICloseableFSMockRecorder) Exists(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Exists", reflect.TypeOf((*MockICloseableFS)(nil).Exists), arg0) +} + +// FetchOwners mocks base method. +func (m *MockICloseableFS) FetchOwners(arg0 string) (int, int, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "FetchOwners", arg0) + ret0, _ := ret[0].(int) + ret1, _ := ret[1].(int) + ret2, _ := ret[2].(error) + return ret0, ret1, ret2 +} + +// FetchOwners indicates an expected call of FetchOwners. +func (mr *MockICloseableFSMockRecorder) FetchOwners(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FetchOwners", reflect.TypeOf((*MockICloseableFS)(nil).FetchOwners), arg0) +} + +// FileHash mocks base method. +func (m *MockICloseableFS) FileHash(arg0, arg1 string) (string, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "FileHash", arg0, arg1) + ret0, _ := ret[0].(string) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// FileHash indicates an expected call of FileHash. +func (mr *MockICloseableFSMockRecorder) FileHash(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FileHash", reflect.TypeOf((*MockICloseableFS)(nil).FileHash), arg0, arg1) +} + +// FileHashWithContext mocks base method. +func (m *MockICloseableFS) FileHashWithContext(arg0 context.Context, arg1, arg2 string) (string, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "FileHashWithContext", arg0, arg1, arg2) + ret0, _ := ret[0].(string) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// FileHashWithContext indicates an expected call of FileHashWithContext. +func (mr *MockICloseableFSMockRecorder) FileHashWithContext(arg0, arg1, arg2 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FileHashWithContext", reflect.TypeOf((*MockICloseableFS)(nil).FileHashWithContext), arg0, arg1, arg2) +} + +// FindAll mocks base method. +func (m *MockICloseableFS) FindAll(arg0 string, arg1 ...string) ([]string, error) { + m.ctrl.T.Helper() + varargs := []interface{}{arg0} + for _, a := range arg1 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "FindAll", varargs...) + ret0, _ := ret[0].([]string) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// FindAll indicates an expected call of FindAll. +func (mr *MockICloseableFSMockRecorder) FindAll(arg0 interface{}, arg1 ...interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]interface{}{arg0}, arg1...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FindAll", reflect.TypeOf((*MockICloseableFS)(nil).FindAll), varargs...) +} + +// GarbageCollect mocks base method. +func (m *MockICloseableFS) GarbageCollect(arg0 string, arg1 time.Duration) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GarbageCollect", arg0, arg1) + ret0, _ := ret[0].(error) + return ret0 +} + +// GarbageCollect indicates an expected call of GarbageCollect. +func (mr *MockICloseableFSMockRecorder) GarbageCollect(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GarbageCollect", reflect.TypeOf((*MockICloseableFS)(nil).GarbageCollect), arg0, arg1) +} + +// GarbageCollectWithContext mocks base method. +func (m *MockICloseableFS) GarbageCollectWithContext(arg0 context.Context, arg1 string, arg2 time.Duration) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GarbageCollectWithContext", arg0, arg1, arg2) + ret0, _ := ret[0].(error) + return ret0 +} + +// GarbageCollectWithContext indicates an expected call of GarbageCollectWithContext. +func (mr *MockICloseableFSMockRecorder) GarbageCollectWithContext(arg0, arg1, arg2 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GarbageCollectWithContext", reflect.TypeOf((*MockICloseableFS)(nil).GarbageCollectWithContext), arg0, arg1, arg2) +} + +// GenericOpen mocks base method. +func (m *MockICloseableFS) GenericOpen(arg0 string) (filesystem.File, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GenericOpen", arg0) + ret0, _ := ret[0].(filesystem.File) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GenericOpen indicates an expected call of GenericOpen. +func (mr *MockICloseableFSMockRecorder) GenericOpen(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GenericOpen", reflect.TypeOf((*MockICloseableFS)(nil).GenericOpen), arg0) +} + +// GetFileSize mocks base method. +func (m *MockICloseableFS) GetFileSize(arg0 string) (int64, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetFileSize", arg0) + ret0, _ := ret[0].(int64) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetFileSize indicates an expected call of GetFileSize. +func (mr *MockICloseableFSMockRecorder) GetFileSize(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetFileSize", reflect.TypeOf((*MockICloseableFS)(nil).GetFileSize), arg0) +} + +// GetType mocks base method. +func (m *MockICloseableFS) GetType() filesystem.FilesystemType { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetType") + ret0, _ := ret[0].(filesystem.FilesystemType) + return ret0 +} + +// GetType indicates an expected call of GetType. +func (mr *MockICloseableFSMockRecorder) GetType() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetType", reflect.TypeOf((*MockICloseableFS)(nil).GetType)) +} + +// IsDir mocks base method. +func (m *MockICloseableFS) IsDir(arg0 string) (bool, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "IsDir", arg0) + ret0, _ := ret[0].(bool) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// IsDir indicates an expected call of IsDir. +func (mr *MockICloseableFSMockRecorder) IsDir(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IsDir", reflect.TypeOf((*MockICloseableFS)(nil).IsDir), arg0) +} + +// IsEmpty mocks base method. +func (m *MockICloseableFS) IsEmpty(arg0 string) (bool, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "IsEmpty", arg0) + ret0, _ := ret[0].(bool) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// IsEmpty indicates an expected call of IsEmpty. +func (mr *MockICloseableFSMockRecorder) IsEmpty(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IsEmpty", reflect.TypeOf((*MockICloseableFS)(nil).IsEmpty), arg0) +} + +// IsFile mocks base method. +func (m *MockICloseableFS) IsFile(arg0 string) (bool, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "IsFile", arg0) + ret0, _ := ret[0].(bool) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// IsFile indicates an expected call of IsFile. +func (mr *MockICloseableFSMockRecorder) IsFile(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IsFile", reflect.TypeOf((*MockICloseableFS)(nil).IsFile), arg0) +} + +// IsLink mocks base method. +func (m *MockICloseableFS) IsLink(arg0 string) (bool, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "IsLink", arg0) + ret0, _ := ret[0].(bool) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// IsLink indicates an expected call of IsLink. +func (mr *MockICloseableFSMockRecorder) IsLink(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IsLink", reflect.TypeOf((*MockICloseableFS)(nil).IsLink), arg0) +} + +// IsZip mocks base method. +func (m *MockICloseableFS) IsZip(arg0 string) bool { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "IsZip", arg0) + ret0, _ := ret[0].(bool) + return ret0 +} + +// IsZip indicates an expected call of IsZip. +func (mr *MockICloseableFSMockRecorder) IsZip(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IsZip", reflect.TypeOf((*MockICloseableFS)(nil).IsZip), arg0) +} + +// IsZipWithContext mocks base method. +func (m *MockICloseableFS) IsZipWithContext(arg0 context.Context, arg1 string) (bool, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "IsZipWithContext", arg0, arg1) + ret0, _ := ret[0].(bool) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// IsZipWithContext indicates an expected call of IsZipWithContext. +func (mr *MockICloseableFSMockRecorder) IsZipWithContext(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IsZipWithContext", reflect.TypeOf((*MockICloseableFS)(nil).IsZipWithContext), arg0, arg1) +} + +// Link mocks base method. +func (m *MockICloseableFS) Link(arg0, arg1 string) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Link", arg0, arg1) + ret0, _ := ret[0].(error) + return ret0 +} + +// Link indicates an expected call of Link. +func (mr *MockICloseableFSMockRecorder) Link(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Link", reflect.TypeOf((*MockICloseableFS)(nil).Link), arg0, arg1) +} + +// ListDirTree mocks base method. +func (m *MockICloseableFS) ListDirTree(arg0 string, arg1 *[]string) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ListDirTree", arg0, arg1) + ret0, _ := ret[0].(error) + return ret0 +} + +// ListDirTree indicates an expected call of ListDirTree. +func (mr *MockICloseableFSMockRecorder) ListDirTree(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListDirTree", reflect.TypeOf((*MockICloseableFS)(nil).ListDirTree), arg0, arg1) +} + +// ListDirTreeWithContext mocks base method. +func (m *MockICloseableFS) ListDirTreeWithContext(arg0 context.Context, arg1 string, arg2 *[]string) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ListDirTreeWithContext", arg0, arg1, arg2) + ret0, _ := ret[0].(error) + return ret0 +} + +// ListDirTreeWithContext indicates an expected call of ListDirTreeWithContext. +func (mr *MockICloseableFSMockRecorder) ListDirTreeWithContext(arg0, arg1, arg2 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListDirTreeWithContext", reflect.TypeOf((*MockICloseableFS)(nil).ListDirTreeWithContext), arg0, arg1, arg2) +} + +// ListDirTreeWithContextAndExclusionPatterns mocks base method. +func (m *MockICloseableFS) ListDirTreeWithContextAndExclusionPatterns(arg0 context.Context, arg1 string, arg2 *[]string, arg3 ...string) error { + m.ctrl.T.Helper() + varargs := []interface{}{arg0, arg1, arg2} + for _, a := range arg3 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "ListDirTreeWithContextAndExclusionPatterns", varargs...) + ret0, _ := ret[0].(error) + return ret0 +} + +// ListDirTreeWithContextAndExclusionPatterns indicates an expected call of ListDirTreeWithContextAndExclusionPatterns. +func (mr *MockICloseableFSMockRecorder) ListDirTreeWithContextAndExclusionPatterns(arg0, arg1, arg2 interface{}, arg3 ...interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]interface{}{arg0, arg1, arg2}, arg3...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListDirTreeWithContextAndExclusionPatterns", reflect.TypeOf((*MockICloseableFS)(nil).ListDirTreeWithContextAndExclusionPatterns), varargs...) +} + +// Lls mocks base method. +func (m *MockICloseableFS) Lls(arg0 string) ([]fs.FileInfo, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Lls", arg0) + ret0, _ := ret[0].([]fs.FileInfo) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// Lls indicates an expected call of Lls. +func (mr *MockICloseableFSMockRecorder) Lls(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Lls", reflect.TypeOf((*MockICloseableFS)(nil).Lls), arg0) +} + +// LlsFromOpenedDirectory mocks base method. +func (m *MockICloseableFS) LlsFromOpenedDirectory(arg0 filesystem.File) ([]fs.FileInfo, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "LlsFromOpenedDirectory", arg0) + ret0, _ := ret[0].([]fs.FileInfo) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// LlsFromOpenedDirectory indicates an expected call of LlsFromOpenedDirectory. +func (mr *MockICloseableFSMockRecorder) LlsFromOpenedDirectory(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "LlsFromOpenedDirectory", reflect.TypeOf((*MockICloseableFS)(nil).LlsFromOpenedDirectory), arg0) +} + +// Ls mocks base method. +func (m *MockICloseableFS) Ls(arg0 string) ([]string, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Ls", arg0) + ret0, _ := ret[0].([]string) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// Ls indicates an expected call of Ls. +func (mr *MockICloseableFSMockRecorder) Ls(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Ls", reflect.TypeOf((*MockICloseableFS)(nil).Ls), arg0) +} + +// LsFromOpenedDirectory mocks base method. +func (m *MockICloseableFS) LsFromOpenedDirectory(arg0 filesystem.File) ([]string, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "LsFromOpenedDirectory", arg0) + ret0, _ := ret[0].([]string) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// LsFromOpenedDirectory indicates an expected call of LsFromOpenedDirectory. +func (mr *MockICloseableFSMockRecorder) LsFromOpenedDirectory(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "LsFromOpenedDirectory", reflect.TypeOf((*MockICloseableFS)(nil).LsFromOpenedDirectory), arg0) +} + +// LsWithExclusionPatterns mocks base method. +func (m *MockICloseableFS) LsWithExclusionPatterns(arg0 string, arg1 ...string) ([]string, error) { + m.ctrl.T.Helper() + varargs := []interface{}{arg0} + for _, a := range arg1 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "LsWithExclusionPatterns", varargs...) + ret0, _ := ret[0].([]string) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// LsWithExclusionPatterns indicates an expected call of LsWithExclusionPatterns. +func (mr *MockICloseableFSMockRecorder) LsWithExclusionPatterns(arg0 interface{}, arg1 ...interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]interface{}{arg0}, arg1...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "LsWithExclusionPatterns", reflect.TypeOf((*MockICloseableFS)(nil).LsWithExclusionPatterns), varargs...) +} + +// Lstat mocks base method. +func (m *MockICloseableFS) Lstat(arg0 string) (fs.FileInfo, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Lstat", arg0) + ret0, _ := ret[0].(fs.FileInfo) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// Lstat indicates an expected call of Lstat. +func (mr *MockICloseableFSMockRecorder) Lstat(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Lstat", reflect.TypeOf((*MockICloseableFS)(nil).Lstat), arg0) +} + +// MkDir mocks base method. +func (m *MockICloseableFS) MkDir(arg0 string) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "MkDir", arg0) + ret0, _ := ret[0].(error) + return ret0 +} + +// MkDir indicates an expected call of MkDir. +func (mr *MockICloseableFSMockRecorder) MkDir(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "MkDir", reflect.TypeOf((*MockICloseableFS)(nil).MkDir), arg0) +} + +// MkDirAll mocks base method. +func (m *MockICloseableFS) MkDirAll(arg0 string, arg1 fs.FileMode) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "MkDirAll", arg0, arg1) + ret0, _ := ret[0].(error) + return ret0 +} + +// MkDirAll indicates an expected call of MkDirAll. +func (mr *MockICloseableFSMockRecorder) MkDirAll(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "MkDirAll", reflect.TypeOf((*MockICloseableFS)(nil).MkDirAll), arg0, arg1) +} + +// Move mocks base method. +func (m *MockICloseableFS) Move(arg0, arg1 string) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Move", arg0, arg1) + ret0, _ := ret[0].(error) + return ret0 +} + +// Move indicates an expected call of Move. +func (mr *MockICloseableFSMockRecorder) Move(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Move", reflect.TypeOf((*MockICloseableFS)(nil).Move), arg0, arg1) +} + +// MoveWithContext mocks base method. +func (m *MockICloseableFS) MoveWithContext(arg0 context.Context, arg1, arg2 string) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "MoveWithContext", arg0, arg1, arg2) + ret0, _ := ret[0].(error) + return ret0 +} + +// MoveWithContext indicates an expected call of MoveWithContext. +func (mr *MockICloseableFSMockRecorder) MoveWithContext(arg0, arg1, arg2 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "MoveWithContext", reflect.TypeOf((*MockICloseableFS)(nil).MoveWithContext), arg0, arg1, arg2) +} + +// NewRemoteLockFile mocks base method. +func (m *MockICloseableFS) NewRemoteLockFile(arg0, arg1 string) filesystem.ILock { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "NewRemoteLockFile", arg0, arg1) + ret0, _ := ret[0].(filesystem.ILock) + return ret0 +} + +// NewRemoteLockFile indicates an expected call of NewRemoteLockFile. +func (mr *MockICloseableFSMockRecorder) NewRemoteLockFile(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NewRemoteLockFile", reflect.TypeOf((*MockICloseableFS)(nil).NewRemoteLockFile), arg0, arg1) +} + +// Open mocks base method. +func (m *MockICloseableFS) Open(arg0 string) (doublestar.File, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Open", arg0) + ret0, _ := ret[0].(doublestar.File) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// Open indicates an expected call of Open. +func (mr *MockICloseableFSMockRecorder) Open(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Open", reflect.TypeOf((*MockICloseableFS)(nil).Open), arg0) +} + +// OpenFile mocks base method. +func (m *MockICloseableFS) OpenFile(arg0 string, arg1 int, arg2 fs.FileMode) (filesystem.File, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "OpenFile", arg0, arg1, arg2) + ret0, _ := ret[0].(filesystem.File) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// OpenFile indicates an expected call of OpenFile. +func (mr *MockICloseableFSMockRecorder) OpenFile(arg0, arg1, arg2 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OpenFile", reflect.TypeOf((*MockICloseableFS)(nil).OpenFile), arg0, arg1, arg2) +} + +// PathSeparator mocks base method. +func (m *MockICloseableFS) PathSeparator() int32 { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "PathSeparator") + ret0, _ := ret[0].(int32) + return ret0 +} + +// PathSeparator indicates an expected call of PathSeparator. +func (mr *MockICloseableFSMockRecorder) PathSeparator() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PathSeparator", reflect.TypeOf((*MockICloseableFS)(nil).PathSeparator)) +} + +// ReadFile mocks base method. +func (m *MockICloseableFS) ReadFile(arg0 string) ([]byte, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ReadFile", arg0) + ret0, _ := ret[0].([]byte) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// ReadFile indicates an expected call of ReadFile. +func (mr *MockICloseableFSMockRecorder) ReadFile(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ReadFile", reflect.TypeOf((*MockICloseableFS)(nil).ReadFile), arg0) +} + +// ReadFileContent mocks base method. +func (m *MockICloseableFS) ReadFileContent(arg0 context.Context, arg1 filesystem.File, arg2 filesystem.ILimits) ([]byte, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ReadFileContent", arg0, arg1, arg2) + ret0, _ := ret[0].([]byte) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// ReadFileContent indicates an expected call of ReadFileContent. +func (mr *MockICloseableFSMockRecorder) ReadFileContent(arg0, arg1, arg2 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ReadFileContent", reflect.TypeOf((*MockICloseableFS)(nil).ReadFileContent), arg0, arg1, arg2) +} + +// ReadFileWithContext mocks base method. +func (m *MockICloseableFS) ReadFileWithContext(arg0 context.Context, arg1 string) ([]byte, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ReadFileWithContext", arg0, arg1) + ret0, _ := ret[0].([]byte) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// ReadFileWithContext indicates an expected call of ReadFileWithContext. +func (mr *MockICloseableFSMockRecorder) ReadFileWithContext(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ReadFileWithContext", reflect.TypeOf((*MockICloseableFS)(nil).ReadFileWithContext), arg0, arg1) +} + +// ReadFileWithContextAndLimits mocks base method. +func (m *MockICloseableFS) ReadFileWithContextAndLimits(arg0 context.Context, arg1 string, arg2 filesystem.ILimits) ([]byte, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ReadFileWithContextAndLimits", arg0, arg1, arg2) + ret0, _ := ret[0].([]byte) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// ReadFileWithContextAndLimits indicates an expected call of ReadFileWithContextAndLimits. +func (mr *MockICloseableFSMockRecorder) ReadFileWithContextAndLimits(arg0, arg1, arg2 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ReadFileWithContextAndLimits", reflect.TypeOf((*MockICloseableFS)(nil).ReadFileWithContextAndLimits), arg0, arg1, arg2) +} + +// ReadFileWithLimits mocks base method. +func (m *MockICloseableFS) ReadFileWithLimits(arg0 string, arg1 filesystem.ILimits) ([]byte, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ReadFileWithLimits", arg0, arg1) + ret0, _ := ret[0].([]byte) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// ReadFileWithLimits indicates an expected call of ReadFileWithLimits. +func (mr *MockICloseableFSMockRecorder) ReadFileWithLimits(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ReadFileWithLimits", reflect.TypeOf((*MockICloseableFS)(nil).ReadFileWithLimits), arg0, arg1) +} + +// Readlink mocks base method. +func (m *MockICloseableFS) Readlink(arg0 string) (string, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Readlink", arg0) + ret0, _ := ret[0].(string) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// Readlink indicates an expected call of Readlink. +func (mr *MockICloseableFSMockRecorder) Readlink(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Readlink", reflect.TypeOf((*MockICloseableFS)(nil).Readlink), arg0) +} + +// RemoveWithContext mocks base method. +func (m *MockICloseableFS) RemoveWithContext(arg0 context.Context, arg1 string) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "RemoveWithContext", arg0, arg1) + ret0, _ := ret[0].(error) + return ret0 +} + +// RemoveWithContext indicates an expected call of RemoveWithContext. +func (mr *MockICloseableFSMockRecorder) RemoveWithContext(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RemoveWithContext", reflect.TypeOf((*MockICloseableFS)(nil).RemoveWithContext), arg0, arg1) +} + +// RemoveWithContextAndExclusionPatterns mocks base method. +func (m *MockICloseableFS) RemoveWithContextAndExclusionPatterns(arg0 context.Context, arg1 string, arg2 ...string) error { + m.ctrl.T.Helper() + varargs := []interface{}{arg0, arg1} + for _, a := range arg2 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "RemoveWithContextAndExclusionPatterns", varargs...) + ret0, _ := ret[0].(error) + return ret0 +} + +// RemoveWithContextAndExclusionPatterns indicates an expected call of RemoveWithContextAndExclusionPatterns. +func (mr *MockICloseableFSMockRecorder) RemoveWithContextAndExclusionPatterns(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]interface{}{arg0, arg1}, arg2...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RemoveWithContextAndExclusionPatterns", reflect.TypeOf((*MockICloseableFS)(nil).RemoveWithContextAndExclusionPatterns), varargs...) +} + +// Rm mocks base method. +func (m *MockICloseableFS) Rm(arg0 string) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Rm", arg0) + ret0, _ := ret[0].(error) + return ret0 +} + +// Rm indicates an expected call of Rm. +func (mr *MockICloseableFSMockRecorder) Rm(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Rm", reflect.TypeOf((*MockICloseableFS)(nil).Rm), arg0) +} + +// Stat mocks base method. +func (m *MockICloseableFS) Stat(arg0 string) (fs.FileInfo, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Stat", arg0) + ret0, _ := ret[0].(fs.FileInfo) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// Stat indicates an expected call of Stat. +func (mr *MockICloseableFSMockRecorder) Stat(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Stat", reflect.TypeOf((*MockICloseableFS)(nil).Stat), arg0) +} + +// StatTimes mocks base method. +func (m *MockICloseableFS) StatTimes(arg0 string) (filesystem.FileTimeInfo, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "StatTimes", arg0) + ret0, _ := ret[0].(filesystem.FileTimeInfo) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// StatTimes indicates an expected call of StatTimes. +func (mr *MockICloseableFSMockRecorder) StatTimes(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "StatTimes", reflect.TypeOf((*MockICloseableFS)(nil).StatTimes), arg0) +} + +// SubDirectories mocks base method. +func (m *MockICloseableFS) SubDirectories(arg0 string) ([]string, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "SubDirectories", arg0) + ret0, _ := ret[0].([]string) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// SubDirectories indicates an expected call of SubDirectories. +func (mr *MockICloseableFSMockRecorder) SubDirectories(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SubDirectories", reflect.TypeOf((*MockICloseableFS)(nil).SubDirectories), arg0) +} + +// SubDirectoriesWithContext mocks base method. +func (m *MockICloseableFS) SubDirectoriesWithContext(arg0 context.Context, arg1 string) ([]string, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "SubDirectoriesWithContext", arg0, arg1) + ret0, _ := ret[0].([]string) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// SubDirectoriesWithContext indicates an expected call of SubDirectoriesWithContext. +func (mr *MockICloseableFSMockRecorder) SubDirectoriesWithContext(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SubDirectoriesWithContext", reflect.TypeOf((*MockICloseableFS)(nil).SubDirectoriesWithContext), arg0, arg1) +} + +// SubDirectoriesWithContextAndExclusionPatterns mocks base method. +func (m *MockICloseableFS) SubDirectoriesWithContextAndExclusionPatterns(arg0 context.Context, arg1 string, arg2 ...string) ([]string, error) { + m.ctrl.T.Helper() + varargs := []interface{}{arg0, arg1} + for _, a := range arg2 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "SubDirectoriesWithContextAndExclusionPatterns", varargs...) + ret0, _ := ret[0].([]string) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// SubDirectoriesWithContextAndExclusionPatterns indicates an expected call of SubDirectoriesWithContextAndExclusionPatterns. +func (mr *MockICloseableFSMockRecorder) SubDirectoriesWithContextAndExclusionPatterns(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]interface{}{arg0, arg1}, arg2...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SubDirectoriesWithContextAndExclusionPatterns", reflect.TypeOf((*MockICloseableFS)(nil).SubDirectoriesWithContextAndExclusionPatterns), varargs...) +} + +// Symlink mocks base method. +func (m *MockICloseableFS) Symlink(arg0, arg1 string) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Symlink", arg0, arg1) + ret0, _ := ret[0].(error) + return ret0 +} + +// Symlink indicates an expected call of Symlink. +func (mr *MockICloseableFSMockRecorder) Symlink(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Symlink", reflect.TypeOf((*MockICloseableFS)(nil).Symlink), arg0, arg1) +} + +// TempDir mocks base method. +func (m *MockICloseableFS) TempDir(arg0, arg1 string) (string, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "TempDir", arg0, arg1) + ret0, _ := ret[0].(string) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// TempDir indicates an expected call of TempDir. +func (mr *MockICloseableFSMockRecorder) TempDir(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TempDir", reflect.TypeOf((*MockICloseableFS)(nil).TempDir), arg0, arg1) +} + +// TempDirInTempDir mocks base method. +func (m *MockICloseableFS) TempDirInTempDir(arg0 string) (string, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "TempDirInTempDir", arg0) + ret0, _ := ret[0].(string) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// TempDirInTempDir indicates an expected call of TempDirInTempDir. +func (mr *MockICloseableFSMockRecorder) TempDirInTempDir(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TempDirInTempDir", reflect.TypeOf((*MockICloseableFS)(nil).TempDirInTempDir), arg0) +} + +// TempDirectory mocks base method. +func (m *MockICloseableFS) TempDirectory() string { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "TempDirectory") + ret0, _ := ret[0].(string) + return ret0 +} + +// TempDirectory indicates an expected call of TempDirectory. +func (mr *MockICloseableFSMockRecorder) TempDirectory() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TempDirectory", reflect.TypeOf((*MockICloseableFS)(nil).TempDirectory)) +} + +// TempFile mocks base method. +func (m *MockICloseableFS) TempFile(arg0, arg1 string) (filesystem.File, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "TempFile", arg0, arg1) + ret0, _ := ret[0].(filesystem.File) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// TempFile indicates an expected call of TempFile. +func (mr *MockICloseableFSMockRecorder) TempFile(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TempFile", reflect.TypeOf((*MockICloseableFS)(nil).TempFile), arg0, arg1) +} + +// TempFileInTempDir mocks base method. +func (m *MockICloseableFS) TempFileInTempDir(arg0 string) (filesystem.File, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "TempFileInTempDir", arg0) + ret0, _ := ret[0].(filesystem.File) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// TempFileInTempDir indicates an expected call of TempFileInTempDir. +func (mr *MockICloseableFSMockRecorder) TempFileInTempDir(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TempFileInTempDir", reflect.TypeOf((*MockICloseableFS)(nil).TempFileInTempDir), arg0) +} + +// Unzip mocks base method. +func (m *MockICloseableFS) Unzip(arg0, arg1 string) ([]string, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Unzip", arg0, arg1) + ret0, _ := ret[0].([]string) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// Unzip indicates an expected call of Unzip. +func (mr *MockICloseableFSMockRecorder) Unzip(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Unzip", reflect.TypeOf((*MockICloseableFS)(nil).Unzip), arg0, arg1) +} + +// UnzipWithContext mocks base method. +func (m *MockICloseableFS) UnzipWithContext(arg0 context.Context, arg1, arg2 string) ([]string, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "UnzipWithContext", arg0, arg1, arg2) + ret0, _ := ret[0].([]string) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// UnzipWithContext indicates an expected call of UnzipWithContext. +func (mr *MockICloseableFSMockRecorder) UnzipWithContext(arg0, arg1, arg2 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UnzipWithContext", reflect.TypeOf((*MockICloseableFS)(nil).UnzipWithContext), arg0, arg1, arg2) +} + +// UnzipWithContextAndLimits mocks base method. +func (m *MockICloseableFS) UnzipWithContextAndLimits(arg0 context.Context, arg1, arg2 string, arg3 filesystem.ILimits) ([]string, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "UnzipWithContextAndLimits", arg0, arg1, arg2, arg3) + ret0, _ := ret[0].([]string) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// UnzipWithContextAndLimits indicates an expected call of UnzipWithContextAndLimits. +func (mr *MockICloseableFSMockRecorder) UnzipWithContextAndLimits(arg0, arg1, arg2, arg3 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UnzipWithContextAndLimits", reflect.TypeOf((*MockICloseableFS)(nil).UnzipWithContextAndLimits), arg0, arg1, arg2, arg3) +} + +// Walk mocks base method. +func (m *MockICloseableFS) Walk(arg0 string, arg1 filepath.WalkFunc) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Walk", arg0, arg1) + ret0, _ := ret[0].(error) + return ret0 +} + +// Walk indicates an expected call of Walk. +func (mr *MockICloseableFSMockRecorder) Walk(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Walk", reflect.TypeOf((*MockICloseableFS)(nil).Walk), arg0, arg1) +} + +// WalkWithContext mocks base method. +func (m *MockICloseableFS) WalkWithContext(arg0 context.Context, arg1 string, arg2 filepath.WalkFunc) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "WalkWithContext", arg0, arg1, arg2) + ret0, _ := ret[0].(error) + return ret0 +} + +// WalkWithContext indicates an expected call of WalkWithContext. +func (mr *MockICloseableFSMockRecorder) WalkWithContext(arg0, arg1, arg2 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "WalkWithContext", reflect.TypeOf((*MockICloseableFS)(nil).WalkWithContext), arg0, arg1, arg2) +} + +// WalkWithContextAndExclusionPatterns mocks base method. +func (m *MockICloseableFS) WalkWithContextAndExclusionPatterns(arg0 context.Context, arg1 string, arg2 filepath.WalkFunc, arg3 ...string) error { + m.ctrl.T.Helper() + varargs := []interface{}{arg0, arg1, arg2} + for _, a := range arg3 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "WalkWithContextAndExclusionPatterns", varargs...) + ret0, _ := ret[0].(error) + return ret0 +} + +// WalkWithContextAndExclusionPatterns indicates an expected call of WalkWithContextAndExclusionPatterns. +func (mr *MockICloseableFSMockRecorder) WalkWithContextAndExclusionPatterns(arg0, arg1, arg2 interface{}, arg3 ...interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]interface{}{arg0, arg1, arg2}, arg3...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "WalkWithContextAndExclusionPatterns", reflect.TypeOf((*MockICloseableFS)(nil).WalkWithContextAndExclusionPatterns), varargs...) +} + +// WriteFile mocks base method. +func (m *MockICloseableFS) WriteFile(arg0 string, arg1 []byte, arg2 fs.FileMode) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "WriteFile", arg0, arg1, arg2) + ret0, _ := ret[0].(error) + return ret0 +} + +// WriteFile indicates an expected call of WriteFile. +func (mr *MockICloseableFSMockRecorder) WriteFile(arg0, arg1, arg2 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "WriteFile", reflect.TypeOf((*MockICloseableFS)(nil).WriteFile), arg0, arg1, arg2) +} + +// WriteFileWithContext mocks base method. +func (m *MockICloseableFS) WriteFileWithContext(arg0 context.Context, arg1 string, arg2 []byte, arg3 fs.FileMode) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "WriteFileWithContext", arg0, arg1, arg2, arg3) + ret0, _ := ret[0].(error) + return ret0 +} + +// WriteFileWithContext indicates an expected call of WriteFileWithContext. +func (mr *MockICloseableFSMockRecorder) WriteFileWithContext(arg0, arg1, arg2, arg3 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "WriteFileWithContext", reflect.TypeOf((*MockICloseableFS)(nil).WriteFileWithContext), arg0, arg1, arg2, arg3) +} + +// WriteToFile mocks base method. +func (m *MockICloseableFS) WriteToFile(arg0 context.Context, arg1 string, arg2 io.Reader, arg3 fs.FileMode) (int64, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "WriteToFile", arg0, arg1, arg2, arg3) + ret0, _ := ret[0].(int64) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// WriteToFile indicates an expected call of WriteToFile. +func (mr *MockICloseableFSMockRecorder) WriteToFile(arg0, arg1, arg2, arg3 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "WriteToFile", reflect.TypeOf((*MockICloseableFS)(nil).WriteToFile), arg0, arg1, arg2, arg3) +} + +// Zip mocks base method. +func (m *MockICloseableFS) Zip(arg0, arg1 string) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Zip", arg0, arg1) + ret0, _ := ret[0].(error) + return ret0 +} + +// Zip indicates an expected call of Zip. +func (mr *MockICloseableFSMockRecorder) Zip(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Zip", reflect.TypeOf((*MockICloseableFS)(nil).Zip), arg0, arg1) +} + +// ZipWithContext mocks base method. +func (m *MockICloseableFS) ZipWithContext(arg0 context.Context, arg1, arg2 string) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ZipWithContext", arg0, arg1, arg2) + ret0, _ := ret[0].(error) + return ret0 +} + +// ZipWithContext indicates an expected call of ZipWithContext. +func (mr *MockICloseableFSMockRecorder) ZipWithContext(arg0, arg1, arg2 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ZipWithContext", reflect.TypeOf((*MockICloseableFS)(nil).ZipWithContext), arg0, arg1, arg2) +} + +// ZipWithContextAndLimits mocks base method. +func (m *MockICloseableFS) ZipWithContextAndLimits(arg0 context.Context, arg1, arg2 string, arg3 filesystem.ILimits) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ZipWithContextAndLimits", arg0, arg1, arg2, arg3) + ret0, _ := ret[0].(error) + return ret0 +} + +// ZipWithContextAndLimits indicates an expected call of ZipWithContextAndLimits. +func (mr *MockICloseableFSMockRecorder) ZipWithContextAndLimits(arg0, arg1, arg2, arg3 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ZipWithContextAndLimits", reflect.TypeOf((*MockICloseableFS)(nil).ZipWithContextAndLimits), arg0, arg1, arg2, arg3) +} + +// ZipWithContextAndLimitsAndExclusionPatterns mocks base method. +func (m *MockICloseableFS) ZipWithContextAndLimitsAndExclusionPatterns(arg0 context.Context, arg1, arg2 string, arg3 filesystem.ILimits, arg4 ...string) error { + m.ctrl.T.Helper() + varargs := []interface{}{arg0, arg1, arg2, arg3} + for _, a := range arg4 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "ZipWithContextAndLimitsAndExclusionPatterns", varargs...) + ret0, _ := ret[0].(error) + return ret0 +} + +// ZipWithContextAndLimitsAndExclusionPatterns indicates an expected call of ZipWithContextAndLimitsAndExclusionPatterns. +func (mr *MockICloseableFSMockRecorder) ZipWithContextAndLimitsAndExclusionPatterns(arg0, arg1, arg2, arg3 interface{}, arg4 ...interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]interface{}{arg0, arg1, arg2, arg3}, arg4...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ZipWithContextAndLimitsAndExclusionPatterns", reflect.TypeOf((*MockICloseableFS)(nil).ZipWithContextAndLimitsAndExclusionPatterns), varargs...) +} diff --git a/utils/mocks/mock_resource.go b/utils/mocks/mock_resource.go new file mode 100644 index 0000000000..4bccdc3b0a --- /dev/null +++ b/utils/mocks/mock_resource.go @@ -0,0 +1,76 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: github.com/ARM-software/golang-utils/utils/resource (interfaces: ICloseableResource) + +// Package mocks is a generated GoMock package. +package mocks + +import ( + reflect "reflect" + + gomock "github.com/golang/mock/gomock" +) + +// MockICloseableResource is a mock of ICloseableResource interface. +type MockICloseableResource struct { + ctrl *gomock.Controller + recorder *MockICloseableResourceMockRecorder +} + +// MockICloseableResourceMockRecorder is the mock recorder for MockICloseableResource. +type MockICloseableResourceMockRecorder struct { + mock *MockICloseableResource +} + +// NewMockICloseableResource creates a new mock instance. +func NewMockICloseableResource(ctrl *gomock.Controller) *MockICloseableResource { + mock := &MockICloseableResource{ctrl: ctrl} + mock.recorder = &MockICloseableResourceMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockICloseableResource) EXPECT() *MockICloseableResourceMockRecorder { + return m.recorder +} + +// Close mocks base method. +func (m *MockICloseableResource) Close() error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Close") + ret0, _ := ret[0].(error) + return ret0 +} + +// Close indicates an expected call of Close. +func (mr *MockICloseableResourceMockRecorder) Close() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Close", reflect.TypeOf((*MockICloseableResource)(nil).Close)) +} + +// IsClosed mocks base method. +func (m *MockICloseableResource) IsClosed() bool { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "IsClosed") + ret0, _ := ret[0].(bool) + return ret0 +} + +// IsClosed indicates an expected call of IsClosed. +func (mr *MockICloseableResourceMockRecorder) IsClosed() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IsClosed", reflect.TypeOf((*MockICloseableResource)(nil).IsClosed)) +} + +// String mocks base method. +func (m *MockICloseableResource) String() string { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "String") + ret0, _ := ret[0].(string) + return ret0 +} + +// String indicates an expected call of String. +func (mr *MockICloseableResourceMockRecorder) String() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "String", reflect.TypeOf((*MockICloseableResource)(nil).String)) +} diff --git a/utils/resource/interfaces.go b/utils/resource/interfaces.go new file mode 100644 index 0000000000..64462400a5 --- /dev/null +++ b/utils/resource/interfaces.go @@ -0,0 +1,21 @@ +/* + * Copyright (C) 2020-2022 Arm Limited or its affiliates and Contributors. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +// Package resource resource defines utilities about generic resources. +package resource + +import ( + "fmt" + "io" +) + +//go:generate mockgen -destination=../mocks/mock_$GOPACKAGE.go -package=mocks github.com/ARM-software/golang-utils/utils/$GOPACKAGE ICloseableResource + +// ICloseableResource defines a resource which must be closed after use e.g. an open file. +type ICloseableResource interface { + io.Closer + fmt.Stringer + IsClosed() bool +} diff --git a/utils/resource/resource.go b/utils/resource/resource.go new file mode 100644 index 0000000000..0ea8c6efa3 --- /dev/null +++ b/utils/resource/resource.go @@ -0,0 +1,69 @@ +package resource + +import ( + "io" + "sync" +) + +type closeableResource struct { + io.Closer + mu sync.RWMutex + closeableResource io.Closer + closed bool + description string +} + +func (c *closeableResource) IsClosed() bool { + c.mu.RLock() + defer c.mu.RUnlock() + return c.closed +} + +func (c *closeableResource) Close() error { + c.mu.Lock() + defer c.mu.Unlock() + if c.closeableResource != nil { + err := c.closeableResource.Close() + if err != nil { + return err + } + } + c.closed = true + c.closeableResource = nil + return nil +} + +func (c *closeableResource) String() string { + c.mu.RLock() + defer c.mu.RUnlock() + return c.description +} + +// NewCloseableResource returns a Closeable resource. +func NewCloseableResource(resource io.Closer, description string) ICloseableResource { + return &closeableResource{ + closeableResource: resource, + closed: false, + description: description, + } +} + +type closeableNilResource struct { +} + +func (c *closeableNilResource) Close() error { + return nil +} + +func (c *closeableNilResource) String() string { + return "non closeable resource" +} + +func (c *closeableNilResource) IsClosed() bool { + return false +} + +// NewNonCloseableResource returns a resource which cannot be closed. +func NewNonCloseableResource() ICloseableResource { + return &closeableNilResource{} +} diff --git a/utils/resource/resource_test.go b/utils/resource/resource_test.go new file mode 100644 index 0000000000..3efa102b79 --- /dev/null +++ b/utils/resource/resource_test.go @@ -0,0 +1,25 @@ +package resource + +import ( + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func Test_CloseableResource(t *testing.T) { + desc := "test nil resource" + testResource := NewCloseableResource(nil, desc) + assert.Contains(t, testResource.String(), desc) + assert.False(t, testResource.IsClosed()) + require.NoError(t, testResource.Close()) + assert.True(t, testResource.IsClosed()) +} + +func Test_NonCloseableResource(t *testing.T) { + testResource := NewNonCloseableResource() + assert.NotEmpty(t, testResource.String()) + assert.False(t, testResource.IsClosed()) + require.NoError(t, testResource.Close()) + assert.False(t, testResource.IsClosed()) +}