google-cloud-storage 1.35.0 → 1.54.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -109,6 +109,24 @@ module Google
109
109
  @gapi.id
110
110
  end
111
111
 
112
+ ##
113
+ # The autoclass configuration of the bucket
114
+ #
115
+ # @return [Google::Apis::StorageV1::Bucket::Autoclass]
116
+ #
117
+ def autoclass
118
+ @gapi.autoclass
119
+ end
120
+
121
+ ##
122
+ # The object retention configuration of the bucket
123
+ #
124
+ # @return [Google::Apis::StorageV1::Bucket::ObjectRetention]
125
+ #
126
+ def object_retention
127
+ @gapi.object_retention
128
+ end
129
+
112
130
  ##
113
131
  # The name of the bucket.
114
132
  #
@@ -279,7 +297,7 @@ module Google
279
297
  #
280
298
  # @return [String]
281
299
  #
282
- # @see https://cloud.google.com/storage/docs/concepts-techniques
300
+ # @see https://cloud.google.com/storage/docs/locations
283
301
  #
284
302
  def location
285
303
  @gapi.location
@@ -301,6 +319,20 @@ module Google
301
319
  @gapi.location_type
302
320
  end
303
321
 
322
+ ##
323
+ # Returns the list of regional locations for custom dual-region buckets.
324
+ #
325
+ # @return [String, nil] Returns nil if the property has not been set before creation,
326
+ # if the bucket's resource has not been loaded from the server,
327
+ # or if the bucket is not a dual-regions bucket.
328
+
329
+ # @see https://cloud.google.com/storage/docs/json_api/v1/buckets and
330
+ # https://cloud.google.com/storage/docs/locations
331
+ #
332
+ def data_locations
333
+ @gapi.custom_placement_config&.data_locations
334
+ end
335
+
304
336
  ##
305
337
  # The destination bucket name for the bucket's logs.
306
338
  #
@@ -393,6 +425,77 @@ module Google
393
425
  patch_gapi! :storage_class
394
426
  end
395
427
 
428
+ ##
429
+ # Whether Autoclass is enabled for the bucket.
430
+ #
431
+ # @return [Boolean]
432
+ #
433
+ def autoclass_enabled
434
+ @gapi.autoclass&.enabled?
435
+ end
436
+
437
+ ##
438
+ # Toggle time of the autoclass
439
+ #
440
+ # @return [DateTime]
441
+ #
442
+ def autoclass_toggle_time
443
+ @gapi.autoclass&.toggle_time
444
+ end
445
+
446
+ ##
447
+ # Terminal Storage class of the autoclass
448
+ #
449
+ # @return [String]
450
+ #
451
+ def autoclass_terminal_storage_class
452
+ @gapi.autoclass&.terminal_storage_class
453
+ end
454
+
455
+ ##
456
+ # Update time at which the autoclass terminal storage class was last modified
457
+ #
458
+ # @return [DateTime]
459
+ #
460
+ def autoclass_terminal_storage_class_update_time
461
+ @gapi.autoclass&.terminal_storage_class_update_time
462
+ end
463
+
464
+ ##
465
+ # Updates bucket's autoclass configuration. This defines the default class for objects in the
466
+ # bucket and down/up-grades the storage class of objects based on the access patterns.
467
+ # Accepted values are `:false`, and `:true`.
468
+ #
469
+ # For more information, see [Storage
470
+ # Classes](https://cloud.google.com/storage/docs/using-autoclass).
471
+ #
472
+ # @param [Boolean] toggle for autoclass configuration of the bucket.
473
+ #
474
+ def autoclass_enabled= toggle
475
+ @gapi.autoclass ||= API::Bucket::Autoclass.new
476
+ @gapi.autoclass.enabled = toggle
477
+ patch_gapi! :autoclass
478
+ end
479
+
480
+ ##
481
+ # Update method to update all attributes of autoclass of a bucket
482
+ # It accepts params as a Hash of attributes in the following format:
483
+ #
484
+ # { enabled: true, terminal_storage_class: "ARCHIVE" }
485
+ #
486
+ # terminal_storage_class field is optional. It defaults to `NEARLINE`.
487
+ # Valid terminal_storage_class values are `NEARLINE` and `ARCHIVE`.
488
+ #
489
+ # @param [Hash(String => String)] autoclass_attributes
490
+ #
491
+ def update_autoclass autoclass_attributes
492
+ @gapi.autoclass ||= API::Bucket::Autoclass.new
493
+ autoclass_attributes.each do |k, v|
494
+ @gapi.autoclass.send "#{k}=", v
495
+ end
496
+ patch_gapi! :autoclass
497
+ end
498
+
396
499
  ##
397
500
  # Whether [Object
398
501
  # Versioning](https://cloud.google.com/storage/docs/object-versioning)
@@ -1035,6 +1138,177 @@ module Google
1035
1138
 
1036
1139
  alias public_access_prevention_unspecified? public_access_prevention_inherited?
1037
1140
 
1141
+ ##
1142
+ # Recovery Point Objective (RPO) is another attribute of a bucket, it measures how long it takes for a set of
1143
+ # updates to be asynchronously copied to the other region.
1144
+ # Currently, `DEFAULT` and `ASYNC_TURBO` are supported. When set to `ASYNC_TURBO`, Turbo Replication is enabled
1145
+ # for a bucket. `DEFAULT` is used to reset rpo on an existing bucket with rpo set to `ASYNC_TURBO`.
1146
+ # This value can be modified by calling {#rpo=}.
1147
+ #
1148
+ # @return [String, nil] Currently, `DEFAULT` and `ASYNC_TURBO` are supported. Returns `nil` if the bucket has
1149
+ # no RPO.
1150
+ #
1151
+ # @example
1152
+ # require "google/cloud/storage"
1153
+ #
1154
+ # storage = Google::Cloud::Storage.new
1155
+ #
1156
+ # bucket = storage.bucket "my-bucket"
1157
+ #
1158
+ # bucket.rpo = :DEFAULT
1159
+ # bucket.rpo #=> "DEFAULT"
1160
+ #
1161
+ def rpo
1162
+ @gapi.rpo
1163
+ end
1164
+
1165
+ ##
1166
+ # Sets the value for Recovery Point Objective (RPO) in the bucket. This value can be queried by calling {#rpo}.
1167
+ #
1168
+ # @param [Symbol, String] new_rpo The bucket's new Recovery Point Objective metadata.
1169
+ # Currently, `DEFAULT` and `ASYNC_TURBO` are supported. When set to `ASYNC_TURBO`, Turbo Replication
1170
+ # is enabled for a bucket.
1171
+ #
1172
+ # @example Set RPO to DEFAULT:
1173
+ # require "google/cloud/storage"
1174
+ #
1175
+ # storage = Google::Cloud::Storage.new
1176
+ #
1177
+ # bucket = storage.bucket "my-bucket"
1178
+ #
1179
+ # bucket.rpo = :DEFAULT
1180
+ # bucket.rpo #=> "DEFAULT"
1181
+ #
1182
+ # @example Set RPO to ASYNC_TURBO:
1183
+ # require "google/cloud/storage"
1184
+ #
1185
+ # storage = Google::Cloud::Storage.new
1186
+ #
1187
+ # bucket = storage.bucket "my-bucket"
1188
+ #
1189
+ # bucket.rpo = :ASYNC_TURBO
1190
+ # bucket.rpo #=> "ASYNC_TURBO"
1191
+ #
1192
+ def rpo= new_rpo
1193
+ @gapi.rpo = new_rpo&.to_s
1194
+ patch_gapi! :rpo
1195
+ end
1196
+
1197
+ ##
1198
+ # The bucket's soft delete policy. If this policy is set, any deleted
1199
+ # objects will be soft-deleted according to the time specified in the
1200
+ # policy.
1201
+ # This value can be modified by calling {#soft_delete_policy=}.
1202
+ #
1203
+ # @return [Google::Apis::StorageV1::Bucket::SoftDeletePolicy] The default retention policy is for 7
1204
+ # days.
1205
+ #
1206
+ # @example
1207
+ # require "google/cloud/storage"
1208
+ #
1209
+ # storage = Google::Cloud::Storage.new
1210
+ #
1211
+ # bucket = storage.bucket "my-bucket"
1212
+ #
1213
+ # bucket.soft_delete_policy
1214
+ #
1215
+ def soft_delete_policy
1216
+ @gapi.soft_delete_policy
1217
+ end
1218
+
1219
+ ##
1220
+ # Sets the value for Soft Delete Policy in the bucket. This value can
1221
+ # be queried by calling {#soft_delete_policy}.
1222
+ #
1223
+ # @param [Google::Apis::StorageV1::Bucket::SoftDeletePolicy,
1224
+ # Hash(String => String)] new_soft_delete_policy The bucket's
1225
+ # new Soft Delete Policy.
1226
+ #
1227
+ # @example Set Soft Delete Policy to 10 days using SoftDeletePolicy class:
1228
+ # require "google/cloud/storage"
1229
+ # require "date"
1230
+ #
1231
+ # storage = Google::Cloud::Storage.new
1232
+ #
1233
+ # bucket = storage.bucket "my-bucket"
1234
+ #
1235
+ # soft_delete_policy = Google::Apis::StorageV1::Bucket::SoftDeletePolicy.new
1236
+ # soft_delete_policy.retention_duration_seconds = 10*24*60*60
1237
+ #
1238
+ # bucket.soft_delete_policy = soft_delete_policy
1239
+ #
1240
+ # @example Set Soft Delete Policy to 5 days using Hash:
1241
+ # require "google/cloud/storage"
1242
+ # require "date"
1243
+ #
1244
+ # storage = Google::Cloud::Storage.new
1245
+ #
1246
+ # bucket = storage.bucket "my-bucket"
1247
+ #
1248
+ # soft_delete_policy = { retention_duration_seconds: 432000 }
1249
+ # bucket.soft_delete_policy = soft_delete_policy
1250
+ #
1251
+ def soft_delete_policy= new_soft_delete_policy
1252
+ @gapi.soft_delete_policy = new_soft_delete_policy || {}
1253
+ patch_gapi! :soft_delete_policy
1254
+ end
1255
+
1256
+ ##
1257
+ # The bucket's hierarchical namespace (Folders) configuration.
1258
+ # This value can be modified by calling {#hierarchical_namespace=}.
1259
+ #
1260
+ # @return [Google::Apis::StorageV1::Bucket::HierarchicalNamespace]
1261
+ #
1262
+ # @example
1263
+ # require "google/cloud/storage"
1264
+ #
1265
+ # storage = Google::Cloud::Storage.new
1266
+ #
1267
+ # bucket = storage.bucket "my-bucket"
1268
+ #
1269
+ # bucket.hierarchical_namespace
1270
+ #
1271
+ def hierarchical_namespace
1272
+ @gapi.hierarchical_namespace
1273
+ end
1274
+
1275
+ ##
1276
+ # Sets the value of Hierarchical Namespace (Folders) for the bucket.
1277
+ # This can only be enabled at bucket create time. If this is enabled,
1278
+ # Uniform Bucket-Level Access must also be enabled.
1279
+ # This value can be queried by calling {#hierarchical_namespace}.
1280
+ #
1281
+ # @param [Google::Apis::StorageV1::Bucket::HierarchicalNamespace,
1282
+ # Hash(String => String)] new_hierarchical_namespace The
1283
+ # bucket's new Hierarchical Namespace Configuration.
1284
+ #
1285
+ # @example Enabled Hierarchical Namespace using HierarchicalNamespace class:
1286
+ # require "google/cloud/storage"
1287
+ #
1288
+ # storage = Google::Cloud::Storage.new
1289
+ #
1290
+ # bucket = storage.bucket "my-bucket"
1291
+ #
1292
+ # hierarchical_namespace = Google::Apis::StorageV1::Bucket::HierarchicalNamespace.new
1293
+ # hierarchical_namespace.enabled = true
1294
+ #
1295
+ # bucket.hierarchical_namespace = hierarchical_namespace
1296
+ #
1297
+ # @example Disable Hierarchical Namespace using Hash:
1298
+ # require "google/cloud/storage"
1299
+ #
1300
+ # storage = Google::Cloud::Storage.new
1301
+ #
1302
+ # bucket = storage.bucket "my-bucket"
1303
+ #
1304
+ # hierarchical_namespace = { enabled: false }
1305
+ # bucket.hierarchical_namespace = hierarchical_namespace
1306
+ #
1307
+ def hierarchical_namespace= new_hierarchical_namespace
1308
+ @gapi.hierarchical_namespace = new_hierarchical_namespace || {}
1309
+ patch_gapi! :hierarchical_namespace
1310
+ end
1311
+
1038
1312
  ##
1039
1313
  # Updates the bucket with changes made in the given block in a single
1040
1314
  # PATCH request. The following attributes may be set: {#cors},
@@ -1100,9 +1374,9 @@ module Google
1100
1374
  updater.check_for_mutable_cors!
1101
1375
  updater.check_for_mutable_lifecycle!
1102
1376
  return if updater.updates.empty?
1103
- patch_gapi! updater.updates,
1104
- if_metageneration_match: if_metageneration_match,
1105
- if_metageneration_not_match: if_metageneration_not_match
1377
+ update_gapi! updater.updates,
1378
+ if_metageneration_match: if_metageneration_match,
1379
+ if_metageneration_not_match: if_metageneration_not_match
1106
1380
  end
1107
1381
 
1108
1382
  ##
@@ -1149,6 +1423,9 @@ module Google
1149
1423
  # `prefixes` are omitted.
1150
1424
  # @param [String] token A previously-returned page token representing
1151
1425
  # part of the larger set of results to view.
1426
+ # @param [String] match_glob A glob pattern used to filter results returned in items (e.g. `foo*bar`).
1427
+ # The string value must be UTF-8 encoded. See:
1428
+ # https://cloud.google.com/storage/docs/json_api/v1/objects/list#list-object-glob
1152
1429
  # @param [Integer] max Maximum number of items plus prefixes to return.
1153
1430
  # As duplicate prefixes are omitted, fewer total results may be
1154
1431
  # returned than requested. The default value of this parameter is
@@ -1157,6 +1434,11 @@ module Google
1157
1434
  # as distinct results. The default is `false`. For more information,
1158
1435
  # see [Object Versioning
1159
1436
  # ](https://cloud.google.com/storage/docs/object-versioning).
1437
+ # @param [Boolean] include_folders_as_prefixes If `true`, will also include
1438
+ # folders and managed folders, besides objects, in the returned prefixes.
1439
+ # Only applicable if delimiter is set to '/'.
1440
+ # @param [Boolean] soft_deleted If true, only soft-deleted object
1441
+ # versions will be listed. The default is false.
1160
1442
  #
1161
1443
  # @return [Array<Google::Cloud::Storage::File>] (See
1162
1444
  # {Google::Cloud::Storage::File::List})
@@ -1184,14 +1466,22 @@ module Google
1184
1466
  # end
1185
1467
  #
1186
1468
  def files prefix: nil, delimiter: nil, token: nil, max: nil,
1187
- versions: nil
1469
+ versions: nil, match_glob: nil, include_folders_as_prefixes: nil,
1470
+ soft_deleted: nil
1188
1471
  ensure_service!
1189
1472
  gapi = service.list_files name, prefix: prefix, delimiter: delimiter,
1190
1473
  token: token, max: max,
1191
1474
  versions: versions,
1192
- user_project: user_project
1475
+ user_project: user_project,
1476
+ match_glob: match_glob,
1477
+ include_folders_as_prefixes: include_folders_as_prefixes,
1478
+ soft_deleted: soft_deleted
1193
1479
  File::List.from_gapi gapi, service, name, prefix, delimiter, max,
1194
- versions, user_project: user_project
1480
+ versions,
1481
+ user_project: user_project,
1482
+ match_glob: match_glob,
1483
+ include_folders_as_prefixes: include_folders_as_prefixes,
1484
+ soft_deleted: soft_deleted
1195
1485
  end
1196
1486
  alias find_files files
1197
1487
 
@@ -1227,6 +1517,8 @@ module Google
1227
1517
  # @param [String] encryption_key Optional. The customer-supplied,
1228
1518
  # AES-256 encryption key used to encrypt the file, if one was provided
1229
1519
  # to {#create_file}. (Not used if `skip_lookup` is also set.)
1520
+ # @param [Boolean] soft_deleted Optional. If true, only soft-deleted
1521
+ # object versions will be listed. The default is false.
1230
1522
  #
1231
1523
  # @return [Google::Cloud::Storage::File, nil] Returns nil if file does
1232
1524
  # not exist
@@ -1248,7 +1540,8 @@ module Google
1248
1540
  if_metageneration_match: nil,
1249
1541
  if_metageneration_not_match: nil,
1250
1542
  skip_lookup: nil,
1251
- encryption_key: nil
1543
+ encryption_key: nil,
1544
+ soft_deleted: nil
1252
1545
  ensure_service!
1253
1546
  if skip_lookup
1254
1547
  return File.new_lazy name, path, service,
@@ -1261,7 +1554,8 @@ module Google
1261
1554
  if_metageneration_match: if_metageneration_match,
1262
1555
  if_metageneration_not_match: if_metageneration_not_match,
1263
1556
  key: encryption_key,
1264
- user_project: user_project
1557
+ user_project: user_project,
1558
+ soft_deleted: soft_deleted
1265
1559
  File.from_gapi gapi, service, user_project: user_project
1266
1560
  rescue Google::Cloud::NotFoundError
1267
1561
  nil
@@ -1542,6 +1836,77 @@ module Google
1542
1836
  alias upload_file create_file
1543
1837
  alias new_file create_file
1544
1838
 
1839
+ ##
1840
+ # Restores a soft-deleted object.
1841
+ #
1842
+ # @param [String] file_path
1843
+ # Name of the file.
1844
+ # @param [Fixnum] generation
1845
+ # Selects a specific revision of this object.
1846
+ # @param [Boolean] copy_source_acl
1847
+ # If true, copies the source file's ACL; otherwise, uses the
1848
+ # bucket's default file ACL. The default is false.
1849
+ # @param [Fixnum] if_generation_match
1850
+ # Makes the operation conditional on whether the file's one live
1851
+ # generation matches the given value. Setting to 0 makes the
1852
+ # operation succeed only if there are no live versions of the file.
1853
+ # @param [Fixnum] if_generation_not_match
1854
+ # Makes the operation conditional on whether none of the file's live
1855
+ # generations match the given value. If no live file exists, the
1856
+ # precondition fails. Setting to 0 makes the operation succeed only
1857
+ # if there is a live version of the file.
1858
+ # @param [Fixnum] if_metageneration_match
1859
+ # Makes the operation conditional on whether the file's one live
1860
+ # metageneration matches the given value.
1861
+ # @param [Fixnum] if_metageneration_not_match
1862
+ # Makes the operation conditional on whether none of the object's
1863
+ # live metagenerations match the given value.
1864
+ # @param [String] projection
1865
+ # Set of properties to return. Defaults to full.
1866
+ # @param [String] user_project
1867
+ # The project to be billed for this request. Required for Requester
1868
+ # Pays buckets.
1869
+ # @param [String] fields
1870
+ # Selector specifying which fields to include in a partial response.
1871
+ #
1872
+ # @return [Google::Cloud::Storage::File]
1873
+ #
1874
+ # @example
1875
+ # require "google/cloud/storage"
1876
+ #
1877
+ # storage = Google::Cloud::Storage.new
1878
+ #
1879
+ # bucket = storage.bucket "my-bucket"
1880
+ #
1881
+ # bucket.restore_file "path/of/file", <generation-of-the-file>
1882
+ #
1883
+ def restore_file file_path,
1884
+ generation,
1885
+ copy_source_acl: nil,
1886
+ if_generation_match: nil,
1887
+ if_generation_not_match: nil,
1888
+ if_metageneration_match: nil,
1889
+ if_metageneration_not_match: nil,
1890
+ projection: nil,
1891
+ user_project: nil,
1892
+ fields: nil,
1893
+ options: {}
1894
+ ensure_service!
1895
+ gapi = service.restore_file name,
1896
+ file_path,
1897
+ generation,
1898
+ copy_source_acl: File::Acl.predefined_rule_for(copy_source_acl),
1899
+ if_generation_match: if_generation_match,
1900
+ if_generation_not_match: if_generation_not_match,
1901
+ if_metageneration_match: if_metageneration_match,
1902
+ if_metageneration_not_match: if_metageneration_not_match,
1903
+ projection: projection,
1904
+ user_project: user_project,
1905
+ fields: fields,
1906
+ options: options
1907
+ File.from_gapi gapi, service, user_project: user_project
1908
+ end
1909
+
1545
1910
  ##
1546
1911
  # Concatenates a list of existing files in the bucket into a new file in
1547
1912
  # the bucket. There is a limit (currently 32) to the number of files
@@ -2822,9 +3187,9 @@ module Google
2822
3187
  attributes.flatten!
2823
3188
  return if attributes.empty?
2824
3189
  ensure_service!
2825
- patch_args = Hash[attributes.map do |attr|
3190
+ patch_args = attributes.to_h do |attr|
2826
3191
  [attr, @gapi.send(attr)]
2827
- end]
3192
+ end
2828
3193
  patch_gapi = API::Bucket.new(**patch_args)
2829
3194
  @gapi = service.patch_bucket name,
2830
3195
  patch_gapi,
@@ -2835,6 +3200,26 @@ module Google
2835
3200
  self
2836
3201
  end
2837
3202
 
3203
+ def update_gapi! attributes,
3204
+ if_metageneration_match: nil,
3205
+ if_metageneration_not_match: nil
3206
+ attributes = Array(attributes)
3207
+ attributes.flatten!
3208
+ return if attributes.empty?
3209
+ ensure_service!
3210
+ update_args = attributes.to_h do |attr|
3211
+ [attr, @gapi.send(attr)]
3212
+ end
3213
+ update_gapi = API::Bucket.new(**update_args)
3214
+ @gapi = service.update_bucket name,
3215
+ update_gapi,
3216
+ if_metageneration_match: if_metageneration_match,
3217
+ if_metageneration_not_match: if_metageneration_not_match,
3218
+ user_project: user_project
3219
+ @lazy = nil
3220
+ self
3221
+ end
3222
+
2838
3223
  ##
2839
3224
  # Raise an error if the file is not found.
2840
3225
  def ensure_io_or_file_exists! file
@@ -83,10 +83,12 @@ module Google
83
83
  token: @token,
84
84
  max: @max,
85
85
  versions: @versions,
86
- user_project: @user_project
86
+ user_project: @user_project,
87
+ match_glob: @match_glob
87
88
  File::List.from_gapi gapi, @service, @bucket, @prefix,
88
89
  @delimiter, @max, @versions,
89
- user_project: @user_project
90
+ user_project: @user_project,
91
+ match_glob: @match_glob
90
92
  end
91
93
 
92
94
  ##
@@ -163,7 +165,9 @@ module Google
163
165
  # Google::Apis::StorageV1::Objects object.
164
166
  def self.from_gapi gapi_list, service, bucket = nil, prefix = nil,
165
167
  delimiter = nil, max = nil, versions = nil,
166
- user_project: nil
168
+ user_project: nil, match_glob: nil,
169
+ include_folders_as_prefixes: nil,
170
+ soft_deleted: nil
167
171
  files = new(Array(gapi_list.items).map do |gapi_object|
168
172
  File.from_gapi gapi_object, service, user_project: user_project
169
173
  end)
@@ -176,6 +180,9 @@ module Google
176
180
  files.instance_variable_set :@max, max
177
181
  files.instance_variable_set :@versions, versions
178
182
  files.instance_variable_set :@user_project, user_project
183
+ files.instance_variable_set :@match_glob, match_glob
184
+ files.instance_variable_set :@include_folders_as_prefixes, include_folders_as_prefixes
185
+ files.instance_variable_set :@soft_deleted, soft_deleted
179
186
  files
180
187
  end
181
188
 
@@ -48,7 +48,7 @@ module Google
48
48
  #
49
49
  def ext_path
50
50
  path = "/#{@bucket}/#{@path}"
51
- escaped = Addressable::URI.escape path
51
+ escaped = Addressable::URI.encode_component path, Addressable::URI::CharacterClasses::PATH
52
52
  special_var = "${filename}"
53
53
  # Restore the unencoded `${filename}` variable, if present.
54
54
  if path.include? special_var
@@ -60,7 +60,8 @@ module Google
60
60
  ##
61
61
  # The external url to the file.
62
62
  def ext_url
63
- "#{GOOGLEAPIS_URL}#{ext_path}"
63
+ root_url = @service.service.root_url.chomp "/"
64
+ "#{root_url}#{ext_path}"
64
65
  end
65
66
 
66
67
  def apply_option_defaults options
@@ -91,7 +92,7 @@ module Google
91
92
 
92
93
  def error_msg attr_name
93
94
  "Service account credentials '#{attr_name}' is missing. To generate service account credentials " \
94
- "see https://cloud.google.com/iam/docs/service-accounts"
95
+ "see https://cloud.google.com/iam/docs/service-accounts"
95
96
  end
96
97
 
97
98
  def post_object options
@@ -144,8 +145,8 @@ module Google
144
145
 
145
146
  def generate_signed_url issuer, signed_string, expires, query
146
147
  url = "#{ext_url}?GoogleAccessId=#{url_escape issuer}" \
147
- "&Expires=#{expires}" \
148
- "&Signature=#{url_escape signed_string}"
148
+ "&Expires=#{expires}" \
149
+ "&Signature=#{url_escape signed_string}"
149
150
 
150
151
  query&.each do |name, value|
151
152
  url << "&#{url_escape name}=#{url_escape value}"
@@ -131,7 +131,7 @@ module Google
131
131
  # methods below are public visibility only for unit testing
132
132
  # rubocop:disable Style/StringLiterals
133
133
  def escape_characters str
134
- str.split("").map do |s|
134
+ str.chars.map do |s|
135
135
  if s.ascii_only?
136
136
  case s
137
137
  when "\\"
@@ -207,7 +207,7 @@ module Google
207
207
 
208
208
  def error_msg attr_name
209
209
  "Service account credentials '#{attr_name}' is missing. To generate service account credentials " \
210
- "see https://cloud.google.com/iam/docs/service-accounts"
210
+ "see https://cloud.google.com/iam/docs/service-accounts"
211
211
  end
212
212
 
213
213
  def service_account_signer signer
@@ -243,7 +243,7 @@ module Google
243
243
  headers_arr = canonical_headers.map do |k, v|
244
244
  [k.downcase, v.strip.gsub(/[^\S\t]+/, " ").gsub(/\t+/, " ")]
245
245
  end
246
- canonical_headers = Hash[headers_arr]
246
+ canonical_headers = headers_arr.to_h
247
247
  canonical_headers["host"] = host_name virtual_hosted_style, bucket_bound_hostname
248
248
 
249
249
  canonical_headers = canonical_headers.sort_by(&:first).to_h
@@ -295,13 +295,13 @@ module Google
295
295
  ##
296
296
  # The external path to the bucket, with trailing slash.
297
297
  def bucket_path path_style
298
- return "/#{@bucket_name}/" if path_style
298
+ "/#{@bucket_name}/" if path_style
299
299
  end
300
300
 
301
301
  ##
302
302
  # The external url to the file.
303
303
  def ext_url scheme, virtual_hosted_style, bucket_bound_hostname
304
- url = GOOGLEAPIS_URL.dup
304
+ url = @service.service.root_url.chomp "/"
305
305
  if virtual_hosted_style
306
306
  parts = url.split "//"
307
307
  parts[1] = "#{@bucket_name}.#{parts[1]}"
@@ -326,7 +326,7 @@ module Google
326
326
  #
327
327
  def post_object_ext_path
328
328
  path = "/#{@bucket_name}/#{@file_name}"
329
- escaped = Addressable::URI.escape path
329
+ escaped = Addressable::URI.encode_component path, Addressable::URI::CharacterClasses::PATH
330
330
  special_var = "${filename}"
331
331
  # Restore the unencoded `${filename}` variable, if present.
332
332
  if path.include? special_var