google-cloud-storage 0.20.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.
- checksums.yaml +7 -0
- data/lib/google-cloud-storage.rb +124 -0
- data/lib/google/cloud/storage.rb +412 -0
- data/lib/google/cloud/storage/bucket.rb +783 -0
- data/lib/google/cloud/storage/bucket/acl.rb +815 -0
- data/lib/google/cloud/storage/bucket/cors.rb +157 -0
- data/lib/google/cloud/storage/bucket/list.rb +174 -0
- data/lib/google/cloud/storage/credentials.rb +31 -0
- data/lib/google/cloud/storage/errors.rb +67 -0
- data/lib/google/cloud/storage/file.rb +849 -0
- data/lib/google/cloud/storage/file/acl.rb +429 -0
- data/lib/google/cloud/storage/file/list.rb +193 -0
- data/lib/google/cloud/storage/file/verifier.rb +69 -0
- data/lib/google/cloud/storage/project.rb +321 -0
- data/lib/google/cloud/storage/service.rb +310 -0
- data/lib/google/cloud/storage/version.rb +22 -0
- metadata +215 -0
@@ -0,0 +1,783 @@
|
|
1
|
+
# Copyright 2014 Google Inc. All rights reserved.
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at
|
6
|
+
#
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
#
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
# See the License for the specific language governing permissions and
|
13
|
+
# limitations under the License.
|
14
|
+
|
15
|
+
|
16
|
+
require "google/cloud/storage/bucket/acl"
|
17
|
+
require "google/cloud/storage/bucket/list"
|
18
|
+
require "google/cloud/storage/bucket/cors"
|
19
|
+
require "google/cloud/storage/file"
|
20
|
+
require "pathname"
|
21
|
+
|
22
|
+
module Google
|
23
|
+
module Cloud
|
24
|
+
module Storage
|
25
|
+
##
|
26
|
+
# # Bucket
|
27
|
+
#
|
28
|
+
# Represents a Storage bucket. Belongs to a Project and has many Files.
|
29
|
+
#
|
30
|
+
# @example
|
31
|
+
# require "google/cloud"
|
32
|
+
#
|
33
|
+
# gcloud = Google::Cloud.new
|
34
|
+
# storage = gcloud.storage
|
35
|
+
#
|
36
|
+
# bucket = storage.bucket "my-bucket"
|
37
|
+
# file = bucket.file "path/to/my-file.ext"
|
38
|
+
#
|
39
|
+
class Bucket
|
40
|
+
##
|
41
|
+
# @private The Service object.
|
42
|
+
attr_accessor :service
|
43
|
+
|
44
|
+
##
|
45
|
+
# @private The Google API Client object.
|
46
|
+
attr_accessor :gapi
|
47
|
+
|
48
|
+
##
|
49
|
+
# @private Create an empty Bucket object.
|
50
|
+
def initialize
|
51
|
+
@service = nil
|
52
|
+
@gapi = Google::Apis::StorageV1::Bucket.new
|
53
|
+
end
|
54
|
+
|
55
|
+
##
|
56
|
+
# The kind of item this is.
|
57
|
+
# For buckets, this is always `storage#bucket`.
|
58
|
+
def kind
|
59
|
+
@gapi.kind
|
60
|
+
end
|
61
|
+
|
62
|
+
##
|
63
|
+
# The ID of the bucket.
|
64
|
+
def id
|
65
|
+
@gapi.id
|
66
|
+
end
|
67
|
+
|
68
|
+
##
|
69
|
+
# The name of the bucket.
|
70
|
+
def name
|
71
|
+
@gapi.name
|
72
|
+
end
|
73
|
+
|
74
|
+
##
|
75
|
+
# A URL that can be used to access the bucket using the REST API.
|
76
|
+
def api_url
|
77
|
+
@gapi.self_link
|
78
|
+
end
|
79
|
+
|
80
|
+
##
|
81
|
+
# Creation time of the bucket.
|
82
|
+
def created_at
|
83
|
+
@gapi.time_created
|
84
|
+
end
|
85
|
+
|
86
|
+
##
|
87
|
+
# Returns the current CORS configuration for a static website served
|
88
|
+
# from the bucket.
|
89
|
+
#
|
90
|
+
# The return value is a frozen (unmodifiable) array of hashes containing
|
91
|
+
# the attributes specified for the Bucket resource field
|
92
|
+
# [cors](https://cloud.google.com/storage/docs/json_api/v1/buckets#cors).
|
93
|
+
#
|
94
|
+
# This method also accepts a block for updating the bucket's CORS rules.
|
95
|
+
# See {Bucket::Cors} for details.
|
96
|
+
#
|
97
|
+
# @see https://cloud.google.com/storage/docs/cross-origin Cross-Origin
|
98
|
+
# Resource Sharing (CORS)
|
99
|
+
#
|
100
|
+
# @yield [cors] a block for setting CORS rules
|
101
|
+
# @yieldparam [Bucket::Cors] cors the object accepting CORS rules
|
102
|
+
#
|
103
|
+
# @example Retrieving the bucket's CORS rules.
|
104
|
+
# require "google/cloud"
|
105
|
+
#
|
106
|
+
# gcloud = Google::Cloud.new
|
107
|
+
# storage = gcloud.storage
|
108
|
+
#
|
109
|
+
# bucket = storage.bucket "my-todo-app"
|
110
|
+
# bucket.cors #=> [{"origin"=>["http://example.org"],
|
111
|
+
# # "method"=>["GET","POST","DELETE"],
|
112
|
+
# # "responseHeader"=>["X-My-Custom-Header"],
|
113
|
+
# # "maxAgeSeconds"=>3600}]
|
114
|
+
#
|
115
|
+
# @example Updating the bucket's CORS rules inside a block.
|
116
|
+
# require "google/cloud"
|
117
|
+
#
|
118
|
+
# gcloud = Google::Cloud.new
|
119
|
+
# storage = gcloud.storage
|
120
|
+
# bucket = storage.bucket "my-todo-app"
|
121
|
+
#
|
122
|
+
# bucket.update do |b|
|
123
|
+
# b.cors do |c|
|
124
|
+
# c.add_rule ["http://example.org", "https://example.org"],
|
125
|
+
# "*",
|
126
|
+
# response_headers: ["X-My-Custom-Header"],
|
127
|
+
# max_age: 3600
|
128
|
+
# end
|
129
|
+
# end
|
130
|
+
#
|
131
|
+
def cors
|
132
|
+
cors_builder = Bucket::Cors.from_gapi @gapi.cors_configurations
|
133
|
+
if block_given?
|
134
|
+
yield cors_builder
|
135
|
+
if cors_builder.changed?
|
136
|
+
@gapi.cors_configurations = cors_builder.to_gapi
|
137
|
+
patch_gapi! :cors_configurations
|
138
|
+
end
|
139
|
+
end
|
140
|
+
cors_builder.freeze # always return frozen objects
|
141
|
+
end
|
142
|
+
|
143
|
+
##
|
144
|
+
# The location of the bucket.
|
145
|
+
# Object data for objects in the bucket resides in physical
|
146
|
+
# storage within this region. Defaults to US.
|
147
|
+
# See the developer's guide for the authoritative list.
|
148
|
+
#
|
149
|
+
# @see https://cloud.google.com/storage/docs/concepts-techniques
|
150
|
+
def location
|
151
|
+
@gapi.location
|
152
|
+
end
|
153
|
+
|
154
|
+
##
|
155
|
+
# The destination bucket name for the bucket's logs.
|
156
|
+
#
|
157
|
+
# @see https://cloud.google.com/storage/docs/access-logs Access Logs
|
158
|
+
#
|
159
|
+
def logging_bucket
|
160
|
+
@gapi.logging.log_bucket if @gapi.logging
|
161
|
+
end
|
162
|
+
|
163
|
+
##
|
164
|
+
# Updates the destination bucket for the bucket's logs.
|
165
|
+
#
|
166
|
+
# @see https://cloud.google.com/storage/docs/access-logs Access Logs
|
167
|
+
#
|
168
|
+
# @param [String] logging_bucket The bucket to hold the logging output
|
169
|
+
#
|
170
|
+
def logging_bucket= logging_bucket
|
171
|
+
@gapi.logging ||= Google::Apis::StorageV1::Bucket::Logging.new
|
172
|
+
@gapi.logging.log_bucket = logging_bucket
|
173
|
+
patch_gapi! :logging
|
174
|
+
end
|
175
|
+
|
176
|
+
##
|
177
|
+
# The logging object prefix for the bucket's logs. For more information,
|
178
|
+
#
|
179
|
+
# @see https://cloud.google.com/storage/docs/access-logs Access Logs
|
180
|
+
#
|
181
|
+
def logging_prefix
|
182
|
+
@gapi.logging.log_object_prefix if @gapi.logging
|
183
|
+
end
|
184
|
+
|
185
|
+
##
|
186
|
+
# Updates the logging object prefix. This prefix will be used to create
|
187
|
+
# log object names for the bucket. It can be at most 900 characters and
|
188
|
+
# must be a [valid object
|
189
|
+
# name](https://cloud.google.com/storage/docs/bucket-naming#objectnames).
|
190
|
+
# By default, the object prefix is the name of the bucket for which the
|
191
|
+
# logs are enabled.
|
192
|
+
#
|
193
|
+
# @see https://cloud.google.com/storage/docs/access-logs Access Logs
|
194
|
+
#
|
195
|
+
def logging_prefix= logging_prefix
|
196
|
+
@gapi.logging ||= Google::Apis::StorageV1::Bucket::Logging.new
|
197
|
+
@gapi.logging.log_object_prefix = logging_prefix
|
198
|
+
patch_gapi! :logging
|
199
|
+
end
|
200
|
+
|
201
|
+
##
|
202
|
+
# The bucket's storage class. This defines how objects in the bucket are
|
203
|
+
# stored and determines the SLA and the cost of storage. Values include
|
204
|
+
# `STANDARD`, `NEARLINE`, and `DURABLE_REDUCED_AVAILABILITY`.
|
205
|
+
def storage_class
|
206
|
+
@gapi.storage_class
|
207
|
+
end
|
208
|
+
|
209
|
+
##
|
210
|
+
# Whether [Object
|
211
|
+
# Versioning](https://cloud.google.com/storage/docs/object-versioning)
|
212
|
+
# is enabled for the bucket.
|
213
|
+
def versioning?
|
214
|
+
@gapi.versioning.enabled? unless @gapi.versioning.nil?
|
215
|
+
end
|
216
|
+
|
217
|
+
##
|
218
|
+
# Updates whether [Object
|
219
|
+
# Versioning](https://cloud.google.com/storage/docs/object-versioning)
|
220
|
+
# is enabled for the bucket.
|
221
|
+
#
|
222
|
+
# @return [Boolean]
|
223
|
+
#
|
224
|
+
def versioning= new_versioning
|
225
|
+
@gapi.versioning ||= Google::Apis::StorageV1::Bucket::Versioning.new
|
226
|
+
@gapi.versioning.enabled = new_versioning
|
227
|
+
patch_gapi! :versioning
|
228
|
+
end
|
229
|
+
|
230
|
+
##
|
231
|
+
# The index page returned from a static website served from the bucket
|
232
|
+
# when a site visitor requests the top level directory.
|
233
|
+
#
|
234
|
+
# @see https://cloud.google.com/storage/docs/website-configuration#step4
|
235
|
+
# How to Host a Static Website
|
236
|
+
#
|
237
|
+
def website_main
|
238
|
+
@gapi.website.main_page_suffix if @gapi.website
|
239
|
+
end
|
240
|
+
|
241
|
+
##
|
242
|
+
# Updates the index page returned from a static website served from the
|
243
|
+
# bucket when a site visitor requests the top level directory.
|
244
|
+
#
|
245
|
+
# @see https://cloud.google.com/storage/docs/website-configuration#step4
|
246
|
+
# How to Host a Static Website
|
247
|
+
#
|
248
|
+
def website_main= website_main
|
249
|
+
@gapi.website ||= Google::Apis::StorageV1::Bucket::Website.new
|
250
|
+
@gapi.website.main_page_suffix = website_main
|
251
|
+
patch_gapi! :website
|
252
|
+
end
|
253
|
+
|
254
|
+
##
|
255
|
+
# The page returned from a static website served from the bucket when a
|
256
|
+
# site visitor requests a resource that does not exist.
|
257
|
+
#
|
258
|
+
# @see https://cloud.google.com/storage/docs/website-configuration#step4
|
259
|
+
# How to Host a Static Website
|
260
|
+
#
|
261
|
+
def website_404
|
262
|
+
@gapi.website.not_found_page if @gapi.website
|
263
|
+
end
|
264
|
+
|
265
|
+
##
|
266
|
+
# Updates the page returned from a static website served from the bucket
|
267
|
+
# when a site visitor requests a resource that does not exist.
|
268
|
+
#
|
269
|
+
# @see https://cloud.google.com/storage/docs/website-configuration#step4
|
270
|
+
# How to Host a Static Website
|
271
|
+
#
|
272
|
+
def website_404= website_404
|
273
|
+
@gapi.website ||= Google::Apis::StorageV1::Bucket::Website.new
|
274
|
+
@gapi.website.not_found_page = website_404
|
275
|
+
patch_gapi! :website
|
276
|
+
end
|
277
|
+
|
278
|
+
##
|
279
|
+
# Updates the bucket with changes made in the given block in a single
|
280
|
+
# PATCH request. The following attributes may be set: {#cors},
|
281
|
+
# {#logging_bucket=}, {#logging_prefix=}, {#versioning=},
|
282
|
+
# {#website_main=}, and {#website_404=}. In addition, the #cors
|
283
|
+
# configuration accessible in the block is completely mutable and will
|
284
|
+
# be included in the request. (See {Bucket::Cors})
|
285
|
+
#
|
286
|
+
# @yield [bucket] a block yielding a delegate object for updating the
|
287
|
+
# file
|
288
|
+
#
|
289
|
+
# @example
|
290
|
+
# require "google/cloud"
|
291
|
+
#
|
292
|
+
# gcloud = Google::Cloud.new
|
293
|
+
# storage = gcloud.storage
|
294
|
+
#
|
295
|
+
# bucket = storage.bucket "my-bucket"
|
296
|
+
# bucket.update do |b|
|
297
|
+
# b.website_main = "index.html"
|
298
|
+
# b.website_404 = "not_found.html"
|
299
|
+
# b.cors[0]["method"] = ["GET","POST","DELETE"]
|
300
|
+
# b.cors[1]["responseHeader"] << "X-Another-Custom-Header"
|
301
|
+
# end
|
302
|
+
#
|
303
|
+
# @example New CORS rules can also be added in a nested block:
|
304
|
+
# require "google/cloud"
|
305
|
+
#
|
306
|
+
# gcloud = Google::Cloud.new
|
307
|
+
# storage = gcloud.storage
|
308
|
+
# bucket = storage.bucket "my-todo-app"
|
309
|
+
#
|
310
|
+
# bucket.update do |b|
|
311
|
+
# b.cors do |c|
|
312
|
+
# c.add_rule ["http://example.org", "https://example.org"],
|
313
|
+
# "*",
|
314
|
+
# response_headers: ["X-My-Custom-Header"],
|
315
|
+
# max_age: 300
|
316
|
+
# end
|
317
|
+
# end
|
318
|
+
#
|
319
|
+
def update
|
320
|
+
updater = Updater.new @gapi
|
321
|
+
yield updater
|
322
|
+
# Add check for mutable cors
|
323
|
+
updater.check_for_mutable_cors!
|
324
|
+
patch_gapi! updater.updates unless updater.updates.empty?
|
325
|
+
end
|
326
|
+
|
327
|
+
##
|
328
|
+
# Permanently deletes the bucket.
|
329
|
+
# The bucket must be empty before it can be deleted.
|
330
|
+
#
|
331
|
+
# The API call to delete the bucket may be retried under certain
|
332
|
+
# conditions. See {Google::Cloud#storage} to control this behavior.
|
333
|
+
#
|
334
|
+
# @return [Boolean] Returns `true` if the bucket was deleted.
|
335
|
+
#
|
336
|
+
# @example
|
337
|
+
# require "google/cloud"
|
338
|
+
#
|
339
|
+
# gcloud = Google::Cloud.new
|
340
|
+
# storage = gcloud.storage
|
341
|
+
#
|
342
|
+
# bucket = storage.bucket "my-bucket"
|
343
|
+
# bucket.delete
|
344
|
+
#
|
345
|
+
def delete
|
346
|
+
ensure_service!
|
347
|
+
service.delete_bucket name
|
348
|
+
true
|
349
|
+
end
|
350
|
+
|
351
|
+
##
|
352
|
+
# Retrieves a list of files matching the criteria.
|
353
|
+
#
|
354
|
+
# @param [String] prefix Filter results to files whose names begin with
|
355
|
+
# this prefix.
|
356
|
+
# @param [String] delimiter Returns results in a directory-like mode.
|
357
|
+
# `items` will contain only objects whose names, aside from the
|
358
|
+
# `prefix`, do not contain `delimiter`. Objects whose names, aside
|
359
|
+
# from the `prefix`, contain `delimiter` will have their name,
|
360
|
+
# truncated after the `delimiter`, returned in `prefixes`. Duplicate
|
361
|
+
# `prefixes` are omitted.
|
362
|
+
# @param [String] token A previously-returned page token representing
|
363
|
+
# part of the larger set of results to view.
|
364
|
+
# @param [Integer] max Maximum number of items plus prefixes to return.
|
365
|
+
# As duplicate prefixes are omitted, fewer total results may be
|
366
|
+
# returned than requested. The default value of this parameter is
|
367
|
+
# 1,000 items.
|
368
|
+
# @param [Boolean] versions If `true`, lists all versions of an object
|
369
|
+
# as distinct results. The default is `false`. For more information,
|
370
|
+
# see [Object Versioning
|
371
|
+
# ](https://cloud.google.com/storage/docs/object-versioning).
|
372
|
+
#
|
373
|
+
# @return [Array<Google::Cloud::Storage::File>] (See
|
374
|
+
# {Google::Cloud::Storage::File::List})
|
375
|
+
#
|
376
|
+
# @example
|
377
|
+
# require "google/cloud"
|
378
|
+
#
|
379
|
+
# gcloud = Google::Cloud.new
|
380
|
+
# storage = gcloud.storage
|
381
|
+
#
|
382
|
+
# bucket = storage.bucket "my-bucket"
|
383
|
+
# files = bucket.files
|
384
|
+
# files.each do |file|
|
385
|
+
# puts file.name
|
386
|
+
# end
|
387
|
+
#
|
388
|
+
# @example Retrieve all files: (See {File::List#all})
|
389
|
+
# require "google/cloud"
|
390
|
+
#
|
391
|
+
# gcloud = Google::Cloud.new
|
392
|
+
# storage = gcloud.storage
|
393
|
+
#
|
394
|
+
# bucket = storage.bucket "my-bucket"
|
395
|
+
# files = bucket.files
|
396
|
+
# files.all do |file|
|
397
|
+
# puts file.name
|
398
|
+
# end
|
399
|
+
#
|
400
|
+
def files prefix: nil, delimiter: nil, token: nil, max: nil,
|
401
|
+
versions: nil
|
402
|
+
ensure_service!
|
403
|
+
options = {
|
404
|
+
prefix: prefix,
|
405
|
+
delimiter: delimiter,
|
406
|
+
token: token,
|
407
|
+
max: max,
|
408
|
+
versions: versions
|
409
|
+
}
|
410
|
+
gapi = service.list_files name, options
|
411
|
+
File::List.from_gapi gapi, service, name, prefix, delimiter, max,
|
412
|
+
versions
|
413
|
+
end
|
414
|
+
alias_method :find_files, :files
|
415
|
+
|
416
|
+
##
|
417
|
+
# Retrieves a file matching the path.
|
418
|
+
#
|
419
|
+
# If a [customer-supplied encryption
|
420
|
+
# key](https://cloud.google.com/storage/docs/encryption#customer-supplied)
|
421
|
+
# was used with {#create_file}, the `encryption_key` and
|
422
|
+
# `encryption_key_sha256` options must be provided or else the file's
|
423
|
+
# CRC32C checksum and MD5 hash will not be returned.
|
424
|
+
#
|
425
|
+
# @param [String] path Name (path) of the file.
|
426
|
+
# @param [Integer] generation When present, selects a specific revision
|
427
|
+
# of this object. Default is the latest version.
|
428
|
+
# @param [String] encryption_key Optional. The customer-supplied,
|
429
|
+
# AES-256 encryption key used to encrypt the file, if one was provided
|
430
|
+
# to {#create_file}. Must be provided if `encryption_key_sha256` is
|
431
|
+
# provided.
|
432
|
+
# @param [String] encryption_key_sha256 Optional. The SHA256 hash of the
|
433
|
+
# customer-supplied, AES-256 encryption key used to encrypt the file,
|
434
|
+
# if one was provided to {#create_file}. Must be provided if
|
435
|
+
# `encryption_key` is provided.
|
436
|
+
#
|
437
|
+
# @return [Google::Cloud::Storage::File, nil] Returns nil if file does
|
438
|
+
# not exist
|
439
|
+
#
|
440
|
+
# @example
|
441
|
+
# require "google/cloud"
|
442
|
+
#
|
443
|
+
# gcloud = Google::Cloud.new
|
444
|
+
# storage = gcloud.storage
|
445
|
+
#
|
446
|
+
# bucket = storage.bucket "my-bucket"
|
447
|
+
#
|
448
|
+
# file = bucket.file "path/to/my-file.ext"
|
449
|
+
# puts file.name
|
450
|
+
#
|
451
|
+
def file path, generation: nil, encryption_key: nil,
|
452
|
+
encryption_key_sha256: nil
|
453
|
+
ensure_service!
|
454
|
+
options = { generation: generation, key: encryption_key,
|
455
|
+
key_sha256: encryption_key_sha256 }
|
456
|
+
gapi = service.get_file name, path, options
|
457
|
+
File.from_gapi gapi, service
|
458
|
+
rescue Google::Cloud::NotFoundError
|
459
|
+
nil
|
460
|
+
end
|
461
|
+
alias_method :find_file, :file
|
462
|
+
|
463
|
+
##
|
464
|
+
# Creates a new {File} object by providing a path to a local file to
|
465
|
+
# upload and the path to store it with in the bucket.
|
466
|
+
#
|
467
|
+
# #### Customer-supplied encryption keys
|
468
|
+
#
|
469
|
+
# By default, Google Cloud Storage manages server-side encryption keys
|
470
|
+
# on your behalf. However, a [customer-supplied encryption
|
471
|
+
# key](https://cloud.google.com/storage/docs/encryption#customer-supplied)
|
472
|
+
# can be provided with the `encryption_key` and `encryption_key_sha256`
|
473
|
+
# options. If given, the same key and SHA256 hash also must be provided
|
474
|
+
# to subsequently download or copy the file. If you use
|
475
|
+
# customer-supplied encryption keys, you must securely manage your keys
|
476
|
+
# and ensure that they are not lost. Also, please note that file
|
477
|
+
# metadata is not encrypted, with the exception of the CRC32C checksum
|
478
|
+
# and MD5 hash. The names of files and buckets are also not encrypted,
|
479
|
+
# and you can read or update the metadata of an encrypted file without
|
480
|
+
# providing the encryption key.
|
481
|
+
#
|
482
|
+
# @param [String] file Path of the file on the filesystem to upload.
|
483
|
+
# @param [String] path Path to store the file in Google Cloud Storage.
|
484
|
+
# @param [String] acl A predefined set of access controls to apply to
|
485
|
+
# this file.
|
486
|
+
#
|
487
|
+
# Acceptable values are:
|
488
|
+
#
|
489
|
+
# * `auth`, `auth_read`, `authenticated`, `authenticated_read`,
|
490
|
+
# `authenticatedRead` - File owner gets OWNER access, and
|
491
|
+
# allAuthenticatedUsers get READER access.
|
492
|
+
# * `owner_full`, `bucketOwnerFullControl` - File owner gets OWNER
|
493
|
+
# access, and project team owners get OWNER access.
|
494
|
+
# * `owner_read`, `bucketOwnerRead` - File owner gets OWNER access,
|
495
|
+
# and project team owners get READER access.
|
496
|
+
# * `private` - File owner gets OWNER access.
|
497
|
+
# * `project_private`, `projectPrivate` - File owner gets OWNER
|
498
|
+
# access, and project team members get access according to their
|
499
|
+
# roles.
|
500
|
+
# * `public`, `public_read`, `publicRead` - File owner gets OWNER
|
501
|
+
# access, and allUsers get READER access.
|
502
|
+
# @param [String] cache_control The
|
503
|
+
# [Cache-Control](https://tools.ietf.org/html/rfc7234#section-5.2)
|
504
|
+
# response header to be returned when the file is downloaded.
|
505
|
+
# @param [String] content_disposition The
|
506
|
+
# [Content-Disposition](https://tools.ietf.org/html/rfc6266)
|
507
|
+
# response header to be returned when the file is downloaded.
|
508
|
+
# @param [String] content_encoding The [Content-Encoding
|
509
|
+
# ](https://tools.ietf.org/html/rfc7231#section-3.1.2.2) response
|
510
|
+
# header to be returned when the file is downloaded.
|
511
|
+
# @param [String] content_language The
|
512
|
+
# [Content-Language](http://tools.ietf.org/html/bcp47) response
|
513
|
+
# header to be returned when the file is downloaded.
|
514
|
+
# @param [String] content_type The
|
515
|
+
# [Content-Type](https://tools.ietf.org/html/rfc2616#section-14.17)
|
516
|
+
# response header to be returned when the file is downloaded.
|
517
|
+
# @param [String] crc32c The CRC32c checksum of the file data, as
|
518
|
+
# described in [RFC 4960, Appendix
|
519
|
+
# B](http://tools.ietf.org/html/rfc4960#appendix-B).
|
520
|
+
# If provided, Cloud Storage will only create the file if the value
|
521
|
+
# matches the value calculated by the service. See
|
522
|
+
# [Validation](https://cloud.google.com/storage/docs/hashes-etags)
|
523
|
+
# for more information.
|
524
|
+
# @param [String] md5 The MD5 hash of the file data. If provided, Cloud
|
525
|
+
# Storage will only create the file if the value matches the value
|
526
|
+
# calculated by the service. See
|
527
|
+
# [Validation](https://cloud.google.com/storage/docs/hashes-etags) for
|
528
|
+
# more information.
|
529
|
+
# @param [Hash] metadata A hash of custom, user-provided web-safe keys
|
530
|
+
# and arbitrary string values that will returned with requests for the
|
531
|
+
# file as "x-goog-meta-" response headers.
|
532
|
+
# @param [String] encryption_key Optional. A customer-supplied, AES-256
|
533
|
+
# encryption key that will be used to encrypt the file. Must be
|
534
|
+
# provided if `encryption_key_sha256` is provided.
|
535
|
+
# @param [String] encryption_key_sha256 Optional. The SHA256 hash of the
|
536
|
+
# customer-supplied, AES-256 encryption key that will be used to
|
537
|
+
# encrypt the file. Must be provided if `encryption_key` is provided.
|
538
|
+
#
|
539
|
+
# @return [Google::Cloud::Storage::File]
|
540
|
+
#
|
541
|
+
# @example
|
542
|
+
# require "google/cloud"
|
543
|
+
#
|
544
|
+
# gcloud = Google::Cloud.new
|
545
|
+
# storage = gcloud.storage
|
546
|
+
#
|
547
|
+
# bucket = storage.bucket "my-bucket"
|
548
|
+
#
|
549
|
+
# bucket.create_file "path/to/local.file.ext"
|
550
|
+
#
|
551
|
+
# @example Specifying a destination path:
|
552
|
+
# require "google/cloud"
|
553
|
+
#
|
554
|
+
# gcloud = Google::Cloud.new
|
555
|
+
# storage = gcloud.storage
|
556
|
+
#
|
557
|
+
# bucket = storage.bucket "my-bucket"
|
558
|
+
#
|
559
|
+
# bucket.create_file "path/to/local.file.ext",
|
560
|
+
# "destination/path/file.ext"
|
561
|
+
#
|
562
|
+
# @example Providing a customer-supplied encryption key:
|
563
|
+
# require "google/cloud"
|
564
|
+
# require "digest/sha2"
|
565
|
+
#
|
566
|
+
# gcloud = Google::Cloud.new
|
567
|
+
# storage = gcloud.storage
|
568
|
+
# bucket = storage.bucket "my-bucket"
|
569
|
+
#
|
570
|
+
# # Key generation shown for example purposes only. Write your own.
|
571
|
+
# cipher = OpenSSL::Cipher.new "aes-256-cfb"
|
572
|
+
# cipher.encrypt
|
573
|
+
# key = cipher.random_key
|
574
|
+
# key_hash = Digest::SHA256.digest key
|
575
|
+
#
|
576
|
+
# bucket.create_file "path/to/local.file.ext",
|
577
|
+
# "destination/path/file.ext",
|
578
|
+
# encryption_key: key,
|
579
|
+
# encryption_key_sha256: key_hash
|
580
|
+
#
|
581
|
+
# # Store your key and hash securely for later use.
|
582
|
+
# file = bucket.file "destination/path/file.ext",
|
583
|
+
# encryption_key: key,
|
584
|
+
# encryption_key_sha256: key_hash
|
585
|
+
#
|
586
|
+
def create_file file, path = nil, acl: nil, cache_control: nil,
|
587
|
+
content_disposition: nil, content_encoding: nil,
|
588
|
+
content_language: nil, content_type: nil,
|
589
|
+
crc32c: nil, md5: nil, metadata: nil,
|
590
|
+
encryption_key: nil, encryption_key_sha256: nil
|
591
|
+
ensure_service!
|
592
|
+
options = { acl: File::Acl.predefined_rule_for(acl), md5: md5,
|
593
|
+
cache_control: cache_control, content_type: content_type,
|
594
|
+
content_disposition: content_disposition, crc32c: crc32c,
|
595
|
+
content_encoding: content_encoding,
|
596
|
+
content_language: content_language, metadata: metadata,
|
597
|
+
key: encryption_key, key_sha256: encryption_key_sha256 }
|
598
|
+
ensure_file_exists! file
|
599
|
+
# TODO: Handle file as an IO and path is missing more gracefully
|
600
|
+
path ||= Pathname(file).to_path
|
601
|
+
gapi = service.insert_file name, file, path, options
|
602
|
+
File.from_gapi gapi, service
|
603
|
+
end
|
604
|
+
alias_method :upload_file, :create_file
|
605
|
+
alias_method :new_file, :create_file
|
606
|
+
|
607
|
+
##
|
608
|
+
# The Bucket::Acl instance used to control access to the bucket.
|
609
|
+
#
|
610
|
+
# A bucket has owners, writers, and readers. Permissions can be granted
|
611
|
+
# to an individual user's email address, a group's email address, as
|
612
|
+
# well as many predefined lists.
|
613
|
+
#
|
614
|
+
# @see https://cloud.google.com/storage/docs/access-control Access
|
615
|
+
# Control guide
|
616
|
+
#
|
617
|
+
# @example Grant access to a user by prepending `"user-"` to an email:
|
618
|
+
# require "google/cloud"
|
619
|
+
#
|
620
|
+
# gcloud = Google::Cloud.new
|
621
|
+
# storage = gcloud.storage
|
622
|
+
#
|
623
|
+
# bucket = storage.bucket "my-todo-app"
|
624
|
+
#
|
625
|
+
# email = "heidi@example.net"
|
626
|
+
# bucket.acl.add_reader "user-#{email}"
|
627
|
+
#
|
628
|
+
# @example Grant access to a group by prepending `"group-"` to an email:
|
629
|
+
# require "google/cloud"
|
630
|
+
#
|
631
|
+
# gcloud = Google::Cloud.new
|
632
|
+
# storage = gcloud.storage
|
633
|
+
#
|
634
|
+
# bucket = storage.bucket "my-todo-app"
|
635
|
+
#
|
636
|
+
# email = "authors@example.net"
|
637
|
+
# bucket.acl.add_reader "group-#{email}"
|
638
|
+
#
|
639
|
+
# @example Or, grant access via a predefined permissions list:
|
640
|
+
# require "google/cloud"
|
641
|
+
#
|
642
|
+
# gcloud = Google::Cloud.new
|
643
|
+
# storage = gcloud.storage
|
644
|
+
#
|
645
|
+
# bucket = storage.bucket "my-todo-app"
|
646
|
+
#
|
647
|
+
# bucket.acl.public!
|
648
|
+
#
|
649
|
+
def acl
|
650
|
+
@acl ||= Bucket::Acl.new self
|
651
|
+
end
|
652
|
+
|
653
|
+
##
|
654
|
+
# The Bucket::DefaultAcl instance used to control access to the bucket's
|
655
|
+
# files.
|
656
|
+
#
|
657
|
+
# A bucket's files have owners, writers, and readers. Permissions can be
|
658
|
+
# granted to an individual user's email address, a group's email
|
659
|
+
# address, as well as many predefined lists.
|
660
|
+
#
|
661
|
+
# @see https://cloud.google.com/storage/docs/access-control Access
|
662
|
+
# Control guide
|
663
|
+
#
|
664
|
+
# @example Grant access to a user by prepending `"user-"` to an email:
|
665
|
+
# require "google/cloud"
|
666
|
+
#
|
667
|
+
# gcloud = Google::Cloud.new
|
668
|
+
# storage = gcloud.storage
|
669
|
+
#
|
670
|
+
# bucket = storage.bucket "my-todo-app"
|
671
|
+
#
|
672
|
+
# email = "heidi@example.net"
|
673
|
+
# bucket.default_acl.add_reader "user-#{email}"
|
674
|
+
#
|
675
|
+
# @example Grant access to a group by prepending `"group-"` to an email
|
676
|
+
# require "google/cloud"
|
677
|
+
#
|
678
|
+
# gcloud = Google::Cloud.new
|
679
|
+
# storage = gcloud.storage
|
680
|
+
#
|
681
|
+
# bucket = storage.bucket "my-todo-app"
|
682
|
+
#
|
683
|
+
# email = "authors@example.net"
|
684
|
+
# bucket.default_acl.add_reader "group-#{email}"
|
685
|
+
#
|
686
|
+
# @example Or, grant access via a predefined permissions list:
|
687
|
+
# require "google/cloud"
|
688
|
+
#
|
689
|
+
# gcloud = Google::Cloud.new
|
690
|
+
# storage = gcloud.storage
|
691
|
+
#
|
692
|
+
# bucket = storage.bucket "my-todo-app"
|
693
|
+
#
|
694
|
+
# bucket.default_acl.public!
|
695
|
+
#
|
696
|
+
def default_acl
|
697
|
+
@default_acl ||= Bucket::DefaultAcl.new self
|
698
|
+
end
|
699
|
+
|
700
|
+
##
|
701
|
+
# Reloads the bucket with current data from the Storage service.
|
702
|
+
def reload!
|
703
|
+
ensure_service!
|
704
|
+
@gapi = service.get_bucket name
|
705
|
+
end
|
706
|
+
alias_method :refresh!, :reload!
|
707
|
+
|
708
|
+
##
|
709
|
+
# @private New Bucket from a Google API Client object.
|
710
|
+
def self.from_gapi gapi, conn
|
711
|
+
new.tap do |f|
|
712
|
+
f.gapi = gapi
|
713
|
+
f.service = conn
|
714
|
+
end
|
715
|
+
end
|
716
|
+
|
717
|
+
protected
|
718
|
+
|
719
|
+
##
|
720
|
+
# Raise an error unless an active service is available.
|
721
|
+
def ensure_service!
|
722
|
+
fail "Must have active connection" unless service
|
723
|
+
end
|
724
|
+
|
725
|
+
def patch_gapi! *attributes
|
726
|
+
attributes.flatten!
|
727
|
+
return if attributes.empty?
|
728
|
+
ensure_service!
|
729
|
+
patch_args = Hash[attributes.map do |attr|
|
730
|
+
[attr, @gapi.send(attr)]
|
731
|
+
end]
|
732
|
+
patch_gapi = Google::Apis::StorageV1::Bucket.new patch_args
|
733
|
+
@gapi = service.patch_bucket name, patch_gapi
|
734
|
+
end
|
735
|
+
|
736
|
+
##
|
737
|
+
# Raise an error if the file is not found.
|
738
|
+
def ensure_file_exists! file
|
739
|
+
return if ::File.file? file
|
740
|
+
fail ArgumentError, "cannot find file #{file}"
|
741
|
+
end
|
742
|
+
|
743
|
+
##
|
744
|
+
# Yielded to a block to accumulate changes for a patch request.
|
745
|
+
class Updater < Bucket
|
746
|
+
attr_reader :updates
|
747
|
+
##
|
748
|
+
# Create an Updater object.
|
749
|
+
def initialize gapi
|
750
|
+
@updates = []
|
751
|
+
@gapi = gapi
|
752
|
+
@cors_builder = nil
|
753
|
+
end
|
754
|
+
|
755
|
+
def cors
|
756
|
+
# Same as Bucket#cors, but not frozen
|
757
|
+
@cors_builder ||= Bucket::Cors.from_gapi @gapi.cors_configurations
|
758
|
+
yield @cors_builder if block_given?
|
759
|
+
@cors_builder
|
760
|
+
end
|
761
|
+
|
762
|
+
##
|
763
|
+
# @private Make sure any cors changes are saved
|
764
|
+
def check_for_mutable_cors!
|
765
|
+
return if @cors_builder.nil?
|
766
|
+
return unless @cors_builder.changed?
|
767
|
+
@gapi.cors_configurations = @cors_builder.to_gapi
|
768
|
+
patch_gapi! :cors_configurations
|
769
|
+
end
|
770
|
+
|
771
|
+
protected
|
772
|
+
|
773
|
+
##
|
774
|
+
# Queue up all the updates instead of making them.
|
775
|
+
def patch_gapi! attribute
|
776
|
+
@updates << attribute
|
777
|
+
@updates.uniq!
|
778
|
+
end
|
779
|
+
end
|
780
|
+
end
|
781
|
+
end
|
782
|
+
end
|
783
|
+
end
|