gcloud 0.11.0 → 0.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (121) hide show
  1. checksums.yaml +8 -8
  2. data/AUTHENTICATION.md +3 -3
  3. data/CHANGELOG.md +92 -0
  4. data/OVERVIEW.md +3 -3
  5. data/lib/gcloud.rb +75 -25
  6. data/lib/gcloud/backoff.rb +5 -1
  7. data/lib/gcloud/bigquery.rb +25 -43
  8. data/lib/gcloud/bigquery/copy_job.rb +13 -13
  9. data/lib/gcloud/bigquery/data.rb +20 -16
  10. data/lib/gcloud/bigquery/dataset.rb +202 -177
  11. data/lib/gcloud/bigquery/dataset/access.rb +118 -104
  12. data/lib/gcloud/bigquery/dataset/list.rb +14 -18
  13. data/lib/gcloud/bigquery/extract_job.rb +12 -12
  14. data/lib/gcloud/bigquery/insert_response.rb +12 -14
  15. data/lib/gcloud/bigquery/job.rb +45 -57
  16. data/lib/gcloud/bigquery/job/list.rb +18 -24
  17. data/lib/gcloud/bigquery/load_job.rb +35 -27
  18. data/lib/gcloud/bigquery/project.rb +53 -73
  19. data/lib/gcloud/bigquery/query_data.rb +28 -35
  20. data/lib/gcloud/bigquery/query_job.rb +18 -18
  21. data/lib/gcloud/bigquery/schema.rb +359 -0
  22. data/lib/gcloud/bigquery/service.rb +506 -0
  23. data/lib/gcloud/bigquery/table.rb +185 -266
  24. data/lib/gcloud/bigquery/table/list.rb +15 -19
  25. data/lib/gcloud/bigquery/view.rb +126 -81
  26. data/lib/gcloud/datastore.rb +39 -27
  27. data/lib/gcloud/datastore/commit.rb +2 -2
  28. data/lib/gcloud/datastore/dataset.rb +8 -19
  29. data/lib/gcloud/datastore/dataset/lookup_results.rb +2 -4
  30. data/lib/gcloud/datastore/dataset/query_results.rb +0 -2
  31. data/lib/gcloud/datastore/entity.rb +7 -1
  32. data/lib/gcloud/datastore/errors.rb +5 -27
  33. data/lib/gcloud/datastore/grpc_utils.rb +4 -3
  34. data/lib/gcloud/datastore/key.rb +6 -0
  35. data/lib/gcloud/datastore/service.rb +18 -12
  36. data/lib/gcloud/datastore/transaction.rb +0 -10
  37. data/lib/gcloud/dns.rb +29 -19
  38. data/lib/gcloud/dns/change.rb +10 -15
  39. data/lib/gcloud/dns/change/list.rb +4 -4
  40. data/lib/gcloud/dns/importer.rb +1 -1
  41. data/lib/gcloud/dns/project.rb +32 -49
  42. data/lib/gcloud/dns/record.rb +8 -2
  43. data/lib/gcloud/dns/record/list.rb +4 -4
  44. data/lib/gcloud/dns/service.rb +167 -0
  45. data/lib/gcloud/dns/zone.rb +33 -52
  46. data/lib/gcloud/dns/zone/list.rb +12 -16
  47. data/lib/gcloud/errors.rb +31 -19
  48. data/lib/gcloud/logging.rb +50 -39
  49. data/lib/gcloud/logging/entry.rb +197 -24
  50. data/lib/gcloud/logging/entry/list.rb +0 -2
  51. data/lib/gcloud/logging/logger.rb +1 -1
  52. data/lib/gcloud/logging/metric.rb +3 -9
  53. data/lib/gcloud/logging/metric/list.rb +0 -2
  54. data/lib/gcloud/logging/project.rb +58 -54
  55. data/lib/gcloud/logging/resource_descriptor.rb +2 -2
  56. data/lib/gcloud/logging/resource_descriptor/list.rb +0 -2
  57. data/lib/gcloud/logging/service.rb +32 -23
  58. data/lib/gcloud/logging/sink.rb +8 -14
  59. data/lib/gcloud/logging/sink/list.rb +0 -2
  60. data/lib/gcloud/pubsub.rb +21 -16
  61. data/lib/gcloud/pubsub/policy.rb +204 -0
  62. data/lib/gcloud/pubsub/project.rb +26 -38
  63. data/lib/gcloud/pubsub/service.rb +39 -31
  64. data/lib/gcloud/pubsub/subscription.rb +56 -59
  65. data/lib/gcloud/pubsub/subscription/list.rb +4 -4
  66. data/lib/gcloud/pubsub/topic.rb +69 -66
  67. data/lib/gcloud/pubsub/topic/list.rb +0 -2
  68. data/lib/gcloud/pubsub/topic/{batch.rb → publisher.rb} +15 -2
  69. data/lib/gcloud/resource_manager.rb +27 -26
  70. data/lib/gcloud/resource_manager/manager.rb +19 -39
  71. data/lib/gcloud/resource_manager/policy.rb +211 -0
  72. data/lib/gcloud/resource_manager/project.rb +97 -121
  73. data/lib/gcloud/resource_manager/project/list.rb +7 -7
  74. data/lib/gcloud/resource_manager/project/updater.rb +4 -9
  75. data/lib/gcloud/resource_manager/service.rb +127 -0
  76. data/lib/gcloud/storage.rb +24 -42
  77. data/lib/gcloud/storage/bucket.rb +104 -192
  78. data/lib/gcloud/storage/bucket/acl.rb +47 -143
  79. data/lib/gcloud/storage/bucket/cors.rb +55 -11
  80. data/lib/gcloud/storage/bucket/list.rb +14 -14
  81. data/lib/gcloud/storage/errors.rb +3 -43
  82. data/lib/gcloud/storage/file.rb +114 -111
  83. data/lib/gcloud/storage/file/acl.rb +27 -113
  84. data/lib/gcloud/storage/file/list.rb +21 -21
  85. data/lib/gcloud/storage/project.rb +49 -59
  86. data/lib/gcloud/storage/service.rb +347 -0
  87. data/lib/gcloud/translate.rb +24 -14
  88. data/lib/gcloud/translate/api.rb +12 -21
  89. data/lib/gcloud/translate/detection.rb +5 -5
  90. data/lib/gcloud/translate/language.rb +1 -1
  91. data/lib/gcloud/translate/service.rb +80 -0
  92. data/lib/gcloud/translate/translation.rb +6 -6
  93. data/lib/gcloud/version.rb +1 -1
  94. data/lib/gcloud/vision.rb +24 -15
  95. data/lib/gcloud/vision/annotate.rb +24 -21
  96. data/lib/gcloud/vision/annotation.rb +9 -9
  97. data/lib/gcloud/vision/annotation/entity.rb +11 -11
  98. data/lib/gcloud/vision/annotation/face.rb +25 -25
  99. data/lib/gcloud/vision/annotation/properties.rb +8 -8
  100. data/lib/gcloud/vision/annotation/safe_search.rb +4 -4
  101. data/lib/gcloud/vision/annotation/text.rb +7 -7
  102. data/lib/gcloud/vision/annotation/vertex.rb +1 -1
  103. data/lib/gcloud/vision/image.rb +11 -11
  104. data/lib/gcloud/vision/location.rb +5 -2
  105. data/lib/gcloud/vision/project.rb +14 -16
  106. data/lib/gcloud/vision/service.rb +66 -0
  107. data/lib/google/api_client.rb +0 -0
  108. metadata +27 -24
  109. data/lib/gcloud/bigquery/connection.rb +0 -624
  110. data/lib/gcloud/bigquery/errors.rb +0 -68
  111. data/lib/gcloud/bigquery/table/schema.rb +0 -234
  112. data/lib/gcloud/dns/connection.rb +0 -173
  113. data/lib/gcloud/dns/errors.rb +0 -68
  114. data/lib/gcloud/resource_manager/connection.rb +0 -134
  115. data/lib/gcloud/resource_manager/errors.rb +0 -68
  116. data/lib/gcloud/storage/connection.rb +0 -444
  117. data/lib/gcloud/translate/connection.rb +0 -85
  118. data/lib/gcloud/translate/errors.rb +0 -68
  119. data/lib/gcloud/upload.rb +0 -95
  120. data/lib/gcloud/vision/connection.rb +0 -63
  121. data/lib/gcloud/vision/errors.rb +0 -69
@@ -49,7 +49,7 @@ module Gcloud
49
49
  class File
50
50
  ##
51
51
  # @private The Connection object.
52
- attr_accessor :connection
52
+ attr_accessor :service
53
53
 
54
54
  ##
55
55
  # @private The Google API Client object.
@@ -58,40 +58,40 @@ module Gcloud
58
58
  ##
59
59
  # @private Create an empty File object.
60
60
  def initialize
61
- @connection = nil
62
- @gapi = {}
61
+ @service = nil
62
+ @gapi = Google::Apis::StorageV1::Object.new
63
63
  end
64
64
 
65
65
  ##
66
66
  # The kind of item this is.
67
67
  # For files, this is always storage#object.
68
68
  def kind
69
- @gapi["kind"]
69
+ @gapi.kind
70
70
  end
71
71
 
72
72
  ##
73
73
  # The ID of the file.
74
74
  def id
75
- @gapi["id"]
75
+ @gapi.id
76
76
  end
77
77
 
78
78
  ##
79
79
  # The name of this file.
80
80
  def name
81
- @gapi["name"]
81
+ @gapi.name
82
82
  end
83
83
 
84
84
  ##
85
85
  # The name of the {Bucket} containing this file.
86
86
  def bucket
87
- @gapi["bucket"]
87
+ @gapi.bucket
88
88
  end
89
89
 
90
90
  ##
91
91
  # The content generation of this file.
92
92
  # Used for object versioning.
93
93
  def generation
94
- @gapi["generation"]
94
+ @gapi.generation
95
95
  end
96
96
 
97
97
  ##
@@ -100,31 +100,31 @@ module Gcloud
100
100
  # A metageneration number is only meaningful in the context of a
101
101
  # particular generation of a particular file.
102
102
  def metageneration
103
- @gapi["metageneration"]
103
+ @gapi.metageneration
104
104
  end
105
105
 
106
106
  ##
107
107
  # A URL that can be used to access the file using the REST API.
108
108
  def api_url
109
- @gapi["selfLink"]
109
+ @gapi.self_link
110
110
  end
111
111
 
112
112
  ##
113
113
  # A URL that can be used to download the file using the REST API.
114
114
  def media_url
115
- @gapi["mediaLink"]
115
+ @gapi.media_link
116
116
  end
117
117
 
118
118
  ##
119
119
  # Content-Length of the data in bytes.
120
120
  def size
121
- @gapi["size"]
121
+ @gapi.size.to_i if @gapi.size
122
122
  end
123
123
 
124
124
  ##
125
125
  # Creation time of the file.
126
126
  def created_at
127
- @gapi["timeCreated"]
127
+ @gapi.time_created
128
128
  end
129
129
 
130
130
  ##
@@ -132,13 +132,13 @@ module Gcloud
132
132
  # For buckets with versioning enabled, changing an object's
133
133
  # metadata does not change this property.
134
134
  def updated_at
135
- @gapi["updated"]
135
+ @gapi.updated
136
136
  end
137
137
 
138
138
  ##
139
139
  # MD5 hash of the data; encoded using base64.
140
140
  def md5
141
- @gapi["md5Hash"]
141
+ @gapi.md5_hash
142
142
  end
143
143
 
144
144
  ##
@@ -146,20 +146,20 @@ module Gcloud
146
146
  # [RFC 4960, Appendix B](http://tools.ietf.org/html/rfc4960#appendix-B).
147
147
  # Encoded using base64 in big-endian byte order.
148
148
  def crc32c
149
- @gapi["crc32c"]
149
+ @gapi.crc32c
150
150
  end
151
151
 
152
152
  ##
153
153
  # HTTP 1.1 Entity tag for the file.
154
154
  def etag
155
- @gapi["etag"]
155
+ @gapi.etag
156
156
  end
157
157
 
158
158
  ##
159
159
  # The [Cache-Control](https://tools.ietf.org/html/rfc7234#section-5.2)
160
160
  # directive for the file data.
161
161
  def cache_control
162
- @gapi["cacheControl"]
162
+ @gapi.cache_control
163
163
  end
164
164
 
165
165
  ##
@@ -167,56 +167,60 @@ module Gcloud
167
167
  # [Cache-Control](https://tools.ietf.org/html/rfc7234#section-5.2)
168
168
  # directive for the file data.
169
169
  def cache_control= cache_control
170
- patch_gapi! cache_control: cache_control
170
+ @gapi.cache_control = cache_control
171
+ patch_gapi! :cache_control
171
172
  end
172
173
 
173
174
  ##
174
175
  # The [Content-Disposition](https://tools.ietf.org/html/rfc6266) of the
175
176
  # file data.
176
177
  def content_disposition
177
- @gapi["contentDisposition"]
178
+ @gapi.content_disposition
178
179
  end
179
180
 
180
181
  ##
181
182
  # Updates the [Content-Disposition](https://tools.ietf.org/html/rfc6266)
182
183
  # of the file data.
183
184
  def content_disposition= content_disposition
184
- patch_gapi! content_disposition: content_disposition
185
+ @gapi.content_disposition = content_disposition
186
+ patch_gapi! :content_disposition
185
187
  end
186
188
 
187
189
  ##
188
190
  # The [Content-Encoding
189
191
  # ](https://tools.ietf.org/html/rfc7231#section-3.1.2.2) of the file data.
190
192
  def content_encoding
191
- @gapi["contentEncoding"]
193
+ @gapi.content_encoding
192
194
  end
193
195
 
194
196
  ##
195
197
  # Updates the [Content-Encoding
196
198
  # ](https://tools.ietf.org/html/rfc7231#section-3.1.2.2) of the file data.
197
199
  def content_encoding= content_encoding
198
- patch_gapi! content_encoding: content_encoding
200
+ @gapi.content_encoding = content_encoding
201
+ patch_gapi! :content_encoding
199
202
  end
200
203
 
201
204
  ##
202
205
  # The [Content-Language](http://tools.ietf.org/html/bcp47) of the file
203
206
  # data.
204
207
  def content_language
205
- @gapi["contentLanguage"]
208
+ @gapi.content_language
206
209
  end
207
210
 
208
211
  ##
209
212
  # Updates the [Content-Language](http://tools.ietf.org/html/bcp47) of the
210
213
  # file data.
211
214
  def content_language= content_language
212
- patch_gapi! content_language: content_language
215
+ @gapi.content_language = content_language
216
+ patch_gapi! :content_language
213
217
  end
214
218
 
215
219
  ##
216
220
  # The [Content-Type](https://tools.ietf.org/html/rfc2616#section-14.17) of
217
221
  # the file data.
218
222
  def content_type
219
- @gapi["contentType"]
223
+ @gapi.content_type
220
224
  end
221
225
 
222
226
  ##
@@ -224,7 +228,8 @@ module Gcloud
224
228
  # [Content-Type](https://tools.ietf.org/html/rfc2616#section-14.17) of the
225
229
  # file data.
226
230
  def content_type= content_type
227
- patch_gapi! content_type: content_type
231
+ @gapi.content_type = content_type
232
+ patch_gapi! :content_type
228
233
  end
229
234
 
230
235
  ##
@@ -232,9 +237,9 @@ module Gcloud
232
237
  # values that will returned with requests for the file as "x-goog-meta-"
233
238
  # response headers.
234
239
  def metadata
235
- m = @gapi["metadata"]
236
- m = m.to_hash if m.respond_to? :to_hash
237
- m.freeze
240
+ m = @gapi.metadata
241
+ m = m.to_h if m.respond_to? :to_h
242
+ m.dup.freeze
238
243
  end
239
244
 
240
245
  ##
@@ -242,7 +247,8 @@ module Gcloud
242
247
  # string values that will returned with requests for the file as
243
248
  # "x-goog-meta-" response headers.
244
249
  def metadata= metadata
245
- patch_gapi! metadata: metadata
250
+ @gapi.metadata = metadata
251
+ patch_gapi! :metadata
246
252
  end
247
253
 
248
254
  ##
@@ -252,8 +258,8 @@ module Gcloud
252
258
  # You can use this SHA256 hash to uniquely identify the AES-256 encryption
253
259
  # key required to decrypt this file.
254
260
  def encryption_key_sha256
255
- return nil unless @gapi["customerEncryption"]
256
- Base64.decode64 @gapi["customerEncryption"]["keySha256"]
261
+ return nil unless @gapi.customer_encryption
262
+ Base64.decode64 @gapi.customer_encryption.key_sha256
257
263
  end
258
264
 
259
265
  ##
@@ -286,8 +292,9 @@ module Gcloud
286
292
  # end
287
293
  #
288
294
  def update
289
- updater = Updater.new metadata
295
+ updater = Updater.new gapi
290
296
  yield updater
297
+ updater.check_for_changed_metadata!
291
298
  patch_gapi! updater.updates unless updater.updates.empty?
292
299
  end
293
300
 
@@ -298,7 +305,7 @@ module Gcloud
298
305
  #
299
306
  # If a [customer-supplied encryption
300
307
  # key](https://cloud.google.com/storage/docs/encryption#customer-supplied)
301
- # was used with {#create_file}, the `encryption_key` and
308
+ # was used with {Bucket#create_file}, the `encryption_key` and
302
309
  # `encryption_key_sha256` options must be provided.
303
310
  #
304
311
  # @param [String] path The path on the local file system to write the data
@@ -315,11 +322,11 @@ module Gcloud
315
322
  #
316
323
  # @param [String] encryption_key Optional. The customer-supplied, AES-256
317
324
  # encryption key used to encrypt the file, if one was provided to
318
- # {#create_file}. Must be provided if `encryption_key_sha256` is
325
+ # {Bucket#create_file}. Must be provided if `encryption_key_sha256` is
319
326
  # provided.
320
327
  # @param [String] encryption_key_sha256 Optional. The SHA256 hash of the
321
328
  # customer-supplied, AES-256 encryption key used to encrypt the file, if
322
- # one was provided to {#create_file}. Must be provided if
329
+ # one was provided to {Bucket#create_file}. Must be provided if
323
330
  # `encryption_key` is provided.
324
331
  #
325
332
  # @return [File] Returns a `::File` object on the local file system
@@ -370,18 +377,11 @@ module Gcloud
370
377
  #
371
378
  def download path, verify: :md5, encryption_key: nil,
372
379
  encryption_key_sha256: nil
373
- ensure_connection!
374
- options = { encryption_key: encryption_key,
375
- encryption_key_sha256: encryption_key_sha256 }
376
- resp = connection.download_file bucket, name, options
377
- if resp.success?
378
- ::File.open path, "wb+" do |f|
379
- f.write resp.body
380
- end
381
- verify_file! ::File.new(path), verify
382
- else
383
- fail ApiError.from_response(resp)
384
- end
380
+ ensure_service!
381
+ service.download_file \
382
+ bucket, name, path,
383
+ key: encryption_key, key_sha256: encryption_key_sha256
384
+ verify_file! ::File.new(path), verify
385
385
  end
386
386
 
387
387
  ##
@@ -389,7 +389,7 @@ module Gcloud
389
389
  #
390
390
  # If a [customer-supplied encryption
391
391
  # key](https://cloud.google.com/storage/docs/encryption#customer-supplied)
392
- # was used with {#create_file}, the `encryption_key` and
392
+ # was used with {Bucket#create_file}, the `encryption_key` and
393
393
  # `encryption_key_sha256` options must be provided.
394
394
  #
395
395
  # @param [String] dest_bucket_or_path Either the bucket to copy the file
@@ -418,11 +418,11 @@ module Gcloud
418
418
  # copy. The default is the latest version.
419
419
  # @param [String] encryption_key Optional. The customer-supplied, AES-256
420
420
  # encryption key used to encrypt the file, if one was provided to
421
- # {#create_file}. Must be provided if `encryption_key_sha256` is
421
+ # {Bucket#create_file}. Must be provided if `encryption_key_sha256` is
422
422
  # provided.
423
423
  # @param [String] encryption_key_sha256 Optional. The SHA256 hash of the
424
424
  # customer-supplied, AES-256 encryption key used to encrypt the file, if
425
- # one was provided to {#create_file}. Must be provided if
425
+ # one was provided to {Bucket#create_file}. Must be provided if
426
426
  # `encryption_key` is provided.
427
427
  #
428
428
  # @return [Gcloud::Storage::File]
@@ -456,20 +456,15 @@ module Gcloud
456
456
  #
457
457
  def copy dest_bucket_or_path, dest_path = nil, acl: nil, generation: nil,
458
458
  encryption_key: nil, encryption_key_sha256: nil
459
- ensure_connection!
459
+ ensure_service!
460
460
  options = { acl: acl, generation: generation,
461
- encryption_key: encryption_key,
462
- encryption_key_sha256: encryption_key_sha256 }
461
+ key: encryption_key, key_sha256: encryption_key_sha256 }
463
462
  dest_bucket, dest_path, options = fix_copy_args dest_bucket_or_path,
464
463
  dest_path, options
465
464
 
466
- resp = connection.copy_file bucket, name,
467
- dest_bucket, dest_path, options
468
- if resp.success?
469
- File.from_gapi resp.data, connection
470
- else
471
- fail ApiError.from_response(resp)
472
- end
465
+ gapi = service.copy_file bucket, name,
466
+ dest_bucket, dest_path, options
467
+ File.from_gapi gapi, service
473
468
  end
474
469
 
475
470
  ##
@@ -489,13 +484,9 @@ module Gcloud
489
484
  # file.delete
490
485
  #
491
486
  def delete
492
- ensure_connection!
493
- resp = connection.delete_file bucket, name
494
- if resp.success?
495
- true
496
- else
497
- fail ApiError.from_response(resp)
498
- end
487
+ ensure_service!
488
+ service.delete_file bucket, name
489
+ true
499
490
  end
500
491
 
501
492
  ##
@@ -607,7 +598,7 @@ module Gcloud
607
598
  def signed_url method: nil, expires: nil, content_type: nil,
608
599
  content_md5: nil, issuer: nil, client_email: nil,
609
600
  signing_key: nil, private_key: nil
610
- ensure_connection!
601
+ ensure_service!
611
602
  options = { method: method, expires: expires,
612
603
  content_type: content_type, content_md5: content_md5,
613
604
  issuer: issuer, client_email: client_email,
@@ -668,13 +659,8 @@ module Gcloud
668
659
  ##
669
660
  # Reloads the file with current data from the Storage service.
670
661
  def reload!
671
- ensure_connection!
672
- resp = connection.get_file bucket, name
673
- if resp.success?
674
- @gapi = resp.data
675
- else
676
- fail ApiError.from_response(resp)
677
- end
662
+ ensure_service!
663
+ @gapi = service.get_file bucket, name
678
664
  end
679
665
  alias_method :refresh!, :reload!
680
666
 
@@ -687,29 +673,30 @@ module Gcloud
687
673
 
688
674
  ##
689
675
  # @private New File from a Google API Client object.
690
- def self.from_gapi gapi, conn
676
+ def self.from_gapi gapi, service
691
677
  new.tap do |f|
692
678
  f.gapi = gapi
693
- f.connection = conn
679
+ f.service = service
694
680
  end
695
681
  end
696
682
 
697
683
  protected
698
684
 
699
685
  ##
700
- # Raise an error unless an active connection is available.
701
- def ensure_connection!
702
- fail "Must have active connection" unless connection
686
+ # Raise an error unless an active service is available.
687
+ def ensure_service!
688
+ fail "Must have active connection" unless service
703
689
  end
704
690
 
705
- def patch_gapi! options = {}
706
- ensure_connection!
707
- resp = connection.patch_file bucket, name, options
708
- if resp.success?
709
- @gapi = resp.data
710
- else
711
- fail ApiError.from_response(resp)
712
- end
691
+ def patch_gapi! *attributes
692
+ attributes.flatten!
693
+ return if attributes.empty?
694
+ ensure_service!
695
+ patch_args = Hash[attributes.map do |attr|
696
+ [attr, @gapi.send(attr)]
697
+ end]
698
+ patch_gapi = Google::Apis::StorageV1::Object.new patch_args
699
+ @gapi = service.patch_file bucket, name, patch_gapi
713
700
  end
714
701
 
715
702
  def fix_copy_args dest_bucket, dest_path, options = {}
@@ -768,12 +755,12 @@ module Gcloud
768
755
 
769
756
  def determine_signing_key options = {}
770
757
  options[:signing_key] || options[:private_key] ||
771
- @file.connection.credentials.signing_key
758
+ @file.service.credentials.signing_key
772
759
  end
773
760
 
774
761
  def determine_issuer options = {}
775
762
  options[:issuer] || options[:client_email] ||
776
- @file.connection.credentials.issuer
763
+ @file.service.credentials.issuer
777
764
  end
778
765
 
779
766
  def signed_url options
@@ -796,7 +783,7 @@ module Gcloud
796
783
  end
797
784
 
798
785
  def generate_signed_url issuer, signed_string, expires
799
- signature = Base64.encode64(signed_string).delete("\n")
786
+ signature = Base64.strict_encode64(signed_string).delete("\n")
800
787
  "#{ext_url}?GoogleAccessId=#{CGI.escape issuer}" \
801
788
  "&Expires=#{expires}" \
802
789
  "&Signature=#{CGI.escape signature}"
@@ -805,33 +792,49 @@ module Gcloud
805
792
 
806
793
  ##
807
794
  # Yielded to a block to accumulate changes for a patch request.
808
- class Updater
795
+ class Updater < File
809
796
  attr_reader :updates
810
797
  ##
811
798
  # Create an Updater object.
812
- def initialize metadata
813
- @metadata = if metadata.nil?
814
- {}
815
- else
816
- metadata.dup
817
- end
818
- @updates = {}
799
+ def initialize gapi
800
+ @updates = []
801
+ @gapi = gapi
802
+ end
803
+
804
+ ##
805
+ # A hash of custom, user-provided web-safe keys and arbitrary string
806
+ # values that will returned with requests for the file as "x-goog-meta-"
807
+ # response headers.
808
+ def metadata
809
+ # do not freeze metadata
810
+ @metadata ||= @gapi.metadata.to_h.dup
819
811
  end
820
812
 
821
- ATTRS = [:cache_control, :content_disposition, :content_encoding,
822
- :content_language, :content_type, :metadata]
813
+ ##
814
+ # Updates the hash of custom, user-provided web-safe keys and arbitrary
815
+ # string values that will returned with requests for the file as
816
+ # "x-goog-meta-" response headers.
817
+ def metadata= metadata
818
+ @metadata = metadata
819
+ @gapi.metadata = @metadata
820
+ patch_gapi! :metadata
821
+ end
823
822
 
824
- ATTRS.each do |attr|
825
- define_method "#{attr}=" do |arg|
826
- updates[attr] = arg
827
- end
823
+ ##
824
+ # @private Make sure any metadata changes are saved
825
+ def check_for_changed_metadata!
826
+ return if @metadata == @gapi.metadata
827
+ @gapi.metadata = @metadata
828
+ patch_gapi! :metadata
828
829
  end
829
830
 
831
+ protected
832
+
830
833
  ##
831
- # Return metadata for mutation. Also adds metadata to @updates so that
832
- # it is included in the patch request.
833
- def metadata
834
- updates[:metadata] ||= @metadata
834
+ # Queue up all the updates instead of making them.
835
+ def patch_gapi! attribute
836
+ @updates << attribute
837
+ @updates.uniq!
835
838
  end
836
839
  end
837
840
  end