Skip to content

Commit 55da7cf

Browse files
authored
Add GetClient functions for each backend to allow for direct access t… (#246)
* Add GetClient functions for each backend to allow for direct access to the underlying client. Fixes #245. * fix lint issue
1 parent 086d466 commit 55da7cf

15 files changed

+81
-29
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
66

77
## [Unreleased]
88

9+
## [v7.1.0] - 2025-03-19
10+
### Added
11+
- Add GetClient functions for each backend to allow for direct access to the underlying client. Fixes #245.
12+
913
## [v7.0.1] - 2025-03-18
1014
### Fixes
1115
- [#243](https://github.com/C2FO/vfs/issues/243) - gs backend fails with cloud.google.com/go/storage v1.51.0 due to new wrapped errors.

backend/azure/client.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -284,3 +284,13 @@ func (a *DefaultClient) getBlobVersions(cli *container.Client, blobName string)
284284
}
285285
return versions, nil
286286
}
287+
288+
// GetClient returns a container.Client for the given container name and options
289+
func GetClient(container string, opts *Options) (*container.Client, error) {
290+
client, err := NewClient(opts)
291+
if err != nil {
292+
return nil, err
293+
}
294+
295+
return client.newContainerClient(container)
296+
}

backend/ftp/dataconn_test.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,9 @@ func (s *dataConnSuite) TestGetDataConn_errorClientSetup() {
9494
s.Error(err, "error is expected")
9595
s.ErrorIs(err, errClientGetter, "error is right kind of error")
9696
s.Nil(dc, "dataconn should be nil on error")
97-
defaultClientGetter = getClient
97+
defaultClientGetter = func(ctx context.Context, auth authority.Authority, opts Options) (client types.Client, err error) {
98+
return GetClient(ctx, auth, opts)
99+
}
98100
}
99101

100102
func (s *dataConnSuite) TestGetDataConn_ReadError() {

backend/ftp/fileSystem.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,9 @@ func (fs *FileSystem) WithClient(client types.Client) *FileSystem {
169169
}
170170

171171
func init() {
172-
defaultClientGetter = getClient
172+
defaultClientGetter = func(ctx context.Context, auth authority.Authority, opts Options) (client types.Client, err error) {
173+
return GetClient(ctx, auth, opts)
174+
}
173175
dataConnGetterFunc = getDataConn
174176
// registers a default FileSystem
175177
backend.Register(Scheme, NewFileSystem())

backend/ftp/file_test.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -700,7 +700,9 @@ func (ts *fileTestSuite) TestMoveToFile_sameAuthority() {
700700
err = sourceFile.MoveToFile(targetFile)
701701
ts.Error(err, "error is expected")
702702
ts.ErrorIs(err, errClientGetter, "error is the right kind of error")
703-
defaultClientGetter = getClient
703+
defaultClientGetter = func(ctx context.Context, auth authority.Authority, opts Options) (client types.Client, err error) {
704+
return GetClient(ctx, auth, opts)
705+
}
704706
targetFile.Location().FileSystem().(*FileSystem).ftpclient = tgtMockFTPClient
705707
dataConnGetterFunc = getFakeDataConn
706708

backend/ftp/options.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ import (
1111

1212
_ftp "github.com/jlaffaye/ftp"
1313

14-
"github.com/c2fo/vfs/v7/backend/ftp/types"
1514
"github.com/c2fo/vfs/v7/utils/authority"
1615
)
1716

@@ -43,7 +42,8 @@ const (
4342
envPassword = "VFS_FTP_PASSWORD" //nolint:gosec
4443
)
4544

46-
func getClient(ctx context.Context, authority authority.Authority, opts Options) (types.Client, error) {
45+
// GetClient returns a new FTP client with the given authority and options.
46+
func GetClient(ctx context.Context, authority authority.Authority, opts Options) (*_ftp.ServerConn, error) {
4747
// dial connection
4848
c, err := _ftp.Dial(fetchHostPortString(authority), fetchDialOptions(ctx, authority, opts)...)
4949
if err != nil {

backend/gs/fileSystem.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,3 +195,10 @@ func init() {
195195
// registers a default FileSystem
196196
backend.Register(Scheme, NewFileSystem())
197197
}
198+
199+
// GetClient returns a new Google Cloud Storage client with the provided context and Options.
200+
func GetClient(ctx context.Context, opts Options) (*storage.Client, error) {
201+
gsClientOpts := parseClientOptions(opts)
202+
creator := &defaultClientCreator{}
203+
return creator.NewClient(ctx, gsClientOpts...)
204+
}

backend/s3/fileSystem.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ func (fs *FileSystem) Scheme() string {
106106
func (fs *FileSystem) Client() (Client, error) {
107107
if fs.client == nil {
108108
var err error
109-
fs.client, err = getClient(fs.options)
109+
fs.client, err = GetClient(fs.options)
110110
if err != nil {
111111
return nil, err
112112
}

backend/s3/options.go

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,8 @@ type Options struct {
3030
UploadPartitionSize int64 // Partition size in bytes used to multipart upload of large files using manager.Uploader
3131
}
3232

33-
// getClient setup S3 client
34-
func getClient(opt Options) (Client, error) {
33+
// GetClient setup S3 client
34+
func GetClient(opt Options) (*s3.Client, error) {
3535
// setup default config
3636
awsConfig, err := config.LoadDefaultConfig(context.Background())
3737
if err != nil {
@@ -56,6 +56,10 @@ func getClient(opt Options) (Client, error) {
5656
opts.Retryer = opt.Retry
5757
}
5858

59+
if opt.MaxRetries > 0 {
60+
opts.RetryMaxAttempts = opt.MaxRetries
61+
}
62+
5963
if opt.AccessKeyID != "" && opt.SecretAccessKey != "" {
6064
opts.Credentials = credentials.NewStaticCredentialsProvider(
6165
opt.AccessKeyID,
@@ -67,3 +71,26 @@ func getClient(opt Options) (Client, error) {
6771
}
6872
}), nil
6973
}
74+
75+
// StringToACL converts a string to an ObjectCannedACL
76+
// see https://pkg.go.dev/github.com/aws/aws-sdk-go-v2/service/s3/types#ObjectCannedACL
77+
func StringToACL(acl string) types.ObjectCannedACL {
78+
switch acl {
79+
case "private":
80+
return types.ObjectCannedACLPrivate
81+
case "public-read":
82+
return types.ObjectCannedACLPublicRead
83+
case "public-read-write":
84+
return types.ObjectCannedACLPublicReadWrite
85+
case "authenticated-read":
86+
return types.ObjectCannedACLAuthenticatedRead
87+
case "aws-exec-read":
88+
return types.ObjectCannedACLAwsExecRead
89+
case "bucket-owner-read":
90+
return types.ObjectCannedACLBucketOwnerRead
91+
case "bucket-owner-full-control":
92+
return types.ObjectCannedACLBucketOwnerFullControl
93+
default:
94+
return types.ObjectCannedACLPrivate
95+
}
96+
}

backend/s3/options_test.go

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ import (
44
"os"
55
"testing"
66

7-
"github.com/aws/aws-sdk-go-v2/service/s3"
87
"github.com/stretchr/testify/suite"
98
)
109

@@ -19,10 +18,10 @@ func (o *optionsTestSuite) SetupTest() {
1918
func (o *optionsTestSuite) TestGetClient() {
2019
// no options
2120
opts := Options{}
22-
client, err := getClient(opts)
21+
client, err := GetClient(opts)
2322
o.NoError(err)
2423
o.NotNil(client, "client is set")
25-
o.Empty(client.(*s3.Client).Options().AppID, "config is empty")
24+
o.Empty(client.Options().AppID, "config is empty")
2625

2726
// options set
2827
opts = Options{
@@ -31,19 +30,19 @@ func (o *optionsTestSuite) TestGetClient() {
3130
Region: "some-region",
3231
ForcePathStyle: true,
3332
}
34-
client, err = getClient(opts)
33+
client, err = GetClient(opts)
3534
o.NoError(err)
3635
o.NotNil(client, "client is set")
37-
o.Equal("some-region", client.(*s3.Client).Options().Region, "region is set")
38-
o.Truef(client.(*s3.Client).Options().UsePathStyle, "region is set")
36+
o.Equal("some-region", client.Options().Region, "region is set")
37+
o.Truef(client.Options().UsePathStyle, "region is set")
3938

4039
// env var
4140
_ = os.Setenv("AWS_DEFAULT_REGION", "set-by-envvar")
4241
opts = Options{}
43-
client, err = getClient(opts)
42+
client, err = GetClient(opts)
4443
o.NoError(err)
4544
o.NotNil(client, "client is set")
46-
o.Equal("set-by-envvar", client.(*s3.Client).Options().Region, "region is set by env var")
45+
o.Equal("set-by-envvar", client.Options().Region, "region is set by env var")
4746

4847
// role ARN set
4948
opts = Options{
@@ -52,11 +51,11 @@ func (o *optionsTestSuite) TestGetClient() {
5251
Region: "some-region",
5352
RoleARN: "arn:aws:iam::123456789012:role/my-role",
5453
}
55-
client, err = getClient(opts)
54+
client, err = GetClient(opts)
5655
o.NoError(err)
5756
o.NotNil(client, "client is set")
58-
o.Equal("some-region", client.(*s3.Client).Options().Region, "region is set")
59-
o.NotNil(client.(*s3.Client).Options().Credentials, "credentials are set")
57+
o.Equal("some-region", client.Options().Region, "region is set")
58+
o.NotNil(client.Options().Credentials, "credentials are set")
6059
}
6160

6261
func TestOptions(t *testing.T) {

0 commit comments

Comments
 (0)