mirror of
https://github.com/distribution/distribution.git
synced 2025-09-09 02:40:00 +00:00
Bump google storage module
Also bump the golangci version Signed-off-by: Milos Gajdos <milosthegajdos@gmail.com>
This commit is contained in:
382
vendor/cloud.google.com/go/storage/storage.go
generated
vendored
382
vendor/cloud.google.com/go/storage/storage.go
generated
vendored
@@ -41,7 +41,7 @@ import (
|
||||
"cloud.google.com/go/internal/optional"
|
||||
"cloud.google.com/go/internal/trace"
|
||||
"cloud.google.com/go/storage/internal"
|
||||
storagepb "cloud.google.com/go/storage/internal/apiv2/stubs"
|
||||
"cloud.google.com/go/storage/internal/apiv2/storagepb"
|
||||
"github.com/googleapis/gax-go/v2"
|
||||
"golang.org/x/oauth2/google"
|
||||
"google.golang.org/api/googleapi"
|
||||
@@ -109,21 +109,17 @@ type Client struct {
|
||||
raw *raw.Service
|
||||
// Scheme describes the scheme under the current host.
|
||||
scheme string
|
||||
// ReadHost is the default host used on the reader.
|
||||
readHost string
|
||||
// xmlHost is the default host used for XML requests.
|
||||
xmlHost string
|
||||
// May be nil.
|
||||
creds *google.Credentials
|
||||
retry *retryConfig
|
||||
|
||||
// tc is the transport-agnostic client implemented with either gRPC or HTTP.
|
||||
tc storageClient
|
||||
// useGRPC flags whether the client uses gRPC. This is needed while the
|
||||
// integration piece is only partially complete.
|
||||
// TODO: remove before merging to main.
|
||||
useGRPC bool
|
||||
}
|
||||
|
||||
// NewClient creates a new Google Cloud Storage client.
|
||||
// NewClient creates a new Google Cloud Storage client using the HTTP transport.
|
||||
// The default scope is ScopeFullControl. To use a different scope, like
|
||||
// ScopeReadOnly, use option.WithScopes.
|
||||
//
|
||||
@@ -133,12 +129,6 @@ type Client struct {
|
||||
// You may configure the client by passing in options from the [google.golang.org/api/option]
|
||||
// package. You may also use options defined in this package, such as [WithJSONReads].
|
||||
func NewClient(ctx context.Context, opts ...option.ClientOption) (*Client, error) {
|
||||
// Use the experimental gRPC client if the env var is set.
|
||||
// This is an experimental API and not intended for public use.
|
||||
if withGRPC := os.Getenv("STORAGE_USE_GRPC"); withGRPC != "" {
|
||||
return newGRPCClient(ctx, opts...)
|
||||
}
|
||||
|
||||
var creds *google.Credentials
|
||||
|
||||
// In general, it is recommended to use raw.NewService instead of htransport.NewClient
|
||||
@@ -152,8 +142,10 @@ func NewClient(ctx context.Context, opts ...option.ClientOption) (*Client, error
|
||||
// Prepend default options to avoid overriding options passed by the user.
|
||||
opts = append([]option.ClientOption{option.WithScopes(ScopeFullControl, "https://www.googleapis.com/auth/cloud-platform"), option.WithUserAgent(userAgent)}, opts...)
|
||||
|
||||
opts = append(opts, internaloption.WithDefaultEndpoint("https://storage.googleapis.com/storage/v1/"))
|
||||
opts = append(opts, internaloption.WithDefaultMTLSEndpoint("https://storage.mtls.googleapis.com/storage/v1/"))
|
||||
opts = append(opts, internaloption.WithDefaultEndpointTemplate("https://storage.UNIVERSE_DOMAIN/storage/v1/"),
|
||||
internaloption.WithDefaultMTLSEndpoint("https://storage.mtls.googleapis.com/storage/v1/"),
|
||||
internaloption.WithDefaultUniverseDomain("googleapis.com"),
|
||||
)
|
||||
|
||||
// Don't error out here. The user may have passed in their own HTTP
|
||||
// client which does not auth with ADC or other common conventions.
|
||||
@@ -184,12 +176,12 @@ func NewClient(ctx context.Context, opts ...option.ClientOption) (*Client, error
|
||||
opts = append([]option.ClientOption{
|
||||
option.WithoutAuthentication(),
|
||||
internaloption.SkipDialSettingsValidation(),
|
||||
internaloption.WithDefaultEndpoint(endpoint),
|
||||
internaloption.WithDefaultEndpointTemplate(endpoint),
|
||||
internaloption.WithDefaultMTLSEndpoint(endpoint),
|
||||
}, opts...)
|
||||
}
|
||||
|
||||
// htransport selects the correct endpoint among WithEndpoint (user override), WithDefaultEndpoint, and WithDefaultMTLSEndpoint.
|
||||
// htransport selects the correct endpoint among WithEndpoint (user override), WithDefaultEndpointTemplate, and WithDefaultMTLSEndpoint.
|
||||
hc, ep, err := htransport.NewClient(ctx, opts...)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("dialing: %w", err)
|
||||
@@ -199,7 +191,7 @@ func NewClient(ctx context.Context, opts ...option.ClientOption) (*Client, error
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("storage client: %w", err)
|
||||
}
|
||||
// Update readHost and scheme with the chosen endpoint.
|
||||
// Update xmlHost and scheme with the chosen endpoint.
|
||||
u, err := url.Parse(ep)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("supplied endpoint %q is not valid: %w", ep, err)
|
||||
@@ -211,27 +203,34 @@ func NewClient(ctx context.Context, opts ...option.ClientOption) (*Client, error
|
||||
}
|
||||
|
||||
return &Client{
|
||||
hc: hc,
|
||||
raw: rawService,
|
||||
scheme: u.Scheme,
|
||||
readHost: u.Host,
|
||||
creds: creds,
|
||||
tc: tc,
|
||||
hc: hc,
|
||||
raw: rawService,
|
||||
scheme: u.Scheme,
|
||||
xmlHost: u.Host,
|
||||
creds: creds,
|
||||
tc: tc,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// newGRPCClient creates a new Storage client that initializes a gRPC-based
|
||||
// client. Calls that have not been implemented in gRPC will panic.
|
||||
// NewGRPCClient creates a new Storage client using the gRPC transport and API.
|
||||
// Client methods which have not been implemented in gRPC will return an error.
|
||||
// In particular, methods for Cloud Pub/Sub notifications, Service Account HMAC
|
||||
// keys, and ServiceAccount are not supported.
|
||||
// Using a non-default universe domain is also not supported with the Storage
|
||||
// gRPC client.
|
||||
//
|
||||
// This is an experimental API and not intended for public use.
|
||||
func newGRPCClient(ctx context.Context, opts ...option.ClientOption) (*Client, error) {
|
||||
opts = append(defaultGRPCOptions(), opts...)
|
||||
// Clients should be reused instead of created as needed. The methods of Client
|
||||
// are safe for concurrent use by multiple goroutines.
|
||||
//
|
||||
// You may configure the client by passing in options from the [google.golang.org/api/option]
|
||||
// package.
|
||||
func NewGRPCClient(ctx context.Context, opts ...option.ClientOption) (*Client, error) {
|
||||
tc, err := newGRPCStorageClient(ctx, withClientOptions(opts...))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &Client{tc: tc, useGRPC: true}, nil
|
||||
return &Client{tc: tc}, nil
|
||||
}
|
||||
|
||||
// Close closes the Client.
|
||||
@@ -262,13 +261,13 @@ const (
|
||||
SigningSchemeV4
|
||||
)
|
||||
|
||||
// URLStyle determines the style to use for the signed URL. pathStyle is the
|
||||
// URLStyle determines the style to use for the signed URL. PathStyle is the
|
||||
// default. All non-default options work with V4 scheme only. See
|
||||
// https://cloud.google.com/storage/docs/request-endpoints for details.
|
||||
type URLStyle interface {
|
||||
// host should return the host portion of the signed URL, not including
|
||||
// the scheme (e.g. storage.googleapis.com).
|
||||
host(bucket string) string
|
||||
host(hostname, bucket string) string
|
||||
|
||||
// path should return the path portion of the signed URL, which may include
|
||||
// both the bucket and object name or only the object name depending on the
|
||||
@@ -284,7 +283,11 @@ type bucketBoundHostname struct {
|
||||
hostname string
|
||||
}
|
||||
|
||||
func (s pathStyle) host(bucket string) string {
|
||||
func (s pathStyle) host(hostname, bucket string) string {
|
||||
if hostname != "" {
|
||||
return stripScheme(hostname)
|
||||
}
|
||||
|
||||
if host := os.Getenv("STORAGE_EMULATOR_HOST"); host != "" {
|
||||
return stripScheme(host)
|
||||
}
|
||||
@@ -292,7 +295,11 @@ func (s pathStyle) host(bucket string) string {
|
||||
return "storage.googleapis.com"
|
||||
}
|
||||
|
||||
func (s virtualHostedStyle) host(bucket string) string {
|
||||
func (s virtualHostedStyle) host(hostname, bucket string) string {
|
||||
if hostname != "" {
|
||||
return bucket + "." + stripScheme(hostname)
|
||||
}
|
||||
|
||||
if host := os.Getenv("STORAGE_EMULATOR_HOST"); host != "" {
|
||||
return bucket + "." + stripScheme(host)
|
||||
}
|
||||
@@ -300,7 +307,7 @@ func (s virtualHostedStyle) host(bucket string) string {
|
||||
return bucket + ".storage.googleapis.com"
|
||||
}
|
||||
|
||||
func (s bucketBoundHostname) host(bucket string) string {
|
||||
func (s bucketBoundHostname) host(_, bucket string) string {
|
||||
return s.hostname
|
||||
}
|
||||
|
||||
@@ -321,7 +328,10 @@ func (s bucketBoundHostname) path(bucket, object string) string {
|
||||
}
|
||||
|
||||
// PathStyle is the default style, and will generate a URL of the form
|
||||
// "storage.googleapis.com/<bucket-name>/<object-name>".
|
||||
// "<host-name>/<bucket-name>/<object-name>". By default, <host-name> is
|
||||
// storage.googleapis.com, but setting an endpoint on the storage Client or
|
||||
// through STORAGE_EMULATOR_HOST overrides this. Setting Hostname on
|
||||
// SignedURLOptions or PostPolicyV4Options overrides everything else.
|
||||
func PathStyle() URLStyle {
|
||||
return pathStyle{}
|
||||
}
|
||||
@@ -442,6 +452,12 @@ type SignedURLOptions struct {
|
||||
// Scheme determines the version of URL signing to use. Default is
|
||||
// SigningSchemeV2.
|
||||
Scheme SigningScheme
|
||||
|
||||
// Hostname sets the host of the signed URL. This field overrides any
|
||||
// endpoint set on a storage Client or through STORAGE_EMULATOR_HOST.
|
||||
// Only compatible with PathStyle and VirtualHostedStyle URLStyles.
|
||||
// Optional.
|
||||
Hostname string
|
||||
}
|
||||
|
||||
func (opts *SignedURLOptions) clone() *SignedURLOptions {
|
||||
@@ -458,6 +474,7 @@ func (opts *SignedURLOptions) clone() *SignedURLOptions {
|
||||
Style: opts.Style,
|
||||
Insecure: opts.Insecure,
|
||||
Scheme: opts.Scheme,
|
||||
Hostname: opts.Hostname,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -716,7 +733,7 @@ func signedURLV4(bucket, name string, opts *SignedURLOptions, now time.Time) (st
|
||||
fmt.Fprintf(buf, "%s\n", escapedQuery)
|
||||
|
||||
// Fill in the hostname based on the desired URL style.
|
||||
u.Host = opts.Style.host(bucket)
|
||||
u.Host = opts.Style.host(opts.Hostname, bucket)
|
||||
|
||||
// Fill in the URL scheme.
|
||||
if opts.Insecure {
|
||||
@@ -726,7 +743,7 @@ func signedURLV4(bucket, name string, opts *SignedURLOptions, now time.Time) (st
|
||||
}
|
||||
|
||||
var headersWithValue []string
|
||||
headersWithValue = append(headersWithValue, "host:"+u.Host)
|
||||
headersWithValue = append(headersWithValue, "host:"+u.Hostname())
|
||||
headersWithValue = append(headersWithValue, opts.Headers...)
|
||||
if opts.ContentType != "" {
|
||||
headersWithValue = append(headersWithValue, "content-type:"+opts.ContentType)
|
||||
@@ -850,7 +867,7 @@ func signedURLV2(bucket, name string, opts *SignedURLOptions) (string, error) {
|
||||
}
|
||||
encoded := base64.StdEncoding.EncodeToString(b)
|
||||
u.Scheme = "https"
|
||||
u.Host = PathStyle().host(bucket)
|
||||
u.Host = PathStyle().host(opts.Hostname, bucket)
|
||||
q := u.Query()
|
||||
q.Set("GoogleAccessId", opts.GoogleAccessID)
|
||||
q.Set("Expires", fmt.Sprintf("%d", opts.Expires.Unix()))
|
||||
@@ -862,16 +879,18 @@ func signedURLV2(bucket, name string, opts *SignedURLOptions) (string, error) {
|
||||
// ObjectHandle provides operations on an object in a Google Cloud Storage bucket.
|
||||
// Use BucketHandle.Object to get a handle.
|
||||
type ObjectHandle struct {
|
||||
c *Client
|
||||
bucket string
|
||||
object string
|
||||
acl ACLHandle
|
||||
gen int64 // a negative value indicates latest
|
||||
conds *Conditions
|
||||
encryptionKey []byte // AES-256 key
|
||||
userProject string // for requester-pays buckets
|
||||
readCompressed bool // Accept-Encoding: gzip
|
||||
retry *retryConfig
|
||||
c *Client
|
||||
bucket string
|
||||
object string
|
||||
acl ACLHandle
|
||||
gen int64 // a negative value indicates latest
|
||||
conds *Conditions
|
||||
encryptionKey []byte // AES-256 key
|
||||
userProject string // for requester-pays buckets
|
||||
readCompressed bool // Accept-Encoding: gzip
|
||||
retry *retryConfig
|
||||
overrideRetention *bool
|
||||
softDeleted bool
|
||||
}
|
||||
|
||||
// ACL provides access to the object's access control list.
|
||||
@@ -893,7 +912,9 @@ func (o *ObjectHandle) Generation(gen int64) *ObjectHandle {
|
||||
}
|
||||
|
||||
// If returns a new ObjectHandle that applies a set of preconditions.
|
||||
// Preconditions already set on the ObjectHandle are ignored.
|
||||
// Preconditions already set on the ObjectHandle are ignored. The supplied
|
||||
// Conditions must have at least one field set to a non-default value;
|
||||
// otherwise an error will be returned from any operation on the ObjectHandle.
|
||||
// Operations on the new handle will return an error if the preconditions are not
|
||||
// satisfied. See https://cloud.google.com/storage/docs/generations-preconditions
|
||||
// for more details.
|
||||
@@ -924,7 +945,7 @@ func (o *ObjectHandle) Attrs(ctx context.Context) (attrs *ObjectAttrs, err error
|
||||
return nil, err
|
||||
}
|
||||
opts := makeStorageOpts(true, o.retry, o.userProject)
|
||||
return o.c.tc.GetObject(ctx, o.bucket, o.object, o.gen, o.encryptionKey, o.conds, opts...)
|
||||
return o.c.tc.GetObject(ctx, &getObjectParams{o.bucket, o.object, o.gen, o.encryptionKey, o.conds, o.softDeleted}, opts...)
|
||||
}
|
||||
|
||||
// Update updates an object with the provided attributes. See
|
||||
@@ -939,7 +960,16 @@ func (o *ObjectHandle) Update(ctx context.Context, uattrs ObjectAttrsToUpdate) (
|
||||
}
|
||||
isIdempotent := o.conds != nil && o.conds.MetagenerationMatch != 0
|
||||
opts := makeStorageOpts(isIdempotent, o.retry, o.userProject)
|
||||
return o.c.tc.UpdateObject(ctx, o.bucket, o.object, &uattrs, o.gen, o.encryptionKey, o.conds, opts...)
|
||||
return o.c.tc.UpdateObject(ctx,
|
||||
&updateObjectParams{
|
||||
bucket: o.bucket,
|
||||
object: o.object,
|
||||
uattrs: &uattrs,
|
||||
gen: o.gen,
|
||||
encryptionKey: o.encryptionKey,
|
||||
conds: o.conds,
|
||||
overrideRetention: o.overrideRetention,
|
||||
}, opts...)
|
||||
}
|
||||
|
||||
// BucketName returns the name of the bucket.
|
||||
@@ -954,16 +984,19 @@ func (o *ObjectHandle) ObjectName() string {
|
||||
|
||||
// ObjectAttrsToUpdate is used to update the attributes of an object.
|
||||
// Only fields set to non-nil values will be updated.
|
||||
// For all fields except CustomTime, set the field to its zero value to delete
|
||||
// it. CustomTime cannot be deleted or changed to an earlier time once set.
|
||||
// For all fields except CustomTime and Retention, set the field to its zero
|
||||
// value to delete it. CustomTime cannot be deleted or changed to an earlier
|
||||
// time once set. Retention can be deleted (only if the Mode is Unlocked) by
|
||||
// setting it to an empty value (not nil).
|
||||
//
|
||||
// For example, to change ContentType and delete ContentEncoding and
|
||||
// Metadata, use
|
||||
// For example, to change ContentType and delete ContentEncoding, Metadata and
|
||||
// Retention, use:
|
||||
//
|
||||
// ObjectAttrsToUpdate{
|
||||
// ContentType: "text/html",
|
||||
// ContentEncoding: "",
|
||||
// Metadata: map[string]string{},
|
||||
// Retention: &ObjectRetention{},
|
||||
// }
|
||||
type ObjectAttrsToUpdate struct {
|
||||
EventBasedHold optional.Bool
|
||||
@@ -980,6 +1013,12 @@ type ObjectAttrsToUpdate struct {
|
||||
// If not empty, applies a predefined set of access controls. ACL must be nil.
|
||||
// See https://cloud.google.com/storage/docs/json_api/v1/objects/patch.
|
||||
PredefinedACL string
|
||||
|
||||
// Retention contains the retention configuration for this object.
|
||||
// Operations other than setting the retention for the first time or
|
||||
// extending the RetainUntil time on the object retention must be done
|
||||
// on an ObjectHandle with OverrideUnlockedRetention set to true.
|
||||
Retention *ObjectRetention
|
||||
}
|
||||
|
||||
// Delete deletes the single specified object.
|
||||
@@ -1001,6 +1040,61 @@ func (o *ObjectHandle) ReadCompressed(compressed bool) *ObjectHandle {
|
||||
return &o2
|
||||
}
|
||||
|
||||
// OverrideUnlockedRetention provides an option for overriding an Unlocked
|
||||
// Retention policy. This must be set to true in order to change a policy
|
||||
// from Unlocked to Locked, to set it to null, or to reduce its
|
||||
// RetainUntil attribute. It is not required for setting the ObjectRetention for
|
||||
// the first time nor for extending the RetainUntil time.
|
||||
func (o *ObjectHandle) OverrideUnlockedRetention(override bool) *ObjectHandle {
|
||||
o2 := *o
|
||||
o2.overrideRetention = &override
|
||||
return &o2
|
||||
}
|
||||
|
||||
// SoftDeleted returns an object handle that can be used to get an object that
|
||||
// has been soft deleted. To get a soft deleted object, the generation must be
|
||||
// set on the object using ObjectHandle.Generation.
|
||||
// Note that an error will be returned if a live object is queried using this.
|
||||
func (o *ObjectHandle) SoftDeleted() *ObjectHandle {
|
||||
o2 := *o
|
||||
o2.softDeleted = true
|
||||
return &o2
|
||||
}
|
||||
|
||||
// RestoreOptions allows you to set options when restoring an object.
|
||||
type RestoreOptions struct {
|
||||
/// CopySourceACL indicates whether the restored object should copy the
|
||||
// access controls of the source object. Only valid for buckets with
|
||||
// fine-grained access. If uniform bucket-level access is enabled, setting
|
||||
// CopySourceACL will cause an error.
|
||||
CopySourceACL bool
|
||||
}
|
||||
|
||||
// Restore will restore a soft-deleted object to a live object.
|
||||
// Note that you must specify a generation to use this method.
|
||||
func (o *ObjectHandle) Restore(ctx context.Context, opts *RestoreOptions) (*ObjectAttrs, error) {
|
||||
if err := o.validate(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Since the generation is required by restore calls, we set the default to
|
||||
// 0 instead of a negative value, which returns a more descriptive error.
|
||||
gen := o.gen
|
||||
if o.gen == defaultGen {
|
||||
gen = 0
|
||||
}
|
||||
|
||||
// Restore is always idempotent because Generation is a required param.
|
||||
sOpts := makeStorageOpts(true, o.retry, o.userProject)
|
||||
return o.c.tc.RestoreObject(ctx, &restoreObjectParams{
|
||||
bucket: o.bucket,
|
||||
object: o.object,
|
||||
gen: gen,
|
||||
conds: o.conds,
|
||||
copySourceACL: opts.CopySourceACL,
|
||||
}, sOpts...)
|
||||
}
|
||||
|
||||
// NewWriter returns a storage Writer that writes to the GCS object
|
||||
// associated with this ObjectHandle.
|
||||
//
|
||||
@@ -1020,6 +1114,7 @@ func (o *ObjectHandle) ReadCompressed(compressed bool) *ObjectHandle {
|
||||
// It is the caller's responsibility to call Close when writing is done. To
|
||||
// stop writing without saving the data, cancel the context.
|
||||
func (o *ObjectHandle) NewWriter(ctx context.Context) *Writer {
|
||||
ctx = trace.StartSpan(ctx, "cloud.google.com/go/storage.Object.Writer")
|
||||
return &Writer{
|
||||
ctx: ctx,
|
||||
o: o,
|
||||
@@ -1039,6 +1134,10 @@ func (o *ObjectHandle) validate() error {
|
||||
if !utf8.ValidString(o.object) {
|
||||
return fmt.Errorf("storage: object name %q is not valid UTF-8", o.object)
|
||||
}
|
||||
// Names . and .. are not valid; see https://cloud.google.com/storage/docs/objects#naming
|
||||
if o.object == "." || o.object == ".." {
|
||||
return fmt.Errorf("storage: object name %q is not valid", o.object)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -1089,6 +1188,7 @@ func (o *ObjectAttrs) toRawObject(bucket string) *raw.Object {
|
||||
Acl: toRawObjectACL(o.ACL),
|
||||
Metadata: o.Metadata,
|
||||
CustomTime: ct,
|
||||
Retention: o.Retention.toRawObjectRetention(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1163,7 +1263,7 @@ func (uattrs *ObjectAttrsToUpdate) toProtoObject(bucket, object string) *storage
|
||||
o.Acl = toProtoObjectACL(uattrs.ACL)
|
||||
}
|
||||
|
||||
// TODO(cathyo): Handle metadata. Pending b/230510191.
|
||||
o.Metadata = uattrs.Metadata
|
||||
|
||||
return o
|
||||
}
|
||||
@@ -1324,6 +1424,57 @@ type ObjectAttrs struct {
|
||||
// For non-composite objects, the value will be zero.
|
||||
// This field is read-only.
|
||||
ComponentCount int64
|
||||
|
||||
// Retention contains the retention configuration for this object.
|
||||
// ObjectRetention cannot be configured or reported through the gRPC API.
|
||||
Retention *ObjectRetention
|
||||
|
||||
// SoftDeleteTime is the time when the object became soft-deleted.
|
||||
// Soft-deleted objects are only accessible on an object handle returned by
|
||||
// ObjectHandle.SoftDeleted; if ObjectHandle.SoftDeleted has not been set,
|
||||
// ObjectHandle.Attrs will return ErrObjectNotExist if the object is soft-deleted.
|
||||
// This field is read-only.
|
||||
SoftDeleteTime time.Time
|
||||
|
||||
// HardDeleteTime is the time when the object will be permanently deleted.
|
||||
// Only set when an object becomes soft-deleted with a soft delete policy.
|
||||
// Soft-deleted objects are only accessible on an object handle returned by
|
||||
// ObjectHandle.SoftDeleted; if ObjectHandle.SoftDeleted has not been set,
|
||||
// ObjectHandle.Attrs will return ErrObjectNotExist if the object is soft-deleted.
|
||||
// This field is read-only.
|
||||
HardDeleteTime time.Time
|
||||
}
|
||||
|
||||
// ObjectRetention contains the retention configuration for this object.
|
||||
type ObjectRetention struct {
|
||||
// Mode is the retention policy's mode on this object. Valid values are
|
||||
// "Locked" and "Unlocked".
|
||||
// Locked retention policies cannot be changed. Unlocked policies require an
|
||||
// override to change.
|
||||
Mode string
|
||||
|
||||
// RetainUntil is the time this object will be retained until.
|
||||
RetainUntil time.Time
|
||||
}
|
||||
|
||||
func (r *ObjectRetention) toRawObjectRetention() *raw.ObjectRetention {
|
||||
if r == nil {
|
||||
return nil
|
||||
}
|
||||
return &raw.ObjectRetention{
|
||||
Mode: r.Mode,
|
||||
RetainUntilTime: r.RetainUntil.Format(time.RFC3339),
|
||||
}
|
||||
}
|
||||
|
||||
func toObjectRetention(r *raw.ObjectRetention) *ObjectRetention {
|
||||
if r == nil {
|
||||
return nil
|
||||
}
|
||||
return &ObjectRetention{
|
||||
Mode: r.Mode,
|
||||
RetainUntil: convertTime(r.RetainUntilTime),
|
||||
}
|
||||
}
|
||||
|
||||
// convertTime converts a time in RFC3339 format to time.Time.
|
||||
@@ -1395,6 +1546,9 @@ func newObject(o *raw.Object) *ObjectAttrs {
|
||||
Etag: o.Etag,
|
||||
CustomTime: convertTime(o.CustomTime),
|
||||
ComponentCount: o.ComponentCount,
|
||||
Retention: toObjectRetention(o.Retention),
|
||||
SoftDeleteTime: convertTime(o.SoftDeleteTime),
|
||||
HardDeleteTime: convertTime(o.HardDeleteTime),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1430,6 +1584,8 @@ func newObjectFromProto(o *storagepb.Object) *ObjectAttrs {
|
||||
Updated: convertProtoTime(o.GetUpdateTime()),
|
||||
CustomTime: convertProtoTime(o.GetCustomTime()),
|
||||
ComponentCount: int64(o.ComponentCount),
|
||||
SoftDeleteTime: convertProtoTime(o.GetSoftDeleteTime()),
|
||||
HardDeleteTime: convertProtoTime(o.GetHardDeleteTime()),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1484,6 +1640,8 @@ type Query struct {
|
||||
// aside from the prefix, contain delimiter will have their name,
|
||||
// truncated after the delimiter, returned in prefixes.
|
||||
// Duplicate prefixes are omitted.
|
||||
// Must be set to / when used with the MatchGlob parameter to filter results
|
||||
// in a directory-like mode.
|
||||
// Optional.
|
||||
Delimiter string
|
||||
|
||||
@@ -1497,9 +1655,9 @@ type Query struct {
|
||||
Versions bool
|
||||
|
||||
// attrSelection is used to select only specific fields to be returned by
|
||||
// the query. It is set by the user calling calling SetAttrSelection. These
|
||||
// the query. It is set by the user calling SetAttrSelection. These
|
||||
// are used by toFieldMask and toFieldSelection for gRPC and HTTP/JSON
|
||||
// clients repsectively.
|
||||
// clients respectively.
|
||||
attrSelection []string
|
||||
|
||||
// StartOffset is used to filter results to objects whose names are
|
||||
@@ -1525,6 +1683,21 @@ type Query struct {
|
||||
// true, they will also be included as objects and their metadata will be
|
||||
// populated in the returned ObjectAttrs.
|
||||
IncludeTrailingDelimiter bool
|
||||
|
||||
// MatchGlob is a glob pattern used to filter results (for example, foo*bar). See
|
||||
// https://cloud.google.com/storage/docs/json_api/v1/objects/list#list-object-glob
|
||||
// for syntax details. When Delimiter is set in conjunction with MatchGlob,
|
||||
// it must be set to /.
|
||||
MatchGlob string
|
||||
|
||||
// IncludeFoldersAsPrefixes includes Folders and Managed Folders in the set of
|
||||
// prefixes returned by the query. Only applicable if Delimiter is set to /.
|
||||
IncludeFoldersAsPrefixes bool
|
||||
|
||||
// SoftDeleted indicates whether to list soft-deleted objects.
|
||||
// If true, only objects that have been soft-deleted will be listed.
|
||||
// By default, soft-deleted objects are not listed.
|
||||
SoftDeleted bool
|
||||
}
|
||||
|
||||
// attrToFieldMap maps the field names of ObjectAttrs to the underlying field
|
||||
@@ -1559,6 +1732,9 @@ var attrToFieldMap = map[string]string{
|
||||
"Etag": "etag",
|
||||
"CustomTime": "customTime",
|
||||
"ComponentCount": "componentCount",
|
||||
"Retention": "retention",
|
||||
"HardDeleteTime": "hardDeleteTime",
|
||||
"SoftDeleteTime": "softDeleteTime",
|
||||
}
|
||||
|
||||
// attrToProtoFieldMap maps the field names of ObjectAttrs to the underlying field
|
||||
@@ -1591,8 +1767,11 @@ var attrToProtoFieldMap = map[string]string{
|
||||
"CustomerKeySHA256": "customer_encryption",
|
||||
"CustomTime": "custom_time",
|
||||
"ComponentCount": "component_count",
|
||||
"HardDeleteTime": "hard_delete_time",
|
||||
"SoftDeleteTime": "soft_delete_time",
|
||||
// MediaLink was explicitly excluded from the proto as it is an HTTP-ism.
|
||||
// "MediaLink": "mediaLink",
|
||||
// TODO: add object retention - b/308194853
|
||||
}
|
||||
|
||||
// SetAttrSelection makes the query populate only specific attributes of
|
||||
@@ -1778,7 +1957,7 @@ func (c *Conditions) isMetagenerationValid() bool {
|
||||
func applyConds(method string, gen int64, conds *Conditions, call interface{}) error {
|
||||
cval := reflect.ValueOf(call)
|
||||
if gen >= 0 {
|
||||
if !setConditionField(cval, "Generation", gen) {
|
||||
if !setGeneration(cval, gen) {
|
||||
return fmt.Errorf("storage: %s: generation not supported", method)
|
||||
}
|
||||
}
|
||||
@@ -1790,25 +1969,25 @@ func applyConds(method string, gen int64, conds *Conditions, call interface{}) e
|
||||
}
|
||||
switch {
|
||||
case conds.GenerationMatch != 0:
|
||||
if !setConditionField(cval, "IfGenerationMatch", conds.GenerationMatch) {
|
||||
if !setIfGenerationMatch(cval, conds.GenerationMatch) {
|
||||
return fmt.Errorf("storage: %s: ifGenerationMatch not supported", method)
|
||||
}
|
||||
case conds.GenerationNotMatch != 0:
|
||||
if !setConditionField(cval, "IfGenerationNotMatch", conds.GenerationNotMatch) {
|
||||
if !setIfGenerationNotMatch(cval, conds.GenerationNotMatch) {
|
||||
return fmt.Errorf("storage: %s: ifGenerationNotMatch not supported", method)
|
||||
}
|
||||
case conds.DoesNotExist:
|
||||
if !setConditionField(cval, "IfGenerationMatch", int64(0)) {
|
||||
if !setIfGenerationMatch(cval, int64(0)) {
|
||||
return fmt.Errorf("storage: %s: DoesNotExist not supported", method)
|
||||
}
|
||||
}
|
||||
switch {
|
||||
case conds.MetagenerationMatch != 0:
|
||||
if !setConditionField(cval, "IfMetagenerationMatch", conds.MetagenerationMatch) {
|
||||
if !setIfMetagenerationMatch(cval, conds.MetagenerationMatch) {
|
||||
return fmt.Errorf("storage: %s: ifMetagenerationMatch not supported", method)
|
||||
}
|
||||
case conds.MetagenerationNotMatch != 0:
|
||||
if !setConditionField(cval, "IfMetagenerationNotMatch", conds.MetagenerationNotMatch) {
|
||||
if !setIfMetagenerationNotMatch(cval, conds.MetagenerationNotMatch) {
|
||||
return fmt.Errorf("storage: %s: ifMetagenerationNotMatch not supported", method)
|
||||
}
|
||||
}
|
||||
@@ -1869,16 +2048,45 @@ func applySourceCondsProto(gen int64, conds *Conditions, call *storagepb.Rewrite
|
||||
return nil
|
||||
}
|
||||
|
||||
// setConditionField sets a field on a *raw.WhateverCall.
|
||||
// setGeneration sets Generation on a *raw.WhateverCall.
|
||||
// We can't use anonymous interfaces because the return type is
|
||||
// different, since the field setters are builders.
|
||||
func setConditionField(call reflect.Value, name string, value interface{}) bool {
|
||||
m := call.MethodByName(name)
|
||||
if !m.IsValid() {
|
||||
return false
|
||||
// We also make sure to supply a compile-time constant to MethodByName;
|
||||
// otherwise, the Go Linker will disable dead code elimination, leading
|
||||
// to larger binaries for all packages that import storage.
|
||||
func setGeneration(cval reflect.Value, value interface{}) bool {
|
||||
return setCondition(cval.MethodByName("Generation"), value)
|
||||
}
|
||||
|
||||
// setIfGenerationMatch sets IfGenerationMatch on a *raw.WhateverCall.
|
||||
// See also setGeneration.
|
||||
func setIfGenerationMatch(cval reflect.Value, value interface{}) bool {
|
||||
return setCondition(cval.MethodByName("IfGenerationMatch"), value)
|
||||
}
|
||||
|
||||
// setIfGenerationNotMatch sets IfGenerationNotMatch on a *raw.WhateverCall.
|
||||
// See also setGeneration.
|
||||
func setIfGenerationNotMatch(cval reflect.Value, value interface{}) bool {
|
||||
return setCondition(cval.MethodByName("IfGenerationNotMatch"), value)
|
||||
}
|
||||
|
||||
// setIfMetagenerationMatch sets IfMetagenerationMatch on a *raw.WhateverCall.
|
||||
// See also setGeneration.
|
||||
func setIfMetagenerationMatch(cval reflect.Value, value interface{}) bool {
|
||||
return setCondition(cval.MethodByName("IfMetagenerationMatch"), value)
|
||||
}
|
||||
|
||||
// setIfMetagenerationNotMatch sets IfMetagenerationNotMatch on a *raw.WhateverCall.
|
||||
// See also setGeneration.
|
||||
func setIfMetagenerationNotMatch(cval reflect.Value, value interface{}) bool {
|
||||
return setCondition(cval.MethodByName("IfMetagenerationNotMatch"), value)
|
||||
}
|
||||
|
||||
func setCondition(setter reflect.Value, value interface{}) bool {
|
||||
if setter.IsValid() {
|
||||
setter.Call([]reflect.Value{reflect.ValueOf(value)})
|
||||
}
|
||||
m.Call([]reflect.Value{reflect.ValueOf(value)})
|
||||
return true
|
||||
return setter.IsValid()
|
||||
}
|
||||
|
||||
// Retryer returns an object handle that is configured with custom retry
|
||||
@@ -1950,6 +2158,26 @@ func (wb *withBackoff) apply(config *retryConfig) {
|
||||
config.backoff = &wb.backoff
|
||||
}
|
||||
|
||||
// WithMaxAttempts configures the maximum number of times an API call can be made
|
||||
// in the case of retryable errors.
|
||||
// For example, if you set WithMaxAttempts(5), the operation will be attempted up to 5
|
||||
// times total (initial call plus 4 retries).
|
||||
// Without this setting, operations will continue retrying indefinitely
|
||||
// until either the context is canceled or a deadline is reached.
|
||||
func WithMaxAttempts(maxAttempts int) RetryOption {
|
||||
return &withMaxAttempts{
|
||||
maxAttempts: maxAttempts,
|
||||
}
|
||||
}
|
||||
|
||||
type withMaxAttempts struct {
|
||||
maxAttempts int
|
||||
}
|
||||
|
||||
func (wb *withMaxAttempts) apply(config *retryConfig) {
|
||||
config.maxAttempts = &wb.maxAttempts
|
||||
}
|
||||
|
||||
// RetryPolicy describes the available policies for which operations should be
|
||||
// retried. The default is `RetryIdempotent`.
|
||||
type RetryPolicy int
|
||||
@@ -2022,6 +2250,7 @@ type retryConfig struct {
|
||||
backoff *gax.Backoff
|
||||
policy RetryPolicy
|
||||
shouldRetry func(err error) bool
|
||||
maxAttempts *int
|
||||
}
|
||||
|
||||
func (r *retryConfig) clone() *retryConfig {
|
||||
@@ -2042,6 +2271,7 @@ func (r *retryConfig) clone() *retryConfig {
|
||||
backoff: bo,
|
||||
policy: r.policy,
|
||||
shouldRetry: r.shouldRetry,
|
||||
maxAttempts: r.maxAttempts,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2116,10 +2346,10 @@ func toProtoChecksums(sendCRC32C bool, attrs *ObjectAttrs) *storagepb.ObjectChec
|
||||
}
|
||||
|
||||
// ServiceAccount fetches the email address of the given project's Google Cloud Storage service account.
|
||||
// Note: gRPC is not supported.
|
||||
func (c *Client) ServiceAccount(ctx context.Context, projectID string) (string, error) {
|
||||
o := makeStorageOpts(true, c.retry, "")
|
||||
return c.tc.GetServiceAccount(ctx, projectID, o...)
|
||||
|
||||
}
|
||||
|
||||
// bucketResourceName formats the given project ID and bucketResourceName ID
|
||||
@@ -2162,8 +2392,6 @@ func toProjectResource(project string) string {
|
||||
|
||||
// setConditionProtoField uses protobuf reflection to set named condition field
|
||||
// to the given condition value if supported on the protobuf message.
|
||||
//
|
||||
// This is an experimental API and not intended for public use.
|
||||
func setConditionProtoField(m protoreflect.Message, f string, v int64) bool {
|
||||
fields := m.Descriptor().Fields()
|
||||
if rf := fields.ByName(protoreflect.Name(f)); rf != nil {
|
||||
@@ -2176,8 +2404,6 @@ func setConditionProtoField(m protoreflect.Message, f string, v int64) bool {
|
||||
|
||||
// applyCondsProto validates and attempts to set the conditions on a protobuf
|
||||
// message using protobuf reflection.
|
||||
//
|
||||
// This is an experimental API and not intended for public use.
|
||||
func applyCondsProto(method string, gen int64, conds *Conditions, msg proto.Message) error {
|
||||
rmsg := msg.ProtoReflect()
|
||||
|
||||
|
Reference in New Issue
Block a user