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.
@@ -38,17 +38,21 @@ module Google
38
38
 
39
39
  ##
40
40
  # Creates a new Service instance.
41
- def initialize project, credentials,
42
- retries: nil, timeout: nil, host: nil, quota_project: nil
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, user_project: nil
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
- user_project: user_project(user_project)
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, bucket_gapi = nil, predefined_acl: nil,
110
- predefined_default_acl: nil, user_project: nil
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
- bucket_name, bucket_gapi,
118
- predefined_acl: predefined_acl,
119
- predefined_default_object_acl: predefined_default_acl,
120
- user_project: user_project(user_project)
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, user_project: nil
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
- user_project: user_project(user_project)
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, source, path = nil, acl: nil,
294
- cache_control: nil, content_disposition: nil,
295
- content_encoding: nil, content_language: nil,
296
- content_type: nil, custom_time: nil, crc32c: nil, md5: nil, metadata: nil,
297
- storage_class: nil, key: nil, kms_key: nil,
298
- temporary_hold: nil, event_based_hold: nil,
299
- user_project: nil
300
- params =
301
- { cache_control: cache_control, content_type: content_type, custom_time: custom_time,
302
- content_disposition: content_disposition, md5_hash: md5,
303
- content_encoding: content_encoding, crc32c: crc32c,
304
- content_language: content_language, metadata: metadata,
305
- storage_class: storage_class, temporary_hold: temporary_hold,
306
- event_based_hold: event_based_hold }.delete_if { |_k, v| v.nil? }
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
- bucket_name, file_obj,
313
- name: path, predefined_acl: acl, upload_source: source,
314
- content_encoding: content_encoding, content_type: content_type,
315
- kms_key_name: kms_key, user_project: user_project(user_project),
316
- options: key_options(key)
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, file_path, generation: nil, key: nil,
323
- user_project: nil
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, source_file_path,
336
- destination_bucket_name, destination_file_path,
337
- file_gapi = nil, source_key: nil, destination_key: nil,
338
- destination_kms_key: nil, acl: nil, generation: nil,
339
- token: nil, user_project: nil
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
- source_bucket_name, source_file_path,
344
- destination_bucket_name, destination_file_path,
345
- file_gapi,
346
- destination_kms_key_name: destination_kms_key,
347
- destination_predefined_acl: acl,
348
- source_generation: generation,
349
- rewrite_token: token,
350
- user_project: user_project(user_project),
351
- options: key_options
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, source_files, destination_path,
358
- destination_gapi, acl: nil, key: nil, user_project: nil
359
-
360
- compose_req = Google::Apis::StorageV1::ComposeRequest.new \
361
- source_objects: compose_file_source_objects(source_files),
362
- destination: destination_gapi
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
- bucket_name, destination_path,
367
- compose_req,
368
- destination_predefined_acl: acl,
369
- user_project: user_project(user_project),
370
- options: key_options(key)
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 key
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.get_object_with_response \
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, file_path, file_gapi = nil,
400
- predefined_acl: nil, user_project: nil
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
- bucket_name, file_path, file_gapi,
405
- predefined_acl: predefined_acl,
406
- user_project: user_project(user_project)
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, file_path, generation: nil,
413
- user_project: nil
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
- user_project: user_project(user_project)
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
- # rubocop:disable all
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