diff options
Diffstat (limited to 'vendor/cloud.google.com/go/storage/copy.go')
-rw-r--r-- | vendor/cloud.google.com/go/storage/copy.go | 228 |
1 files changed, 228 insertions, 0 deletions
diff --git a/vendor/cloud.google.com/go/storage/copy.go b/vendor/cloud.google.com/go/storage/copy.go new file mode 100644 index 0000000..52162e7 --- /dev/null +++ b/vendor/cloud.google.com/go/storage/copy.go | |||
@@ -0,0 +1,228 @@ | |||
1 | // Copyright 2016 Google LLC | ||
2 | // | ||
3 | // Licensed under the Apache License, Version 2.0 (the "License"); | ||
4 | // you may not use this file except in compliance with the License. | ||
5 | // You may obtain a copy of the License at | ||
6 | // | ||
7 | // http://www.apache.org/licenses/LICENSE-2.0 | ||
8 | // | ||
9 | // Unless required by applicable law or agreed to in writing, software | ||
10 | // distributed under the License is distributed on an "AS IS" BASIS, | ||
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
12 | // See the License for the specific language governing permissions and | ||
13 | // limitations under the License. | ||
14 | |||
15 | package storage | ||
16 | |||
17 | import ( | ||
18 | "context" | ||
19 | "errors" | ||
20 | "fmt" | ||
21 | |||
22 | "cloud.google.com/go/internal/trace" | ||
23 | raw "google.golang.org/api/storage/v1" | ||
24 | ) | ||
25 | |||
26 | // CopierFrom creates a Copier that can copy src to dst. | ||
27 | // You can immediately call Run on the returned Copier, or | ||
28 | // you can configure it first. | ||
29 | // | ||
30 | // For Requester Pays buckets, the user project of dst is billed, unless it is empty, | ||
31 | // in which case the user project of src is billed. | ||
32 | func (dst *ObjectHandle) CopierFrom(src *ObjectHandle) *Copier { | ||
33 | return &Copier{dst: dst, src: src} | ||
34 | } | ||
35 | |||
36 | // A Copier copies a source object to a destination. | ||
37 | type Copier struct { | ||
38 | // ObjectAttrs are optional attributes to set on the destination object. | ||
39 | // Any attributes must be initialized before any calls on the Copier. Nil | ||
40 | // or zero-valued attributes are ignored. | ||
41 | ObjectAttrs | ||
42 | |||
43 | // RewriteToken can be set before calling Run to resume a copy | ||
44 | // operation. After Run returns a non-nil error, RewriteToken will | ||
45 | // have been updated to contain the value needed to resume the copy. | ||
46 | RewriteToken string | ||
47 | |||
48 | // ProgressFunc can be used to monitor the progress of a multi-RPC copy | ||
49 | // operation. If ProgressFunc is not nil and copying requires multiple | ||
50 | // calls to the underlying service (see | ||
51 | // https://cloud.google.com/storage/docs/json_api/v1/objects/rewrite), then | ||
52 | // ProgressFunc will be invoked after each call with the number of bytes of | ||
53 | // content copied so far and the total size in bytes of the source object. | ||
54 | // | ||
55 | // ProgressFunc is intended to make upload progress available to the | ||
56 | // application. For example, the implementation of ProgressFunc may update | ||
57 | // a progress bar in the application's UI, or log the result of | ||
58 | // float64(copiedBytes)/float64(totalBytes). | ||
59 | // | ||
60 | // ProgressFunc should return quickly without blocking. | ||
61 | ProgressFunc func(copiedBytes, totalBytes uint64) | ||
62 | |||
63 | // The Cloud KMS key, in the form projects/P/locations/L/keyRings/R/cryptoKeys/K, | ||
64 | // that will be used to encrypt the object. Overrides the object's KMSKeyName, if | ||
65 | // any. | ||
66 | // | ||
67 | // Providing both a DestinationKMSKeyName and a customer-supplied encryption key | ||
68 | // (via ObjectHandle.Key) on the destination object will result in an error when | ||
69 | // Run is called. | ||
70 | DestinationKMSKeyName string | ||
71 | |||
72 | dst, src *ObjectHandle | ||
73 | } | ||
74 | |||
75 | // Run performs the copy. | ||
76 | func (c *Copier) Run(ctx context.Context) (attrs *ObjectAttrs, err error) { | ||
77 | ctx = trace.StartSpan(ctx, "cloud.google.com/go/storage.Copier.Run") | ||
78 | defer func() { trace.EndSpan(ctx, err) }() | ||
79 | |||
80 | if err := c.src.validate(); err != nil { | ||
81 | return nil, err | ||
82 | } | ||
83 | if err := c.dst.validate(); err != nil { | ||
84 | return nil, err | ||
85 | } | ||
86 | if c.DestinationKMSKeyName != "" && c.dst.encryptionKey != nil { | ||
87 | return nil, errors.New("storage: cannot use DestinationKMSKeyName with a customer-supplied encryption key") | ||
88 | } | ||
89 | // Convert destination attributes to raw form, omitting the bucket. | ||
90 | // If the bucket is included but name or content-type aren't, the service | ||
91 | // returns a 400 with "Required" as the only message. Omitting the bucket | ||
92 | // does not cause any problems. | ||
93 | rawObject := c.ObjectAttrs.toRawObject("") | ||
94 | for { | ||
95 | res, err := c.callRewrite(ctx, rawObject) | ||
96 | if err != nil { | ||
97 | return nil, err | ||
98 | } | ||
99 | if c.ProgressFunc != nil { | ||
100 | c.ProgressFunc(uint64(res.TotalBytesRewritten), uint64(res.ObjectSize)) | ||
101 | } | ||
102 | if res.Done { // Finished successfully. | ||
103 | return newObject(res.Resource), nil | ||
104 | } | ||
105 | } | ||
106 | } | ||
107 | |||
108 | func (c *Copier) callRewrite(ctx context.Context, rawObj *raw.Object) (*raw.RewriteResponse, error) { | ||
109 | call := c.dst.c.raw.Objects.Rewrite(c.src.bucket, c.src.object, c.dst.bucket, c.dst.object, rawObj) | ||
110 | |||
111 | call.Context(ctx).Projection("full") | ||
112 | if c.RewriteToken != "" { | ||
113 | call.RewriteToken(c.RewriteToken) | ||
114 | } | ||
115 | if c.DestinationKMSKeyName != "" { | ||
116 | call.DestinationKmsKeyName(c.DestinationKMSKeyName) | ||
117 | } | ||
118 | if c.PredefinedACL != "" { | ||
119 | call.DestinationPredefinedAcl(c.PredefinedACL) | ||
120 | } | ||
121 | if err := applyConds("Copy destination", c.dst.gen, c.dst.conds, call); err != nil { | ||
122 | return nil, err | ||
123 | } | ||
124 | if c.dst.userProject != "" { | ||
125 | call.UserProject(c.dst.userProject) | ||
126 | } else if c.src.userProject != "" { | ||
127 | call.UserProject(c.src.userProject) | ||
128 | } | ||
129 | if err := applySourceConds(c.src.gen, c.src.conds, call); err != nil { | ||
130 | return nil, err | ||
131 | } | ||
132 | if err := setEncryptionHeaders(call.Header(), c.dst.encryptionKey, false); err != nil { | ||
133 | return nil, err | ||
134 | } | ||
135 | if err := setEncryptionHeaders(call.Header(), c.src.encryptionKey, true); err != nil { | ||
136 | return nil, err | ||
137 | } | ||
138 | var res *raw.RewriteResponse | ||
139 | var err error | ||
140 | setClientHeader(call.Header()) | ||
141 | err = runWithRetry(ctx, func() error { res, err = call.Do(); return err }) | ||
142 | if err != nil { | ||
143 | return nil, err | ||
144 | } | ||
145 | c.RewriteToken = res.RewriteToken | ||
146 | return res, nil | ||
147 | } | ||
148 | |||
149 | // ComposerFrom creates a Composer that can compose srcs into dst. | ||
150 | // You can immediately call Run on the returned Composer, or you can | ||
151 | // configure it first. | ||
152 | // | ||
153 | // The encryption key for the destination object will be used to decrypt all | ||
154 | // source objects and encrypt the destination object. It is an error | ||
155 | // to specify an encryption key for any of the source objects. | ||
156 | func (dst *ObjectHandle) ComposerFrom(srcs ...*ObjectHandle) *Composer { | ||
157 | return &Composer{dst: dst, srcs: srcs} | ||
158 | } | ||
159 | |||
160 | // A Composer composes source objects into a destination object. | ||
161 | // | ||
162 | // For Requester Pays buckets, the user project of dst is billed. | ||
163 | type Composer struct { | ||
164 | // ObjectAttrs are optional attributes to set on the destination object. | ||
165 | // Any attributes must be initialized before any calls on the Composer. Nil | ||
166 | // or zero-valued attributes are ignored. | ||
167 | ObjectAttrs | ||
168 | |||
169 | dst *ObjectHandle | ||
170 | srcs []*ObjectHandle | ||
171 | } | ||
172 | |||
173 | // Run performs the compose operation. | ||
174 | func (c *Composer) Run(ctx context.Context) (attrs *ObjectAttrs, err error) { | ||
175 | ctx = trace.StartSpan(ctx, "cloud.google.com/go/storage.Composer.Run") | ||
176 | defer func() { trace.EndSpan(ctx, err) }() | ||
177 | |||
178 | if err := c.dst.validate(); err != nil { | ||
179 | return nil, err | ||
180 | } | ||
181 | if len(c.srcs) == 0 { | ||
182 | return nil, errors.New("storage: at least one source object must be specified") | ||
183 | } | ||
184 | |||
185 | req := &raw.ComposeRequest{} | ||
186 | // Compose requires a non-empty Destination, so we always set it, | ||
187 | // even if the caller-provided ObjectAttrs is the zero value. | ||
188 | req.Destination = c.ObjectAttrs.toRawObject(c.dst.bucket) | ||
189 | for _, src := range c.srcs { | ||
190 | if err := src.validate(); err != nil { | ||
191 | return nil, err | ||
192 | } | ||
193 | if src.bucket != c.dst.bucket { | ||
194 | return nil, fmt.Errorf("storage: all source objects must be in bucket %q, found %q", c.dst.bucket, src.bucket) | ||
195 | } | ||
196 | if src.encryptionKey != nil { | ||
197 | return nil, fmt.Errorf("storage: compose source %s.%s must not have encryption key", src.bucket, src.object) | ||
198 | } | ||
199 | srcObj := &raw.ComposeRequestSourceObjects{ | ||
200 | Name: src.object, | ||
201 | } | ||
202 | if err := applyConds("ComposeFrom source", src.gen, src.conds, composeSourceObj{srcObj}); err != nil { | ||
203 | return nil, err | ||
204 | } | ||
205 | req.SourceObjects = append(req.SourceObjects, srcObj) | ||
206 | } | ||
207 | |||
208 | call := c.dst.c.raw.Objects.Compose(c.dst.bucket, c.dst.object, req).Context(ctx) | ||
209 | if err := applyConds("ComposeFrom destination", c.dst.gen, c.dst.conds, call); err != nil { | ||
210 | return nil, err | ||
211 | } | ||
212 | if c.dst.userProject != "" { | ||
213 | call.UserProject(c.dst.userProject) | ||
214 | } | ||
215 | if c.PredefinedACL != "" { | ||
216 | call.DestinationPredefinedAcl(c.PredefinedACL) | ||
217 | } | ||
218 | if err := setEncryptionHeaders(call.Header(), c.dst.encryptionKey, false); err != nil { | ||
219 | return nil, err | ||
220 | } | ||
221 | var obj *raw.Object | ||
222 | setClientHeader(call.Header()) | ||
223 | err = runWithRetry(ctx, func() error { obj, err = call.Do(); return err }) | ||
224 | if err != nil { | ||
225 | return nil, err | ||
226 | } | ||
227 | return newObject(obj), nil | ||
228 | } | ||