aboutsummaryrefslogtreecommitdiffstats
path: root/vendor/cloud.google.com/go/storage/bucket.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/cloud.google.com/go/storage/bucket.go')
-rw-r--r--vendor/cloud.google.com/go/storage/bucket.go1129
1 files changed, 1129 insertions, 0 deletions
diff --git a/vendor/cloud.google.com/go/storage/bucket.go b/vendor/cloud.google.com/go/storage/bucket.go
new file mode 100644
index 000000000..3b0018aff
--- /dev/null
+++ b/vendor/cloud.google.com/go/storage/bucket.go
@@ -0,0 +1,1129 @@
+// Copyright 2014 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package storage
+
+import (
+ "context"
+ "fmt"
+ "net/http"
+ "reflect"
+ "time"
+
+ "cloud.google.com/go/internal/optional"
+ "cloud.google.com/go/internal/trace"
+ "google.golang.org/api/googleapi"
+ "google.golang.org/api/iterator"
+ raw "google.golang.org/api/storage/v1"
+)
+
+// BucketHandle provides operations on a Google Cloud Storage bucket.
+// Use Client.Bucket to get a handle.
+type BucketHandle struct {
+ c *Client
+ name string
+ acl ACLHandle
+ defaultObjectACL ACLHandle
+ conds *BucketConditions
+ userProject string // project for Requester Pays buckets
+}
+
+// Bucket returns a BucketHandle, which provides operations on the named bucket.
+// This call does not perform any network operations.
+//
+// The supplied name must contain only lowercase letters, numbers, dashes,
+// underscores, and dots. The full specification for valid bucket names can be
+// found at:
+// https://cloud.google.com/storage/docs/bucket-naming
+func (c *Client) Bucket(name string) *BucketHandle {
+ return &BucketHandle{
+ c: c,
+ name: name,
+ acl: ACLHandle{
+ c: c,
+ bucket: name,
+ },
+ defaultObjectACL: ACLHandle{
+ c: c,
+ bucket: name,
+ isDefault: true,
+ },
+ }
+}
+
+// Create creates the Bucket in the project.
+// If attrs is nil the API defaults will be used.
+func (b *BucketHandle) Create(ctx context.Context, projectID string, attrs *BucketAttrs) (err error) {
+ ctx = trace.StartSpan(ctx, "cloud.google.com/go/storage.Bucket.Create")
+ defer func() { trace.EndSpan(ctx, err) }()
+
+ var bkt *raw.Bucket
+ if attrs != nil {
+ bkt = attrs.toRawBucket()
+ } else {
+ bkt = &raw.Bucket{}
+ }
+ bkt.Name = b.name
+ // If there is lifecycle information but no location, explicitly set
+ // the location. This is a GCS quirk/bug.
+ if bkt.Location == "" && bkt.Lifecycle != nil {
+ bkt.Location = "US"
+ }
+ req := b.c.raw.Buckets.Insert(projectID, bkt)
+ setClientHeader(req.Header())
+ if attrs != nil && attrs.PredefinedACL != "" {
+ req.PredefinedAcl(attrs.PredefinedACL)
+ }
+ if attrs != nil && attrs.PredefinedDefaultObjectACL != "" {
+ req.PredefinedDefaultObjectAcl(attrs.PredefinedDefaultObjectACL)
+ }
+ return runWithRetry(ctx, func() error { _, err := req.Context(ctx).Do(); return err })
+}
+
+// Delete deletes the Bucket.
+func (b *BucketHandle) Delete(ctx context.Context) (err error) {
+ ctx = trace.StartSpan(ctx, "cloud.google.com/go/storage.Bucket.Delete")
+ defer func() { trace.EndSpan(ctx, err) }()
+
+ req, err := b.newDeleteCall()
+ if err != nil {
+ return err
+ }
+ return runWithRetry(ctx, func() error { return req.Context(ctx).Do() })
+}
+
+func (b *BucketHandle) newDeleteCall() (*raw.BucketsDeleteCall, error) {
+ req := b.c.raw.Buckets.Delete(b.name)
+ setClientHeader(req.Header())
+ if err := applyBucketConds("BucketHandle.Delete", b.conds, req); err != nil {
+ return nil, err
+ }
+ if b.userProject != "" {
+ req.UserProject(b.userProject)
+ }
+ return req, nil
+}
+
+// ACL returns an ACLHandle, which provides access to the bucket's access control list.
+// This controls who can list, create or overwrite the objects in a bucket.
+// This call does not perform any network operations.
+func (b *BucketHandle) ACL() *ACLHandle {
+ return &b.acl
+}
+
+// DefaultObjectACL returns an ACLHandle, which provides access to the bucket's default object ACLs.
+// These ACLs are applied to newly created objects in this bucket that do not have a defined ACL.
+// This call does not perform any network operations.
+func (b *BucketHandle) DefaultObjectACL() *ACLHandle {
+ return &b.defaultObjectACL
+}
+
+// Object returns an ObjectHandle, which provides operations on the named object.
+// This call does not perform any network operations.
+//
+// name must consist entirely of valid UTF-8-encoded runes. The full specification
+// for valid object names can be found at:
+// https://cloud.google.com/storage/docs/bucket-naming
+func (b *BucketHandle) Object(name string) *ObjectHandle {
+ return &ObjectHandle{
+ c: b.c,
+ bucket: b.name,
+ object: name,
+ acl: ACLHandle{
+ c: b.c,
+ bucket: b.name,
+ object: name,
+ userProject: b.userProject,
+ },
+ gen: -1,
+ userProject: b.userProject,
+ }
+}
+
+// Attrs returns the metadata for the bucket.
+func (b *BucketHandle) Attrs(ctx context.Context) (attrs *BucketAttrs, err error) {
+ ctx = trace.StartSpan(ctx, "cloud.google.com/go/storage.Bucket.Attrs")
+ defer func() { trace.EndSpan(ctx, err) }()
+
+ req, err := b.newGetCall()
+ if err != nil {
+ return nil, err
+ }
+ var resp *raw.Bucket
+ err = runWithRetry(ctx, func() error {
+ resp, err = req.Context(ctx).Do()
+ return err
+ })
+ if e, ok := err.(*googleapi.Error); ok && e.Code == http.StatusNotFound {
+ return nil, ErrBucketNotExist
+ }
+ if err != nil {
+ return nil, err
+ }
+ return newBucket(resp)
+}
+
+func (b *BucketHandle) newGetCall() (*raw.BucketsGetCall, error) {
+ req := b.c.raw.Buckets.Get(b.name).Projection("full")
+ setClientHeader(req.Header())
+ if err := applyBucketConds("BucketHandle.Attrs", b.conds, req); err != nil {
+ return nil, err
+ }
+ if b.userProject != "" {
+ req.UserProject(b.userProject)
+ }
+ return req, nil
+}
+
+// Update updates a bucket's attributes.
+func (b *BucketHandle) Update(ctx context.Context, uattrs BucketAttrsToUpdate) (attrs *BucketAttrs, err error) {
+ ctx = trace.StartSpan(ctx, "cloud.google.com/go/storage.Bucket.Create")
+ defer func() { trace.EndSpan(ctx, err) }()
+
+ req, err := b.newPatchCall(&uattrs)
+ if err != nil {
+ return nil, err
+ }
+ if uattrs.PredefinedACL != "" {
+ req.PredefinedAcl(uattrs.PredefinedACL)
+ }
+ if uattrs.PredefinedDefaultObjectACL != "" {
+ req.PredefinedDefaultObjectAcl(uattrs.PredefinedDefaultObjectACL)
+ }
+ // TODO(jba): retry iff metagen is set?
+ rb, err := req.Context(ctx).Do()
+ if err != nil {
+ return nil, err
+ }
+ return newBucket(rb)
+}
+
+func (b *BucketHandle) newPatchCall(uattrs *BucketAttrsToUpdate) (*raw.BucketsPatchCall, error) {
+ rb := uattrs.toRawBucket()
+ req := b.c.raw.Buckets.Patch(b.name, rb).Projection("full")
+ setClientHeader(req.Header())
+ if err := applyBucketConds("BucketHandle.Update", b.conds, req); err != nil {
+ return nil, err
+ }
+ if b.userProject != "" {
+ req.UserProject(b.userProject)
+ }
+ return req, nil
+}
+
+// BucketAttrs represents the metadata for a Google Cloud Storage bucket.
+// Read-only fields are ignored by BucketHandle.Create.
+type BucketAttrs struct {
+ // Name is the name of the bucket.
+ // This field is read-only.
+ Name string
+
+ // ACL is the list of access control rules on the bucket.
+ ACL []ACLRule
+
+ // DefaultObjectACL is the list of access controls to
+ // apply to new objects when no object ACL is provided.
+ DefaultObjectACL []ACLRule
+
+ // DefaultEventBasedHold is the default value for event-based hold on
+ // newly created objects in this bucket. It defaults to false.
+ DefaultEventBasedHold bool
+
+ // If not empty, applies a predefined set of access controls. It should be set
+ // only when creating a bucket.
+ // It is always empty for BucketAttrs returned from the service.
+ // See https://cloud.google.com/storage/docs/json_api/v1/buckets/insert
+ // for valid values.
+ PredefinedACL string
+
+ // If not empty, applies a predefined set of default object access controls.
+ // It should be set only when creating a bucket.
+ // It is always empty for BucketAttrs returned from the service.
+ // See https://cloud.google.com/storage/docs/json_api/v1/buckets/insert
+ // for valid values.
+ PredefinedDefaultObjectACL string
+
+ // Location is the location of the bucket. It defaults to "US".
+ Location string
+
+ // MetaGeneration is the metadata generation of the bucket.
+ // This field is read-only.
+ MetaGeneration int64
+
+ // StorageClass is the default storage class of the bucket. This defines
+ // how objects in the bucket are stored and determines the SLA
+ // and the cost of storage. Typical values are "MULTI_REGIONAL",
+ // "REGIONAL", "NEARLINE", "COLDLINE", "STANDARD" and
+ // "DURABLE_REDUCED_AVAILABILITY". Defaults to "STANDARD", which
+ // is equivalent to "MULTI_REGIONAL" or "REGIONAL" depending on
+ // the bucket's location settings.
+ StorageClass string
+
+ // Created is the creation time of the bucket.
+ // This field is read-only.
+ Created time.Time
+
+ // VersioningEnabled reports whether this bucket has versioning enabled.
+ VersioningEnabled bool
+
+ // Labels are the bucket's labels.
+ Labels map[string]string
+
+ // RequesterPays reports whether the bucket is a Requester Pays bucket.
+ // Clients performing operations on Requester Pays buckets must provide
+ // a user project (see BucketHandle.UserProject), which will be billed
+ // for the operations.
+ RequesterPays bool
+
+ // Lifecycle is the lifecycle configuration for objects in the bucket.
+ Lifecycle Lifecycle
+
+ // Retention policy enforces a minimum retention time for all objects
+ // contained in the bucket. A RetentionPolicy of nil implies the bucket
+ // has no minimum data retention.
+ //
+ // This feature is in private alpha release. It is not currently available to
+ // most customers. It might be changed in backwards-incompatible ways and is not
+ // subject to any SLA or deprecation policy.
+ RetentionPolicy *RetentionPolicy
+
+ // The bucket's Cross-Origin Resource Sharing (CORS) configuration.
+ CORS []CORS
+
+ // The encryption configuration used by default for newly inserted objects.
+ Encryption *BucketEncryption
+
+ // The logging configuration.
+ Logging *BucketLogging
+
+ // The website configuration.
+ Website *BucketWebsite
+}
+
+// Lifecycle is the lifecycle configuration for objects in the bucket.
+type Lifecycle struct {
+ Rules []LifecycleRule
+}
+
+// RetentionPolicy enforces a minimum retention time for all objects
+// contained in the bucket.
+//
+// Any attempt to overwrite or delete objects younger than the retention
+// period will result in an error. An unlocked retention policy can be
+// modified or removed from the bucket via the Update method. A
+// locked retention policy cannot be removed or shortened in duration
+// for the lifetime of the bucket.
+//
+// This feature is in private alpha release. It is not currently available to
+// most customers. It might be changed in backwards-incompatible ways and is not
+// subject to any SLA or deprecation policy.
+type RetentionPolicy struct {
+ // RetentionPeriod specifies the duration that objects need to be
+ // retained. Retention duration must be greater than zero and less than
+ // 100 years. Note that enforcement of retention periods less than a day
+ // is not guaranteed. Such periods should only be used for testing
+ // purposes.
+ RetentionPeriod time.Duration
+
+ // EffectiveTime is the time from which the policy was enforced and
+ // effective. This field is read-only.
+ EffectiveTime time.Time
+
+ // IsLocked describes whether the bucket is locked. Once locked, an
+ // object retention policy cannot be modified.
+ // This field is read-only.
+ IsLocked bool
+}
+
+const (
+ // RFC3339 date with only the date segment, used for CreatedBefore in LifecycleRule.
+ rfc3339Date = "2006-01-02"
+
+ // DeleteAction is a lifecycle action that deletes a live and/or archived
+ // objects. Takes precedence over SetStorageClass actions.
+ DeleteAction = "Delete"
+
+ // SetStorageClassAction changes the storage class of live and/or archived
+ // objects.
+ SetStorageClassAction = "SetStorageClass"
+)
+
+// LifecycleRule is a lifecycle configuration rule.
+//
+// When all the configured conditions are met by an object in the bucket, the
+// configured action will automatically be taken on that object.
+type LifecycleRule struct {
+ // Action is the action to take when all of the associated conditions are
+ // met.
+ Action LifecycleAction
+
+ // Condition is the set of conditions that must be met for the associated
+ // action to be taken.
+ Condition LifecycleCondition
+}
+
+// LifecycleAction is a lifecycle configuration action.
+type LifecycleAction struct {
+ // Type is the type of action to take on matching objects.
+ //
+ // Acceptable values are "Delete" to delete matching objects and
+ // "SetStorageClass" to set the storage class defined in StorageClass on
+ // matching objects.
+ Type string
+
+ // StorageClass is the storage class to set on matching objects if the Action
+ // is "SetStorageClass".
+ StorageClass string
+}
+
+// Liveness specifies whether the object is live or not.
+type Liveness int
+
+const (
+ // LiveAndArchived includes both live and archived objects.
+ LiveAndArchived Liveness = iota
+ // Live specifies that the object is still live.
+ Live
+ // Archived specifies that the object is archived.
+ Archived
+)
+
+// LifecycleCondition is a set of conditions used to match objects and take an
+// action automatically.
+//
+// All configured conditions must be met for the associated action to be taken.
+type LifecycleCondition struct {
+ // AgeInDays is the age of the object in days.
+ AgeInDays int64
+
+ // CreatedBefore is the time the object was created.
+ //
+ // This condition is satisfied when an object is created before midnight of
+ // the specified date in UTC.
+ CreatedBefore time.Time
+
+ // Liveness specifies the object's liveness. Relevant only for versioned objects
+ Liveness Liveness
+
+ // MatchesStorageClasses is the condition matching the object's storage
+ // class.
+ //
+ // Values include "MULTI_REGIONAL", "REGIONAL", "NEARLINE", "COLDLINE",
+ // "STANDARD", and "DURABLE_REDUCED_AVAILABILITY".
+ MatchesStorageClasses []string
+
+ // NumNewerVersions is the condition matching objects with a number of newer versions.
+ //
+ // If the value is N, this condition is satisfied when there are at least N
+ // versions (including the live version) newer than this version of the
+ // object.
+ NumNewerVersions int64
+}
+
+// BucketLogging holds the bucket's logging configuration, which defines the
+// destination bucket and optional name prefix for the current bucket's
+// logs.
+type BucketLogging struct {
+ // The destination bucket where the current bucket's logs
+ // should be placed.
+ LogBucket string
+
+ // A prefix for log object names.
+ LogObjectPrefix string
+}
+
+// BucketWebsite holds the bucket's website configuration, controlling how the
+// service behaves when accessing bucket contents as a web site. See
+// https://cloud.google.com/storage/docs/static-website for more information.
+type BucketWebsite struct {
+ // If the requested object path is missing, the service will ensure the path has
+ // a trailing '/', append this suffix, and attempt to retrieve the resulting
+ // object. This allows the creation of index.html objects to represent directory
+ // pages.
+ MainPageSuffix string
+
+ // If the requested object path is missing, and any mainPageSuffix object is
+ // missing, if applicable, the service will return the named object from this
+ // bucket as the content for a 404 Not Found result.
+ NotFoundPage string
+}
+
+func newBucket(b *raw.Bucket) (*BucketAttrs, error) {
+ if b == nil {
+ return nil, nil
+ }
+ rp, err := toRetentionPolicy(b.RetentionPolicy)
+ if err != nil {
+ return nil, err
+ }
+ return &BucketAttrs{
+ Name: b.Name,
+ Location: b.Location,
+ MetaGeneration: b.Metageneration,
+ DefaultEventBasedHold: b.DefaultEventBasedHold,
+ StorageClass: b.StorageClass,
+ Created: convertTime(b.TimeCreated),
+ VersioningEnabled: b.Versioning != nil && b.Versioning.Enabled,
+ ACL: toBucketACLRules(b.Acl),
+ DefaultObjectACL: toObjectACLRules(b.DefaultObjectAcl),
+ Labels: b.Labels,
+ RequesterPays: b.Billing != nil && b.Billing.RequesterPays,
+ Lifecycle: toLifecycle(b.Lifecycle),
+ RetentionPolicy: rp,
+ CORS: toCORS(b.Cors),
+ Encryption: toBucketEncryption(b.Encryption),
+ Logging: toBucketLogging(b.Logging),
+ Website: toBucketWebsite(b.Website),
+ }, nil
+}
+
+// toRawBucket copies the editable attribute from b to the raw library's Bucket type.
+func (b *BucketAttrs) toRawBucket() *raw.Bucket {
+ // Copy label map.
+ var labels map[string]string
+ if len(b.Labels) > 0 {
+ labels = make(map[string]string, len(b.Labels))
+ for k, v := range b.Labels {
+ labels[k] = v
+ }
+ }
+ // Ignore VersioningEnabled if it is false. This is OK because
+ // we only call this method when creating a bucket, and by default
+ // new buckets have versioning off.
+ var v *raw.BucketVersioning
+ if b.VersioningEnabled {
+ v = &raw.BucketVersioning{Enabled: true}
+ }
+ var bb *raw.BucketBilling
+ if b.RequesterPays {
+ bb = &raw.BucketBilling{RequesterPays: true}
+ }
+ return &raw.Bucket{
+ Name: b.Name,
+ Location: b.Location,
+ StorageClass: b.StorageClass,
+ Acl: toRawBucketACL(b.ACL),
+ DefaultObjectAcl: toRawObjectACL(b.DefaultObjectACL),
+ Versioning: v,
+ Labels: labels,
+ Billing: bb,
+ Lifecycle: toRawLifecycle(b.Lifecycle),
+ RetentionPolicy: b.RetentionPolicy.toRawRetentionPolicy(),
+ Cors: toRawCORS(b.CORS),
+ Encryption: b.Encryption.toRawBucketEncryption(),
+ Logging: b.Logging.toRawBucketLogging(),
+ Website: b.Website.toRawBucketWebsite(),
+ }
+}
+
+// CORS is the bucket's Cross-Origin Resource Sharing (CORS) configuration.
+type CORS struct {
+ // MaxAge is the value to return in the Access-Control-Max-Age
+ // header used in preflight responses.
+ MaxAge time.Duration
+
+ // Methods is the list of HTTP methods on which to include CORS response
+ // headers, (GET, OPTIONS, POST, etc) Note: "*" is permitted in the list
+ // of methods, and means "any method".
+ Methods []string
+
+ // Origins is the list of Origins eligible to receive CORS response
+ // headers. Note: "*" is permitted in the list of origins, and means
+ // "any Origin".
+ Origins []string
+
+ // ResponseHeaders is the list of HTTP headers other than the simple
+ // response headers to give permission for the user-agent to share
+ // across domains.
+ ResponseHeaders []string
+}
+
+// BucketEncryption is a bucket's encryption configuration.
+type BucketEncryption struct {
+ // A Cloud KMS key name, in the form
+ // projects/P/locations/L/keyRings/R/cryptoKeys/K, that will be used to encrypt
+ // objects inserted into this bucket, if no encryption method is specified.
+ // The key's location must be the same as the bucket's.
+ DefaultKMSKeyName string
+}
+
+// BucketAttrsToUpdate define the attributes to update during an Update call.
+type BucketAttrsToUpdate struct {
+ // If set, updates whether the bucket uses versioning.
+ VersioningEnabled optional.Bool
+
+ // If set, updates whether the bucket is a Requester Pays bucket.
+ RequesterPays optional.Bool
+
+ // DefaultEventBasedHold is the default value for event-based hold on
+ // newly created objects in this bucket.
+ DefaultEventBasedHold optional.Bool
+
+ // If set, updates the retention policy of the bucket. Using
+ // RetentionPolicy.RetentionPeriod = 0 will delete the existing policy.
+ //
+ // This feature is in private alpha release. It is not currently available to
+ // most customers. It might be changed in backwards-incompatible ways and is not
+ // subject to any SLA or deprecation policy.
+ RetentionPolicy *RetentionPolicy
+
+ // If set, replaces the CORS configuration with a new configuration.
+ // An empty (rather than nil) slice causes all CORS policies to be removed.
+ CORS []CORS
+
+ // If set, replaces the encryption configuration of the bucket. Using
+ // BucketEncryption.DefaultKMSKeyName = "" will delete the existing
+ // configuration.
+ Encryption *BucketEncryption
+
+ // If set, replaces the lifecycle configuration of the bucket.
+ Lifecycle *Lifecycle
+
+ // If set, replaces the logging configuration of the bucket.
+ Logging *BucketLogging
+
+ // If set, replaces the website configuration of the bucket.
+ Website *BucketWebsite
+
+ // If not empty, applies a predefined set of access controls.
+ // See https://cloud.google.com/storage/docs/json_api/v1/buckets/patch.
+ PredefinedACL string
+
+ // If not empty, applies a predefined set of default object access controls.
+ // See https://cloud.google.com/storage/docs/json_api/v1/buckets/patch.
+ PredefinedDefaultObjectACL string
+
+ setLabels map[string]string
+ deleteLabels map[string]bool
+}
+
+// SetLabel causes a label to be added or modified when ua is used
+// in a call to Bucket.Update.
+func (ua *BucketAttrsToUpdate) SetLabel(name, value string) {
+ if ua.setLabels == nil {
+ ua.setLabels = map[string]string{}
+ }
+ ua.setLabels[name] = value
+}
+
+// DeleteLabel causes a label to be deleted when ua is used in a
+// call to Bucket.Update.
+func (ua *BucketAttrsToUpdate) DeleteLabel(name string) {
+ if ua.deleteLabels == nil {
+ ua.deleteLabels = map[string]bool{}
+ }
+ ua.deleteLabels[name] = true
+}
+
+func (ua *BucketAttrsToUpdate) toRawBucket() *raw.Bucket {
+ rb := &raw.Bucket{}
+ if ua.CORS != nil {
+ rb.Cors = toRawCORS(ua.CORS)
+ rb.ForceSendFields = append(rb.ForceSendFields, "Cors")
+ }
+ if ua.DefaultEventBasedHold != nil {
+ rb.DefaultEventBasedHold = optional.ToBool(ua.DefaultEventBasedHold)
+ rb.ForceSendFields = append(rb.ForceSendFields, "DefaultEventBasedHold")
+ }
+ if ua.RetentionPolicy != nil {
+ if ua.RetentionPolicy.RetentionPeriod == 0 {
+ rb.NullFields = append(rb.NullFields, "RetentionPolicy")
+ rb.RetentionPolicy = nil
+ } else {
+ rb.RetentionPolicy = ua.RetentionPolicy.toRawRetentionPolicy()
+ }
+ }
+ if ua.VersioningEnabled != nil {
+ rb.Versioning = &raw.BucketVersioning{
+ Enabled: optional.ToBool(ua.VersioningEnabled),
+ ForceSendFields: []string{"Enabled"},
+ }
+ }
+ if ua.RequesterPays != nil {
+ rb.Billing = &raw.BucketBilling{
+ RequesterPays: optional.ToBool(ua.RequesterPays),
+ ForceSendFields: []string{"RequesterPays"},
+ }
+ }
+ if ua.Encryption != nil {
+ if ua.Encryption.DefaultKMSKeyName == "" {
+ rb.NullFields = append(rb.NullFields, "Encryption")
+ rb.Encryption = nil
+ } else {
+ rb.Encryption = ua.Encryption.toRawBucketEncryption()
+ }
+ }
+ if ua.Lifecycle != nil {
+ rb.Lifecycle = toRawLifecycle(*ua.Lifecycle)
+ }
+ if ua.Logging != nil {
+ if *ua.Logging == (BucketLogging{}) {
+ rb.NullFields = append(rb.NullFields, "Logging")
+ rb.Logging = nil
+ } else {
+ rb.Logging = ua.Logging.toRawBucketLogging()
+ }
+ }
+ if ua.Website != nil {
+ if *ua.Website == (BucketWebsite{}) {
+ rb.NullFields = append(rb.NullFields, "Website")
+ rb.Website = nil
+ } else {
+ rb.Website = ua.Website.toRawBucketWebsite()
+ }
+ }
+ if ua.PredefinedACL != "" {
+ // Clear ACL or the call will fail.
+ rb.Acl = nil
+ rb.ForceSendFields = append(rb.ForceSendFields, "Acl")
+ }
+ if ua.PredefinedDefaultObjectACL != "" {
+ // Clear ACLs or the call will fail.
+ rb.DefaultObjectAcl = nil
+ rb.ForceSendFields = append(rb.ForceSendFields, "DefaultObjectAcl")
+ }
+ if ua.setLabels != nil || ua.deleteLabels != nil {
+ rb.Labels = map[string]string{}
+ for k, v := range ua.setLabels {
+ rb.Labels[k] = v
+ }
+ if len(rb.Labels) == 0 && len(ua.deleteLabels) > 0 {
+ rb.ForceSendFields = append(rb.ForceSendFields, "Labels")
+ }
+ for l := range ua.deleteLabels {
+ rb.NullFields = append(rb.NullFields, "Labels."+l)
+ }
+ }
+ return rb
+}
+
+// If returns a new BucketHandle that applies a set of preconditions.
+// Preconditions already set on the BucketHandle are ignored.
+// Operations on the new handle will return an error if the preconditions are not
+// satisfied. The only valid preconditions for buckets are MetagenerationMatch
+// and MetagenerationNotMatch.
+func (b *BucketHandle) If(conds BucketConditions) *BucketHandle {
+ b2 := *b
+ b2.conds = &conds
+ return &b2
+}
+
+// BucketConditions constrain bucket methods to act on specific metagenerations.
+//
+// The zero value is an empty set of constraints.
+type BucketConditions struct {
+ // MetagenerationMatch specifies that the bucket must have the given
+ // metageneration for the operation to occur.
+ // If MetagenerationMatch is zero, it has no effect.
+ MetagenerationMatch int64
+
+ // MetagenerationNotMatch specifies that the bucket must not have the given
+ // metageneration for the operation to occur.
+ // If MetagenerationNotMatch is zero, it has no effect.
+ MetagenerationNotMatch int64
+}
+
+func (c *BucketConditions) validate(method string) error {
+ if *c == (BucketConditions{}) {
+ return fmt.Errorf("storage: %s: empty conditions", method)
+ }
+ if c.MetagenerationMatch != 0 && c.MetagenerationNotMatch != 0 {
+ return fmt.Errorf("storage: %s: multiple conditions specified for metageneration", method)
+ }
+ return nil
+}
+
+// UserProject returns a new BucketHandle that passes the project ID as the user
+// project for all subsequent calls. Calls with a user project will be billed to that
+// project rather than to the bucket's owning project.
+//
+// A user project is required for all operations on Requester Pays buckets.
+func (b *BucketHandle) UserProject(projectID string) *BucketHandle {
+ b2 := *b
+ b2.userProject = projectID
+ b2.acl.userProject = projectID
+ b2.defaultObjectACL.userProject = projectID
+ return &b2
+}
+
+// LockRetentionPolicy locks a bucket's retention policy until a previously-configured
+// RetentionPeriod past the EffectiveTime. Note that if RetentionPeriod is set to less
+// than a day, the retention policy is treated as a development configuration and locking
+// will have no effect. The BucketHandle must have a metageneration condition that
+// matches the bucket's metageneration. See BucketHandle.If.
+//
+// This feature is in private alpha release. It is not currently available to
+// most customers. It might be changed in backwards-incompatible ways and is not
+// subject to any SLA or deprecation policy.
+func (b *BucketHandle) LockRetentionPolicy(ctx context.Context) error {
+ var metageneration int64
+ if b.conds != nil {
+ metageneration = b.conds.MetagenerationMatch
+ }
+ req := b.c.raw.Buckets.LockRetentionPolicy(b.name, metageneration)
+ _, err := req.Context(ctx).Do()
+ return err
+}
+
+// applyBucketConds modifies the provided call using the conditions in conds.
+// call is something that quacks like a *raw.WhateverCall.
+func applyBucketConds(method string, conds *BucketConditions, call interface{}) error {
+ if conds == nil {
+ return nil
+ }
+ if err := conds.validate(method); err != nil {
+ return err
+ }
+ cval := reflect.ValueOf(call)
+ switch {
+ case conds.MetagenerationMatch != 0:
+ if !setConditionField(cval, "IfMetagenerationMatch", conds.MetagenerationMatch) {
+ return fmt.Errorf("storage: %s: ifMetagenerationMatch not supported", method)
+ }
+ case conds.MetagenerationNotMatch != 0:
+ if !setConditionField(cval, "IfMetagenerationNotMatch", conds.MetagenerationNotMatch) {
+ return fmt.Errorf("storage: %s: ifMetagenerationNotMatch not supported", method)
+ }
+ }
+ return nil
+}
+
+func (rp *RetentionPolicy) toRawRetentionPolicy() *raw.BucketRetentionPolicy {
+ if rp == nil {
+ return nil
+ }
+ return &raw.BucketRetentionPolicy{
+ RetentionPeriod: int64(rp.RetentionPeriod / time.Second),
+ }
+}
+
+func toRetentionPolicy(rp *raw.BucketRetentionPolicy) (*RetentionPolicy, error) {
+ if rp == nil {
+ return nil, nil
+ }
+ t, err := time.Parse(time.RFC3339, rp.EffectiveTime)
+ if err != nil {
+ return nil, err
+ }
+ return &RetentionPolicy{
+ RetentionPeriod: time.Duration(rp.RetentionPeriod) * time.Second,
+ EffectiveTime: t,
+ IsLocked: rp.IsLocked,
+ }, nil
+}
+
+func toRawCORS(c []CORS) []*raw.BucketCors {
+ var out []*raw.BucketCors
+ for _, v := range c {
+ out = append(out, &raw.BucketCors{
+ MaxAgeSeconds: int64(v.MaxAge / time.Second),
+ Method: v.Methods,
+ Origin: v.Origins,
+ ResponseHeader: v.ResponseHeaders,
+ })
+ }
+ return out
+}
+
+func toCORS(rc []*raw.BucketCors) []CORS {
+ var out []CORS
+ for _, v := range rc {
+ out = append(out, CORS{
+ MaxAge: time.Duration(v.MaxAgeSeconds) * time.Second,
+ Methods: v.Method,
+ Origins: v.Origin,
+ ResponseHeaders: v.ResponseHeader,
+ })
+ }
+ return out
+}
+
+func toRawLifecycle(l Lifecycle) *raw.BucketLifecycle {
+ var rl raw.BucketLifecycle
+ if len(l.Rules) == 0 {
+ return nil
+ }
+ for _, r := range l.Rules {
+ rr := &raw.BucketLifecycleRule{
+ Action: &raw.BucketLifecycleRuleAction{
+ Type: r.Action.Type,
+ StorageClass: r.Action.StorageClass,
+ },
+ Condition: &raw.BucketLifecycleRuleCondition{
+ Age: r.Condition.AgeInDays,
+ MatchesStorageClass: r.Condition.MatchesStorageClasses,
+ NumNewerVersions: r.Condition.NumNewerVersions,
+ },
+ }
+
+ switch r.Condition.Liveness {
+ case LiveAndArchived:
+ rr.Condition.IsLive = nil
+ case Live:
+ rr.Condition.IsLive = googleapi.Bool(true)
+ case Archived:
+ rr.Condition.IsLive = googleapi.Bool(false)
+ }
+
+ if !r.Condition.CreatedBefore.IsZero() {
+ rr.Condition.CreatedBefore = r.Condition.CreatedBefore.Format(rfc3339Date)
+ }
+ rl.Rule = append(rl.Rule, rr)
+ }
+ return &rl
+}
+
+func toLifecycle(rl *raw.BucketLifecycle) Lifecycle {
+ var l Lifecycle
+ if rl == nil {
+ return l
+ }
+ for _, rr := range rl.Rule {
+ r := LifecycleRule{
+ Action: LifecycleAction{
+ Type: rr.Action.Type,
+ StorageClass: rr.Action.StorageClass,
+ },
+ Condition: LifecycleCondition{
+ AgeInDays: rr.Condition.Age,
+ MatchesStorageClasses: rr.Condition.MatchesStorageClass,
+ NumNewerVersions: rr.Condition.NumNewerVersions,
+ },
+ }
+
+ switch {
+ case rr.Condition.IsLive == nil:
+ r.Condition.Liveness = LiveAndArchived
+ case *rr.Condition.IsLive == true:
+ r.Condition.Liveness = Live
+ case *rr.Condition.IsLive == false:
+ r.Condition.Liveness = Archived
+ }
+
+ if rr.Condition.CreatedBefore != "" {
+ r.Condition.CreatedBefore, _ = time.Parse(rfc3339Date, rr.Condition.CreatedBefore)
+ }
+ l.Rules = append(l.Rules, r)
+ }
+ return l
+}
+
+func (e *BucketEncryption) toRawBucketEncryption() *raw.BucketEncryption {
+ if e == nil {
+ return nil
+ }
+ return &raw.BucketEncryption{
+ DefaultKmsKeyName: e.DefaultKMSKeyName,
+ }
+}
+
+func toBucketEncryption(e *raw.BucketEncryption) *BucketEncryption {
+ if e == nil {
+ return nil
+ }
+ return &BucketEncryption{DefaultKMSKeyName: e.DefaultKmsKeyName}
+}
+
+func (b *BucketLogging) toRawBucketLogging() *raw.BucketLogging {
+ if b == nil {
+ return nil
+ }
+ return &raw.BucketLogging{
+ LogBucket: b.LogBucket,
+ LogObjectPrefix: b.LogObjectPrefix,
+ }
+}
+
+func toBucketLogging(b *raw.BucketLogging) *BucketLogging {
+ if b == nil {
+ return nil
+ }
+ return &BucketLogging{
+ LogBucket: b.LogBucket,
+ LogObjectPrefix: b.LogObjectPrefix,
+ }
+}
+
+func (w *BucketWebsite) toRawBucketWebsite() *raw.BucketWebsite {
+ if w == nil {
+ return nil
+ }
+ return &raw.BucketWebsite{
+ MainPageSuffix: w.MainPageSuffix,
+ NotFoundPage: w.NotFoundPage,
+ }
+}
+
+func toBucketWebsite(w *raw.BucketWebsite) *BucketWebsite {
+ if w == nil {
+ return nil
+ }
+ return &BucketWebsite{
+ MainPageSuffix: w.MainPageSuffix,
+ NotFoundPage: w.NotFoundPage,
+ }
+}
+
+// Objects returns an iterator over the objects in the bucket that match the Query q.
+// If q is nil, no filtering is done.
+func (b *BucketHandle) Objects(ctx context.Context, q *Query) *ObjectIterator {
+ it := &ObjectIterator{
+ ctx: ctx,
+ bucket: b,
+ }
+ it.pageInfo, it.nextFunc = iterator.NewPageInfo(
+ it.fetch,
+ func() int { return len(it.items) },
+ func() interface{} { b := it.items; it.items = nil; return b })
+ if q != nil {
+ it.query = *q
+ }
+ return it
+}
+
+// An ObjectIterator is an iterator over ObjectAttrs.
+type ObjectIterator struct {
+ ctx context.Context
+ bucket *BucketHandle
+ query Query
+ pageInfo *iterator.PageInfo
+ nextFunc func() error
+ items []*ObjectAttrs
+}
+
+// PageInfo supports pagination. See the google.golang.org/api/iterator package for details.
+func (it *ObjectIterator) PageInfo() *iterator.PageInfo { return it.pageInfo }
+
+// Next returns the next result. Its second return value is iterator.Done if
+// there are no more results. Once Next returns iterator.Done, all subsequent
+// calls will return iterator.Done.
+//
+// If Query.Delimiter is non-empty, some of the ObjectAttrs returned by Next will
+// have a non-empty Prefix field, and a zero value for all other fields. These
+// represent prefixes.
+func (it *ObjectIterator) Next() (*ObjectAttrs, error) {
+ if err := it.nextFunc(); err != nil {
+ return nil, err
+ }
+ item := it.items[0]
+ it.items = it.items[1:]
+ return item, nil
+}
+
+func (it *ObjectIterator) fetch(pageSize int, pageToken string) (string, error) {
+ req := it.bucket.c.raw.Objects.List(it.bucket.name)
+ setClientHeader(req.Header())
+ req.Projection("full")
+ req.Delimiter(it.query.Delimiter)
+ req.Prefix(it.query.Prefix)
+ req.Versions(it.query.Versions)
+ req.PageToken(pageToken)
+ if it.bucket.userProject != "" {
+ req.UserProject(it.bucket.userProject)
+ }
+ if pageSize > 0 {
+ req.MaxResults(int64(pageSize))
+ }
+ var resp *raw.Objects
+ var err error
+ err = runWithRetry(it.ctx, func() error {
+ resp, err = req.Context(it.ctx).Do()
+ return err
+ })
+ if err != nil {
+ if e, ok := err.(*googleapi.Error); ok && e.Code == http.StatusNotFound {
+ err = ErrBucketNotExist
+ }
+ return "", err
+ }
+ for _, item := range resp.Items {
+ it.items = append(it.items, newObject(item))
+ }
+ for _, prefix := range resp.Prefixes {
+ it.items = append(it.items, &ObjectAttrs{Prefix: prefix})
+ }
+ return resp.NextPageToken, nil
+}
+
+// Buckets returns an iterator over the buckets in the project. You may
+// optionally set the iterator's Prefix field to restrict the list to buckets
+// whose names begin with the prefix. By default, all buckets in the project
+// are returned.
+func (c *Client) Buckets(ctx context.Context, projectID string) *BucketIterator {
+ it := &BucketIterator{
+ ctx: ctx,
+ client: c,
+ projectID: projectID,
+ }
+ it.pageInfo, it.nextFunc = iterator.NewPageInfo(
+ it.fetch,
+ func() int { return len(it.buckets) },
+ func() interface{} { b := it.buckets; it.buckets = nil; return b })
+ return it
+}
+
+// A BucketIterator is an iterator over BucketAttrs.
+type BucketIterator struct {
+ // Prefix restricts the iterator to buckets whose names begin with it.
+ Prefix string
+
+ ctx context.Context
+ client *Client
+ projectID string
+ buckets []*BucketAttrs
+ pageInfo *iterator.PageInfo
+ nextFunc func() error
+}
+
+// Next returns the next result. Its second return value is iterator.Done if
+// there are no more results. Once Next returns iterator.Done, all subsequent
+// calls will return iterator.Done.
+func (it *BucketIterator) Next() (*BucketAttrs, error) {
+ if err := it.nextFunc(); err != nil {
+ return nil, err
+ }
+ b := it.buckets[0]
+ it.buckets = it.buckets[1:]
+ return b, nil
+}
+
+// PageInfo supports pagination. See the google.golang.org/api/iterator package for details.
+func (it *BucketIterator) PageInfo() *iterator.PageInfo { return it.pageInfo }
+
+func (it *BucketIterator) fetch(pageSize int, pageToken string) (token string, err error) {
+ req := it.client.raw.Buckets.List(it.projectID)
+ setClientHeader(req.Header())
+ req.Projection("full")
+ req.Prefix(it.Prefix)
+ req.PageToken(pageToken)
+ if pageSize > 0 {
+ req.MaxResults(int64(pageSize))
+ }
+ var resp *raw.Buckets
+ err = runWithRetry(it.ctx, func() error {
+ resp, err = req.Context(it.ctx).Do()
+ return err
+ })
+ if err != nil {
+ return "", err
+ }
+ for _, item := range resp.Items {
+ b, err := newBucket(item)
+ if err != nil {
+ return "", err
+ }
+ it.buckets = append(it.buckets, b)
+ }
+ return resp.NextPageToken, nil
+}