diff options
author | 6543 <6543@obermui.de> | 2020-10-16 07:06:27 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-10-16 01:06:27 -0400 |
commit | 12a1f914f443cc31af4bc54ab43802a75742cd57 (patch) | |
tree | 998e159281cf41de8b6d7bb1ab5075b3286ce5a9 /vendor/github.com/minio | |
parent | 91f2afdb546364195ff909186983b94a61ab3181 (diff) | |
download | gitea-12a1f914f443cc31af4bc54ab43802a75742cd57.tar.gz gitea-12a1f914f443cc31af4bc54ab43802a75742cd57.zip |
Vendor Update Go Libs (#13166)
* update github.com/alecthomas/chroma v0.8.0 -> v0.8.1
* github.com/blevesearch/bleve v1.0.10 -> v1.0.12
* editorconfig-core-go v2.1.1 -> v2.3.7
* github.com/gliderlabs/ssh v0.2.2 -> v0.3.1
* migrate editorconfig.ParseBytes to Parse
* github.com/shurcooL/vfsgen to 0d455de96546
* github.com/go-git/go-git/v5 v5.1.0 -> v5.2.0
* github.com/google/uuid v1.1.1 -> v1.1.2
* github.com/huandu/xstrings v1.3.0 -> v1.3.2
* github.com/klauspost/compress v1.10.11 -> v1.11.1
* github.com/markbates/goth v1.61.2 -> v1.65.0
* github.com/mattn/go-sqlite3 v1.14.0 -> v1.14.4
* github.com/mholt/archiver v3.3.0 -> v3.3.2
* github.com/microcosm-cc/bluemonday 4f7140c49acb -> v1.0.4
* github.com/minio/minio-go v7.0.4 -> v7.0.5
* github.com/olivere/elastic v7.0.9 -> v7.0.20
* github.com/urfave/cli v1.20.0 -> v1.22.4
* github.com/prometheus/client_golang v1.1.0 -> v1.8.0
* github.com/xanzy/go-gitlab v0.37.0 -> v0.38.1
* mvdan.cc/xurls v2.1.0 -> v2.2.0
Co-authored-by: Lauris BH <lauris@nix.lv>
Diffstat (limited to 'vendor/github.com/minio')
8 files changed, 183 insertions, 72 deletions
diff --git a/vendor/github.com/minio/minio-go/v7/README.md b/vendor/github.com/minio/minio-go/v7/README.md index 0c83e9efb1..d289f615af 100644 --- a/vendor/github.com/minio/minio-go/v7/README.md +++ b/vendor/github.com/minio/minio-go/v7/README.md @@ -45,7 +45,7 @@ func main() { log.Fatalln(err) } - log.Printf("%#v\n", minioClient) // minioClient is now setup + log.Printf("%#v\n", minioClient) // minioClient is now set up } ``` @@ -67,6 +67,7 @@ import ( ) func main() { + ctx := context.Background() endpoint := "play.min.io" accessKeyID := "Q3AM3UQ867SPQQA43P2F" secretAccessKey := "zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG" @@ -85,10 +86,10 @@ func main() { bucketName := "mymusic" location := "us-east-1" - err = minioClient.MakeBucket(context.Background(), bucketName, minio.MakeBucketOptions{Region: location}) + err = minioClient.MakeBucket(ctx, bucketName, minio.MakeBucketOptions{Region: location}) if err != nil { // Check to see if we already own this bucket (which happens if you run this twice) - exists, errBucketExists := minioClient.BucketExists(bucketName) + exists, errBucketExists := minioClient.BucketExists(ctx, bucketName) if errBucketExists == nil && exists { log.Printf("We already own %s\n", bucketName) } else { @@ -104,7 +105,7 @@ func main() { contentType := "application/zip" // Upload the zip file with FPutObject - n, err := minioClient.FPutObject(context.Background(), bucketName, objectName, filePath, minio.PutObjectOptions{ContentType: contentType}) + n, err := minioClient.FPutObject(ctx, bucketName, objectName, filePath, minio.PutObjectOptions{ContentType: contentType}) if err != nil { log.Fatalln(err) } diff --git a/vendor/github.com/minio/minio-go/v7/api-put-object-streaming.go b/vendor/github.com/minio/minio-go/v7/api-put-object-streaming.go index 251fee9f84..cd29096323 100644 --- a/vendor/github.com/minio/minio-go/v7/api-put-object-streaming.go +++ b/vendor/github.com/minio/minio-go/v7/api-put-object-streaming.go @@ -457,8 +457,12 @@ func (c Client) putObjectDo(ctx context.Context, bucketName, objectName string, } urlValues := make(url.Values) urlValues.Set("versionId", opts.ReplicationVersionID) + if opts.ReplicationETag != "" { + urlValues.Set("etag", opts.ReplicationETag) + } reqMetadata.queryValues = urlValues } + // Execute PUT an objectName. resp, err := c.executeMethod(ctx, http.MethodPut, reqMetadata) defer closeResponse(resp) diff --git a/vendor/github.com/minio/minio-go/v7/api-put-object.go b/vendor/github.com/minio/minio-go/v7/api-put-object.go index b0d5af466b..14a2c16a0e 100644 --- a/vendor/github.com/minio/minio-go/v7/api-put-object.go +++ b/vendor/github.com/minio/minio-go/v7/api-put-object.go @@ -73,6 +73,7 @@ type PutObjectOptions struct { SendContentMd5 bool DisableMultipart bool ReplicationVersionID string + ReplicationETag string ReplicationStatus ReplicationStatus ReplicationMTime time.Time } @@ -142,6 +143,9 @@ func (opts PutObjectOptions) Header() (header http.Header) { if !opts.ReplicationMTime.IsZero() { header.Set(minIOBucketReplicationSourceMTime, opts.ReplicationMTime.Format(time.RFC3339)) } + if opts.ReplicationETag != "" { + header.Set(minIOBucketReplicationETag, opts.ReplicationETag) + } if len(opts.UserTags) != 0 { header.Set(amzTaggingHeader, s3utils.TagEncode(opts.UserTags)) } diff --git a/vendor/github.com/minio/minio-go/v7/api.go b/vendor/github.com/minio/minio-go/v7/api.go index 206e05dee2..e36c796603 100644 --- a/vendor/github.com/minio/minio-go/v7/api.go +++ b/vendor/github.com/minio/minio-go/v7/api.go @@ -108,7 +108,7 @@ type Options struct { // Global constants. const ( libraryName = "minio-go" - libraryVersion = "v7.0.4" + libraryVersion = "v7.0.5" ) // User Agent should always following the below style. @@ -517,13 +517,6 @@ func (c Client) executeMethod(ctx context.Context, method string, metadata reque var bodySeeker io.Seeker // Extracted seeker from io.Reader. var reqRetry = MaxRetry // Indicates how many times we can retry the request - defer func() { - if err != nil { - // close idle connections before returning, upon error. - c.httpClient.CloseIdleConnections() - } - }() - if metadata.contentBody != nil { // Check if body is seekable then it is retryable. bodySeeker, retryable = metadata.contentBody.(io.Seeker) @@ -578,15 +571,14 @@ func (c Client) executeMethod(ctx context.Context, method string, metadata reque return nil, err } - // Add context to request - req = req.WithContext(ctx) - // Initiate the request. res, err = c.do(req) if err != nil { - if err == context.Canceled || err == context.DeadlineExceeded { + if errors.Is(err, context.Canceled) || errors.Is(err, context.DeadlineExceeded) { return nil, err } + + // Retry the request continue } @@ -710,7 +702,7 @@ func (c Client) newRequest(ctx context.Context, method string, metadata requestM } // Initialize a new HTTP request for the method. - req, err = http.NewRequest(method, targetURL.String(), nil) + req, err = http.NewRequestWithContext(ctx, method, targetURL.String(), nil) if err != nil { return nil, err } diff --git a/vendor/github.com/minio/minio-go/v7/constants.go b/vendor/github.com/minio/minio-go/v7/constants.go index e1da72e79f..6a1b8d3dda 100644 --- a/vendor/github.com/minio/minio-go/v7/constants.go +++ b/vendor/github.com/minio/minio-go/v7/constants.go @@ -83,4 +83,5 @@ const ( amzBucketReplicationStatus = "X-Amz-Replication-Status" // Minio specific Replication extension minIOBucketReplicationSourceMTime = "X-Minio-Source-Mtime" + minIOBucketReplicationETag = "X-Minio-Source-Etag" ) diff --git a/vendor/github.com/minio/minio-go/v7/go.mod b/vendor/github.com/minio/minio-go/v7/go.mod index 670f6ea94c..448b4bbf17 100644 --- a/vendor/github.com/minio/minio-go/v7/go.mod +++ b/vendor/github.com/minio/minio-go/v7/go.mod @@ -3,7 +3,6 @@ module github.com/minio/minio-go/v7 go 1.12 require ( - github.com/dustin/go-humanize v1.0.0 // indirect github.com/google/uuid v1.1.1 github.com/json-iterator/go v1.1.10 github.com/klauspost/cpuid v1.3.1 // indirect @@ -14,7 +13,6 @@ require ( github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.1 // indirect github.com/rs/xid v1.2.1 - github.com/sirupsen/logrus v1.6.0 // indirect github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a // indirect github.com/stretchr/testify v1.4.0 // indirect golang.org/x/crypto v0.0.0-20200709230013-948cd5f35899 diff --git a/vendor/github.com/minio/minio-go/v7/go.sum b/vendor/github.com/minio/minio-go/v7/go.sum index 1dce33dd45..1858b6ff38 100644 --- a/vendor/github.com/minio/minio-go/v7/go.sum +++ b/vendor/github.com/minio/minio-go/v7/go.sum @@ -1,8 +1,6 @@ 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= -github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo= -github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= @@ -16,7 +14,6 @@ github.com/klauspost/cpuid v1.2.3 h1:CCtW0xUnWGVINKvE/WWOYKdsPV6mawAtvQuSl8guwQs github.com/klauspost/cpuid v1.2.3/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= github.com/klauspost/cpuid v1.3.1 h1:5JNjFYYQrZeKRJ0734q51WCEEn2huer72Dc7K+R/b6s= github.com/klauspost/cpuid v1.3.1/go.mod h1:bYW4mA6ZgKPob1/Dlai2LviZJO7KGI3uoWLd42rAQw4= -github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= @@ -40,14 +37,11 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/rs/xid v1.2.1 h1:mhH9Nq+C1fY2l1XIpgxIiUOfNpRBYH1kKcr+qfKgjRc= github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ= -github.com/sirupsen/logrus v1.6.0 h1:UBcNElsrwanuuMsnGSlYmtmgbb23qDR5dG+6X6Oo89I= -github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a h1:pa8hGb/2YqsZKovtsgrwcDH1RZhVbTKCjLp47XpqCDs= github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= @@ -63,7 +57,6 @@ golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81R golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d h1:+R4KGOnez64A81RvjARKc4UT5/tI9ujCIVX+P5KiHuI= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae h1:Ih9Yo4hSPImZOpfGuA4bR/ORKTAbhZo2AbWNRCnevdo= golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= diff --git a/vendor/github.com/minio/minio-go/v7/pkg/replication/replication.go b/vendor/github.com/minio/minio-go/v7/pkg/replication/replication.go index 57e63a08cd..fdd0afbc8d 100644 --- a/vendor/github.com/minio/minio-go/v7/pkg/replication/replication.go +++ b/vendor/github.com/minio/minio-go/v7/pkg/replication/replication.go @@ -53,7 +53,10 @@ type Options struct { Priority string TagString string StorageClass string - Arn string + RoleArn string + DestBucket string + IsTagSet bool + IsSCSet bool } // Tags returns a slice of tags for a rule @@ -89,6 +92,24 @@ func (c *Config) Empty() bool { // AddRule adds a new rule to existing replication config. If a rule exists with the // same ID, then the rule is replaced. func (c *Config) AddRule(opts Options) error { + priority, err := strconv.Atoi(opts.Priority) + if err != nil { + return err + } + if opts.RoleArn != c.Role && c.Role != "" { + return fmt.Errorf("Role ARN does not match existing configuration") + } + var status Status + // toggle rule status for edit option + switch opts.RuleStatus { + case "enable": + status = Enabled + case "disable": + status = Disabled + default: + return fmt.Errorf("Rule state should be either [enable|disable]") + } + tags := opts.Tags() andVal := And{ Tags: opts.Tags(), @@ -103,32 +124,33 @@ func (c *Config) AddRule(opts Options) error { filter.And = andVal filter.And.Prefix = opts.Prefix filter.Prefix = "" + filter.Tag = Tag{} } if opts.ID == "" { opts.ID = xid.New().String() } - var status Status - // toggle rule status for edit option - switch opts.RuleStatus { - case "enable": - status = Enabled - case "disable": - status = Disabled - } - arnStr := opts.Arn - if opts.Arn == "" { + arnStr := opts.RoleArn + if opts.RoleArn == "" { arnStr = c.Role } + if arnStr == "" { + return fmt.Errorf("Role ARN required") + } tokens := strings.Split(arnStr, ":") if len(tokens) != 6 { return fmt.Errorf("invalid format for replication Arn") } - if c.Role == "" { // for new configurations - c.Role = opts.Arn + if c.Role == "" { + c.Role = arnStr } - priority, err := strconv.Atoi(opts.Priority) - if err != nil { - return err + destBucket := opts.DestBucket + // ref https://docs.aws.amazon.com/AmazonS3/latest/dev/s3-arn-format.html + if btokens := strings.Split(destBucket, ":"); len(btokens) != 6 { + if len(btokens) == 1 { + destBucket = fmt.Sprintf("arn:aws:s3:::%s", destBucket) + } else { + return fmt.Errorf("destination bucket needs to be in Arn format") + } } newRule := Rule{ ID: opts.ID, @@ -136,56 +158,147 @@ func (c *Config) AddRule(opts Options) error { Status: status, Filter: filter, Destination: Destination{ - Bucket: fmt.Sprintf("arn:aws:s3:::%s", tokens[5]), + Bucket: destBucket, StorageClass: opts.StorageClass, }, DeleteMarkerReplication: DeleteMarkerReplication{Status: Disabled}, } - ruleFound := false - for i, rule := range c.Rules { - if rule.Priority == newRule.Priority && rule.ID != newRule.ID { + // validate rule after overlaying priority for pre-existing rule being disabled. + if err := newRule.Validate(); err != nil { + return err + } + for _, rule := range c.Rules { + if rule.Priority == newRule.Priority { return fmt.Errorf("Priority must be unique. Replication configuration already has a rule with this priority") } if rule.Destination.Bucket != newRule.Destination.Bucket { return fmt.Errorf("The destination bucket must be same for all rules") } - if rule.ID != newRule.ID { - continue + if rule.ID == newRule.ID { + return fmt.Errorf("A rule exists with this ID") } - if opts.Priority == "" && rule.ID == newRule.ID { - // inherit priority from existing rule, required field on server - newRule.Priority = rule.Priority + } + + c.Rules = append(c.Rules, newRule) + return nil +} + +// EditRule modifies an existing rule in replication config +func (c *Config) EditRule(opts Options) error { + if opts.ID == "" { + return fmt.Errorf("Rule ID missing") + } + rIdx := -1 + var newRule Rule + for i, rule := range c.Rules { + if rule.ID == opts.ID { + rIdx = i + newRule = rule + break + } + } + if rIdx < 0 { + return fmt.Errorf("Rule with ID %s not found in replication configuration", opts.ID) + } + prefixChg := opts.Prefix != newRule.Prefix() + if opts.IsTagSet || prefixChg { + prefix := newRule.Prefix() + if prefix != opts.Prefix { + prefix = opts.Prefix } - if opts.RuleStatus == "" { - newRule.Status = rule.Status + tags := []Tag{newRule.Filter.Tag} + if len(newRule.Filter.And.Tags) != 0 { + tags = newRule.Filter.And.Tags } - c.Rules[i] = newRule - ruleFound = true - break + if opts.IsTagSet { + tags = opts.Tags() + } + andVal := And{ + Tags: tags, + } + + filter := Filter{Prefix: prefix} + // only a single tag is set. + if prefix == "" && len(tags) == 1 { + filter.Tag = tags[0] + } + // both prefix and tag are present + if len(andVal.Tags) > 1 || prefix != "" { + filter.And = andVal + filter.And.Prefix = prefix + filter.Prefix = "" + filter.Tag = Tag{} + } + newRule.Filter = filter } - // validate rule after overlaying priority for pre-existing rule being disabled. + + // toggle rule status for edit option + if opts.RuleStatus != "" { + switch opts.RuleStatus { + case "enable": + newRule.Status = Enabled + case "disable": + newRule.Status = Disabled + default: + return fmt.Errorf("Rule state should be either [enable|disable]") + } + } + + if opts.IsSCSet { + newRule.Destination.StorageClass = opts.StorageClass + } + if opts.Priority != "" { + priority, err := strconv.Atoi(opts.Priority) + if err != nil { + return err + } + newRule.Priority = priority + } + if opts.DestBucket != "" { + destBucket := opts.DestBucket + // ref https://docs.aws.amazon.com/AmazonS3/latest/dev/s3-arn-format.html + if btokens := strings.Split(opts.DestBucket, ":"); len(btokens) != 6 { + if len(btokens) == 1 { + destBucket = fmt.Sprintf("arn:aws:s3:::%s", destBucket) + } else { + return fmt.Errorf("destination bucket needs to be in Arn format") + } + } + newRule.Destination.Bucket = destBucket + } + // validate rule if err := newRule.Validate(); err != nil { return err } - if !ruleFound && opts.Op == SetOption { - return fmt.Errorf("Rule with ID %s not found in replication configuration", opts.ID) - } - if !ruleFound { - c.Rules = append(c.Rules, newRule) + // ensure priority and destination bucket restrictions are not violated + for idx, rule := range c.Rules { + if rule.Priority == newRule.Priority && rIdx != idx { + return fmt.Errorf("Priority must be unique. Replication configuration already has a rule with this priority") + } + if rule.Destination.Bucket != newRule.Destination.Bucket { + return fmt.Errorf("The destination bucket must be same for all rules") + } } + + c.Rules[rIdx] = newRule return nil } // RemoveRule removes a rule from replication config. func (c *Config) RemoveRule(opts Options) error { var newRules []Rule + ruleFound := false for _, rule := range c.Rules { if rule.ID != opts.ID { newRules = append(newRules, rule) + continue } + ruleFound = true + } + if !ruleFound { + return fmt.Errorf("Rule with ID %s not found", opts.ID) } - if len(newRules) == 0 { return fmt.Errorf("Replication configuration should have at least one rule") } @@ -268,17 +381,19 @@ func (r Rule) Prefix() string { // <filter><and></and></filter>. This method returns all the tags from the // rule in the format tag1=value1&tag2=value2 func (r Rule) Tags() string { + ts := []Tag{r.Filter.Tag} if len(r.Filter.And.Tags) != 0 { - var buf bytes.Buffer - for _, t := range r.Filter.And.Tags { - if buf.Len() > 0 { - buf.WriteString("&") - } - buf.WriteString(t.String()) + ts = r.Filter.And.Tags + } + + var buf bytes.Buffer + for _, t := range ts { + if buf.Len() > 0 { + buf.WriteString("&") } - return buf.String() + buf.WriteString(t.String()) } - return "" + return buf.String() } // Filter - a filter for a replication configuration Rule. @@ -321,6 +436,9 @@ type Tag struct { } func (tag Tag) String() string { + if tag.IsEmpty() { + return "" + } return tag.Key + "=" + tag.Value } @@ -352,7 +470,7 @@ type Destination struct { type And struct { XMLName xml.Name `xml:"And,omitempty" json:"-"` Prefix string `xml:"Prefix,omitempty" json:"Prefix,omitempty"` - Tags []Tag `xml:"Tag,omitempty" json:"Tags,omitempty"` + Tags []Tag `xml:"Tags,omitempty" json:"Tags,omitempty"` } // isEmpty returns true if Tags field is null |