gcloud 0.4.0 → 0.4.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
checksums.yaml
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
---
|
2
2
|
!binary "U0hBMQ==":
|
3
3
|
metadata.gz: !binary |-
|
4
|
-
|
4
|
+
MGI1YjI0MjIxZDhhNmI1YjY0ZWM2MjY0YTg5ZDY3OWZlMmVlYjhhNw==
|
5
5
|
data.tar.gz: !binary |-
|
6
|
-
|
6
|
+
MzdkOGRmYTY3MmQ0YzU0ZGM4YmIwZGQwNDdmY2EzNDNjYTY4NjRlYg==
|
7
7
|
SHA512:
|
8
8
|
metadata.gz: !binary |-
|
9
|
-
|
10
|
-
|
11
|
-
|
9
|
+
MTU4ZGJkZmM4YTg2YWY2YWNiYjQyYmQxNDM3YzBhNTczZDViMzgzMGQyMGIz
|
10
|
+
ODVlY2JmNDJjNjljMmRlZTY5MmZhNzdiZTg3ZjUxMTI0MjM5ZTA5OWM4Njg4
|
11
|
+
NzdiNmE4ZTVjOTk3MzIwODliYjM0NTcyNmFmNDVmYWFhZDU3OWM=
|
12
12
|
data.tar.gz: !binary |-
|
13
|
-
|
14
|
-
|
15
|
-
|
13
|
+
NjNkMTAzNDI0YWE1ZWJjOTVjZGMzZjZlMGNhOTQ2NWNmYWZkZGE2NzFkMDY5
|
14
|
+
MGU3OTkxMGRlZWIzNjQzOGM4OTJhNWExY2MyM2E1NzQ1MDNhZTNjMjhkMjAz
|
15
|
+
ZjZkZGI2OGJkMjliYzQyNTkyMmFkNzU2MDRkNmNiYWQxYWE4ZmE=
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,26 @@
|
|
1
1
|
# Release History
|
2
2
|
|
3
|
+
### 0.4.1 / 2015-10-20
|
4
|
+
|
5
|
+
#### Changes
|
6
|
+
|
7
|
+
* Add support for Bucket attributes, including:
|
8
|
+
* CORS
|
9
|
+
* logging
|
10
|
+
* versioning
|
11
|
+
* location
|
12
|
+
* website
|
13
|
+
* storage class
|
14
|
+
* Add support for File attributes, including:
|
15
|
+
* cache_control
|
16
|
+
* content_dispostion
|
17
|
+
* content_encoding
|
18
|
+
* content_language
|
19
|
+
* content_type
|
20
|
+
* Add support for File upload validation with MD5 or CRC32c
|
21
|
+
* Add File#public_url
|
22
|
+
* Improve stability and error reporting of Storage ACL helpers
|
23
|
+
|
3
24
|
### 0.4.0 / 2015-10-12
|
4
25
|
|
5
26
|
#### Major changes
|
data/lib/gcloud/bigquery/view.rb
CHANGED
@@ -15,6 +15,7 @@
|
|
15
15
|
|
16
16
|
require "gcloud/storage/bucket/acl"
|
17
17
|
require "gcloud/storage/bucket/list"
|
18
|
+
require "gcloud/storage/bucket/cors"
|
18
19
|
require "gcloud/storage/file"
|
19
20
|
require "gcloud/upload"
|
20
21
|
|
@@ -69,11 +70,80 @@ module Gcloud
|
|
69
70
|
end
|
70
71
|
|
71
72
|
##
|
72
|
-
#
|
73
|
-
def
|
73
|
+
# A URL that can be used to access the bucket using the REST API.
|
74
|
+
def api_url
|
74
75
|
@gapi["selfLink"]
|
75
76
|
end
|
76
77
|
|
78
|
+
##
|
79
|
+
# Creation time of the bucket.
|
80
|
+
def created_at
|
81
|
+
@gapi["timeCreated"]
|
82
|
+
end
|
83
|
+
|
84
|
+
##
|
85
|
+
# Returns the current CORS configuration for a static website served from
|
86
|
+
# the bucket. For more information, see {Cross-Origin Resource
|
87
|
+
# Sharing (CORS)}[https://cloud.google.com/storage/docs/cross-origin].
|
88
|
+
# The return value is a frozen (unmodifiable) array of hashes containing
|
89
|
+
# the attributes specified for the Bucket resource field
|
90
|
+
# {cors}[https://cloud.google.com/storage/docs/json_api/v1/buckets#cors].
|
91
|
+
#
|
92
|
+
# This method also accepts a block for updating the bucket's CORS rules.
|
93
|
+
# See Bucket::Cors for details.
|
94
|
+
#
|
95
|
+
# === Examples
|
96
|
+
#
|
97
|
+
# Retrieving the bucket's CORS rules.
|
98
|
+
#
|
99
|
+
# require "gcloud"
|
100
|
+
#
|
101
|
+
# gcloud = Gcloud.new
|
102
|
+
# storage = gcloud.storage
|
103
|
+
#
|
104
|
+
# bucket = storage.bucket "my-todo-app"
|
105
|
+
# bucket.cors #=> [{"origin"=>["http://example.org"],
|
106
|
+
# # "method"=>["GET","POST","DELETE"],
|
107
|
+
# # "responseHeader"=>["X-My-Custom-Header"],
|
108
|
+
# # "maxAgeSeconds"=>3600}]
|
109
|
+
#
|
110
|
+
# Updating the bucket's CORS rules inside a block.
|
111
|
+
#
|
112
|
+
# require "gcloud"
|
113
|
+
#
|
114
|
+
# gcloud = Gcloud.new
|
115
|
+
# storage = gcloud.storage
|
116
|
+
# bucket = storage.bucket "my-todo-app"
|
117
|
+
#
|
118
|
+
# bucket.update do |b|
|
119
|
+
# b.cors do |c|
|
120
|
+
# c.add_rule ["http://example.org", "https://example.org"],
|
121
|
+
# "*",
|
122
|
+
# response_headers: ["X-My-Custom-Header"],
|
123
|
+
# max_age: 3600
|
124
|
+
# end
|
125
|
+
# end
|
126
|
+
#
|
127
|
+
def cors
|
128
|
+
if block_given?
|
129
|
+
cors_builder = Bucket::Cors.new @gapi["cors"]
|
130
|
+
yield cors_builder
|
131
|
+
self.cors = cors_builder if cors_builder.changed?
|
132
|
+
end
|
133
|
+
deep_dup_and_freeze @gapi["cors"]
|
134
|
+
end
|
135
|
+
|
136
|
+
##
|
137
|
+
# Updates the CORS configuration for a static website served from the
|
138
|
+
# bucket. For more information, see {Cross-Origin Resource
|
139
|
+
# Sharing (CORS)}[https://cloud.google.com/storage/docs/cross-origin].
|
140
|
+
# Accepts an array of hashes containing the attributes specified for the
|
141
|
+
# {resource description of
|
142
|
+
# cors}[https://cloud.google.com/storage/docs/json_api/v1/buckets#cors].
|
143
|
+
def cors= new_cors
|
144
|
+
patch_gapi! cors: new_cors
|
145
|
+
end
|
146
|
+
|
77
147
|
##
|
78
148
|
# The location of the bucket.
|
79
149
|
# Object data for objects in the bucket resides in physical
|
@@ -86,13 +156,150 @@ module Gcloud
|
|
86
156
|
end
|
87
157
|
|
88
158
|
##
|
89
|
-
#
|
90
|
-
|
91
|
-
|
159
|
+
# The destination bucket name for the bucket's logs. For more information,
|
160
|
+
# see {Access Logs}[https://cloud.google.com/storage/docs/access-logs].
|
161
|
+
def logging_bucket
|
162
|
+
@gapi["logging"]["logBucket"] if @gapi["logging"]
|
163
|
+
end
|
164
|
+
|
165
|
+
##
|
166
|
+
# Updates the destination bucket for the bucket's logs. For more
|
167
|
+
# information, see {Access
|
168
|
+
# Logs}[https://cloud.google.com/storage/docs/access-logs]. (+String+)
|
169
|
+
def logging_bucket= logging_bucket
|
170
|
+
patch_gapi! logging_bucket: logging_bucket
|
171
|
+
end
|
172
|
+
|
173
|
+
##
|
174
|
+
# The logging object prefix for the bucket's logs. For more information,
|
175
|
+
# see {Access Logs}[https://cloud.google.com/storage/docs/access-logs].
|
176
|
+
def logging_prefix
|
177
|
+
@gapi["logging"]["logObjectPrefix"] if @gapi["logging"]
|
178
|
+
end
|
179
|
+
|
180
|
+
##
|
181
|
+
# Updates the logging object prefix. This prefix will be used to create
|
182
|
+
# log object names for the bucket. It can be at most 900 characters and
|
183
|
+
# must be a {valid object
|
184
|
+
# name}[https://cloud.google.com/storage/docs/bucket-naming#objectnames].
|
185
|
+
# By default, the object prefix is the name
|
186
|
+
# of the bucket for which the logs are enabled. For more information, see
|
187
|
+
# {Access Logs}[https://cloud.google.com/storage/docs/access-logs].
|
188
|
+
# (+String+)
|
189
|
+
def logging_prefix= logging_prefix
|
190
|
+
patch_gapi! logging_prefix: logging_prefix
|
191
|
+
end
|
192
|
+
|
193
|
+
##
|
194
|
+
# The bucket's storage class. This defines how objects in the bucket are
|
195
|
+
# stored and determines the SLA and the cost of storage. Values include
|
196
|
+
# +STANDARD+, +NEARLINE+, and +DURABLE_REDUCED_AVAILABILITY+.
|
197
|
+
def storage_class
|
198
|
+
@gapi["storageClass"]
|
199
|
+
end
|
200
|
+
|
201
|
+
##
|
202
|
+
# Whether {Object
|
203
|
+
# Versioning}[https://cloud.google.com/storage/docs/object-versioning] is
|
204
|
+
# enabled for the bucket.
|
205
|
+
def versioning?
|
206
|
+
!@gapi["versioning"].nil? && @gapi["versioning"]["enabled"]
|
207
|
+
end
|
208
|
+
|
209
|
+
##
|
210
|
+
# Updates whether {Object
|
211
|
+
# Versioning}[https://cloud.google.com/storage/docs/object-versioning] is
|
212
|
+
# enabled for the bucket. (+Boolean+)
|
213
|
+
def versioning= new_versioning
|
214
|
+
patch_gapi! versioning: new_versioning
|
215
|
+
end
|
216
|
+
|
217
|
+
##
|
218
|
+
# The index page returned from a static website served from the bucket
|
219
|
+
# when a site visitor requests the top level directory. For more
|
220
|
+
# information, see {How to Host a Static Website
|
221
|
+
# }[https://cloud.google.com/storage/docs/website-configuration#step4].
|
222
|
+
def website_main
|
223
|
+
@gapi["website"]["mainPageSuffix"] if @gapi["website"]
|
92
224
|
end
|
93
225
|
|
94
226
|
##
|
95
|
-
#
|
227
|
+
# Updates the index page returned from a static website served from the
|
228
|
+
# bucket when a site visitor requests the top level directory. For more
|
229
|
+
# information, see {How to Host a Static Website
|
230
|
+
# }[https://cloud.google.com/storage/docs/website-configuration#step4].
|
231
|
+
# (+String+)
|
232
|
+
def website_main= website_main
|
233
|
+
patch_gapi! website_main: website_main
|
234
|
+
end
|
235
|
+
|
236
|
+
##
|
237
|
+
# The page returned from a static website served from the bucket when a
|
238
|
+
# site visitor requests a resource that does not exist. For more
|
239
|
+
# information, see {How to Host a Static Website
|
240
|
+
# }[https://cloud.google.com/storage/docs/website-configuration#step4].
|
241
|
+
def website_404
|
242
|
+
@gapi["website"]["notFoundPage"] if @gapi["website"]
|
243
|
+
end
|
244
|
+
|
245
|
+
##
|
246
|
+
# Updates the page returned from a static website served from the bucket
|
247
|
+
# when a site visitor requests a resource that does not exist. For more
|
248
|
+
# information, see {How to Host a Static Website
|
249
|
+
# }[https://cloud.google.com/storage/docs/website-configuration#step4].
|
250
|
+
# (+String+)
|
251
|
+
def website_404= website_404
|
252
|
+
patch_gapi! website_404: website_404
|
253
|
+
end
|
254
|
+
|
255
|
+
##
|
256
|
+
# Updates the bucket with changes made in the given block in a single
|
257
|
+
# PATCH request. The following attributes may be set: #cors=,
|
258
|
+
# #logging_bucket=, #logging_prefix=, #versioning=, #website_main=, and
|
259
|
+
# #website_404=. In addition, the #cors configuration accessible in the
|
260
|
+
# block is completely mutable and will be included in the request.
|
261
|
+
#
|
262
|
+
# === Examples
|
263
|
+
#
|
264
|
+
# require "gcloud"
|
265
|
+
#
|
266
|
+
# gcloud = Gcloud.new
|
267
|
+
# storage = gcloud.storage
|
268
|
+
#
|
269
|
+
# bucket = storage.bucket "my-bucket"
|
270
|
+
# bucket.update do |b|
|
271
|
+
# b.website_main = "index.html"
|
272
|
+
# b.website_404 = "not_found.html"
|
273
|
+
# b.cors[0]["method"] = ["GET","POST","DELETE"]
|
274
|
+
# b.cors[1]["responseHeader"] << "X-Another-Custom-Header"
|
275
|
+
# end
|
276
|
+
#
|
277
|
+
# New CORS rules can also be added in a nested block. See Bucket::Cors for
|
278
|
+
# details.
|
279
|
+
#
|
280
|
+
# require "gcloud"
|
281
|
+
#
|
282
|
+
# gcloud = Gcloud.new
|
283
|
+
# storage = gcloud.storage
|
284
|
+
# bucket = storage.bucket "my-todo-app"
|
285
|
+
#
|
286
|
+
# bucket.update do |b|
|
287
|
+
# b.cors do |c|
|
288
|
+
# c.add_rule ["http://example.org", "https://example.org"],
|
289
|
+
# "*",
|
290
|
+
# response_headers: ["X-My-Custom-Header"],
|
291
|
+
# max_age: 300
|
292
|
+
# end
|
293
|
+
# end
|
294
|
+
#
|
295
|
+
def update
|
296
|
+
updater = Updater.new @gapi["cors"]
|
297
|
+
yield updater
|
298
|
+
patch_gapi! updater.updates unless updater.updates.empty?
|
299
|
+
end
|
300
|
+
|
301
|
+
##
|
302
|
+
# Permanently deletes the bucket.
|
96
303
|
# The bucket must be empty before it can be deleted.
|
97
304
|
#
|
98
305
|
# === Parameters
|
@@ -279,6 +486,43 @@ module Gcloud
|
|
279
486
|
# and project team members get access according to their roles.
|
280
487
|
# * +public+, +public_read+, +publicRead+ - File owner gets OWNER
|
281
488
|
# access, and allUsers get READER access.
|
489
|
+
# <code>options[:cache_control]</code>::
|
490
|
+
# The {Cache-Control}[https://tools.ietf.org/html/rfc7234#section-5.2]
|
491
|
+
# response header to be returned when the file is downloaded. (+String+)
|
492
|
+
# <code>options[:content_disposition]</code>::
|
493
|
+
# The {Content-Disposition}[https://tools.ietf.org/html/rfc6266]
|
494
|
+
# response header to be returned when the file is downloaded. (+String+)
|
495
|
+
# <code>options[:content_encoding]</code>::
|
496
|
+
# The {Content-Encoding
|
497
|
+
# }[https://tools.ietf.org/html/rfc7231#section-3.1.2.2] response header
|
498
|
+
# to be returned when the file is downloaded. (+String+)
|
499
|
+
# <code>options[:content_language]</code>::
|
500
|
+
# The {Content-Language}[http://tools.ietf.org/html/bcp47] response
|
501
|
+
# header to be returned when the file is downloaded. (+String+)
|
502
|
+
# <code>options[:content_type]</code>::
|
503
|
+
# The {Content-Type}[https://tools.ietf.org/html/rfc2616#section-14.17]
|
504
|
+
# response header to be returned when the file is downloaded. (+String+)
|
505
|
+
# <code>options[:chunk_size]</code>::
|
506
|
+
# The number of bytes per chunk in a resumable upload. Must be divisible
|
507
|
+
# by 256KB. If it is not divisible by 265KB then it will be lowered to
|
508
|
+
# the nearest acceptable value. (+Integer+)
|
509
|
+
# <code>options[:crc32c]</code>::
|
510
|
+
# The CRC32c checksum of the file data, as described in
|
511
|
+
# {RFC 4960, Appendix B}[http://tools.ietf.org/html/rfc4960#appendix-B].
|
512
|
+
# If provided, Cloud Storage will only create the file if the value
|
513
|
+
# matches the value calculated by the service. See
|
514
|
+
# {Validation}[https://cloud.google.com/storage/docs/hashes-etags]
|
515
|
+
# for more information. (+String+)
|
516
|
+
# <code>options[:md5]</code>::
|
517
|
+
# The MD5 hash of the file data. If provided, Cloud Storage will only
|
518
|
+
# create the file if the value matches the value calculated by the
|
519
|
+
# service. See
|
520
|
+
# {Validation}[https://cloud.google.com/storage/docs/hashes-etags]
|
521
|
+
# for more information. (+String+)
|
522
|
+
# <code>options[:metadata]</code>::
|
523
|
+
# A hash of custom, user-provided web-safe keys and arbitrary string
|
524
|
+
# values that will returned with requests for the file as "x-goog-meta-"
|
525
|
+
# response headers. (+Hash+)
|
282
526
|
#
|
283
527
|
# === Returns
|
284
528
|
#
|
@@ -310,7 +554,7 @@ module Gcloud
|
|
310
554
|
# A chunk_size value can be provided in the options to be used
|
311
555
|
# in resumable uploads. This value is the number of bytes per
|
312
556
|
# chunk and must be divisible by 256KB. If it is not divisible
|
313
|
-
# by 265KB then it will be lowered to the nearest
|
557
|
+
# by 265KB then it will be lowered to the nearest acceptable
|
314
558
|
# value.
|
315
559
|
#
|
316
560
|
# require "gcloud"
|
@@ -353,13 +597,14 @@ module Gcloud
|
|
353
597
|
def create_file file, path = nil, options = {}
|
354
598
|
ensure_connection!
|
355
599
|
ensure_file_exists! file
|
356
|
-
|
357
600
|
options[:acl] = File::Acl.predefined_rule_for options[:acl]
|
601
|
+
resumable = resumable_upload?(file)
|
602
|
+
resp = @connection.upload_file resumable, name, file, path, options
|
358
603
|
|
359
|
-
if
|
360
|
-
|
604
|
+
if resp.success?
|
605
|
+
File.from_gapi resp.data, connection
|
361
606
|
else
|
362
|
-
|
607
|
+
fail ApiError.from_response(resp)
|
363
608
|
end
|
364
609
|
end
|
365
610
|
alias_method :upload_file, :create_file
|
@@ -503,6 +748,16 @@ module Gcloud
|
|
503
748
|
fail "Must have active connection" unless connection
|
504
749
|
end
|
505
750
|
|
751
|
+
def patch_gapi! options = {}
|
752
|
+
ensure_connection!
|
753
|
+
resp = connection.patch_bucket name, options
|
754
|
+
if resp.success?
|
755
|
+
@gapi = resp.data
|
756
|
+
else
|
757
|
+
fail ApiError.from_response(resp)
|
758
|
+
end
|
759
|
+
end
|
760
|
+
|
506
761
|
##
|
507
762
|
# Raise an error if the file is not found.
|
508
763
|
def ensure_file_exists! file
|
@@ -516,39 +771,53 @@ module Gcloud
|
|
516
771
|
::File.size?(file).to_i > Upload.resumable_threshold
|
517
772
|
end
|
518
773
|
|
519
|
-
|
520
|
-
|
521
|
-
|
522
|
-
|
523
|
-
|
524
|
-
|
525
|
-
|
774
|
+
##
|
775
|
+
# Given nil, empty array, a gapi array of hashes, or any value, returns a
|
776
|
+
# deeply dup'd and frozen array of simple hashes or values (not gapi
|
777
|
+
# objects.)
|
778
|
+
def deep_dup_and_freeze array
|
779
|
+
return [].freeze if array.nil? || array.empty?
|
780
|
+
array = Array(array.dup)
|
781
|
+
array = array.map do |h|
|
782
|
+
h = h.to_hash if h.respond_to? :to_hash
|
783
|
+
h.dup.freeze
|
526
784
|
end
|
785
|
+
array.freeze
|
527
786
|
end
|
528
787
|
|
529
|
-
|
530
|
-
|
788
|
+
##
|
789
|
+
# Yielded to a block to accumulate changes for a patch request.
|
790
|
+
class Updater
|
791
|
+
attr_reader :updates
|
792
|
+
##
|
793
|
+
# Create an Updater object.
|
794
|
+
def initialize cors
|
795
|
+
@cors = cors ? Array(cors.dup) : []
|
796
|
+
@cors = @cors.map { |x| x.to_hash if x.respond_to? :to_hash }
|
797
|
+
@updates = {}
|
798
|
+
end
|
531
799
|
|
532
|
-
|
533
|
-
|
800
|
+
ATTRS = [:cors, :logging_bucket, :logging_prefix, :versioning,
|
801
|
+
:website_main, :website_404]
|
534
802
|
|
535
|
-
|
536
|
-
|
537
|
-
|
538
|
-
|
803
|
+
ATTRS.each do |attr|
|
804
|
+
define_method "#{attr}=" do |arg|
|
805
|
+
updates[attr] = arg
|
806
|
+
end
|
539
807
|
end
|
540
|
-
end
|
541
808
|
|
542
|
-
|
543
|
-
|
544
|
-
|
545
|
-
|
546
|
-
|
547
|
-
|
548
|
-
|
809
|
+
##
|
810
|
+
# Return CORS for mutation. Also adds CORS to @updates so that it
|
811
|
+
# is included in the patch request.
|
812
|
+
def cors
|
813
|
+
updates[:cors] ||= @cors
|
814
|
+
if block_given?
|
815
|
+
cors_builder = Bucket::Cors.new updates[:cors]
|
816
|
+
yield cors_builder
|
817
|
+
updates[:cors] = cors_builder if cors_builder.changed?
|
818
|
+
end
|
819
|
+
updates[:cors]
|
549
820
|
end
|
550
|
-
return if chunk_size.zero?
|
551
|
-
chunk_size
|
552
821
|
end
|
553
822
|
end
|
554
823
|
end
|