google-cloud-storage 1.29.2 → 1.47.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/AUTHENTICATION.md +10 -27
- data/CHANGELOG.md +171 -0
- data/CONTRIBUTING.md +3 -4
- data/OVERVIEW.md +32 -0
- data/lib/google/cloud/storage/bucket/acl.rb +40 -40
- data/lib/google/cloud/storage/bucket/cors.rb +4 -1
- data/lib/google/cloud/storage/bucket/lifecycle.rb +99 -21
- data/lib/google/cloud/storage/bucket/list.rb +3 -3
- data/lib/google/cloud/storage/bucket.rb +571 -84
- data/lib/google/cloud/storage/credentials.rb +16 -14
- data/lib/google/cloud/storage/file/acl.rb +181 -20
- data/lib/google/cloud/storage/file/list.rb +10 -6
- data/lib/google/cloud/storage/file/signer_v2.rb +3 -5
- data/lib/google/cloud/storage/file/signer_v4.rb +12 -10
- data/lib/google/cloud/storage/file/verifier.rb +2 -2
- data/lib/google/cloud/storage/file.rb +288 -32
- data/lib/google/cloud/storage/hmac_key/list.rb +3 -3
- data/lib/google/cloud/storage/policy/binding.rb +5 -3
- data/lib/google/cloud/storage/policy/bindings.rb +2 -2
- data/lib/google/cloud/storage/policy/condition.rb +4 -2
- data/lib/google/cloud/storage/policy.rb +2 -2
- data/lib/google/cloud/storage/post_object.rb +2 -1
- data/lib/google/cloud/storage/project.rb +92 -19
- data/lib/google/cloud/storage/service.rb +430 -284
- data/lib/google/cloud/storage/version.rb +1 -1
- data/lib/google/cloud/storage.rb +74 -13
- data/lib/google-cloud-storage.rb +61 -7
- metadata +52 -18
@@ -38,17 +38,21 @@ module Google
|
|
38
38
|
|
39
39
|
##
|
40
40
|
# Creates a new Service instance.
|
41
|
-
|
42
|
-
|
41
|
+
# rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
42
|
+
def initialize project, credentials, retries: nil,
|
43
|
+
timeout: nil, open_timeout: nil, read_timeout: nil,
|
44
|
+
send_timeout: nil, host: nil, quota_project: nil,
|
45
|
+
max_elapsed_time: nil, base_interval: nil, max_interval: nil,
|
46
|
+
multiplier: nil, upload_chunk_size: nil
|
43
47
|
@project = project
|
44
48
|
@credentials = credentials
|
45
49
|
@service = API::StorageService.new
|
46
50
|
@service.client_options.application_name = "gcloud-ruby"
|
47
51
|
@service.client_options.application_version = \
|
48
52
|
Google::Cloud::Storage::VERSION
|
49
|
-
@service.client_options.open_timeout_sec = timeout
|
50
|
-
@service.client_options.read_timeout_sec = timeout
|
51
|
-
@service.client_options.send_timeout_sec = timeout
|
53
|
+
@service.client_options.open_timeout_sec = (open_timeout || timeout)
|
54
|
+
@service.client_options.read_timeout_sec = (read_timeout || timeout)
|
55
|
+
@service.client_options.send_timeout_sec = (send_timeout || timeout)
|
52
56
|
@service.client_options.transparent_gzip_decompression = false
|
53
57
|
@service.request_options.retries = retries || 3
|
54
58
|
@service.request_options.header ||= {}
|
@@ -56,9 +60,16 @@ module Google
|
|
56
60
|
"gl-ruby/#{RUBY_VERSION} gccl/#{Google::Cloud::Storage::VERSION}"
|
57
61
|
@service.request_options.header["Accept-Encoding"] = "gzip"
|
58
62
|
@service.request_options.quota_project = quota_project if quota_project
|
63
|
+
@service.request_options.max_elapsed_time = max_elapsed_time if max_elapsed_time
|
64
|
+
@service.request_options.base_interval = base_interval if base_interval
|
65
|
+
@service.request_options.max_interval = max_interval if max_interval
|
66
|
+
@service.request_options.multiplier = multiplier if multiplier
|
67
|
+
@service.request_options.add_invocation_id_header = true
|
68
|
+
@service.request_options.upload_chunk_size = upload_chunk_size if upload_chunk_size
|
59
69
|
@service.authorization = @credentials.client if @credentials
|
60
70
|
@service.root_url = host if host
|
61
71
|
end
|
72
|
+
# rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
62
73
|
|
63
74
|
def service
|
64
75
|
return mocked_service if mocked_service
|
@@ -72,21 +83,28 @@ module Google
|
|
72
83
|
|
73
84
|
##
|
74
85
|
# Retrieves a list of buckets for the given project.
|
75
|
-
def list_buckets prefix: nil, token: nil, max: nil, user_project: nil
|
86
|
+
def list_buckets prefix: nil, token: nil, max: nil, user_project: nil, options: {}
|
76
87
|
execute do
|
77
88
|
service.list_buckets \
|
78
89
|
@project, prefix: prefix, page_token: token, max_results: max,
|
79
|
-
user_project: user_project(user_project)
|
90
|
+
user_project: user_project(user_project), options: options
|
80
91
|
end
|
81
92
|
end
|
82
93
|
|
83
94
|
##
|
84
95
|
# Retrieves bucket by name.
|
85
96
|
# Returns Google::Apis::StorageV1::Bucket.
|
86
|
-
def get_bucket bucket_name,
|
97
|
+
def get_bucket bucket_name,
|
98
|
+
if_metageneration_match: nil,
|
99
|
+
if_metageneration_not_match: nil,
|
100
|
+
user_project: nil,
|
101
|
+
options: {}
|
87
102
|
execute do
|
88
103
|
service.get_bucket bucket_name,
|
89
|
-
|
104
|
+
if_metageneration_match: if_metageneration_match,
|
105
|
+
if_metageneration_not_match: if_metageneration_not_match,
|
106
|
+
user_project: user_project(user_project),
|
107
|
+
options: options
|
90
108
|
end
|
91
109
|
end
|
92
110
|
|
@@ -94,146 +112,193 @@ module Google
|
|
94
112
|
# Creates a new bucket.
|
95
113
|
# Returns Google::Apis::StorageV1::Bucket.
|
96
114
|
def insert_bucket bucket_gapi, acl: nil, default_acl: nil,
|
97
|
-
user_project: nil
|
115
|
+
user_project: nil, enable_object_retention: nil,
|
116
|
+
options: {}
|
98
117
|
execute do
|
99
118
|
service.insert_bucket \
|
100
119
|
@project, bucket_gapi,
|
101
120
|
predefined_acl: acl,
|
102
121
|
predefined_default_object_acl: default_acl,
|
103
|
-
user_project: user_project(user_project)
|
122
|
+
user_project: user_project(user_project),
|
123
|
+
options: options,
|
124
|
+
enable_object_retention: enable_object_retention
|
104
125
|
end
|
105
126
|
end
|
106
127
|
|
107
128
|
##
|
108
129
|
# Updates a bucket, including its ACL metadata.
|
109
|
-
def patch_bucket bucket_name,
|
110
|
-
|
130
|
+
def patch_bucket bucket_name,
|
131
|
+
bucket_gapi = nil,
|
132
|
+
predefined_acl: nil,
|
133
|
+
predefined_default_acl: nil,
|
134
|
+
if_metageneration_match: nil,
|
135
|
+
if_metageneration_not_match: nil,
|
136
|
+
user_project: nil,
|
137
|
+
options: {}
|
111
138
|
bucket_gapi ||= Google::Apis::StorageV1::Bucket.new
|
112
139
|
bucket_gapi.acl = [] if predefined_acl
|
113
140
|
bucket_gapi.default_object_acl = [] if predefined_default_acl
|
114
141
|
|
142
|
+
if options[:retries].nil?
|
143
|
+
is_idempotent = retry? if_metageneration_match: if_metageneration_match
|
144
|
+
options = is_idempotent ? {} : { retries: 0 }
|
145
|
+
end
|
146
|
+
|
115
147
|
execute do
|
116
|
-
service.patch_bucket
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
148
|
+
service.patch_bucket bucket_name,
|
149
|
+
bucket_gapi,
|
150
|
+
predefined_acl: predefined_acl,
|
151
|
+
predefined_default_object_acl: predefined_default_acl,
|
152
|
+
if_metageneration_match: if_metageneration_match,
|
153
|
+
if_metageneration_not_match: if_metageneration_not_match,
|
154
|
+
user_project: user_project(user_project),
|
155
|
+
options: options
|
121
156
|
end
|
122
157
|
end
|
123
158
|
|
124
159
|
##
|
125
160
|
# Permanently deletes an empty bucket.
|
126
|
-
def delete_bucket bucket_name,
|
161
|
+
def delete_bucket bucket_name,
|
162
|
+
if_metageneration_match: nil,
|
163
|
+
if_metageneration_not_match: nil,
|
164
|
+
user_project: nil,
|
165
|
+
options: {}
|
127
166
|
execute do
|
128
167
|
service.delete_bucket bucket_name,
|
129
|
-
|
168
|
+
if_metageneration_match: if_metageneration_match,
|
169
|
+
if_metageneration_not_match: if_metageneration_not_match,
|
170
|
+
user_project: user_project(user_project),
|
171
|
+
options: options
|
130
172
|
end
|
131
173
|
end
|
132
174
|
|
133
175
|
##
|
134
176
|
# Locks retention policy on a bucket.
|
135
177
|
def lock_bucket_retention_policy bucket_name, metageneration,
|
136
|
-
user_project: nil
|
178
|
+
user_project: nil,
|
179
|
+
options: {}
|
137
180
|
execute do
|
138
181
|
service.lock_bucket_retention_policy \
|
139
182
|
bucket_name, metageneration,
|
140
|
-
user_project: user_project(user_project)
|
183
|
+
user_project: user_project(user_project),
|
184
|
+
options: options
|
141
185
|
end
|
142
186
|
end
|
143
187
|
|
144
188
|
##
|
145
189
|
# Retrieves a list of ACLs for the given bucket.
|
146
|
-
def list_bucket_acls bucket_name, user_project: nil
|
190
|
+
def list_bucket_acls bucket_name, user_project: nil, options: {}
|
147
191
|
execute do
|
148
192
|
service.list_bucket_access_controls \
|
149
|
-
bucket_name, user_project: user_project(user_project)
|
193
|
+
bucket_name, user_project: user_project(user_project),
|
194
|
+
options: options
|
150
195
|
end
|
151
196
|
end
|
152
197
|
|
153
198
|
##
|
154
199
|
# Creates a new bucket ACL.
|
155
|
-
def insert_bucket_acl bucket_name, entity, role, user_project: nil
|
200
|
+
def insert_bucket_acl bucket_name, entity, role, user_project: nil, options: {}
|
156
201
|
params = { entity: entity, role: role }.delete_if { |_k, v| v.nil? }
|
157
202
|
new_acl = Google::Apis::StorageV1::BucketAccessControl.new(**params)
|
203
|
+
if options[:retries].nil?
|
204
|
+
options = options.merge({ retries: 0 })
|
205
|
+
end
|
158
206
|
execute do
|
159
207
|
service.insert_bucket_access_control \
|
160
|
-
bucket_name, new_acl, user_project: user_project(user_project)
|
208
|
+
bucket_name, new_acl, user_project: user_project(user_project),
|
209
|
+
options: options
|
161
210
|
end
|
162
211
|
end
|
163
212
|
|
164
213
|
##
|
165
214
|
# Permanently deletes a bucket ACL.
|
166
|
-
def delete_bucket_acl bucket_name, entity, user_project: nil
|
215
|
+
def delete_bucket_acl bucket_name, entity, user_project: nil, options: {}
|
216
|
+
if options[:retries].nil?
|
217
|
+
options = options.merge({ retries: 0 })
|
218
|
+
end
|
167
219
|
execute do
|
168
220
|
service.delete_bucket_access_control \
|
169
|
-
bucket_name, entity, user_project: user_project(user_project)
|
221
|
+
bucket_name, entity, user_project: user_project(user_project),
|
222
|
+
options: options
|
170
223
|
end
|
171
224
|
end
|
172
225
|
|
173
226
|
##
|
174
227
|
# Retrieves a list of default ACLs for the given bucket.
|
175
|
-
def list_default_acls bucket_name, user_project: nil
|
228
|
+
def list_default_acls bucket_name, user_project: nil, options: {}
|
176
229
|
execute do
|
177
230
|
service.list_default_object_access_controls \
|
178
|
-
bucket_name, user_project: user_project(user_project)
|
231
|
+
bucket_name, user_project: user_project(user_project),
|
232
|
+
options: options
|
179
233
|
end
|
180
234
|
end
|
181
235
|
|
182
236
|
##
|
183
237
|
# Creates a new default ACL.
|
184
|
-
def insert_default_acl bucket_name, entity, role, user_project: nil
|
238
|
+
def insert_default_acl bucket_name, entity, role, user_project: nil, options: {}
|
239
|
+
if options[:retries].nil?
|
240
|
+
options = options.merge({ retries: 0 })
|
241
|
+
end
|
185
242
|
param = { entity: entity, role: role }.delete_if { |_k, v| v.nil? }
|
186
243
|
new_acl = Google::Apis::StorageV1::ObjectAccessControl.new(**param)
|
187
244
|
execute do
|
188
245
|
service.insert_default_object_access_control \
|
189
|
-
bucket_name, new_acl, user_project: user_project(user_project)
|
246
|
+
bucket_name, new_acl, user_project: user_project(user_project),
|
247
|
+
options: options
|
190
248
|
end
|
191
249
|
end
|
192
250
|
|
193
251
|
##
|
194
252
|
# Permanently deletes a default ACL.
|
195
|
-
def delete_default_acl bucket_name, entity, user_project: nil
|
253
|
+
def delete_default_acl bucket_name, entity, user_project: nil, options: {}
|
254
|
+
if options[:retries].nil?
|
255
|
+
options = options.merge({ retries: 0 })
|
256
|
+
end
|
196
257
|
execute do
|
197
258
|
service.delete_default_object_access_control \
|
198
|
-
bucket_name, entity, user_project: user_project(user_project)
|
259
|
+
bucket_name, entity, user_project: user_project(user_project),
|
260
|
+
options: options
|
199
261
|
end
|
200
262
|
end
|
201
263
|
|
202
264
|
##
|
203
265
|
# Returns Google::Apis::StorageV1::Policy
|
204
|
-
def get_bucket_policy bucket_name, requested_policy_version: nil, user_project: nil
|
266
|
+
def get_bucket_policy bucket_name, requested_policy_version: nil, user_project: nil,
|
267
|
+
options: {}
|
205
268
|
# get_bucket_iam_policy(bucket, fields: nil, quota_user: nil,
|
206
269
|
# user_ip: nil, options: nil)
|
207
270
|
execute do
|
208
271
|
service.get_bucket_iam_policy bucket_name, options_requested_policy_version: requested_policy_version,
|
209
|
-
user_project: user_project(user_project)
|
272
|
+
user_project: user_project(user_project), options: options
|
210
273
|
end
|
211
274
|
end
|
212
275
|
|
213
276
|
##
|
214
277
|
# Returns Google::Apis::StorageV1::Policy
|
215
|
-
def set_bucket_policy bucket_name, new_policy, user_project: nil
|
278
|
+
def set_bucket_policy bucket_name, new_policy, user_project: nil, options: {}
|
216
279
|
execute do
|
217
280
|
service.set_bucket_iam_policy \
|
218
|
-
bucket_name, new_policy, user_project: user_project(user_project)
|
281
|
+
bucket_name, new_policy, user_project: user_project(user_project), options: options
|
219
282
|
end
|
220
283
|
end
|
221
284
|
|
222
285
|
##
|
223
286
|
# Returns Google::Apis::StorageV1::TestIamPermissionsResponse
|
224
|
-
def test_bucket_permissions bucket_name, permissions, user_project: nil
|
287
|
+
def test_bucket_permissions bucket_name, permissions, user_project: nil, options: {}
|
225
288
|
execute do
|
226
289
|
service.test_bucket_iam_permissions \
|
227
|
-
bucket_name, permissions, user_project: user_project(user_project)
|
290
|
+
bucket_name, permissions, user_project: user_project(user_project),
|
291
|
+
options: options
|
228
292
|
end
|
229
293
|
end
|
230
294
|
|
231
295
|
##
|
232
296
|
# Retrieves a list of Pub/Sub notification subscriptions for a bucket.
|
233
|
-
def list_notifications bucket_name, user_project: nil
|
297
|
+
def list_notifications bucket_name, user_project: nil, options: {}
|
234
298
|
execute do
|
235
299
|
service.list_notifications bucket_name,
|
236
|
-
user_project: user_project(user_project)
|
300
|
+
user_project: user_project(user_project),
|
301
|
+
options: options
|
237
302
|
end
|
238
303
|
end
|
239
304
|
|
@@ -241,7 +306,7 @@ module Google
|
|
241
306
|
# Creates a new Pub/Sub notification subscription for a bucket.
|
242
307
|
def insert_notification bucket_name, topic_name, custom_attrs: nil,
|
243
308
|
event_types: nil, prefix: nil, payload: nil,
|
244
|
-
user_project: nil
|
309
|
+
user_project: nil, options: {}
|
245
310
|
params =
|
246
311
|
{ custom_attributes: custom_attrs,
|
247
312
|
event_types: event_types(event_types),
|
@@ -250,124 +315,237 @@ module Google
|
|
250
315
|
topic: topic_path(topic_name) }.delete_if { |_k, v| v.nil? }
|
251
316
|
new_notification = Google::Apis::StorageV1::Notification.new(**params)
|
252
317
|
|
318
|
+
if options[:retries].nil?
|
319
|
+
options = options.merge({ retries: 0 })
|
320
|
+
end
|
321
|
+
|
253
322
|
execute do
|
254
323
|
service.insert_notification \
|
255
324
|
bucket_name, new_notification,
|
256
|
-
user_project: user_project(user_project)
|
325
|
+
user_project: user_project(user_project),
|
326
|
+
options: options
|
257
327
|
end
|
258
328
|
end
|
259
329
|
|
260
330
|
##
|
261
331
|
# Retrieves a Pub/Sub notification subscription for a bucket.
|
262
|
-
def get_notification bucket_name, notification_id, user_project: nil
|
332
|
+
def get_notification bucket_name, notification_id, user_project: nil, options: {}
|
263
333
|
execute do
|
264
334
|
service.get_notification bucket_name, notification_id,
|
265
|
-
user_project: user_project(user_project)
|
335
|
+
user_project: user_project(user_project),
|
336
|
+
options: options
|
266
337
|
end
|
267
338
|
end
|
268
339
|
|
269
340
|
##
|
270
341
|
# Deletes a new Pub/Sub notification subscription for a bucket.
|
271
|
-
def delete_notification bucket_name, notification_id, user_project: nil
|
342
|
+
def delete_notification bucket_name, notification_id, user_project: nil, options: {}
|
272
343
|
execute do
|
273
344
|
service.delete_notification bucket_name, notification_id,
|
274
|
-
user_project: user_project(user_project)
|
345
|
+
user_project: user_project(user_project),
|
346
|
+
options: options
|
275
347
|
end
|
276
348
|
end
|
277
349
|
|
278
350
|
##
|
279
351
|
# Retrieves a list of files matching the criteria.
|
280
352
|
def list_files bucket_name, delimiter: nil, max: nil, token: nil,
|
281
|
-
prefix: nil, versions: nil, user_project: nil
|
353
|
+
prefix: nil, versions: nil, user_project: nil,
|
354
|
+
match_glob: nil,
|
355
|
+
options: {}
|
282
356
|
execute do
|
283
357
|
service.list_objects \
|
284
358
|
bucket_name, delimiter: delimiter, max_results: max,
|
285
359
|
page_token: token, prefix: prefix,
|
286
360
|
versions: versions,
|
287
|
-
user_project: user_project(user_project)
|
361
|
+
user_project: user_project(user_project),
|
362
|
+
match_glob: match_glob,
|
363
|
+
options: options
|
288
364
|
end
|
289
365
|
end
|
290
366
|
|
291
367
|
##
|
292
368
|
# Inserts a new file for the given bucket
|
293
|
-
def insert_file bucket_name,
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
369
|
+
def insert_file bucket_name,
|
370
|
+
source,
|
371
|
+
path = nil,
|
372
|
+
acl: nil,
|
373
|
+
cache_control: nil,
|
374
|
+
content_disposition: nil,
|
375
|
+
content_encoding: nil,
|
376
|
+
content_language: nil,
|
377
|
+
content_type: nil,
|
378
|
+
custom_time: nil,
|
379
|
+
crc32c: nil,
|
380
|
+
md5: nil,
|
381
|
+
metadata: nil,
|
382
|
+
storage_class: nil,
|
383
|
+
key: nil,
|
384
|
+
kms_key: nil,
|
385
|
+
temporary_hold: nil,
|
386
|
+
event_based_hold: nil,
|
387
|
+
if_generation_match: nil,
|
388
|
+
if_generation_not_match: nil,
|
389
|
+
if_metageneration_match: nil,
|
390
|
+
if_metageneration_not_match: nil,
|
391
|
+
user_project: nil,
|
392
|
+
options: {}
|
393
|
+
params = {
|
394
|
+
cache_control: cache_control,
|
395
|
+
content_type: content_type,
|
396
|
+
custom_time: custom_time,
|
397
|
+
content_disposition: content_disposition,
|
398
|
+
md5_hash: md5,
|
399
|
+
content_encoding: content_encoding,
|
400
|
+
crc32c: crc32c,
|
401
|
+
content_language: content_language,
|
402
|
+
metadata: metadata,
|
403
|
+
storage_class: storage_class,
|
404
|
+
temporary_hold: temporary_hold,
|
405
|
+
event_based_hold: event_based_hold
|
406
|
+
}.delete_if { |_k, v| v.nil? }
|
307
407
|
file_obj = Google::Apis::StorageV1::Object.new(**params)
|
308
408
|
content_type ||= mime_type_for(path || Pathname(source).to_path)
|
309
409
|
|
410
|
+
if options[:retries].nil?
|
411
|
+
is_idempotent = retry? if_generation_match: if_generation_match
|
412
|
+
options = is_idempotent ? key_options(key) : key_options(key).merge(retries: 0)
|
413
|
+
else
|
414
|
+
options = key_options(key).merge options
|
415
|
+
end
|
416
|
+
|
310
417
|
execute do
|
311
|
-
service.insert_object
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
418
|
+
service.insert_object bucket_name,
|
419
|
+
file_obj,
|
420
|
+
name: path,
|
421
|
+
predefined_acl: acl,
|
422
|
+
upload_source: source,
|
423
|
+
content_encoding: content_encoding,
|
424
|
+
content_type: content_type,
|
425
|
+
if_generation_match: if_generation_match,
|
426
|
+
if_generation_not_match: if_generation_not_match,
|
427
|
+
if_metageneration_match: if_metageneration_match,
|
428
|
+
if_metageneration_not_match: if_metageneration_not_match,
|
429
|
+
kms_key_name: kms_key,
|
430
|
+
user_project: user_project(user_project),
|
431
|
+
options: options
|
317
432
|
end
|
318
433
|
end
|
319
434
|
|
320
435
|
##
|
321
436
|
# Retrieves an object or its metadata.
|
322
|
-
def get_file bucket_name,
|
323
|
-
|
437
|
+
def get_file bucket_name,
|
438
|
+
file_path,
|
439
|
+
generation: nil,
|
440
|
+
if_generation_match: nil,
|
441
|
+
if_generation_not_match: nil,
|
442
|
+
if_metageneration_match: nil,
|
443
|
+
if_metageneration_not_match: nil,
|
444
|
+
key: nil,
|
445
|
+
user_project: nil,
|
446
|
+
options: {}
|
324
447
|
execute do
|
325
448
|
service.get_object \
|
326
449
|
bucket_name, file_path,
|
327
450
|
generation: generation,
|
451
|
+
if_generation_match: if_generation_match,
|
452
|
+
if_generation_not_match: if_generation_not_match,
|
453
|
+
if_metageneration_match: if_metageneration_match,
|
454
|
+
if_metageneration_not_match: if_metageneration_not_match,
|
328
455
|
user_project: user_project(user_project),
|
329
|
-
options: key_options(key)
|
456
|
+
options: key_options(key).merge(options)
|
330
457
|
end
|
331
458
|
end
|
332
459
|
|
333
460
|
## Rewrite a file from source bucket/object to a
|
334
461
|
# destination bucket/object.
|
335
|
-
def rewrite_file source_bucket_name,
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
|
462
|
+
def rewrite_file source_bucket_name,
|
463
|
+
source_file_path,
|
464
|
+
destination_bucket_name,
|
465
|
+
destination_file_path,
|
466
|
+
file_gapi = nil,
|
467
|
+
source_key: nil,
|
468
|
+
destination_key: nil,
|
469
|
+
destination_kms_key: nil,
|
470
|
+
acl: nil,
|
471
|
+
generation: nil,
|
472
|
+
if_generation_match: nil,
|
473
|
+
if_generation_not_match: nil,
|
474
|
+
if_metageneration_match: nil,
|
475
|
+
if_metageneration_not_match: nil,
|
476
|
+
if_source_generation_match: nil,
|
477
|
+
if_source_generation_not_match: nil,
|
478
|
+
if_source_metageneration_match: nil,
|
479
|
+
if_source_metageneration_not_match: nil,
|
480
|
+
token: nil,
|
481
|
+
user_project: nil,
|
482
|
+
options: {}
|
340
483
|
key_options = rewrite_key_options source_key, destination_key
|
484
|
+
|
485
|
+
if options[:retries].nil?
|
486
|
+
is_idempotent = retry? if_generation_match: if_generation_match
|
487
|
+
options = is_idempotent ? key_options : key_options.merge(retries: 0)
|
488
|
+
else
|
489
|
+
options = key_options.merge options
|
490
|
+
end
|
491
|
+
|
341
492
|
execute do
|
342
|
-
service.rewrite_object
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
493
|
+
service.rewrite_object source_bucket_name,
|
494
|
+
source_file_path,
|
495
|
+
destination_bucket_name,
|
496
|
+
destination_file_path,
|
497
|
+
file_gapi,
|
498
|
+
destination_kms_key_name: destination_kms_key,
|
499
|
+
destination_predefined_acl: acl,
|
500
|
+
source_generation: generation,
|
501
|
+
if_generation_match: if_generation_match,
|
502
|
+
if_generation_not_match: if_generation_not_match,
|
503
|
+
if_metageneration_match: if_metageneration_match,
|
504
|
+
if_metageneration_not_match: if_metageneration_not_match,
|
505
|
+
if_source_generation_match: if_source_generation_match,
|
506
|
+
if_source_generation_not_match: if_source_generation_not_match,
|
507
|
+
if_source_metageneration_match: if_source_metageneration_match,
|
508
|
+
if_source_metageneration_not_match: if_source_metageneration_not_match,
|
509
|
+
rewrite_token: token,
|
510
|
+
user_project: user_project(user_project),
|
511
|
+
options: options
|
352
512
|
end
|
353
513
|
end
|
354
514
|
|
355
515
|
## Copy a file from source bucket/object to a
|
356
516
|
# destination bucket/object.
|
357
|
-
def compose_file bucket_name,
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
|
362
|
-
|
517
|
+
def compose_file bucket_name,
|
518
|
+
source_files,
|
519
|
+
destination_path,
|
520
|
+
destination_gapi,
|
521
|
+
acl: nil,
|
522
|
+
key: nil,
|
523
|
+
if_source_generation_match: nil,
|
524
|
+
if_generation_match: nil,
|
525
|
+
if_metageneration_match: nil,
|
526
|
+
user_project: nil,
|
527
|
+
options: {}
|
528
|
+
|
529
|
+
source_objects = compose_file_source_objects source_files, if_source_generation_match
|
530
|
+
compose_req = Google::Apis::StorageV1::ComposeRequest.new source_objects: source_objects,
|
531
|
+
destination: destination_gapi
|
532
|
+
|
533
|
+
if options[:retries].nil?
|
534
|
+
is_idempotent = retry? if_generation_match: if_generation_match
|
535
|
+
options = is_idempotent ? key_options(key) : key_options(key).merge(retries: 0)
|
536
|
+
else
|
537
|
+
options = key_options.merge options
|
538
|
+
end
|
363
539
|
|
364
540
|
execute do
|
365
|
-
service.compose_object
|
366
|
-
|
367
|
-
|
368
|
-
|
369
|
-
|
370
|
-
|
541
|
+
service.compose_object bucket_name,
|
542
|
+
destination_path,
|
543
|
+
compose_req,
|
544
|
+
destination_predefined_acl: acl,
|
545
|
+
if_generation_match: if_generation_match,
|
546
|
+
if_metageneration_match: if_metageneration_match,
|
547
|
+
user_project: user_project(user_project),
|
548
|
+
options: options
|
371
549
|
end
|
372
550
|
end
|
373
551
|
|
@@ -381,12 +559,12 @@ module Google
|
|
381
559
|
# Apis::StorageV1::StorageService and Apis::Core::DownloadCommand at
|
382
560
|
# the end of this file.
|
383
561
|
def download_file bucket_name, file_path, target_path, generation: nil,
|
384
|
-
key: nil, range: nil, user_project: nil
|
385
|
-
options = key_options
|
562
|
+
key: nil, range: nil, user_project: nil, options: {}
|
563
|
+
options = key_options(key).merge(options)
|
386
564
|
options = range_header options, range
|
387
565
|
|
388
566
|
execute do
|
389
|
-
service.
|
567
|
+
service.get_object \
|
390
568
|
bucket_name, file_path,
|
391
569
|
download_dest: target_path, generation: generation,
|
392
570
|
user_project: user_project(user_project),
|
@@ -396,58 +574,110 @@ module Google
|
|
396
574
|
|
397
575
|
##
|
398
576
|
# Updates a file's metadata.
|
399
|
-
def patch_file bucket_name,
|
400
|
-
|
577
|
+
def patch_file bucket_name,
|
578
|
+
file_path,
|
579
|
+
file_gapi = nil,
|
580
|
+
generation: nil,
|
581
|
+
if_generation_match: nil,
|
582
|
+
if_generation_not_match: nil,
|
583
|
+
if_metageneration_match: nil,
|
584
|
+
if_metageneration_not_match: nil,
|
585
|
+
predefined_acl: nil,
|
586
|
+
user_project: nil,
|
587
|
+
override_unlocked_retention: nil,
|
588
|
+
options: {}
|
401
589
|
file_gapi ||= Google::Apis::StorageV1::Object.new
|
590
|
+
|
591
|
+
if options[:retries].nil?
|
592
|
+
is_idempotent = retry? if_metageneration_match: if_metageneration_match
|
593
|
+
options = is_idempotent ? {} : { retries: 0 }
|
594
|
+
end
|
595
|
+
|
402
596
|
execute do
|
403
|
-
service.patch_object
|
404
|
-
|
405
|
-
|
406
|
-
|
597
|
+
service.patch_object bucket_name,
|
598
|
+
file_path,
|
599
|
+
file_gapi,
|
600
|
+
generation: generation,
|
601
|
+
if_generation_match: if_generation_match,
|
602
|
+
if_generation_not_match: if_generation_not_match,
|
603
|
+
if_metageneration_match: if_metageneration_match,
|
604
|
+
if_metageneration_not_match: if_metageneration_not_match,
|
605
|
+
predefined_acl: predefined_acl,
|
606
|
+
user_project: user_project(user_project),
|
607
|
+
override_unlocked_retention: override_unlocked_retention,
|
608
|
+
options: options
|
407
609
|
end
|
408
610
|
end
|
409
611
|
|
410
612
|
##
|
411
613
|
# Permanently deletes a file.
|
412
|
-
def delete_file bucket_name,
|
413
|
-
|
614
|
+
def delete_file bucket_name,
|
615
|
+
file_path,
|
616
|
+
generation: nil,
|
617
|
+
if_generation_match: nil,
|
618
|
+
if_generation_not_match: nil,
|
619
|
+
if_metageneration_match: nil,
|
620
|
+
if_metageneration_not_match: nil,
|
621
|
+
user_project: nil,
|
622
|
+
options: {}
|
623
|
+
|
624
|
+
if options[:retries].nil?
|
625
|
+
is_idempotent = retry? generation: generation, if_generation_match: if_generation_match
|
626
|
+
options = is_idempotent ? {} : { retries: 0 }
|
627
|
+
end
|
628
|
+
|
414
629
|
execute do
|
415
630
|
service.delete_object bucket_name, file_path,
|
416
631
|
generation: generation,
|
417
|
-
|
632
|
+
if_generation_match: if_generation_match,
|
633
|
+
if_generation_not_match: if_generation_not_match,
|
634
|
+
if_metageneration_match: if_metageneration_match,
|
635
|
+
if_metageneration_not_match: if_metageneration_not_match,
|
636
|
+
user_project: user_project(user_project),
|
637
|
+
options: options
|
418
638
|
end
|
419
639
|
end
|
420
640
|
|
421
641
|
##
|
422
642
|
# Retrieves a list of ACLs for the given file.
|
423
|
-
def list_file_acls bucket_name, file_name, user_project: nil
|
643
|
+
def list_file_acls bucket_name, file_name, user_project: nil, options: {}
|
424
644
|
execute do
|
425
645
|
service.list_object_access_controls \
|
426
|
-
bucket_name, file_name, user_project: user_project(user_project)
|
646
|
+
bucket_name, file_name, user_project: user_project(user_project),
|
647
|
+
options: options
|
427
648
|
end
|
428
649
|
end
|
429
650
|
|
430
651
|
##
|
431
652
|
# Creates a new file ACL.
|
432
653
|
def insert_file_acl bucket_name, file_name, entity, role,
|
433
|
-
generation: nil, user_project: nil
|
654
|
+
generation: nil, user_project: nil,
|
655
|
+
options: {}
|
656
|
+
if options[:retries].nil?
|
657
|
+
options = options.merge({ retries: 0 })
|
658
|
+
end
|
434
659
|
params = { entity: entity, role: role }.delete_if { |_k, v| v.nil? }
|
435
660
|
new_acl = Google::Apis::StorageV1::ObjectAccessControl.new(**params)
|
436
661
|
execute do
|
437
662
|
service.insert_object_access_control \
|
438
663
|
bucket_name, file_name, new_acl,
|
439
|
-
generation: generation, user_project: user_project(user_project)
|
664
|
+
generation: generation, user_project: user_project(user_project),
|
665
|
+
options: options
|
440
666
|
end
|
441
667
|
end
|
442
668
|
|
443
669
|
##
|
444
670
|
# Permanently deletes a file ACL.
|
445
671
|
def delete_file_acl bucket_name, file_name, entity, generation: nil,
|
446
|
-
user_project: nil
|
672
|
+
user_project: nil, options: {}
|
673
|
+
if options[:retries].nil?
|
674
|
+
options = options.merge({ retries: 0 })
|
675
|
+
end
|
447
676
|
execute do
|
448
677
|
service.delete_object_access_control \
|
449
678
|
bucket_name, file_name, entity,
|
450
|
-
generation: generation, user_project: user_project(user_project)
|
679
|
+
generation: generation, user_project: user_project(user_project),
|
680
|
+
options: options
|
451
681
|
end
|
452
682
|
end
|
453
683
|
|
@@ -455,32 +685,42 @@ module Google
|
|
455
685
|
# Creates a new HMAC key for the specified service account.
|
456
686
|
# Returns Google::Apis::StorageV1::HmacKey.
|
457
687
|
def create_hmac_key service_account_email, project_id: nil,
|
458
|
-
user_project: nil
|
688
|
+
user_project: nil, options: {}
|
689
|
+
|
690
|
+
if options[:retries].nil?
|
691
|
+
options = options.merge({ retries: 0 })
|
692
|
+
end
|
693
|
+
|
459
694
|
execute do
|
460
695
|
service.create_project_hmac_key \
|
461
696
|
(project_id || @project), service_account_email,
|
462
|
-
user_project: user_project(user_project)
|
697
|
+
user_project: user_project(user_project),
|
698
|
+
options: options
|
463
699
|
end
|
464
700
|
end
|
465
701
|
|
466
702
|
##
|
467
703
|
# Deletes an HMAC key. Key must be in the INACTIVE state.
|
468
|
-
def delete_hmac_key access_id, project_id: nil, user_project: nil
|
704
|
+
def delete_hmac_key access_id, project_id: nil, user_project: nil,
|
705
|
+
options: {}
|
469
706
|
execute do
|
470
707
|
service.delete_project_hmac_key \
|
471
708
|
(project_id || @project), access_id,
|
472
|
-
user_project: user_project(user_project)
|
709
|
+
user_project: user_project(user_project),
|
710
|
+
options: options
|
473
711
|
end
|
474
712
|
end
|
475
713
|
|
476
714
|
##
|
477
715
|
# Retrieves an HMAC key's metadata.
|
478
716
|
# Returns Google::Apis::StorageV1::HmacKeyMetadata.
|
479
|
-
def get_hmac_key access_id, project_id: nil, user_project: nil
|
717
|
+
def get_hmac_key access_id, project_id: nil, user_project: nil,
|
718
|
+
options: {}
|
480
719
|
execute do
|
481
720
|
service.get_project_hmac_key \
|
482
721
|
(project_id || @project), access_id,
|
483
|
-
user_project: user_project(user_project)
|
722
|
+
user_project: user_project(user_project),
|
723
|
+
options: options
|
484
724
|
end
|
485
725
|
end
|
486
726
|
|
@@ -489,14 +729,15 @@ module Google
|
|
489
729
|
# Returns Google::Apis::StorageV1::HmacKeysMetadata.
|
490
730
|
def list_hmac_keys max: nil, token: nil, service_account_email: nil,
|
491
731
|
project_id: nil, show_deleted_keys: nil,
|
492
|
-
user_project: nil
|
732
|
+
user_project: nil, options: {}
|
493
733
|
execute do
|
494
734
|
service.list_project_hmac_keys \
|
495
735
|
(project_id || @project),
|
496
736
|
max_results: max, page_token: token,
|
497
737
|
service_account_email: service_account_email,
|
498
738
|
show_deleted_keys: show_deleted_keys,
|
499
|
-
user_project: user_project(user_project)
|
739
|
+
user_project: user_project(user_project),
|
740
|
+
options: options
|
500
741
|
end
|
501
742
|
end
|
502
743
|
|
@@ -505,11 +746,44 @@ module Google
|
|
505
746
|
# for valid states.
|
506
747
|
# Returns Google::Apis::StorageV1::HmacKeyMetadata.
|
507
748
|
def update_hmac_key access_id, hmac_key_metadata_object,
|
508
|
-
project_id: nil, user_project: nil
|
749
|
+
project_id: nil, user_project: nil,
|
750
|
+
options: {}
|
509
751
|
execute do
|
510
752
|
service.update_project_hmac_key \
|
511
753
|
(project_id || @project), access_id, hmac_key_metadata_object,
|
512
|
-
user_project: user_project(user_project)
|
754
|
+
user_project: user_project(user_project),
|
755
|
+
options: options
|
756
|
+
end
|
757
|
+
end
|
758
|
+
|
759
|
+
##
|
760
|
+
# Updates a bucket, including its ACL metadata.
|
761
|
+
def update_bucket bucket_name,
|
762
|
+
bucket_gapi = nil,
|
763
|
+
predefined_acl: nil,
|
764
|
+
predefined_default_acl: nil,
|
765
|
+
if_metageneration_match: nil,
|
766
|
+
if_metageneration_not_match: nil,
|
767
|
+
user_project: nil,
|
768
|
+
options: {}
|
769
|
+
bucket_gapi ||= Google::Apis::StorageV1::Bucket.new
|
770
|
+
bucket_gapi.acl = [] if predefined_acl
|
771
|
+
bucket_gapi.default_object_acl = [] if predefined_default_acl
|
772
|
+
|
773
|
+
if options[:retries].nil?
|
774
|
+
is_idempotent = retry? if_metageneration_match: if_metageneration_match
|
775
|
+
options = is_idempotent ? {} : { retries: 0 }
|
776
|
+
end
|
777
|
+
|
778
|
+
execute do
|
779
|
+
service.update_bucket bucket_name,
|
780
|
+
bucket_gapi,
|
781
|
+
predefined_acl: predefined_acl,
|
782
|
+
predefined_default_object_acl: predefined_default_acl,
|
783
|
+
if_metageneration_match: if_metageneration_match,
|
784
|
+
if_metageneration_not_match: if_metageneration_not_match,
|
785
|
+
user_project: user_project(user_project),
|
786
|
+
options: options
|
513
787
|
end
|
514
788
|
end
|
515
789
|
|
@@ -527,6 +801,18 @@ module Google
|
|
527
801
|
"#{self.class}(#{@project})"
|
528
802
|
end
|
529
803
|
|
804
|
+
##
|
805
|
+
# Add custom Google extension headers to the requests that use the signed URLs.
|
806
|
+
def add_custom_headers headers
|
807
|
+
@service.request_options.header.merge! headers
|
808
|
+
end
|
809
|
+
|
810
|
+
##
|
811
|
+
# Add custom Google extension header to the requests that use the signed URLs.
|
812
|
+
def add_custom_header header_name, header_value
|
813
|
+
@service.request_options.header[header_name] = header_value
|
814
|
+
end
|
815
|
+
|
530
816
|
protected
|
531
817
|
|
532
818
|
def user_project user_project
|
@@ -615,8 +901,8 @@ module Google
|
|
615
901
|
"false" => "NONE" }[str_or_bool.to_s.downcase]
|
616
902
|
end
|
617
903
|
|
618
|
-
def compose_file_source_objects source_files
|
619
|
-
source_files.map do |file|
|
904
|
+
def compose_file_source_objects source_files, if_source_generation_match
|
905
|
+
source_objects = source_files.map do |file|
|
620
906
|
if file.is_a? Google::Cloud::Storage::File
|
621
907
|
Google::Apis::StorageV1::ComposeRequest::SourceObject.new \
|
622
908
|
name: file.name,
|
@@ -626,6 +912,18 @@ module Google
|
|
626
912
|
name: file
|
627
913
|
end
|
628
914
|
end
|
915
|
+
return source_objects unless if_source_generation_match
|
916
|
+
if source_files.count != if_source_generation_match.count
|
917
|
+
raise ArgumentError, "if provided, if_source_generation_match length must match sources length"
|
918
|
+
end
|
919
|
+
if_source_generation_match.each_with_index do |generation, i|
|
920
|
+
next unless generation
|
921
|
+
object_preconditions = Google::Apis::StorageV1::ComposeRequest::SourceObject::ObjectPreconditions.new(
|
922
|
+
if_generation_match: generation
|
923
|
+
)
|
924
|
+
source_objects[i].object_preconditions = object_preconditions
|
925
|
+
end
|
926
|
+
source_objects
|
629
927
|
end
|
630
928
|
|
631
929
|
def execute
|
@@ -633,163 +931,11 @@ module Google
|
|
633
931
|
rescue Google::Apis::Error => e
|
634
932
|
raise Google::Cloud::Error.from_error(e)
|
635
933
|
end
|
636
|
-
end
|
637
|
-
end
|
638
|
-
end
|
639
934
|
|
640
|
-
|
641
|
-
|
642
|
-
# @private
|
643
|
-
#
|
644
|
-
# IMPORTANT: These monkey-patches of Apis::StorageV1::StorageService and
|
645
|
-
# Apis::Core::DownloadCommand must be verified and updated (if needed) for
|
646
|
-
# every upgrade of google-api-client.
|
647
|
-
#
|
648
|
-
# The purpose of these modifications is to provide access to response headers
|
649
|
-
# (in particular, the Content-Encoding header) for the #download_file method,
|
650
|
-
# above. If google-api-client is modified to expose response headers to its
|
651
|
-
# clients, this code should be removed, and #download_file updated to use that
|
652
|
-
# solution instead.
|
653
|
-
#
|
654
|
-
module Apis
|
655
|
-
# @private
|
656
|
-
module StorageV1
|
657
|
-
# @private
|
658
|
-
class StorageService
|
659
|
-
# Returns a two-element array containing:
|
660
|
-
# * The `result` that is the usual return type of #get_object.
|
661
|
-
# * The `http_resp` from DownloadCommand#execute_once.
|
662
|
-
def get_object_with_response(bucket, object, generation: nil, if_generation_match: nil, if_generation_not_match: nil, if_metageneration_match: nil, if_metageneration_not_match: nil, projection: nil, user_project: nil, fields: nil, quota_user: nil, user_ip: nil, download_dest: nil, options: nil, &block)
|
663
|
-
if download_dest.nil?
|
664
|
-
command = make_simple_command(:get, 'b/{bucket}/o/{object}', options)
|
665
|
-
else
|
666
|
-
command = make_download_command(:get, 'b/{bucket}/o/{object}', options)
|
667
|
-
command.download_dest = download_dest
|
668
|
-
end
|
669
|
-
command.response_representation = Google::Apis::StorageV1::Object::Representation
|
670
|
-
command.response_class = Google::Apis::StorageV1::Object
|
671
|
-
command.params['bucket'] = bucket unless bucket.nil?
|
672
|
-
command.params['object'] = object unless object.nil?
|
673
|
-
command.query['generation'] = generation unless generation.nil?
|
674
|
-
command.query['ifGenerationMatch'] = if_generation_match unless if_generation_match.nil?
|
675
|
-
command.query['ifGenerationNotMatch'] = if_generation_not_match unless if_generation_not_match.nil?
|
676
|
-
command.query['ifMetagenerationMatch'] = if_metageneration_match unless if_metageneration_match.nil?
|
677
|
-
command.query['ifMetagenerationNotMatch'] = if_metageneration_not_match unless if_metageneration_not_match.nil?
|
678
|
-
command.query['projection'] = projection unless projection.nil?
|
679
|
-
command.query['userProject'] = user_project unless user_project.nil?
|
680
|
-
command.query['fields'] = fields unless fields.nil?
|
681
|
-
command.query['quotaUser'] = quota_user unless quota_user.nil?
|
682
|
-
command.query['userIp'] = user_ip unless user_ip.nil?
|
683
|
-
execute_or_queue_command_with_response(command, &block)
|
684
|
-
end
|
685
|
-
|
686
|
-
# Returns a two-element array containing:
|
687
|
-
# * The `result` that is the usual return type of #execute_or_queue_command.
|
688
|
-
# * The `http_resp` from DownloadCommand#execute_once.
|
689
|
-
def execute_or_queue_command_with_response(command, &callback)
|
690
|
-
batch_command = current_batch
|
691
|
-
if batch_command
|
692
|
-
raise "Can not combine services in a batch" if Thread.current[:google_api_batch_service] != self
|
693
|
-
batch_command.add(command, &callback)
|
694
|
-
nil
|
695
|
-
else
|
696
|
-
command.execute_with_response(client, &callback)
|
697
|
-
end
|
698
|
-
end
|
699
|
-
end
|
700
|
-
end
|
701
|
-
# @private
|
702
|
-
module Core
|
703
|
-
# @private
|
704
|
-
# Streaming/resumable media download support
|
705
|
-
class DownloadCommand < ApiCommand
|
706
|
-
# Returns a two-element array containing:
|
707
|
-
# * The `result` that is the usual return type of #execute.
|
708
|
-
# * The `http_resp` from #execute_once.
|
709
|
-
def execute_with_response(client)
|
710
|
-
prepare!
|
711
|
-
begin
|
712
|
-
Retriable.retriable tries: options.retries + 1,
|
713
|
-
base_interval: 1,
|
714
|
-
multiplier: 2,
|
715
|
-
on: RETRIABLE_ERRORS do |try|
|
716
|
-
# This 2nd level retriable only catches auth errors, and supports 1 retry, which allows
|
717
|
-
# auth to be re-attempted without having to retry all sorts of other failures like
|
718
|
-
# NotFound, etc
|
719
|
-
auth_tries = (try == 1 && authorization_refreshable? ? 2 : 1)
|
720
|
-
Retriable.retriable tries: auth_tries,
|
721
|
-
on: [Google::Apis::AuthorizationError, Signet::AuthorizationError],
|
722
|
-
on_retry: proc { |*| refresh_authorization } do
|
723
|
-
execute_once_with_response(client).tap do |result|
|
724
|
-
if block_given?
|
725
|
-
yield result, nil
|
726
|
-
end
|
727
|
-
end
|
728
|
-
end
|
729
|
-
end
|
730
|
-
rescue => e
|
731
|
-
if block_given?
|
732
|
-
yield nil, e
|
733
|
-
else
|
734
|
-
raise e
|
735
|
-
end
|
736
|
-
end
|
737
|
-
ensure
|
738
|
-
release!
|
739
|
-
end
|
740
|
-
|
741
|
-
# Returns a two-element array containing:
|
742
|
-
# * The `result` that is the usual return type of #execute_once.
|
743
|
-
# * The `http_resp`.
|
744
|
-
def execute_once_with_response(client, &block)
|
745
|
-
request_header = header.dup
|
746
|
-
apply_request_options(request_header)
|
747
|
-
download_offset = nil
|
748
|
-
|
749
|
-
if @offset > 0
|
750
|
-
logger.debug { sprintf('Resuming download from offset %d', @offset) }
|
751
|
-
request_header[RANGE_HEADER] = sprintf('bytes=%d-', @offset)
|
752
|
-
end
|
753
|
-
|
754
|
-
http_res = client.get(url.to_s,
|
755
|
-
query: query,
|
756
|
-
header: request_header,
|
757
|
-
follow_redirect: true) do |res, chunk|
|
758
|
-
status = res.http_header.status_code.to_i
|
759
|
-
next unless OK_STATUS.include?(status)
|
760
|
-
|
761
|
-
download_offset ||= (status == 206 ? @offset : 0)
|
762
|
-
download_offset += chunk.bytesize
|
763
|
-
|
764
|
-
if download_offset - chunk.bytesize == @offset
|
765
|
-
next_chunk = chunk
|
766
|
-
else
|
767
|
-
# Oh no! Requested a chunk, but received the entire content
|
768
|
-
chunk_index = @offset - (download_offset - chunk.bytesize)
|
769
|
-
next_chunk = chunk.byteslice(chunk_index..-1)
|
770
|
-
next if next_chunk.nil?
|
771
|
-
end
|
772
|
-
# logger.debug { sprintf('Writing chunk (%d bytes, %d total)', chunk.length, bytes_read) }
|
773
|
-
@download_io.write(next_chunk)
|
774
|
-
|
775
|
-
@offset += next_chunk.bytesize
|
776
|
-
end
|
777
|
-
|
778
|
-
@download_io.flush
|
779
|
-
|
780
|
-
if @close_io_on_finish
|
781
|
-
result = nil
|
782
|
-
else
|
783
|
-
result = @download_io
|
784
|
-
end
|
785
|
-
check_status(http_res.status.to_i, http_res.header, http_res.body)
|
786
|
-
success([result, http_res], &block)
|
787
|
-
rescue => e
|
788
|
-
@download_io.flush
|
789
|
-
error(e, rethrow: true, &block)
|
935
|
+
def retry? query_params
|
936
|
+
query_params.any? { |_key, val| !val.nil? }
|
790
937
|
end
|
791
938
|
end
|
792
939
|
end
|
793
940
|
end
|
794
|
-
# rubocop:enable all
|
795
941
|
end
|