forked from mirror/afero
Merge pull request #333 from drakkan/gcsfs
GCS fs: move all gcsfs related implementations to its own package
This commit is contained in:
commit
d8a4ef9d05
|
@ -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