diff --git a/Makefile b/Makefile index defde7b..7948877 100644 --- a/Makefile +++ b/Makefile @@ -23,6 +23,7 @@ integration: go test -v ./drivers/aliyun -cover -tags=integration go test -v ./drivers/huawei -cover -tags=integration go test -v ./drivers/tencent -cover -tags=integration + go test -v ./drivers/qiniu -cover -tags=integration_qiniu go test -v ./drivers/minio -cover -tags=integration go test -v ./drivers/s3 -cover -tags=integration go test -v ./goss/* -cover -tags=integration @@ -32,4 +33,3 @@ all: make check make format make test - make integration \ No newline at end of file diff --git a/README.md b/README.md index 2aef5a1..b67d0cf 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # goss -✨ `goss` 是一个简洁的云存储 golang 库,支持**阿里云**、**腾讯云**、**华为云**、**aws s3**、**minio**。 +✨ `goss` 是一个简洁的云存储 golang 库,支持**阿里云**、**腾讯云**、**七牛云**、**华为云**、**aws s3**、**minio**。 [![Go Reference](https://pkg.go.dev/badge/github.com/eleven26/go-filesystem.svg)](https://pkg.go.dev/github.com/eleven26/goss) [![Go Report Card](https://goreportcard.com/badge/github.com/eleven26/go-filesystem)](https://goreportcard.com/report/github.com/eleven26/goss) @@ -24,7 +24,7 @@ go get -u github.com/eleven26/goss ```yaml # 云存储类型 -# 可选值为: aliyun、tencent、huawei、s3、minio +# 可选值为: aliyun、tencent、qiniu、huawei、s3、minio driver: aliyun # 阿里云 oss 配置 @@ -43,6 +43,17 @@ tencent: secret_id: secret_key: +# 七牛云 kodo 配置 +qiniu: + # bucket 名称 + bucket: + access_key: + secret_key: + # bucket 外链域名 + domain: + # 是否是私有空间 + private: + # 华为云 obs 配置 huawei: endpoint: @@ -228,6 +239,7 @@ size, err := storage.Size("test/test.txt") 1. [阿里云对象存储](https://help.aliyun.com/product/31815.html) 2. [腾讯云对象存储](https://cloud.tencent.com/document/product/436) -3. [华为云对象存储](https://support.huaweicloud.com/obs/index.html) -4. [aws s3](https://docs.aws.amazon.com/sdk-for-go/api/service/s3/) -5. [minio](https://github.com/minio/minio) +3. [七牛云对象存储](https://developer.qiniu.com/kodo) +4. [华为云对象存储](https://support.huaweicloud.com/obs/index.html) +5. [aws s3](https://docs.aws.amazon.com/sdk-for-go/api/service/s3/) +6. [minio](https://github.com/minio/minio) diff --git a/drivers/minio/minio_test.go b/drivers/minio/minio_test.go index f01c479..6f33fc1 100644 --- a/drivers/minio/minio_test.go +++ b/drivers/minio/minio_test.go @@ -104,8 +104,12 @@ func TestPut(t *testing.T) { err = storage2.Put(key, f) assert.Nil(t, err) - _, err = store.getObject(key) + obj, err := store.getObject(key) assert.Nil(t, err) + + bs, err := io.ReadAll(obj) + assert.Nil(t, err) + assert.Equal(t, "foo", string(bs)) } func TestPutFromFile(t *testing.T) { diff --git a/drivers/qiniu/chunks.go b/drivers/qiniu/chunks.go new file mode 100644 index 0000000..f8d0ad5 --- /dev/null +++ b/drivers/qiniu/chunks.go @@ -0,0 +1,35 @@ +package qiniu + +import ( + "github.com/eleven26/goss/core" + "github.com/qiniu/go-sdk/v7/storage" +) + +type Chunks struct { + bucket string + prefix string + bucketManager *storage.BucketManager + + nextMarker string +} + +func NewChunks(bucket string, prefix string, bucketManager *storage.BucketManager) core.Chunks { + return &Chunks{ + bucket: bucket, + prefix: prefix, + bucketManager: bucketManager, + } +} + +func (c *Chunks) Chunk() (*core.ListObjectResult, error) { + // 参考文档:https://developer.qiniu.com/kodo/1284/list + // ListFiles 最后一个参数 limit 为单次列举的条目数,范围为1-1000。 默认值为1000。 + entries, _, nextMarker, hasNext, err := c.bucketManager.ListFiles(c.bucket, c.prefix, "", c.nextMarker, 100) + if err != nil { + return nil, err + } + + c.nextMarker = nextMarker + + return NewListObjectResult(entries, hasNext), nil +} diff --git a/drivers/qiniu/config.go b/drivers/qiniu/config.go new file mode 100644 index 0000000..a324299 --- /dev/null +++ b/drivers/qiniu/config.go @@ -0,0 +1,23 @@ +package qiniu + +import "github.com/spf13/viper" + +type config struct { + Bucket string + AccessKey string + SecretKey string + Zone string + Domain string + Private bool +} + +func getConfig(viper *viper.Viper) *config { + return &config{ + Bucket: viper.GetString("qiniu.bucket"), + AccessKey: viper.GetString("qiniu.access_key"), + SecretKey: viper.GetString("qiniu.secret_key"), + Zone: viper.GetString("qiniu.zone"), + Domain: viper.GetString("qiniu.domain"), + Private: viper.GetBool("qiniu.private"), + } +} diff --git a/drivers/qiniu/driver.go b/drivers/qiniu/driver.go new file mode 100644 index 0000000..a3d03c2 --- /dev/null +++ b/drivers/qiniu/driver.go @@ -0,0 +1,46 @@ +package qiniu + +import ( + "github.com/eleven26/goss/core" + "github.com/qiniu/go-sdk/v7/auth/qbox" + "github.com/qiniu/go-sdk/v7/storage" + "github.com/spf13/viper" +) + +type Driver struct { + Viper *viper.Viper +} + +func NewDriver(opts ...core.Option) core.Driver { + driver := &Driver{} + + for _, option := range opts { + option(driver) + } + + return driver +} + +func (d *Driver) Storage() (core.Storage, error) { + conf := getConfig(d.Viper) + + if conf.Bucket == "" || conf.AccessKey == "" || conf.SecretKey == "" { + return nil, core.ErrorConfigEmpty + } + + mac := qbox.NewMac(conf.AccessKey, conf.SecretKey) + cfg := storage.Config{ + UseHTTPS: true, + } + + store := Store{ + config: *conf, + bucketManager: storage.NewBucketManager(mac, &cfg), + } + + return core.NewStorage(&store), nil +} + +func (d Driver) Name() string { + return "qiniu" +} diff --git a/drivers/qiniu/file.go b/drivers/qiniu/file.go new file mode 100644 index 0000000..07a5aa5 --- /dev/null +++ b/drivers/qiniu/file.go @@ -0,0 +1,32 @@ +package qiniu + +import ( + "strconv" + "time" + + "github.com/qiniu/go-sdk/v7/storage" +) + +type File struct { + item storage.ListItem +} + +func (f *File) Key() string { + return f.item.Key +} + +func (f *File) Type() string { + return strconv.Itoa(f.item.Type) +} + +func (f *File) Size() int64 { + return f.item.Fsize +} + +func (f *File) ETag() string { + return f.item.Hash +} + +func (f *File) LastModified() time.Time { + return time.UnixMicro(f.item.PutTime / 10) +} diff --git a/drivers/qiniu/qiniu_test.go b/drivers/qiniu/qiniu_test.go new file mode 100644 index 0000000..b441f18 --- /dev/null +++ b/drivers/qiniu/qiniu_test.go @@ -0,0 +1,228 @@ +//go:build integration_qiniu + +package qiniu + +import ( + "fmt" + "io" + "log" + "os" + "path/filepath" + "strconv" + "strings" + "testing" + "time" + + "github.com/spf13/viper" + + config2 "github.com/eleven26/goss/config" + "github.com/eleven26/goss/core" + "github.com/eleven26/goss/utils" + + fs "github.com/eleven26/go-filesystem" + "github.com/stretchr/testify/assert" +) + +var ( + storage2 core.Storage + + store *Store + + key = "test/foo.txt" + testdata string + fooPath string + localFooPath string +) + +func init() { + err := config2.ReadInUserHomeConfig() + if err != nil { + log.Fatal(err) + } + + v := viper.GetViper() + + d := NewDriver(core.WithViper(v)) + storage2, err = d.Storage() + if err != nil { + log.Fatal(err) + } + + store = storage2.Store().(*Store) + + testdata = filepath.Join(utils.RootDir(), "testdata") + fooPath = filepath.Join(testdata, "foo.txt") + localFooPath = filepath.Join(testdata, "foo1.txt") +} + +func setUp(t *testing.T) { + err := storage2.PutFromFile(key, fooPath) + if err != nil { + t.Fatal(err) + } +} + +func tearDown(t *testing.T) { + deleteLocal(t) + deleteRemote(t) +} + +func deleteRemote(t *testing.T) { + err := store.bucketManager.Delete(store.config.Bucket, key) + if err != nil { + t.Fatal(err) + } +} + +func deleteLocal(t *testing.T) { + exists, _ := fs.Exists(localFooPath) + if exists { + err := fs.Delete(localFooPath) + if err != nil { + t.Fatal(err) + } + } +} + +func TestPut(t *testing.T) { + defer tearDown(t) + + f, err := os.Open(fooPath) + if err != nil { + t.Fatal(err) + } + defer func(f *os.File) { + err = f.Close() + if err != nil { + t.Fatal(err) + } + }(f) + + err = storage2.Put(key, f) + assert.Nil(t, err) + + _, err = store.bucketManager.Stat(store.config.Bucket, key) + assert.Nil(t, err) +} + +func TestPutFromFile(t *testing.T) { + defer tearDown(t) + + err := storage2.PutFromFile(key, fooPath) + assert.Nil(t, err) + + _, err = store.bucketManager.Stat(store.config.Bucket, key) + assert.Nil(t, err) +} + +func TestGet(t *testing.T) { + setUp(t) + defer tearDown(t) + + rc, err := storage2.Get(key) + assert.Nil(t, err) + + bs, err := io.ReadAll(rc) + assert.Nil(t, err) + assert.Equal(t, "foo", string(bs)) +} + +func TestGetString(t *testing.T) { + setUp(t) + defer tearDown(t) + + content, err := storage2.GetString(key) + + assert.Nil(t, err) + assert.Equal(t, "foo", content) +} + +func TestGetBytes(t *testing.T) { + setUp(t) + defer tearDown(t) + + bs, err := storage2.GetBytes(key) + + assert.Nil(t, err) + assert.Equal(t, "foo", string(bs)) +} + +func TestDelete(t *testing.T) { + setUp(t) + defer deleteLocal(t) + + err := storage2.Delete(key) + assert.Nil(t, err) + + _, err = store.bucketManager.Stat(store.config.Bucket, key) + assert.NotNil(t, err) +} + +func TestSave(t *testing.T) { + setUp(t) + defer tearDown(t) + + err := storage2.GetToFile(key, localFooPath) + assert.Nil(t, err) + assert.Equal(t, "foo", fs.MustGetString(localFooPath)) +} + +func TestExists(t *testing.T) { + setUp(t) + defer tearDown(t) + + exists, err := storage2.Exists(key) + + assert.Nil(t, err) + assert.True(t, exists) + + exists, err = storage2.Exists(key + "not_exists") + + assert.NotNil(t, err) + assert.False(t, exists) +} + +func TestFiles(t *testing.T) { + setUp(t) + defer tearDown(t) + + files, err := storage2.Files("test/") + assert.Nil(t, err) + assert.Len(t, files, 1) + + var expectedSize int64 = 3 + assert.Equal(t, key, files[0].Key()) + assert.Equal(t, expectedSize, files[0].Size()) + + today := time.Now().Format("2006-01-02") + assert.Equal(t, today, files[0].LastModified().Format("2006-01-02")) +} + +func TestSize(t *testing.T) { + setUp(t) + defer tearDown(t) + + size, err := storage2.Size(key) + + var siz int64 = 3 + assert.Nil(t, err) + assert.Equal(t, siz, size) +} + +func aTestAb(t *testing.T) { + dir := "test_all/" + + for i := 1; i <= 200; i++ { + err := storage2.Put(fmt.Sprintf("%s%s.txt", dir, strconv.Itoa(i)), strings.NewReader("foo")) + assert.Nil(t, err) + } +} + +func TestFilesWithMultiPage(t *testing.T) { + // Testdata was prepared before. + dir := "test_all/" + + files, err := storage2.Files(dir) + assert.Nil(t, err) + assert.Len(t, files, 200) +} diff --git a/drivers/qiniu/result.go b/drivers/qiniu/result.go new file mode 100644 index 0000000..35dbbd4 --- /dev/null +++ b/drivers/qiniu/result.go @@ -0,0 +1,29 @@ +package qiniu + +import ( + "strings" + + "github.com/eleven26/goss/core" + "github.com/qiniu/go-sdk/v7/storage" +) + +func NewListObjectResult(entries []storage.ListItem, hasNext bool) *core.ListObjectResult { + return &core.ListObjectResult{ + Files: getFiles(entries), + IsFinished: !hasNext, + } +} + +func getFiles(entries []storage.ListItem) []core.File { + var files []core.File + + for _, item := range entries { + if strings.HasSuffix(item.Key, "/") { + continue + } + + files = append(files, &File{item: item}) + } + + return files +} diff --git a/drivers/qiniu/store.go b/drivers/qiniu/store.go new file mode 100644 index 0000000..f1838a1 --- /dev/null +++ b/drivers/qiniu/store.go @@ -0,0 +1,133 @@ +package qiniu + +import ( + "bytes" + "context" + "io" + "net/http" + "strconv" + "time" + + "github.com/eleven26/goss/core" + "github.com/qiniu/go-sdk/v7/auth/qbox" + "github.com/qiniu/go-sdk/v7/storage" +) + +type Store struct { + config + bucketManager *storage.BucketManager +} + +func (s *Store) Put(key string, r io.Reader) error { + upToken := s.upToken() + formUploader := s.uploader() + ret := storage.PutRet{} + + buf := new(bytes.Buffer) + size, err := io.Copy(buf, r) + if err != nil { + return err + } + + err = formUploader.Put(context.Background(), &ret, upToken, key, buf, size, &storage.PutExtra{}) + if err != nil { + return err + } + + return err +} + +func (s *Store) upToken() string { + putPolicy := storage.PutPolicy{ + Scope: s.config.Bucket, + } + + mac := qbox.NewMac(s.config.AccessKey, s.config.SecretKey) + + return putPolicy.UploadToken(mac) +} + +func (s *Store) uploader() *storage.FormUploader { + cfg := storage.Config{} + // 是否使用https域名 + cfg.UseHTTPS = true + // 上传是否使用CDN上传加速 + cfg.UseCdnDomains = false + // 构建表单上传的对象 + return storage.NewFormUploader(&cfg) +} + +func (s *Store) PutFromFile(key string, localPath string) error { + upToken := s.upToken() + formUploader := s.uploader() + ret := storage.PutRet{} + + return formUploader.PutFile(context.Background(), &ret, upToken, key, localPath, nil) +} + +func (s *Store) Get(key string) (io.ReadCloser, error) { + url := s.getDownloadUrl(key) + + return s.getUrlContent(url) +} + +func (s *Store) getDownloadUrl(key string) string { + var url string + + if s.config.Private { + mac := qbox.NewMac(s.config.AccessKey, s.config.SecretKey) + deadline := time.Now().Add(time.Second * 3600).Unix() // 1小时有效期 + url = storage.MakePrivateURL(mac, s.config.Domain, key, deadline) + } else { + url = storage.MakePublicURL(s.config.Domain, key) + } + + return url +} + +func (s *Store) getUrlContent(url string) (io.ReadCloser, error) { + resp, err := http.Get(url) + if err != nil { + return nil, err + } + + return resp.Body, nil +} + +func (s *Store) meta(key string) (http.Header, error) { + fi, err := s.bucketManager.Stat(s.config.Bucket, key) + if err != nil { + return nil, err + } + + header := http.Header{} + header.Set("Content-Length", strconv.FormatInt(fi.Fsize, 10)) + + return header, nil +} + +func (s *Store) Size(key string) (int64, error) { + fi, err := s.bucketManager.Stat(s.config.Bucket, key) + if err != nil { + return 0, err + } + + return fi.Fsize, nil +} + +func (s *Store) Exists(key string) (bool, error) { + _, err := s.meta(key) + if err != nil { + return false, err + } + + return true, nil +} + +func (s *Store) Delete(key string) error { + return s.bucketManager.Delete(s.config.Bucket, key) +} + +func (s *Store) Iterator(prefix string) core.FileIterator { + return core.NewFileIterator(NewChunks(s.config.Bucket, prefix, s.bucketManager)) +} diff --git a/go.mod b/go.mod index f78451a..48a8e17 100644 --- a/go.mod +++ b/go.mod @@ -10,6 +10,7 @@ require ( github.com/eleven26/go-filesystem v1.0.0 github.com/huaweicloud/huaweicloud-sdk-go-obs v3.21.12+incompatible github.com/minio/minio-go/v7 v7.0.45 + github.com/qiniu/go-sdk/v7 v7.14.0 github.com/spf13/viper v1.12.0 github.com/stretchr/testify v1.8.0 github.com/tencentyun/cos-go-sdk-v5 v0.7.36 @@ -39,7 +40,6 @@ require ( github.com/pelletier/go-toml v1.9.5 // indirect github.com/pelletier/go-toml/v2 v2.0.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect - github.com/rogpeppe/go-internal v1.8.0 // indirect github.com/rs/xid v1.4.0 // indirect github.com/satori/go.uuid v1.2.0 // indirect github.com/sirupsen/logrus v1.9.0 // indirect @@ -51,10 +51,10 @@ require ( github.com/subosito/gotenv v1.3.0 // indirect golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa // indirect golang.org/x/net v0.0.0-20220722155237-a158d28d115b // indirect + golang.org/x/sync v0.0.0-20201207232520-09787c993a3a // indirect golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab // indirect golang.org/x/text v0.3.7 // indirect golang.org/x/time v0.0.0-20220722155302-e5dcc9cfc0b9 // indirect - gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect gopkg.in/ini.v1 v1.66.6 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect diff --git a/go.sum b/go.sum index c60b212..70db861 100644 --- a/go.sum +++ b/go.sum @@ -55,6 +55,7 @@ github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDk github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -74,6 +75,12 @@ github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmV github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= +github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8= +github.com/go-playground/locales v0.14.0/go.mod h1:sawfccIbzZTqEDETgFXqTho0QybSa7l++s0DH+LDiLs= +github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA= +github.com/go-playground/universal-translator v0.18.0/go.mod h1:UvRDBj+xPUEGrFYl+lu/H90nyDXpg0fqeB/AQUGNTVA= +github.com/go-playground/validator/v10 v10.8.0/go.mod h1:9JhgTzTaE31GZDpH/HSvHiRJrJ3iKAgqqH0Bl/Ocjdk= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= @@ -163,9 +170,12 @@ github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= +github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY= github.com/magiconair/properties v1.8.6 h1:5ibWZ6iY0NctNGWo87LalDlEZ6R41TqbbDamhfG/Qzo= github.com/magiconair/properties v1.8.6/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= github.com/minio/md5-simd v1.1.2 h1:Gdi1DZK69+ZVMoNHRXJyNcxrMA4dSxoYHZSQbirFg34= @@ -202,7 +212,12 @@ github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qR github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/qiniu/dyn v1.3.0/go.mod h1:E8oERcm8TtwJiZvkQPbcAh0RL8jO1G0VXJMW3FAWdkk= +github.com/qiniu/go-sdk/v7 v7.14.0 h1:6icihMTKHoKMmeU1mqtIoHUv7c1LrLjYm8wTQaYDqmw= +github.com/qiniu/go-sdk/v7 v7.14.0/go.mod h1:btsaOc8CA3hdVloULfFdDgDc+g4f3TDZEFsDY0BLE+w= +github.com/qiniu/x v1.10.5/go.mod h1:03Ni9tj+N2h2aKnAz+6N0Xfl8FwMEDRC2PAlxekASDs= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= github.com/rogpeppe/go-internal v1.8.0 h1:FCbCCtXNOY3UtUuHUYaghJg4y7Fd14rXifAYUAtL9R8= github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE= github.com/rs/xid v1.4.0 h1:qd7wPTDkN6KQx2VmMBLrpHkiyQwgFXRnkOLacUiaSNY= @@ -228,6 +243,7 @@ github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXf github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk= @@ -254,6 +270,8 @@ golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= +golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa h1:zuSxTR4o9y82ebqCUJYNGJbGPo6sKVl54f/TVDObg1c= golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= @@ -342,6 +360,7 @@ golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201207232520-09787c993a3a h1:DcqTD9SDLc+1P/r1EmRBwnVsrOwW+kk2vWf9n+1sGhs= golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -377,6 +396,8 @@ golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211020174200-9d6173849985/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -391,6 +412,7 @@ golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3 golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -549,6 +571,7 @@ gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/goss/driver.go b/goss/driver.go index ee76401..85bd800 100644 --- a/goss/driver.go +++ b/goss/driver.go @@ -9,6 +9,7 @@ import ( "github.com/eleven26/goss/drivers/aliyun" "github.com/eleven26/goss/drivers/huawei" "github.com/eleven26/goss/drivers/minio" + "github.com/eleven26/goss/drivers/qiniu" "github.com/eleven26/goss/drivers/s3" "github.com/eleven26/goss/drivers/tencent" ) @@ -16,6 +17,7 @@ import ( const ( Aliyun = "aliyun" Tencent = "tencent" + Qiniu = "qiniu" Huawei = "huawei" S3 = "s3" Minio = "minio" @@ -42,6 +44,8 @@ func defaultDriver(opts ...core.Option) (core.Driver, error) { return aliyun.NewDriver(opts...), nil case Tencent: return tencent.NewDriver(opts...), nil + case Qiniu: + return qiniu.NewDriver(opts...), nil case Huawei: return huawei.NewDriver(opts...), nil case S3: diff --git a/goss/goss.go b/goss/goss.go index 3c6a430..772b7f6 100644 --- a/goss/goss.go +++ b/goss/goss.go @@ -4,6 +4,7 @@ import ( "github.com/eleven26/goss/config" "github.com/eleven26/goss/core" "github.com/eleven26/goss/drivers/aliyun" + "github.com/eleven26/goss/drivers/qiniu" "github.com/eleven26/goss/drivers/tencent" "github.com/spf13/viper" ) @@ -76,6 +77,11 @@ func (g *Goss) RegisterTencentDriver() error { return g.RegisterDriver(tencent.NewDriver()) } +// RegisterQiniuDriver register qiniu driver. +func (g *Goss) RegisterQiniuDriver() error { + return g.RegisterDriver(qiniu.NewDriver()) +} + // NewFromUserHomeConfigPath creates a new instance based on the configuration file pointed to by user home directory. func NewFromUserHomeConfigPath() (*Goss, error) { path, err := config.UserHomeConfigPath() diff --git a/goss/goss_test.go b/goss/goss_test.go index 6b915f6..15067c5 100644 --- a/goss/goss_test.go +++ b/goss/goss_test.go @@ -30,6 +30,11 @@ func TestNew(t *testing.T) { assert.Nil(t, err) assert.Equal(t, "core.storage", reflect.TypeOf(goss.Storage).Elem().String()) + viper.Set("driver", Qiniu) + goss, err = New(configPath) + assert.Nil(t, err) + assert.Equal(t, "core.storage", reflect.TypeOf(goss.Storage).Elem().String()) + viper.Set("driver", Huawei) goss, err = New(configPath) assert.Nil(t, err) @@ -74,6 +79,11 @@ func TestNewWithViper(t *testing.T) { assert.Nil(t, err) assert.Equal(t, "core.storage", reflect.TypeOf(goss.Storage).Elem().String()) + v.Set("driver", Qiniu) + goss, err = NewWithViper(v) + assert.Nil(t, err) + assert.Equal(t, "core.storage", reflect.TypeOf(goss.Storage).Elem().String()) + v.Set("driver", Huawei) goss, err = NewWithViper(v) assert.Nil(t, err)