mirror of https://github.com/spf13/afero.git
GCS fs: move all gcsfs related implementations to its own package
this way we don't force any application that import afero to include gcfs deps in its binary
This commit is contained in:
parent
d70f944720
commit
165e3dc3a5
|
@ -44,7 +44,7 @@ type GcsFile struct {
|
||||||
|
|
||||||
func NewGcsFile(
|
func NewGcsFile(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
fs *GcsFs,
|
fs *Fs,
|
||||||
obj stiface.ObjectHandle,
|
obj stiface.ObjectHandle,
|
||||||
openFlags int,
|
openFlags int,
|
||||||
// Unused: there is no use to the file mode in GCloud just yet - but we keep it here, just in case we need it
|
// Unused: there is no use to the file mode in GCloud just yet - but we keep it here, just in case we need it
|
||||||
|
|
|
@ -37,7 +37,7 @@ type FileInfo struct {
|
||||||
fileMode os.FileMode
|
fileMode os.FileMode
|
||||||
}
|
}
|
||||||
|
|
||||||
func newFileInfo(name string, fs *GcsFs, fileMode os.FileMode) (*FileInfo, error) {
|
func newFileInfo(name string, fs *Fs, fileMode os.FileMode) (*FileInfo, error) {
|
||||||
res := &FileInfo{
|
res := &FileInfo{
|
||||||
name: name,
|
name: name,
|
||||||
size: folderSize,
|
size: folderSize,
|
||||||
|
|
|
@ -40,7 +40,7 @@ const (
|
||||||
type gcsFileResource struct {
|
type gcsFileResource struct {
|
||||||
ctx context.Context
|
ctx context.Context
|
||||||
|
|
||||||
fs *GcsFs
|
fs *Fs
|
||||||
|
|
||||||
obj stiface.ObjectHandle
|
obj stiface.ObjectHandle
|
||||||
name string
|
name string
|
||||||
|
|
48
gcsfs/fs.go
48
gcsfs/fs.go
|
@ -33,8 +33,8 @@ const (
|
||||||
gsPrefix = "gs://"
|
gsPrefix = "gs://"
|
||||||
)
|
)
|
||||||
|
|
||||||
// GcsFs is a Fs implementation that uses functions provided by google cloud storage
|
// Fs is a Fs implementation that uses functions provided by google cloud storage
|
||||||
type GcsFs struct {
|
type Fs struct {
|
||||||
ctx context.Context
|
ctx context.Context
|
||||||
client stiface.Client
|
client stiface.Client
|
||||||
separator string
|
separator string
|
||||||
|
@ -45,12 +45,12 @@ type GcsFs struct {
|
||||||
autoRemoveEmptyFolders bool //trigger for creating "virtual folders" (not required by GCSs)
|
autoRemoveEmptyFolders bool //trigger for creating "virtual folders" (not required by GCSs)
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewGcsFs(ctx context.Context, client stiface.Client) *GcsFs {
|
func NewGcsFs(ctx context.Context, client stiface.Client) *Fs {
|
||||||
return NewGcsFsWithSeparator(ctx, client, "/")
|
return NewGcsFsWithSeparator(ctx, client, "/")
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewGcsFsWithSeparator(ctx context.Context, client stiface.Client, folderSep string) *GcsFs {
|
func NewGcsFsWithSeparator(ctx context.Context, client stiface.Client, folderSep string) *Fs {
|
||||||
return &GcsFs{
|
return &Fs{
|
||||||
ctx: ctx,
|
ctx: ctx,
|
||||||
client: client,
|
client: client,
|
||||||
separator: folderSep,
|
separator: folderSep,
|
||||||
|
@ -61,17 +61,17 @@ func NewGcsFsWithSeparator(ctx context.Context, client stiface.Client, folderSep
|
||||||
}
|
}
|
||||||
|
|
||||||
// normSeparators will normalize all "\\" and "/" to the provided separator
|
// normSeparators will normalize all "\\" and "/" to the provided separator
|
||||||
func (fs *GcsFs) normSeparators(s string) string {
|
func (fs *Fs) normSeparators(s string) string {
|
||||||
return strings.Replace(strings.Replace(s, "\\", fs.separator, -1), "/", fs.separator, -1)
|
return strings.Replace(strings.Replace(s, "\\", fs.separator, -1), "/", fs.separator, -1)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (fs *GcsFs) ensureTrailingSeparator(s string) string {
|
func (fs *Fs) ensureTrailingSeparator(s string) string {
|
||||||
if len(s) > 0 && !strings.HasSuffix(s, fs.separator) {
|
if len(s) > 0 && !strings.HasSuffix(s, fs.separator) {
|
||||||
return s + fs.separator
|
return s + fs.separator
|
||||||
}
|
}
|
||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
func (fs *GcsFs) ensureNoLeadingSeparator(s string) string {
|
func (fs *Fs) ensureNoLeadingSeparator(s string) string {
|
||||||
if len(s) > 0 && strings.HasPrefix(s, fs.separator) {
|
if len(s) > 0 && strings.HasPrefix(s, fs.separator) {
|
||||||
s = s[len(fs.separator):]
|
s = s[len(fs.separator):]
|
||||||
}
|
}
|
||||||
|
@ -94,13 +94,13 @@ func validateName(s string) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Splits provided name into bucket name and path
|
// Splits provided name into bucket name and path
|
||||||
func (fs *GcsFs) splitName(name string) (bucketName string, path string) {
|
func (fs *Fs) splitName(name string) (bucketName string, path string) {
|
||||||
splitName := strings.Split(name, fs.separator)
|
splitName := strings.Split(name, fs.separator)
|
||||||
|
|
||||||
return splitName[0], strings.Join(splitName[1:], fs.separator)
|
return splitName[0], strings.Join(splitName[1:], fs.separator)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (fs *GcsFs) getBucket(name string) (stiface.BucketHandle, error) {
|
func (fs *Fs) getBucket(name string) (stiface.BucketHandle, error) {
|
||||||
bucket := fs.buckets[name]
|
bucket := fs.buckets[name]
|
||||||
if bucket == nil {
|
if bucket == nil {
|
||||||
bucket = fs.client.Bucket(name)
|
bucket = fs.client.Bucket(name)
|
||||||
|
@ -112,7 +112,7 @@ func (fs *GcsFs) getBucket(name string) (stiface.BucketHandle, error) {
|
||||||
return bucket, nil
|
return bucket, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (fs *GcsFs) getObj(name string) (stiface.ObjectHandle, error) {
|
func (fs *Fs) getObj(name string) (stiface.ObjectHandle, error) {
|
||||||
bucketName, path := fs.splitName(name)
|
bucketName, path := fs.splitName(name)
|
||||||
|
|
||||||
bucket, err := fs.getBucket(bucketName)
|
bucket, err := fs.getBucket(bucketName)
|
||||||
|
@ -123,9 +123,9 @@ func (fs *GcsFs) getObj(name string) (stiface.ObjectHandle, error) {
|
||||||
return bucket.Object(path), nil
|
return bucket.Object(path), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (fs *GcsFs) Name() string { return "GcsFs" }
|
func (fs *Fs) Name() string { return "GcsFs" }
|
||||||
|
|
||||||
func (fs *GcsFs) Create(name string) (*GcsFile, error) {
|
func (fs *Fs) Create(name string) (*GcsFile, error) {
|
||||||
name = fs.ensureNoLeadingSeparator(fs.normSeparators(ensureNoPrefix(name)))
|
name = fs.ensureNoLeadingSeparator(fs.normSeparators(ensureNoPrefix(name)))
|
||||||
if err := validateName(name); err != nil {
|
if err := validateName(name); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -156,7 +156,7 @@ func (fs *GcsFs) Create(name string) (*GcsFile, error) {
|
||||||
return file, nil
|
return file, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (fs *GcsFs) Mkdir(name string, _ os.FileMode) error {
|
func (fs *Fs) Mkdir(name string, _ os.FileMode) error {
|
||||||
name = fs.ensureNoLeadingSeparator(fs.ensureTrailingSeparator(fs.normSeparators(ensureNoPrefix(name))))
|
name = fs.ensureNoLeadingSeparator(fs.ensureTrailingSeparator(fs.normSeparators(ensureNoPrefix(name))))
|
||||||
if err := validateName(name); err != nil {
|
if err := validateName(name); err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -179,7 +179,7 @@ func (fs *GcsFs) Mkdir(name string, _ os.FileMode) error {
|
||||||
return w.Close()
|
return w.Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (fs *GcsFs) MkdirAll(path string, perm os.FileMode) error {
|
func (fs *Fs) MkdirAll(path string, perm os.FileMode) error {
|
||||||
path = fs.ensureNoLeadingSeparator(fs.ensureTrailingSeparator(fs.normSeparators(ensureNoPrefix(path))))
|
path = fs.ensureNoLeadingSeparator(fs.ensureTrailingSeparator(fs.normSeparators(ensureNoPrefix(path))))
|
||||||
if err := validateName(path); err != nil {
|
if err := validateName(path); err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -216,11 +216,11 @@ func (fs *GcsFs) MkdirAll(path string, perm os.FileMode) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (fs *GcsFs) Open(name string) (*GcsFile, error) {
|
func (fs *Fs) Open(name string) (*GcsFile, error) {
|
||||||
return fs.OpenFile(name, os.O_RDONLY, 0)
|
return fs.OpenFile(name, os.O_RDONLY, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (fs *GcsFs) OpenFile(name string, flag int, fileMode os.FileMode) (*GcsFile, error) {
|
func (fs *Fs) OpenFile(name string, flag int, fileMode os.FileMode) (*GcsFile, error) {
|
||||||
var file *GcsFile
|
var file *GcsFile
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
|
@ -277,7 +277,7 @@ func (fs *GcsFs) OpenFile(name string, flag int, fileMode os.FileMode) (*GcsFile
|
||||||
return file, nil
|
return file, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (fs *GcsFs) Remove(name string) error {
|
func (fs *Fs) Remove(name string) error {
|
||||||
name = fs.ensureNoLeadingSeparator(fs.normSeparators(ensureNoPrefix(name)))
|
name = fs.ensureNoLeadingSeparator(fs.normSeparators(ensureNoPrefix(name)))
|
||||||
if err := validateName(name); err != nil {
|
if err := validateName(name); err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -318,7 +318,7 @@ func (fs *GcsFs) Remove(name string) error {
|
||||||
return obj.Delete(fs.ctx)
|
return obj.Delete(fs.ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (fs *GcsFs) RemoveAll(path string) error {
|
func (fs *Fs) RemoveAll(path string) error {
|
||||||
path = fs.ensureNoLeadingSeparator(fs.normSeparators(ensureNoPrefix(path)))
|
path = fs.ensureNoLeadingSeparator(fs.normSeparators(ensureNoPrefix(path)))
|
||||||
if err := validateName(path); err != nil {
|
if err := validateName(path); err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -351,7 +351,7 @@ func (fs *GcsFs) RemoveAll(path string) error {
|
||||||
return fs.Remove(path)
|
return fs.Remove(path)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (fs *GcsFs) Rename(oldName, newName string) error {
|
func (fs *Fs) Rename(oldName, newName string) error {
|
||||||
oldName = fs.ensureNoLeadingSeparator(fs.normSeparators(ensureNoPrefix(oldName)))
|
oldName = fs.ensureNoLeadingSeparator(fs.normSeparators(ensureNoPrefix(oldName)))
|
||||||
if err := validateName(oldName); err != nil {
|
if err := validateName(oldName); err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -378,7 +378,7 @@ func (fs *GcsFs) Rename(oldName, newName string) error {
|
||||||
return src.Delete(fs.ctx)
|
return src.Delete(fs.ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (fs *GcsFs) Stat(name string) (os.FileInfo, error) {
|
func (fs *Fs) Stat(name string) (os.FileInfo, error) {
|
||||||
name = fs.ensureNoLeadingSeparator(fs.normSeparators(ensureNoPrefix(name)))
|
name = fs.ensureNoLeadingSeparator(fs.normSeparators(ensureNoPrefix(name)))
|
||||||
if err := validateName(name); err != nil {
|
if err := validateName(name); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -387,14 +387,14 @@ func (fs *GcsFs) Stat(name string) (os.FileInfo, error) {
|
||||||
return newFileInfo(name, fs, defaultFileMode)
|
return newFileInfo(name, fs, defaultFileMode)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (fs *GcsFs) Chmod(_ string, _ os.FileMode) error {
|
func (fs *Fs) Chmod(_ string, _ os.FileMode) error {
|
||||||
return errors.New("method Chmod is not implemented in GCS")
|
return errors.New("method Chmod is not implemented in GCS")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (fs *GcsFs) Chtimes(_ string, _, _ time.Time) error {
|
func (fs *Fs) Chtimes(_ string, _, _ time.Time) error {
|
||||||
return errors.New("method Chtimes is not implemented. Create, Delete, Updated times are read only fields in GCS and set implicitly")
|
return errors.New("method Chtimes is not implemented. Create, Delete, Updated times are read only fields in GCS and set implicitly")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (fs *GcsFs) Chown(_ string, _, _ int) error {
|
func (fs *Fs) Chown(_ string, _, _ int) error {
|
||||||
return errors.New("method Chown is not implemented for GCS")
|
return errors.New("method Chown is not implemented for GCS")
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,29 +14,28 @@
|
||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
package afero
|
package gcsfs
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"os"
|
"os"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/spf13/afero/gcsfs"
|
|
||||||
|
|
||||||
"cloud.google.com/go/storage"
|
"cloud.google.com/go/storage"
|
||||||
"github.com/googleapis/google-cloud-go-testing/storage/stiface"
|
"github.com/googleapis/google-cloud-go-testing/storage/stiface"
|
||||||
|
"github.com/spf13/afero"
|
||||||
|
|
||||||
"google.golang.org/api/option"
|
"google.golang.org/api/option"
|
||||||
)
|
)
|
||||||
|
|
||||||
type GcsFs struct {
|
type GcsFs struct {
|
||||||
source *gcsfs.GcsFs
|
source *Fs
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewGcsFS creates a GCS file system, automatically instantiating and decorating the storage client.
|
// NewGcsFS creates a GCS file system, automatically instantiating and decorating the storage client.
|
||||||
// You can provide additional options to be passed to the client creation, as per
|
// You can provide additional options to be passed to the client creation, as per
|
||||||
// cloud.google.com/go/storage documentation
|
// cloud.google.com/go/storage documentation
|
||||||
func NewGcsFS(ctx context.Context, opts ...option.ClientOption) (Fs, error) {
|
func NewGcsFS(ctx context.Context, opts ...option.ClientOption) (afero.Fs, error) {
|
||||||
if json := os.Getenv("GOOGLE_APPLICATION_CREDENTIALS_JSON"); json != "" {
|
if json := os.Getenv("GOOGLE_APPLICATION_CREDENTIALS_JSON"); json != "" {
|
||||||
opts = append(opts, option.WithCredentialsJSON([]byte(json)))
|
opts = append(opts, option.WithCredentialsJSON([]byte(json)))
|
||||||
}
|
}
|
||||||
|
@ -49,7 +48,7 @@ func NewGcsFS(ctx context.Context, opts ...option.ClientOption) (Fs, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewGcsFSWithSeparator is the same as NewGcsFS, but the files system will use the provided folder separator.
|
// NewGcsFSWithSeparator is the same as NewGcsFS, but the files system will use the provided folder separator.
|
||||||
func NewGcsFSWithSeparator(ctx context.Context, folderSeparator string, opts ...option.ClientOption) (Fs, error) {
|
func NewGcsFSWithSeparator(ctx context.Context, folderSeparator string, opts ...option.ClientOption) (afero.Fs, error) {
|
||||||
client, err := storage.NewClient(ctx, opts...)
|
client, err := storage.NewClient(ctx, opts...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -59,17 +58,17 @@ func NewGcsFSWithSeparator(ctx context.Context, folderSeparator string, opts ...
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewGcsFSFromClient creates a GCS file system from a given storage client
|
// NewGcsFSFromClient creates a GCS file system from a given storage client
|
||||||
func NewGcsFSFromClient(ctx context.Context, client *storage.Client) (Fs, error) {
|
func NewGcsFSFromClient(ctx context.Context, client *storage.Client) (afero.Fs, error) {
|
||||||
c := stiface.AdaptClient(client)
|
c := stiface.AdaptClient(client)
|
||||||
|
|
||||||
return &GcsFs{gcsfs.NewGcsFs(ctx, c)}, nil
|
return &GcsFs{NewGcsFs(ctx, c)}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewGcsFSFromClientWithSeparator is the same as NewGcsFSFromClient, but the file system will use the provided folder separator.
|
// NewGcsFSFromClientWithSeparator is the same as NewGcsFSFromClient, but the file system will use the provided folder separator.
|
||||||
func NewGcsFSFromClientWithSeparator(ctx context.Context, client *storage.Client, folderSeparator string) (Fs, error) {
|
func NewGcsFSFromClientWithSeparator(ctx context.Context, client *storage.Client, folderSeparator string) (afero.Fs, error) {
|
||||||
c := stiface.AdaptClient(client)
|
c := stiface.AdaptClient(client)
|
||||||
|
|
||||||
return &GcsFs{gcsfs.NewGcsFsWithSeparator(ctx, c, folderSeparator)}, nil
|
return &GcsFs{NewGcsFsWithSeparator(ctx, c, folderSeparator)}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Wraps gcs.GcsFs and convert some return types to afero interfaces.
|
// Wraps gcs.GcsFs and convert some return types to afero interfaces.
|
||||||
|
@ -77,7 +76,7 @@ func NewGcsFSFromClientWithSeparator(ctx context.Context, client *storage.Client
|
||||||
func (fs *GcsFs) Name() string {
|
func (fs *GcsFs) Name() string {
|
||||||
return fs.source.Name()
|
return fs.source.Name()
|
||||||
}
|
}
|
||||||
func (fs *GcsFs) Create(name string) (File, error) {
|
func (fs *GcsFs) Create(name string) (afero.File, error) {
|
||||||
return fs.source.Create(name)
|
return fs.source.Create(name)
|
||||||
}
|
}
|
||||||
func (fs *GcsFs) Mkdir(name string, perm os.FileMode) error {
|
func (fs *GcsFs) Mkdir(name string, perm os.FileMode) error {
|
||||||
|
@ -86,10 +85,10 @@ func (fs *GcsFs) Mkdir(name string, perm os.FileMode) error {
|
||||||
func (fs *GcsFs) MkdirAll(path string, perm os.FileMode) error {
|
func (fs *GcsFs) MkdirAll(path string, perm os.FileMode) error {
|
||||||
return fs.source.MkdirAll(path, perm)
|
return fs.source.MkdirAll(path, perm)
|
||||||
}
|
}
|
||||||
func (fs *GcsFs) Open(name string) (File, error) {
|
func (fs *GcsFs) Open(name string) (afero.File, error) {
|
||||||
return fs.source.Open(name)
|
return fs.source.Open(name)
|
||||||
}
|
}
|
||||||
func (fs *GcsFs) OpenFile(name string, flag int, perm os.FileMode) (File, error) {
|
func (fs *GcsFs) OpenFile(name string, flag int, perm os.FileMode) (afero.File, error) {
|
||||||
return fs.source.OpenFile(name, flag, perm)
|
return fs.source.OpenFile(name, flag, perm)
|
||||||
}
|
}
|
||||||
func (fs *GcsFs) Remove(name string) error {
|
func (fs *GcsFs) Remove(name string) error {
|
|
@ -9,7 +9,7 @@
|
||||||
// switching over to a real bucket - and then the mocks have to be adjusted to match the
|
// switching over to a real bucket - and then the mocks have to be adjusted to match the
|
||||||
// implementation.
|
// implementation.
|
||||||
|
|
||||||
package afero
|
package gcsfs
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
@ -17,10 +17,9 @@ import (
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/spf13/afero/gcsfs"
|
|
||||||
|
|
||||||
"cloud.google.com/go/storage"
|
"cloud.google.com/go/storage"
|
||||||
"github.com/googleapis/google-cloud-go-testing/storage/stiface"
|
"github.com/googleapis/google-cloud-go-testing/storage/stiface"
|
||||||
|
"github.com/spf13/afero"
|
||||||
"google.golang.org/api/iterator"
|
"google.golang.org/api/iterator"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -31,11 +30,11 @@ func normSeparators(s string) string {
|
||||||
|
|
||||||
type clientMock struct {
|
type clientMock struct {
|
||||||
stiface.Client
|
stiface.Client
|
||||||
fs Fs
|
fs afero.Fs
|
||||||
}
|
}
|
||||||
|
|
||||||
func newClientMock() *clientMock {
|
func newClientMock() *clientMock {
|
||||||
return &clientMock{fs: NewMemMapFs()}
|
return &clientMock{fs: afero.NewMemMapFs()}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *clientMock) Bucket(name string) stiface.BucketHandle {
|
func (m *clientMock) Bucket(name string) stiface.BucketHandle {
|
||||||
|
@ -47,7 +46,7 @@ type bucketMock struct {
|
||||||
|
|
||||||
bucketName string
|
bucketName string
|
||||||
|
|
||||||
fs Fs
|
fs afero.Fs
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *bucketMock) Attrs(context.Context) (*storage.BucketAttrs, error) {
|
func (m *bucketMock) Attrs(context.Context) (*storage.BucketAttrs, error) {
|
||||||
|
@ -66,7 +65,7 @@ type objectMock struct {
|
||||||
stiface.ObjectHandle
|
stiface.ObjectHandle
|
||||||
|
|
||||||
name string
|
name string
|
||||||
fs Fs
|
fs afero.Fs
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *objectMock) NewWriter(_ context.Context) stiface.Writer {
|
func (o *objectMock) NewWriter(_ context.Context) stiface.Writer {
|
||||||
|
@ -75,7 +74,7 @@ func (o *objectMock) NewWriter(_ context.Context) stiface.Writer {
|
||||||
|
|
||||||
func (o *objectMock) NewRangeReader(_ context.Context, offset, length int64) (stiface.Reader, error) {
|
func (o *objectMock) NewRangeReader(_ context.Context, offset, length int64) (stiface.Reader, error) {
|
||||||
if o.name == "" {
|
if o.name == "" {
|
||||||
return nil, gcsfs.ErrEmptyObjectName
|
return nil, ErrEmptyObjectName
|
||||||
}
|
}
|
||||||
|
|
||||||
file, err := o.fs.Open(o.name)
|
file, err := o.fs.Open(o.name)
|
||||||
|
@ -104,14 +103,14 @@ func (o *objectMock) NewRangeReader(_ context.Context, offset, length int64) (st
|
||||||
|
|
||||||
func (o *objectMock) Delete(_ context.Context) error {
|
func (o *objectMock) Delete(_ context.Context) error {
|
||||||
if o.name == "" {
|
if o.name == "" {
|
||||||
return gcsfs.ErrEmptyObjectName
|
return ErrEmptyObjectName
|
||||||
}
|
}
|
||||||
return o.fs.Remove(o.name)
|
return o.fs.Remove(o.name)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *objectMock) Attrs(_ context.Context) (*storage.ObjectAttrs, error) {
|
func (o *objectMock) Attrs(_ context.Context) (*storage.ObjectAttrs, error) {
|
||||||
if o.name == "" {
|
if o.name == "" {
|
||||||
return nil, gcsfs.ErrEmptyObjectName
|
return nil, ErrEmptyObjectName
|
||||||
}
|
}
|
||||||
|
|
||||||
info, err := o.fs.Stat(o.name)
|
info, err := o.fs.Stat(o.name)
|
||||||
|
@ -130,7 +129,7 @@ func (o *objectMock) Attrs(_ context.Context) (*storage.ObjectAttrs, error) {
|
||||||
|
|
||||||
if info.IsDir() {
|
if info.IsDir() {
|
||||||
// we have to mock it here, because of FileInfo logic
|
// we have to mock it here, because of FileInfo logic
|
||||||
return nil, gcsfs.ErrObjectDoesNotExist
|
return nil, ErrObjectDoesNotExist
|
||||||
}
|
}
|
||||||
|
|
||||||
return res, nil
|
return res, nil
|
||||||
|
@ -140,14 +139,14 @@ type writerMock struct {
|
||||||
stiface.Writer
|
stiface.Writer
|
||||||
|
|
||||||
name string
|
name string
|
||||||
fs Fs
|
fs afero.Fs
|
||||||
|
|
||||||
file File
|
file afero.File
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *writerMock) Write(p []byte) (n int, err error) {
|
func (w *writerMock) Write(p []byte) (n int, err error) {
|
||||||
if w.name == "" {
|
if w.name == "" {
|
||||||
return 0, gcsfs.ErrEmptyObjectName
|
return 0, ErrEmptyObjectName
|
||||||
}
|
}
|
||||||
|
|
||||||
if w.file == nil {
|
if w.file == nil {
|
||||||
|
@ -162,7 +161,7 @@ func (w *writerMock) Write(p []byte) (n int, err error) {
|
||||||
|
|
||||||
func (w *writerMock) Close() error {
|
func (w *writerMock) Close() error {
|
||||||
if w.name == "" {
|
if w.name == "" {
|
||||||
return gcsfs.ErrEmptyObjectName
|
return ErrEmptyObjectName
|
||||||
}
|
}
|
||||||
if w.file == nil {
|
if w.file == nil {
|
||||||
var err error
|
var err error
|
||||||
|
@ -187,7 +186,7 @@ func (w *writerMock) Close() error {
|
||||||
type readerMock struct {
|
type readerMock struct {
|
||||||
stiface.Reader
|
stiface.Reader
|
||||||
|
|
||||||
file File
|
file afero.File
|
||||||
|
|
||||||
buf []byte
|
buf []byte
|
||||||
}
|
}
|
||||||
|
@ -212,9 +211,9 @@ type objectItMock struct {
|
||||||
stiface.ObjectIterator
|
stiface.ObjectIterator
|
||||||
|
|
||||||
name string
|
name string
|
||||||
fs Fs
|
fs afero.Fs
|
||||||
|
|
||||||
dir File
|
dir afero.File
|
||||||
infos []*storage.ObjectAttrs
|
infos []*storage.ObjectAttrs
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -227,7 +226,7 @@ func (it *objectItMock) Next() (*storage.ObjectAttrs, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
var isDir bool
|
var isDir bool
|
||||||
isDir, err = IsDir(it.fs, it.name)
|
isDir, err = afero.IsDir(it.fs, it.name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
|
@ -3,7 +3,7 @@
|
||||||
// Most of the tests are "derived" from the Afero's own tarfs implementation.
|
// Most of the tests are "derived" from the Afero's own tarfs implementation.
|
||||||
// Write-oriented tests and/or checks have been added on top of that
|
// Write-oriented tests and/or checks have been added on top of that
|
||||||
|
|
||||||
package afero
|
package gcsfs
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
@ -19,10 +19,9 @@ import (
|
||||||
|
|
||||||
"golang.org/x/oauth2/google"
|
"golang.org/x/oauth2/google"
|
||||||
|
|
||||||
"github.com/spf13/afero/gcsfs"
|
|
||||||
|
|
||||||
"cloud.google.com/go/storage"
|
"cloud.google.com/go/storage"
|
||||||
"github.com/googleapis/google-cloud-go-testing/storage/stiface"
|
"github.com/googleapis/google-cloud-go-testing/storage/stiface"
|
||||||
|
"github.com/spf13/afero"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -62,7 +61,7 @@ var dirs = []struct {
|
||||||
{"testDir1", []string{"testFile"}},
|
{"testDir1", []string{"testFile"}},
|
||||||
}
|
}
|
||||||
|
|
||||||
var gcsAfs *Afero
|
var gcsAfs *afero.Afero
|
||||||
|
|
||||||
func TestMain(m *testing.M) {
|
func TestMain(m *testing.M) {
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
|
@ -120,7 +119,7 @@ func TestMain(m *testing.M) {
|
||||||
mockClient := newClientMock()
|
mockClient := newClientMock()
|
||||||
mockClient.Client = client
|
mockClient.Client = client
|
||||||
|
|
||||||
gcsAfs = &Afero{Fs: &GcsFs{gcsfs.NewGcsFs(ctx, mockClient)}}
|
gcsAfs = &afero.Afero{Fs: &GcsFs{NewGcsFs(ctx, mockClient)}}
|
||||||
|
|
||||||
// Uncomment to use the real, not mocked, client
|
// Uncomment to use the real, not mocked, client
|
||||||
//gcsAfs = &Afero{Fs: &GcsFs{gcsfs.NewGcsFs(ctx, client)}}
|
//gcsAfs = &Afero{Fs: &GcsFs{gcsfs.NewGcsFs(ctx, client)}}
|
||||||
|
@ -137,7 +136,7 @@ func createFiles(t *testing.T) {
|
||||||
if !f.isdir && f.exists {
|
if !f.isdir && f.exists {
|
||||||
name := filepath.Join(bucketName, f.name)
|
name := filepath.Join(bucketName, f.name)
|
||||||
|
|
||||||
var freshFile File
|
var freshFile afero.File
|
||||||
freshFile, err = gcsAfs.Create(name)
|
freshFile, err = gcsAfs.Create(name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to create a file \"%s\": %s", f.name, err)
|
t.Fatalf("failed to create a file \"%s\": %s", f.name, err)
|
||||||
|
@ -481,7 +480,7 @@ func TestGcsOpenFile(t *testing.T) {
|
||||||
file, err := gcsAfs.OpenFile(name, os.O_RDONLY, 0400)
|
file, err := gcsAfs.OpenFile(name, os.O_RDONLY, 0400)
|
||||||
if !f.exists {
|
if !f.exists {
|
||||||
if (f.name != "" && !errors.Is(err, syscall.ENOENT)) ||
|
if (f.name != "" && !errors.Is(err, syscall.ENOENT)) ||
|
||||||
(f.name == "" && !errors.Is(err, gcsfs.ErrNoBucketInName)) {
|
(f.name == "" && !errors.Is(err, ErrNoBucketInName)) {
|
||||||
t.Errorf("%v: got %v, expected%v", name, err, syscall.ENOENT)
|
t.Errorf("%v: got %v, expected%v", name, err, syscall.ENOENT)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -524,7 +523,7 @@ func TestGcsFsStat(t *testing.T) {
|
||||||
fi, err := gcsAfs.Stat(name)
|
fi, err := gcsAfs.Stat(name)
|
||||||
if !f.exists {
|
if !f.exists {
|
||||||
if (f.name != "" && !errors.Is(err, syscall.ENOENT)) ||
|
if (f.name != "" && !errors.Is(err, syscall.ENOENT)) ||
|
||||||
(f.name == "" && !errors.Is(err, gcsfs.ErrNoBucketInName)) {
|
(f.name == "" && !errors.Is(err, ErrNoBucketInName)) {
|
||||||
t.Errorf("%v: got %v, expected%v", name, err, syscall.ENOENT)
|
t.Errorf("%v: got %v, expected%v", name, err, syscall.ENOENT)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -698,7 +697,7 @@ func TestGcsGlob(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
for i, prefixedGlob := range prefixedGlobs {
|
for i, prefixedGlob := range prefixedGlobs {
|
||||||
entries, err := Glob(gcsAfs.Fs, prefixedGlob)
|
entries, err := afero.Glob(gcsAfs.Fs, prefixedGlob)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
}
|
}
|
Loading…
Reference in New Issue