gcloud 0.4.0 → 0.4.1
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 +8 -8
- data/CHANGELOG.md +21 -0
- data/lib/gcloud/bigquery/dataset.rb +1 -1
- data/lib/gcloud/bigquery/table.rb +1 -1
- data/lib/gcloud/bigquery/view.rb +1 -1
- data/lib/gcloud/storage/bucket.rb +305 -36
- data/lib/gcloud/storage/bucket/acl.rb +24 -6
- data/lib/gcloud/storage/bucket/cors.rb +112 -0
- data/lib/gcloud/storage/connection.rb +134 -73
- data/lib/gcloud/storage/file.rb +246 -6
- data/lib/gcloud/storage/file/acl.rb +12 -3
- data/lib/gcloud/storage/project.rb +89 -5
- data/lib/gcloud/version.rb +1 -1
- metadata +3 -2
data/lib/gcloud/storage/file.rb
CHANGED
@@ -22,7 +22,16 @@ module Gcloud
|
|
22
22
|
##
|
23
23
|
# = File
|
24
24
|
#
|
25
|
-
# Represents
|
25
|
+
# Represents a File
|
26
|
+
# ({Object}[https://cloud.google.com/storage/docs/json_api/v1/objects]) that
|
27
|
+
# belongs to a Bucket. Files (Objects) are
|
28
|
+
# the individual pieces of data that you store in Google Cloud Storage. A
|
29
|
+
# file can be up to 5 TB in size. Files have two components:
|
30
|
+
# data and metadata. The data component is the data from an external file or
|
31
|
+
# other data source that you want to store in Google Cloud Storage. The
|
32
|
+
# metadata component is a collection of name-value pairs that describe
|
33
|
+
# various qualities of the data. For more information, see {Concepts and
|
34
|
+
# Techniques}[https://cloud.google.com/storage/docs/concepts-techniques].
|
26
35
|
#
|
27
36
|
# require "gcloud"
|
28
37
|
#
|
@@ -92,17 +101,29 @@ module Gcloud
|
|
92
101
|
end
|
93
102
|
|
94
103
|
##
|
95
|
-
#
|
96
|
-
def
|
104
|
+
# A URL that can be used to access the file using the REST API.
|
105
|
+
def api_url
|
97
106
|
@gapi["selfLink"]
|
98
107
|
end
|
99
108
|
|
109
|
+
##
|
110
|
+
# A URL that can be used to download the file using the REST API.
|
111
|
+
def media_url
|
112
|
+
@gapi["mediaLink"]
|
113
|
+
end
|
114
|
+
|
100
115
|
##
|
101
116
|
# Content-Length of the data in bytes.
|
102
117
|
def size
|
103
118
|
@gapi["size"]
|
104
119
|
end
|
105
120
|
|
121
|
+
##
|
122
|
+
# Creation time of the file.
|
123
|
+
def created_at
|
124
|
+
@gapi["timeCreated"]
|
125
|
+
end
|
126
|
+
|
106
127
|
##
|
107
128
|
# The creation or modification time of the file.
|
108
129
|
# For buckets with versioning enabled, changing an object's
|
@@ -118,8 +139,9 @@ module Gcloud
|
|
118
139
|
end
|
119
140
|
|
120
141
|
##
|
121
|
-
# CRC32c checksum, as described in
|
122
|
-
#
|
142
|
+
# The CRC32c checksum of the data, as described in
|
143
|
+
# {RFC 4960, Appendix B}[http://tools.ietf.org/html/rfc4960#appendix-B].
|
144
|
+
# Encoded using base64 in big-endian byte order.
|
123
145
|
def crc32c
|
124
146
|
@gapi["crc32c"]
|
125
147
|
end
|
@@ -130,6 +152,130 @@ module Gcloud
|
|
130
152
|
@gapi["etag"]
|
131
153
|
end
|
132
154
|
|
155
|
+
##
|
156
|
+
# The {Cache-Control}[https://tools.ietf.org/html/rfc7234#section-5.2]
|
157
|
+
# directive for the file data.
|
158
|
+
def cache_control
|
159
|
+
@gapi["cacheControl"]
|
160
|
+
end
|
161
|
+
|
162
|
+
##
|
163
|
+
# Updates the
|
164
|
+
# {Cache-Control}[https://tools.ietf.org/html/rfc7234#section-5.2]
|
165
|
+
# directive for the file data.
|
166
|
+
def cache_control= cache_control
|
167
|
+
patch_gapi! cache_control: cache_control
|
168
|
+
end
|
169
|
+
|
170
|
+
##
|
171
|
+
# The {Content-Disposition}[https://tools.ietf.org/html/rfc6266] of the
|
172
|
+
# file data.
|
173
|
+
def content_disposition
|
174
|
+
@gapi["contentDisposition"]
|
175
|
+
end
|
176
|
+
|
177
|
+
##
|
178
|
+
# Updates the {Content-Disposition}[https://tools.ietf.org/html/rfc6266]
|
179
|
+
# of the file data.
|
180
|
+
def content_disposition= content_disposition
|
181
|
+
patch_gapi! content_disposition: content_disposition
|
182
|
+
end
|
183
|
+
|
184
|
+
##
|
185
|
+
# The {Content-Encoding
|
186
|
+
# }[https://tools.ietf.org/html/rfc7231#section-3.1.2.2] of the file data.
|
187
|
+
def content_encoding
|
188
|
+
@gapi["contentEncoding"]
|
189
|
+
end
|
190
|
+
|
191
|
+
##
|
192
|
+
# Updates the {Content-Encoding
|
193
|
+
# }[https://tools.ietf.org/html/rfc7231#section-3.1.2.2] of the file data.
|
194
|
+
def content_encoding= content_encoding
|
195
|
+
patch_gapi! content_encoding: content_encoding
|
196
|
+
end
|
197
|
+
|
198
|
+
##
|
199
|
+
# The {Content-Language}[http://tools.ietf.org/html/bcp47] of the file
|
200
|
+
# data.
|
201
|
+
def content_language
|
202
|
+
@gapi["contentLanguage"]
|
203
|
+
end
|
204
|
+
|
205
|
+
##
|
206
|
+
# Updates the {Content-Language}[http://tools.ietf.org/html/bcp47] of the
|
207
|
+
# file data.
|
208
|
+
def content_language= content_language
|
209
|
+
patch_gapi! content_language: content_language
|
210
|
+
end
|
211
|
+
|
212
|
+
##
|
213
|
+
# The {Content-Type}[https://tools.ietf.org/html/rfc2616#section-14.17] of
|
214
|
+
# the file data.
|
215
|
+
def content_type
|
216
|
+
@gapi["contentType"]
|
217
|
+
end
|
218
|
+
|
219
|
+
##
|
220
|
+
# Updates the
|
221
|
+
# {Content-Type}[https://tools.ietf.org/html/rfc2616#section-14.17] of the
|
222
|
+
# file data.
|
223
|
+
def content_type= content_type
|
224
|
+
patch_gapi! content_type: content_type
|
225
|
+
end
|
226
|
+
|
227
|
+
##
|
228
|
+
# A hash of custom, user-provided web-safe keys and arbitrary string
|
229
|
+
# values that will returned with requests for the file as "x-goog-meta-"
|
230
|
+
# response headers.
|
231
|
+
def metadata
|
232
|
+
m = @gapi["metadata"]
|
233
|
+
m = m.to_hash if m.respond_to? :to_hash
|
234
|
+
m.freeze
|
235
|
+
end
|
236
|
+
|
237
|
+
##
|
238
|
+
# Updates the hash of custom, user-provided web-safe keys and arbitrary
|
239
|
+
# string values that will returned with requests for the file as
|
240
|
+
# "x-goog-meta-" response headers.
|
241
|
+
def metadata= metadata
|
242
|
+
patch_gapi! metadata: metadata
|
243
|
+
end
|
244
|
+
|
245
|
+
##
|
246
|
+
# Updates the file with changes made in the given block in a single
|
247
|
+
# PATCH request. The following attributes may be set: #cache_control=,
|
248
|
+
# #content_disposition=, #content_encoding=, #content_language=,
|
249
|
+
# #content_type=, and #metadata=. The #metadata hash accessible in the
|
250
|
+
# block is completely mutable and will be included in the request.
|
251
|
+
#
|
252
|
+
# === Examples
|
253
|
+
#
|
254
|
+
# require "gcloud"
|
255
|
+
#
|
256
|
+
# gcloud = Gcloud.new
|
257
|
+
# storage = gcloud.storage
|
258
|
+
#
|
259
|
+
# bucket = storage.bucket "my-bucket"
|
260
|
+
#
|
261
|
+
# file = bucket.file "path/to/my-file.ext"
|
262
|
+
#
|
263
|
+
# file.update do |f|
|
264
|
+
# f.cache_control = "private, max-age=0, no-cache"
|
265
|
+
# f.content_disposition = "inline; filename=filename.ext"
|
266
|
+
# f.content_encoding = "deflate"
|
267
|
+
# f.content_language = "de"
|
268
|
+
# f.content_type = "application/json"
|
269
|
+
# f.metadata["player"] = "Bob"
|
270
|
+
# f.metadata["score"] = "10"
|
271
|
+
# end
|
272
|
+
#
|
273
|
+
def update
|
274
|
+
updater = Updater.new metadata
|
275
|
+
yield updater
|
276
|
+
patch_gapi! updater.updates unless updater.updates.empty?
|
277
|
+
end
|
278
|
+
|
133
279
|
##
|
134
280
|
# Download the file's contents to a local file.
|
135
281
|
#
|
@@ -229,6 +375,9 @@ module Gcloud
|
|
229
375
|
# path to copy the file to in the given bucket. (+String+)
|
230
376
|
# +options+::
|
231
377
|
# An optional Hash for controlling additional behavior. (+Hash+)
|
378
|
+
# <code>options[:generation]</code>::
|
379
|
+
# Select a specific revision of the file to copy. The default is the
|
380
|
+
# latest version. (+Integer+)
|
232
381
|
# <code>options[:acl]</code>::
|
233
382
|
# A predefined set of access controls to apply to new file.
|
234
383
|
# (+String+)
|
@@ -278,6 +427,11 @@ module Gcloud
|
|
278
427
|
# file.copy "new-destination-bucket",
|
279
428
|
# "path/to/destination/file.ext"
|
280
429
|
#
|
430
|
+
# The file can also be copied by specifying a generation:
|
431
|
+
#
|
432
|
+
# file.copy "copy/of/previous/generation/file.ext",
|
433
|
+
# generation: 123456
|
434
|
+
#
|
281
435
|
def copy dest_bucket_or_path, dest_path = nil, options = {}
|
282
436
|
ensure_connection!
|
283
437
|
dest_bucket, dest_path, options = fix_copy_args dest_bucket_or_path,
|
@@ -293,7 +447,7 @@ module Gcloud
|
|
293
447
|
end
|
294
448
|
|
295
449
|
##
|
296
|
-
#
|
450
|
+
# Permanently deletes the file.
|
297
451
|
#
|
298
452
|
# === Returns
|
299
453
|
#
|
@@ -321,6 +475,50 @@ module Gcloud
|
|
321
475
|
end
|
322
476
|
end
|
323
477
|
|
478
|
+
##
|
479
|
+
# Public URL to access the file. If the file is not public, requests to
|
480
|
+
# the URL will return an error. (See File::Acl#public! and
|
481
|
+
# Bucket::DefaultAcl#public!) For more information, read [Accessing Public
|
482
|
+
# Data]{https://cloud.google.com/storage/docs/access-public-data}.
|
483
|
+
#
|
484
|
+
# To share a file that is not public see #signed_url.
|
485
|
+
#
|
486
|
+
# === Parameters
|
487
|
+
#
|
488
|
+
# +options+::
|
489
|
+
# An optional Hash for controlling additional behavior. (+Hash+)
|
490
|
+
# <code>options[:protocol]</code>::
|
491
|
+
# The protocol to use for the URL. Default is +HTTPS+. (+String+)
|
492
|
+
#
|
493
|
+
# === Examples
|
494
|
+
#
|
495
|
+
# require "gcloud"
|
496
|
+
#
|
497
|
+
# gcloud = Gcloud.new
|
498
|
+
# storage = gcloud.storage
|
499
|
+
#
|
500
|
+
# bucket = storage.bucket "my-todo-app"
|
501
|
+
# file = bucket.file "avatars/heidi/400x400.png"
|
502
|
+
# public_url = file.public_url
|
503
|
+
#
|
504
|
+
# To generate the URL with a protocol other than HTTPS, use the +protocol+
|
505
|
+
# option:
|
506
|
+
#
|
507
|
+
# require "gcloud"
|
508
|
+
#
|
509
|
+
# gcloud = Gcloud.new
|
510
|
+
# storage = gcloud.storage
|
511
|
+
#
|
512
|
+
# bucket = storage.bucket "my-todo-app"
|
513
|
+
# file = bucket.file "avatars/heidi/400x400.png"
|
514
|
+
# public_url = file.public_url protocol: "http"
|
515
|
+
#
|
516
|
+
def public_url options = {}
|
517
|
+
protocol = options[:protocol] || :https
|
518
|
+
"#{protocol}://storage.googleapis.com/#{bucket}/#{name}"
|
519
|
+
end
|
520
|
+
alias_method :url, :public_url
|
521
|
+
|
324
522
|
##
|
325
523
|
# Access without authentication can be granted to a File for a specified
|
326
524
|
# period of time. This URL uses a cryptographic signature
|
@@ -500,6 +698,16 @@ module Gcloud
|
|
500
698
|
fail "Must have active connection" unless connection
|
501
699
|
end
|
502
700
|
|
701
|
+
def patch_gapi! options = {}
|
702
|
+
ensure_connection!
|
703
|
+
resp = connection.patch_file bucket, name, options
|
704
|
+
if resp.success?
|
705
|
+
@gapi = resp.data
|
706
|
+
else
|
707
|
+
fail ApiError.from_response(resp)
|
708
|
+
end
|
709
|
+
end
|
710
|
+
|
503
711
|
def fix_copy_args dest_bucket, dest_path, options = {}
|
504
712
|
if dest_path.respond_to?(:to_hash) && options.empty?
|
505
713
|
options, dest_path = dest_path, nil
|
@@ -587,6 +795,38 @@ module Gcloud
|
|
587
795
|
"&Signature=#{CGI.escape signature}"
|
588
796
|
end
|
589
797
|
end
|
798
|
+
|
799
|
+
##
|
800
|
+
# Yielded to a block to accumulate changes for a patch request.
|
801
|
+
class Updater
|
802
|
+
attr_reader :updates
|
803
|
+
##
|
804
|
+
# Create an Updater object.
|
805
|
+
def initialize metadata
|
806
|
+
@metadata = if metadata.nil?
|
807
|
+
{}
|
808
|
+
else
|
809
|
+
metadata.dup
|
810
|
+
end
|
811
|
+
@updates = {}
|
812
|
+
end
|
813
|
+
|
814
|
+
ATTRS = [:cache_control, :content_disposition, :content_encoding,
|
815
|
+
:content_language, :content_type, :metadata]
|
816
|
+
|
817
|
+
ATTRS.each do |attr|
|
818
|
+
define_method "#{attr}=" do |arg|
|
819
|
+
updates[attr] = arg
|
820
|
+
end
|
821
|
+
end
|
822
|
+
|
823
|
+
##
|
824
|
+
# Return metadata for mutation. Also adds metadata to @updates so that
|
825
|
+
# it is included in the patch request.
|
826
|
+
def metadata
|
827
|
+
updates[:metadata] ||= @metadata
|
828
|
+
end
|
829
|
+
end
|
590
830
|
end
|
591
831
|
end
|
592
832
|
end
|
@@ -352,7 +352,7 @@ module Gcloud
|
|
352
352
|
end
|
353
353
|
|
354
354
|
##
|
355
|
-
#
|
355
|
+
# Permanently deletes the entity from the file's access control list.
|
356
356
|
#
|
357
357
|
# === Parameters
|
358
358
|
#
|
@@ -536,11 +536,20 @@ module Gcloud
|
|
536
536
|
|
537
537
|
protected
|
538
538
|
|
539
|
+
def clear!
|
540
|
+
@owners = nil
|
541
|
+
@writers = nil
|
542
|
+
@readers = nil
|
543
|
+
self
|
544
|
+
end
|
545
|
+
|
539
546
|
def update_predefined_acl! acl_role
|
540
547
|
resp = @connection.patch_file @bucket, @file,
|
541
|
-
|
548
|
+
predefined_acl: acl_role,
|
549
|
+
acl: []
|
542
550
|
|
543
|
-
resp.success?
|
551
|
+
return clear! if resp.success?
|
552
|
+
fail Gcloud::Storage::ApiError.from_response(resp)
|
544
553
|
end
|
545
554
|
|
546
555
|
def entities_from_acls acls, role
|
@@ -18,6 +18,7 @@ require "gcloud/storage/errors"
|
|
18
18
|
require "gcloud/storage/connection"
|
19
19
|
require "gcloud/storage/credentials"
|
20
20
|
require "gcloud/storage/bucket"
|
21
|
+
require "gcloud/storage/bucket/cors"
|
21
22
|
require "gcloud/storage/file"
|
22
23
|
|
23
24
|
module Gcloud
|
@@ -190,7 +191,13 @@ module Gcloud
|
|
190
191
|
alias_method :find_bucket, :bucket
|
191
192
|
|
192
193
|
##
|
193
|
-
# Creates a new bucket.
|
194
|
+
# Creates a new bucket with optional attributes. Also accepts a block for
|
195
|
+
# defining the CORS configuration for a static website served from the
|
196
|
+
# bucket. See Bucket::Cors for details. For more information about
|
197
|
+
# configuring buckets as static websites, see {How to Host a Static
|
198
|
+
# Website }[https://cloud.google.com/storage/docs/website-configuration].
|
199
|
+
# For more information about CORS, see {Cross-Origin Resource Sharing
|
200
|
+
# (CORS)}[https://cloud.google.com/storage/docs/cross-origin].
|
194
201
|
#
|
195
202
|
# === Parameters
|
196
203
|
#
|
@@ -198,9 +205,53 @@ module Gcloud
|
|
198
205
|
# Name of a bucket. (+String+)
|
199
206
|
# +options+::
|
200
207
|
# An optional Hash for controlling additional behavior. (+Hash+)
|
208
|
+
# <code>options[:cors]</code>::
|
209
|
+
# The CORS rules for the bucket. Accepts an array of hashes containing
|
210
|
+
# the attributes specified for the {resource description of
|
211
|
+
# cors}[https://cloud.google.com/storage/docs/json_api/v1/buckets#cors].
|
212
|
+
# <code>options[:location]</code>::
|
213
|
+
# The location of the bucket. Object data for objects in the bucket
|
214
|
+
# resides in physical storage within this region. Possible values
|
215
|
+
# include +ASIA+, +EU+, and +US+.(See the {developer's
|
216
|
+
# guide}[https://cloud.google.com/storage/docs/bucket-locations] for the
|
217
|
+
# authoritative list. The default value is +US+. (+String+)
|
218
|
+
# <code>options[:logging_bucket]</code>::
|
219
|
+
# The destination bucket for the bucket's logs. For more information,
|
220
|
+
# see {Access
|
221
|
+
# Logs}[https://cloud.google.com/storage/docs/access-logs]. (+String+)
|
222
|
+
# <code>options[:logging_prefix]</code>::
|
223
|
+
# The prefix used to create log object names for the bucket. It can be
|
224
|
+
# at most 900 characters and must be a {valid object
|
225
|
+
# name}[https://cloud.google.com/storage/docs/bucket-naming#objectnames]
|
226
|
+
# . By default, the object prefix is the name
|
227
|
+
# of the bucket for which the logs are enabled. For more information,
|
228
|
+
# see {Access Logs}[https://cloud.google.com/storage/docs/access-logs].
|
229
|
+
# (+String+)
|
201
230
|
# <code>options[:retries]</code>::
|
202
231
|
# The number of times the API call should be retried.
|
203
232
|
# Default is Gcloud::Backoff.retries. (+Integer+)
|
233
|
+
# <code>options[:storage_class]</code>::
|
234
|
+
# Defines how objects in the bucket are stored and determines the SLA
|
235
|
+
# and the cost of storage. Values include +:standard+, +:nearline+, and
|
236
|
+
# +:dra+ (Durable Reduced Availability), as well as the strings returned
|
237
|
+
# by Bucket#storage_class. For more information, see {Storage
|
238
|
+
# Classes}[https://cloud.google.com/storage/docs/storage-classes].
|
239
|
+
# The default value is +:standard+. (+Symbol+ or +String+)
|
240
|
+
# <code>options[:versioning]</code>::
|
241
|
+
# Whether {Object
|
242
|
+
# Versioning}[https://cloud.google.com/storage/docs/object-versioning]
|
243
|
+
# is to be enabled for the bucket. The default value is +false+.
|
244
|
+
# (+Boolean+)
|
245
|
+
# <code>options[:website_main]</code>::
|
246
|
+
# The index page returned from a static website served from the bucket
|
247
|
+
# when a site visitor requests the top level directory. For more
|
248
|
+
# information, see {How to Host a Static Website
|
249
|
+
# }[https://cloud.google.com/storage/docs/website-configuration#step4].
|
250
|
+
# <code>options[:website_404]</code>::
|
251
|
+
# The page returned from a static website served from the bucket when a
|
252
|
+
# site visitor requests a resource that does not exist. For more
|
253
|
+
# information, see {How to Host a Static Website
|
254
|
+
# }[https://cloud.google.com/storage/docs/website-configuration#step4].
|
204
255
|
#
|
205
256
|
# === Returns
|
206
257
|
#
|
@@ -226,12 +277,45 @@ module Gcloud
|
|
226
277
|
#
|
227
278
|
# bucket = storage.create_bucket "my-bucket", retries: 5
|
228
279
|
#
|
280
|
+
# You can pass {website
|
281
|
+
# settings}[https://cloud.google.com/storage/docs/website-configuration]
|
282
|
+
# for the bucket, including a block that defines CORS rule. See
|
283
|
+
# Bucket::Cors for details.
|
284
|
+
#
|
285
|
+
# require "gcloud"
|
286
|
+
#
|
287
|
+
# gcloud = Gcloud.new
|
288
|
+
# storage = gcloud.storage
|
289
|
+
#
|
290
|
+
# options = {
|
291
|
+
# website_main: "index.html"
|
292
|
+
# website_404: "not_found.html"
|
293
|
+
# }
|
294
|
+
# bucket = storage.create_bucket "my-bucket", options do |c|
|
295
|
+
# c.add_rule ["http://example.org", "https://example.org"],
|
296
|
+
# "*",
|
297
|
+
# response_headers: ["X-My-Custom-Header"],
|
298
|
+
# max_age: 300
|
299
|
+
# end
|
300
|
+
#
|
229
301
|
def create_bucket bucket_name, options = {}
|
230
|
-
options[:acl] =
|
231
|
-
default_acl = options[:default_acl]
|
232
|
-
|
233
|
-
|
302
|
+
options[:acl] = acl_rule options[:acl]
|
303
|
+
options[:default_acl] = acl_rule options[:default_acl]
|
304
|
+
if block_given?
|
305
|
+
cors_builder = Bucket::Cors.new
|
306
|
+
yield cors_builder
|
307
|
+
options[:cors] = cors_builder if cors_builder.changed?
|
308
|
+
end
|
309
|
+
insert_bucket bucket_name, options
|
310
|
+
end
|
311
|
+
|
312
|
+
protected
|
313
|
+
|
314
|
+
def acl_rule option_name
|
315
|
+
Bucket::Acl.predefined_rule_for option_name
|
316
|
+
end
|
234
317
|
|
318
|
+
def insert_bucket bucket_name, options
|
235
319
|
resp = connection.insert_bucket bucket_name, options
|
236
320
|
if resp.success?
|
237
321
|
Bucket.from_gapi resp.data, connection
|