gcloud 0.11.0 → 0.12.0

Sign up to get free protection for your applications and to get access to all the features.
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
@@ -143,14 +143,14 @@ module Gcloud
143
143
 
144
144
  ##
145
145
  # @private New Projects::List from a response object.
146
- def self.from_response resp, manager, filter = nil, max = nil
147
- projects = new(Array(resp.data["projects"]).map do |gapi_object|
148
- Project.from_gapi gapi_object, manager.connection
146
+ def self.from_gapi gapi_list, manager, filter = nil, max = nil
147
+ projects = new(Array(gapi_list.projects).map do |gapi_object|
148
+ Project.from_gapi gapi_object, manager.service
149
149
  end)
150
- projects.instance_variable_set "@token", resp.data["nextPageToken"]
151
- projects.instance_variable_set "@manager", manager
152
- projects.instance_variable_set "@filter", filter
153
- projects.instance_variable_set "@max", max
150
+ projects.instance_variable_set :@token, gapi_list.next_page_token
151
+ projects.instance_variable_set :@manager, manager
152
+ projects.instance_variable_set :@filter, filter
153
+ projects.instance_variable_set :@max, max
154
154
  projects
155
155
  end
156
156
 
@@ -14,7 +14,6 @@
14
14
 
15
15
 
16
16
  require "time"
17
- require "gcloud/resource_manager/errors"
18
17
 
19
18
  module Gcloud
20
19
  module ResourceManager
@@ -61,7 +60,7 @@ module Gcloud
61
60
  # end
62
61
  #
63
62
  def name= new_name
64
- gapi["name"] = new_name
63
+ gapi.name = new_name
65
64
  end
66
65
 
67
66
  ##
@@ -88,7 +87,7 @@ module Gcloud
88
87
  # end
89
88
  #
90
89
  def labels
91
- gapi["labels"]
90
+ gapi.labels
92
91
  end
93
92
 
94
93
  ##
@@ -115,17 +114,13 @@ module Gcloud
115
114
  # end
116
115
  #
117
116
  def labels= new_labels
118
- gapi["labels"] = new_labels
117
+ gapi.labels = new_labels
119
118
  end
120
119
 
121
120
  ##
122
121
  # @private Create an Updater object.
123
122
  def self.from_project project
124
- dupe_gapi = project.gapi.dup
125
- dupe_gapi = dupe_gapi.to_hash if dupe_gapi.respond_to? :to_hash
126
- if dupe_gapi["labels"].respond_to? :to_hash
127
- dupe_gapi["labels"] = dupe_gapi["labels"].to_hash
128
- end
123
+ dupe_gapi = project.gapi.class.new project.gapi.to_h
129
124
  dupe_project = Project.from_gapi dupe_gapi, nil # no way to update
130
125
  Updater.new dupe_project
131
126
  end
@@ -0,0 +1,127 @@
1
+ # Copyright 2016 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 "gcloud/version"
17
+ require "gcloud/errors"
18
+ require "google/apis/cloudresourcemanager_v1"
19
+
20
+ module Gcloud
21
+ module ResourceManager
22
+ ##
23
+ # @private
24
+ # Represents the service to Resource Manager, as well as expose the API
25
+ # calls.
26
+ class Service
27
+ ##
28
+ # Alias to the Google Client API module
29
+ API = Google::Apis::CloudresourcemanagerV1
30
+
31
+ attr_accessor :credentials
32
+
33
+ ##
34
+ # Creates a new Service instance.
35
+ def initialize credentials, retries: nil, timeout: nil
36
+ @credentials = credentials
37
+ @service = API::CloudResourceManagerService.new
38
+ @service.client_options.application_name = "gcloud-ruby"
39
+ @service.client_options.application_version = Gcloud::VERSION
40
+ @service.request_options.retries = retries || 3
41
+ @service.request_options.timeout_sec = timeout if timeout
42
+ @service.authorization = @credentials.client
43
+ end
44
+
45
+ def service
46
+ return mocked_service if mocked_service
47
+ @service
48
+ end
49
+ attr_accessor :mocked_service
50
+
51
+ ##
52
+ # Returns API::ListProjectsResponse
53
+ def list_project filter: nil, token: nil, max: nil
54
+ service.list_projects page_token: token, page_size: max, filter: filter
55
+ end
56
+
57
+ ##
58
+ # Returns API::Project
59
+ def get_project project_id
60
+ service.get_project project_id
61
+ rescue Google::Apis::Error => e
62
+ raise Gcloud::Error.from_error(e)
63
+ end
64
+
65
+ ##
66
+ # Returns API::Project
67
+ def create_project project_id, name, labels
68
+ project_attrs = { projectId: project_id, name: name,
69
+ labels: labels }.delete_if { |_, v| v.nil? }
70
+ service.create_project API::Project.new(project_attrs)
71
+ rescue Google::Apis::Error => e
72
+ raise Gcloud::Error.from_error(e)
73
+ end
74
+
75
+ ##
76
+ # Updated the project, given a API::Project.
77
+ # Returns API::Project
78
+ def update_project project_gapi
79
+ service.update_project project_gapi.project_id, project_gapi
80
+ rescue Google::Apis::Error => e
81
+ raise Gcloud::Error.from_error(e)
82
+ end
83
+
84
+ def delete_project project_id
85
+ service.delete_project project_id
86
+ rescue Google::Apis::Error => e
87
+ raise Gcloud::Error.from_error(e)
88
+ end
89
+
90
+ def undelete_project project_id
91
+ service.undelete_project project_id
92
+ rescue Google::Apis::Error => e
93
+ raise Gcloud::Error.from_error(e)
94
+ end
95
+
96
+ ##
97
+ # Returns API::Policy
98
+ def get_policy project_id
99
+ service.get_project_iam_policy "projects/#{project_id}"
100
+ rescue Google::Apis::Error => e
101
+ raise Gcloud::Error.from_error(e)
102
+ end
103
+
104
+ ##
105
+ # Returns API::Policy
106
+ def set_policy project_id, new_policy
107
+ req = API::SetIamPolicyRequest.new policy: new_policy
108
+ service.set_project_iam_policy "projects/#{project_id}", req
109
+ rescue Google::Apis::Error => e
110
+ raise Gcloud::Error.from_error(e)
111
+ end
112
+
113
+ ##
114
+ # Returns API::TestIamPermissionsResponse
115
+ def test_permissions project_id, permissions
116
+ req = API::TestIamPermissionsRequest.new permissions: permissions
117
+ service.test_project_iam_permissions "projects/#{project_id}", req
118
+ rescue Google::Apis::Error => e
119
+ raise Gcloud::Error.from_error(e)
120
+ end
121
+
122
+ def inspect
123
+ "#{self.class}"
124
+ end
125
+ end
126
+ end
127
+ end
@@ -36,6 +36,9 @@ module Gcloud
36
36
  # The default scope is:
37
37
  #
38
38
  # * `https://www.googleapis.com/auth/devstorage.full_control`
39
+ # @param [Integer] retries Number of times to retry requests on server error.
40
+ # The default value is `3`. Optional.
41
+ # @param [Integer] timeout Default timeout to use in requests. Optional.
39
42
  #
40
43
  # @return [Gcloud::Storage::Project]
41
44
  #
@@ -48,14 +51,21 @@ module Gcloud
48
51
  # bucket = storage.bucket "my-bucket"
49
52
  # file = bucket.file "path/to/my-file.ext"
50
53
  #
51
- def self.storage project = nil, keyfile = nil, scope: nil
54
+ def self.storage project = nil, keyfile = nil, scope: nil, retries: nil,
55
+ timeout: nil
52
56
  project ||= Gcloud::Storage::Project.default_project
57
+ project = project.to_s # Always cast to a string
58
+ fail ArgumentError, "project is missing" if project.empty?
59
+
53
60
  if keyfile.nil?
54
61
  credentials = Gcloud::Storage::Credentials.default scope: scope
55
62
  else
56
63
  credentials = Gcloud::Storage::Credentials.new keyfile, scope: scope
57
64
  end
58
- Gcloud::Storage::Project.new project, credentials
65
+
66
+ Gcloud::Storage::Project.new(
67
+ Gcloud::Storage::Service.new(
68
+ project, credentials, retries: retries, timeout: timeout))
59
69
  end
60
70
 
61
71
  ##
@@ -66,7 +76,7 @@ module Gcloud
66
76
  # time, taking advantage of Google's own reliable and fast networking
67
77
  # infrastructure to perform data operations in a cost effective manner.
68
78
  #
69
- # Gcloud's goal is to provide a API that is familiar and comfortable to
79
+ # The goal of gcloud-ruby is to provide a API that is comfortable to
70
80
  # Rubyists. Authentication is handled by {Gcloud#storage}. You can provide the
71
81
  # project and credential information to connect to the Storage service, or if
72
82
  # you are running on Google Compute Engine this configuration is taken care
@@ -279,33 +289,6 @@ module Gcloud
279
289
  # encryption_key_sha256: key_hash
280
290
  # ```
281
291
  #
282
- # ### A note about large uploads
283
- #
284
- # You may encounter a Broken pipe (Errno::EPIPE) error when attempting to
285
- # upload large files. To avoid this problem, add the
286
- # [httpclient](https://rubygems.org/gems/httpclient) gem to your project, and
287
- # the line (or lines) of configuration shown below. These lines must execute
288
- # after you require gcloud but before you make your first gcloud connection.
289
- # The first statement configures [Faraday](https://rubygems.org/gems/faraday)
290
- # to use httpclient. The second statement, which should only be added if you
291
- # are using a version of Faraday at or above 0.9.2, is a workaround for [this
292
- # gzip issue](https://github.com/GoogleCloudPlatform/gcloud-ruby/issues/367).
293
- #
294
- # ```ruby
295
- # require "gcloud"
296
- #
297
- # # Use httpclient to avoid broken pipe errors with large uploads
298
- # Faraday.default_adapter = :httpclient
299
- #
300
- # # Only add the following statement if using Faraday >= 0.9.2
301
- # # Override gzip middleware with no-op for httpclient
302
- # Faraday::Response.register_middleware :gzip =>
303
- # Faraday::Response::Middleware
304
- #
305
- # gcloud = Gcloud.new
306
- # storage = gcloud.storage
307
- # ```
308
- #
309
292
  # ## Downloading a File
310
293
  #
311
294
  # Files can be downloaded to the local file system. (See
@@ -444,24 +427,23 @@ module Gcloud
444
427
  # file.acl.public!
445
428
  # ```
446
429
  #
447
- # ## Configuring Backoff
430
+ # ## Configuring retries and timeout
448
431
  #
449
- # The {Gcloud::Backoff} class allows users to globally configure how Cloud API
450
- # requests are automatically retried in the case of some errors, such as a
451
- # `500` or `503` status code, or a specific internal error code such as
452
- # `rateLimitExceeded`.
432
+ # You can configure how many times API requests may be automatically retried.
433
+ # When an API request fails, the response will be inspected to see if the
434
+ # request meets criteria indicating that it may succeed on retry, such as
435
+ # `500` and `503` status codes or a specific internal error code such as
436
+ # `rateLimitExceeded`. If it meets the criteria, the request will be retried
437
+ # after a delay. If another error occurs, the delay will be increased before a
438
+ # subsequent attempt, until the `retries` limit is reached.
453
439
  #
454
- # If an API call fails, the response will be inspected to see if the call
455
- # should be retried. If the response matches the criteria, then the request
456
- # will be retried after a delay. If another error occurs, the delay will be
457
- # increased incrementally before a subsequent attempt. The first retry will be
458
- # delayed one second, the second retry two seconds, and so on.
440
+ # You can also set the request `timeout` value in seconds.
459
441
  #
460
442
  # ```ruby
461
443
  # require "gcloud"
462
- # require "gcloud/backoff"
463
444
  #
464
- # Gcloud::Backoff.retries = 5 # Raise the maximum number of retries from 3
445
+ # gcloud = Gcloud.new
446
+ # storage = gcloud.storage retries: 10, timeout: 120
465
447
  # ```
466
448
  #
467
449
  # See the [Storage status and error
@@ -17,7 +17,7 @@ require "gcloud/storage/bucket/acl"
17
17
  require "gcloud/storage/bucket/list"
18
18
  require "gcloud/storage/bucket/cors"
19
19
  require "gcloud/storage/file"
20
- require "gcloud/upload"
20
+ require "pathname"
21
21
 
22
22
  module Gcloud
23
23
  module Storage
@@ -37,8 +37,8 @@ module Gcloud
37
37
  #
38
38
  class Bucket
39
39
  ##
40
- # @private The Connection object.
41
- attr_accessor :connection
40
+ # @private The Service object.
41
+ attr_accessor :service
42
42
 
43
43
  ##
44
44
  # @private The Google API Client object.
@@ -47,39 +47,39 @@ module Gcloud
47
47
  ##
48
48
  # @private Create an empty Bucket object.
49
49
  def initialize
50
- @connection = nil
51
- @gapi = {}
50
+ @service = nil
51
+ @gapi = Google::Apis::StorageV1::Bucket.new
52
52
  end
53
53
 
54
54
  ##
55
55
  # The kind of item this is.
56
56
  # For buckets, this is always `storage#bucket`.
57
57
  def kind
58
- @gapi["kind"]
58
+ @gapi.kind
59
59
  end
60
60
 
61
61
  ##
62
62
  # The ID of the bucket.
63
63
  def id
64
- @gapi["id"]
64
+ @gapi.id
65
65
  end
66
66
 
67
67
  ##
68
68
  # The name of the bucket.
69
69
  def name
70
- @gapi["name"]
70
+ @gapi.name
71
71
  end
72
72
 
73
73
  ##
74
74
  # A URL that can be used to access the bucket using the REST API.
75
75
  def api_url
76
- @gapi["selfLink"]
76
+ @gapi.self_link
77
77
  end
78
78
 
79
79
  ##
80
80
  # Creation time of the bucket.
81
81
  def created_at
82
- @gapi["timeCreated"]
82
+ @gapi.time_created
83
83
  end
84
84
 
85
85
  ##
@@ -128,26 +128,15 @@ module Gcloud
128
128
  # end
129
129
  #
130
130
  def cors
131
+ cors_builder = Bucket::Cors.from_gapi @gapi.cors_configurations
131
132
  if block_given?
132
- cors_builder = Bucket::Cors.new @gapi["cors"]
133
133
  yield cors_builder
134
- self.cors = cors_builder if cors_builder.changed?
134
+ if cors_builder.changed?
135
+ @gapi.cors_configurations = cors_builder.to_gapi
136
+ patch_gapi! :cors_configurations
137
+ end
135
138
  end
136
- deep_dup_and_freeze @gapi["cors"]
137
- end
138
-
139
- ##
140
- # Updates the CORS configuration for a static website served from the
141
- # bucket.
142
- #
143
- # Accepts an array of hashes containing the attributes specified for the
144
- # [resource description of
145
- # cors](https://cloud.google.com/storage/docs/json_api/v1/buckets#cors).
146
- #
147
- # @see https://cloud.google.com/storage/docs/cross-origin Cross-Origin
148
- # Resource Sharing (CORS)
149
- def cors= new_cors
150
- patch_gapi! cors: new_cors
139
+ cors_builder.freeze # always return frozen objects
151
140
  end
152
141
 
153
142
  ##
@@ -158,7 +147,7 @@ module Gcloud
158
147
  #
159
148
  # @see https://cloud.google.com/storage/docs/concepts-techniques
160
149
  def location
161
- @gapi["location"]
150
+ @gapi.location
162
151
  end
163
152
 
164
153
  ##
@@ -167,7 +156,7 @@ module Gcloud
167
156
  # @see https://cloud.google.com/storage/docs/access-logs Access Logs
168
157
  #
169
158
  def logging_bucket
170
- @gapi["logging"]["logBucket"] if @gapi["logging"]
159
+ @gapi.logging.log_bucket if @gapi.logging
171
160
  end
172
161
 
173
162
  ##
@@ -178,7 +167,9 @@ module Gcloud
178
167
  # @param [String] logging_bucket The bucket to hold the logging output
179
168
  #
180
169
  def logging_bucket= logging_bucket
181
- patch_gapi! logging_bucket: logging_bucket
170
+ @gapi.logging ||= Google::Apis::StorageV1::Bucket::Logging.new
171
+ @gapi.logging.log_bucket = logging_bucket
172
+ patch_gapi! :logging
182
173
  end
183
174
 
184
175
  ##
@@ -187,7 +178,7 @@ module Gcloud
187
178
  # @see https://cloud.google.com/storage/docs/access-logs Access Logs
188
179
  #
189
180
  def logging_prefix
190
- @gapi["logging"]["logObjectPrefix"] if @gapi["logging"]
181
+ @gapi.logging.log_object_prefix if @gapi.logging
191
182
  end
192
183
 
193
184
  ##
@@ -201,7 +192,9 @@ module Gcloud
201
192
  # @see https://cloud.google.com/storage/docs/access-logs Access Logs
202
193
  #
203
194
  def logging_prefix= logging_prefix
204
- patch_gapi! logging_prefix: logging_prefix
195
+ @gapi.logging ||= Google::Apis::StorageV1::Bucket::Logging.new
196
+ @gapi.logging.log_object_prefix = logging_prefix
197
+ patch_gapi! :logging
205
198
  end
206
199
 
207
200
  ##
@@ -209,7 +202,7 @@ module Gcloud
209
202
  # stored and determines the SLA and the cost of storage. Values include
210
203
  # `STANDARD`, `NEARLINE`, and `DURABLE_REDUCED_AVAILABILITY`.
211
204
  def storage_class
212
- @gapi["storageClass"]
205
+ @gapi.storage_class
213
206
  end
214
207
 
215
208
  ##
@@ -217,7 +210,7 @@ module Gcloud
217
210
  # Versioning](https://cloud.google.com/storage/docs/object-versioning) is
218
211
  # enabled for the bucket.
219
212
  def versioning?
220
- !@gapi["versioning"].nil? && @gapi["versioning"]["enabled"]
213
+ @gapi.versioning.enabled? unless @gapi.versioning.nil?
221
214
  end
222
215
 
223
216
  ##
@@ -228,7 +221,9 @@ module Gcloud
228
221
  # @return [Boolean]
229
222
  #
230
223
  def versioning= new_versioning
231
- patch_gapi! versioning: new_versioning
224
+ @gapi.versioning ||= Google::Apis::StorageV1::Bucket::Versioning.new
225
+ @gapi.versioning.enabled = new_versioning
226
+ patch_gapi! :versioning
232
227
  end
233
228
 
234
229
  ##
@@ -239,7 +234,7 @@ module Gcloud
239
234
  # How to Host a Static Website
240
235
  #
241
236
  def website_main
242
- @gapi["website"]["mainPageSuffix"] if @gapi["website"]
237
+ @gapi.website.main_page_suffix if @gapi.website
243
238
  end
244
239
 
245
240
  ##
@@ -250,7 +245,9 @@ module Gcloud
250
245
  # How to Host a Static Website
251
246
  #
252
247
  def website_main= website_main
253
- patch_gapi! website_main: website_main
248
+ @gapi.website ||= Google::Apis::StorageV1::Bucket::Website.new
249
+ @gapi.website.main_page_suffix = website_main
250
+ patch_gapi! :website
254
251
  end
255
252
 
256
253
  ##
@@ -261,7 +258,7 @@ module Gcloud
261
258
  # How to Host a Static Website
262
259
  #
263
260
  def website_404
264
- @gapi["website"]["notFoundPage"] if @gapi["website"]
261
+ @gapi.website.not_found_page if @gapi.website
265
262
  end
266
263
 
267
264
  ##
@@ -272,12 +269,14 @@ module Gcloud
272
269
  # How to Host a Static Website
273
270
  #
274
271
  def website_404= website_404
275
- patch_gapi! website_404: website_404
272
+ @gapi.website ||= Google::Apis::StorageV1::Bucket::Website.new
273
+ @gapi.website.not_found_page = website_404
274
+ patch_gapi! :website
276
275
  end
277
276
 
278
277
  ##
279
278
  # Updates the bucket with changes made in the given block in a single
280
- # PATCH request. The following attributes may be set: {#cors=},
279
+ # PATCH request. The following attributes may be set: {#cors},
281
280
  # {#logging_bucket=}, {#logging_prefix=}, {#versioning=},
282
281
  # {#website_main=}, and {#website_404=}. In addition, the #cors
283
282
  # configuration accessible in the block is completely mutable and will be
@@ -316,8 +315,10 @@ module Gcloud
316
315
  # end
317
316
  #
318
317
  def update
319
- updater = Updater.new @gapi["cors"]
318
+ updater = Updater.new @gapi
320
319
  yield updater
320
+ # Add check for mutable cors
321
+ updater.check_for_mutable_cors!
321
322
  patch_gapi! updater.updates unless updater.updates.empty?
322
323
  end
323
324
 
@@ -326,7 +327,7 @@ module Gcloud
326
327
  # The bucket must be empty before it can be deleted.
327
328
  #
328
329
  # The API call to delete the bucket may be retried under certain
329
- # conditions. See {Gcloud::Backoff} to control this behavior.
330
+ # conditions. See {Gcloud#storage} to control this behavior.
330
331
  #
331
332
  # @return [Boolean] Returns `true` if the bucket was deleted.
332
333
  #
@@ -340,13 +341,9 @@ module Gcloud
340
341
  # bucket.delete
341
342
  #
342
343
  def delete
343
- ensure_connection!
344
- resp = connection.delete_bucket name
345
- if resp.success?
346
- true
347
- else
348
- fail ApiError.from_response(resp)
349
- end
344
+ ensure_service!
345
+ service.delete_bucket name
346
+ true
350
347
  end
351
348
 
352
349
  ##
@@ -398,7 +395,7 @@ module Gcloud
398
395
  # end
399
396
  #
400
397
  def files prefix: nil, delimiter: nil, token: nil, max: nil, versions: nil
401
- ensure_connection!
398
+ ensure_service!
402
399
  options = {
403
400
  prefix: prefix,
404
401
  delimiter: delimiter,
@@ -406,10 +403,9 @@ module Gcloud
406
403
  max: max,
407
404
  versions: versions
408
405
  }
409
- resp = connection.list_files name, options
410
- fail ApiError.from_response(resp) unless resp.success?
411
- File::List.from_response resp, connection, name, prefix, delimiter, max,
412
- versions
406
+ gapi = service.list_files name, options
407
+ File::List.from_gapi gapi, service, name, prefix, delimiter, max,
408
+ versions
413
409
  end
414
410
  alias_method :find_files, :files
415
411
 
@@ -449,15 +445,13 @@ module Gcloud
449
445
  #
450
446
  def file path, generation: nil, encryption_key: nil,
451
447
  encryption_key_sha256: nil
452
- ensure_connection!
453
- options = { generation: generation, encryption_key: encryption_key,
454
- encryption_key_sha256: encryption_key_sha256 }
455
- resp = connection.get_file name, path, options
456
- if resp.success?
457
- File.from_gapi resp.data, connection
458
- else
459
- fail ApiError.from_response(resp)
460
- end
448
+ ensure_service!
449
+ options = { generation: generation, key: encryption_key,
450
+ key_sha256: encryption_key_sha256 }
451
+ gapi = service.get_file name, path, options
452
+ File.from_gapi gapi, service
453
+ rescue Gcloud::NotFoundError
454
+ nil
461
455
  end
462
456
  alias_method :find_file, :file
463
457
 
@@ -465,12 +459,6 @@ module Gcloud
465
459
  # Creates a new {File} object by providing a path to a local file to
466
460
  # upload and the path to store it with in the bucket.
467
461
  #
468
- # A `chunk_size` value can be provided in the options to be used
469
- # in resumable uploads. This value is the number of bytes per
470
- # chunk and must be divisible by 256KB. If it is not divisible
471
- # by 256KB then it will be lowered to the nearest acceptable
472
- # value.
473
- #
474
462
  # #### Customer-supplied encryption keys
475
463
  #
476
464
  # By default, Google Cloud Storage manages server-side encryption keys on
@@ -485,29 +473,6 @@ module Gcloud
485
473
  # files and buckets are also not encrypted, and you can read or update the
486
474
  # metadata of an encrypted file without providing the encryption key.
487
475
  #
488
- # #### Troubleshooting large uploads
489
- #
490
- # You may encounter errors while attempting to upload large files. Below
491
- # are a couple of common cases and their solutions.
492
- #
493
- # ##### Handling memory errors
494
- #
495
- # If you encounter a memory error such as `NoMemoryError`, try performing
496
- # a resumable upload and setting the `chunk_size` option to a value that
497
- # works for your environment, as explained in the final example above.
498
- #
499
- # ##### Handling broken pipe errors
500
- #
501
- # To avoid broken pipe (`Errno::EPIPE`) errors when uploading, add the
502
- # [httpclient](https://rubygems.org/gems/httpclient) gem to your project,
503
- # and the configuration shown below. These lines must execute after you
504
- # require gcloud but before you make your first gcloud connection. The
505
- # first statement configures [Faraday](https://rubygems.org/gems/faraday)
506
- # to use httpclient. The second statement, which should only be added if
507
- # you are using a version of Faraday at or above 0.9.2, is a workaround
508
- # for [this gzip
509
- # issue](https://github.com/GoogleCloudPlatform/gcloud-ruby/issues/367).
510
- #
511
476
  # @param [String] file Path of the file on the filesystem to upload.
512
477
  # @param [String] path Path to store the file in Google Cloud Storage.
513
478
  # @param [String] acl A predefined set of access controls to apply to this
@@ -542,10 +507,6 @@ module Gcloud
542
507
  # @param [String] content_type The
543
508
  # [Content-Type](https://tools.ietf.org/html/rfc2616#section-14.17)
544
509
  # response header to be returned when the file is downloaded.
545
- # @param [Integer] chunk_size The number of bytes per chunk in a resumable
546
- # upload. Must be divisible by 256KB. If it is not divisible by 265KB
547
- # then it will be lowered to the nearest acceptable value. If no value
548
- # is provided it will use {Gcloud::Upload.default_chunk_size}. Optional.
549
510
  # @param [String] crc32c The CRC32c checksum of the file data, as
550
511
  # described in [RFC 4960, Appendix
551
512
  # B](http://tools.ietf.org/html/rfc4960#appendix-B).
@@ -591,18 +552,6 @@ module Gcloud
591
552
  # bucket.create_file "path/to/local.file.ext",
592
553
  # "destination/path/file.ext"
593
554
  #
594
- # @example Specifying the chunk size as a number of bytes:
595
- # require "gcloud"
596
- #
597
- # gcloud = Gcloud.new
598
- # storage = gcloud.storage
599
- #
600
- # bucket = storage.bucket "my-bucket"
601
- #
602
- # bucket.create_file "path/to/local.file.ext",
603
- # "destination/path/file.ext",
604
- # chunk_size: 1024*1024 # 1 MB chunk
605
- #
606
555
  # @example Providing a customer-supplied encryption key:
607
556
  # require "gcloud"
608
557
  # require "digest/sha2"
@@ -627,39 +576,23 @@ module Gcloud
627
576
  # encryption_key: key,
628
577
  # encryption_key_sha256: key_hash
629
578
  #
630
- # @example Avoiding broken pipe errors with large uploads:
631
- # require "gcloud"
632
- #
633
- # # Use httpclient to avoid broken pipe errors with large uploads
634
- # Faraday.default_adapter = :httpclient
635
- #
636
- # # Only add the following statement if using Faraday >= 0.9.2
637
- # # Override gzip middleware with no-op for httpclient
638
- # Faraday::Response.register_middleware :gzip =>
639
- # Faraday::Response::Middleware
640
- #
641
- # gcloud = Gcloud.new
642
- # storage = gcloud.storage
643
- #
644
579
  def create_file file, path = nil, acl: nil, cache_control: nil,
645
580
  content_disposition: nil, content_encoding: nil,
646
- content_language: nil, content_type: nil, chunk_size: nil,
581
+ content_language: nil, content_type: nil,
647
582
  crc32c: nil, md5: nil, metadata: nil, encryption_key: nil,
648
583
  encryption_key_sha256: nil
649
- ensure_connection!
584
+ ensure_service!
650
585
  options = { acl: File::Acl.predefined_rule_for(acl), md5: md5,
651
586
  cache_control: cache_control, content_type: content_type,
652
587
  content_disposition: content_disposition, crc32c: crc32c,
653
- content_encoding: content_encoding, chunk_size: chunk_size,
588
+ content_encoding: content_encoding,
654
589
  content_language: content_language, metadata: metadata,
655
- encryption_key: encryption_key,
656
- encryption_key_sha256: encryption_key_sha256 }
590
+ key: encryption_key, key_sha256: encryption_key_sha256 }
657
591
  ensure_file_exists! file
658
- resumable = resumable_upload?(file)
659
- resp = @connection.upload_file resumable, name, file, path, options
660
-
661
- return File.from_gapi(resp.data, connection) if resp.success?
662
- fail ApiError.from_response(resp)
592
+ # TODO: Handle file as an IO and path is missing more gracefully
593
+ path ||= Pathname(file).to_path
594
+ gapi = service.insert_file name, file, path, options
595
+ File.from_gapi gapi, service
663
596
  end
664
597
  alias_method :upload_file, :create_file
665
598
  alias_method :new_file, :create_file
@@ -760,13 +693,8 @@ module Gcloud
760
693
  ##
761
694
  # Reloads the bucket with current data from the Storage service.
762
695
  def reload!
763
- ensure_connection!
764
- resp = connection.get_bucket name
765
- if resp.success?
766
- @gapi = resp.data
767
- else
768
- fail ApiError.from_response(resp)
769
- end
696
+ ensure_service!
697
+ @gapi = service.get_bucket name
770
698
  end
771
699
  alias_method :refresh!, :reload!
772
700
 
@@ -775,26 +703,27 @@ module Gcloud
775
703
  def self.from_gapi gapi, conn
776
704
  new.tap do |f|
777
705
  f.gapi = gapi
778
- f.connection = conn
706
+ f.service = conn
779
707
  end
780
708
  end
781
709
 
782
710
  protected
783
711
 
784
712
  ##
785
- # Raise an error unless an active connection is available.
786
- def ensure_connection!
787
- fail "Must have active connection" unless connection
713
+ # Raise an error unless an active service is available.
714
+ def ensure_service!
715
+ fail "Must have active connection" unless service
788
716
  end
789
717
 
790
- def patch_gapi! options = {}
791
- ensure_connection!
792
- resp = connection.patch_bucket name, options
793
- if resp.success?
794
- @gapi = resp.data
795
- else
796
- fail ApiError.from_response(resp)
797
- end
718
+ def patch_gapi! *attributes
719
+ attributes.flatten!
720
+ return if attributes.empty?
721
+ ensure_service!
722
+ patch_args = Hash[attributes.map do |attr|
723
+ [attr, @gapi.send(attr)]
724
+ end]
725
+ patch_gapi = Google::Apis::StorageV1::Bucket.new patch_args
726
+ @gapi = service.patch_bucket name, patch_gapi
798
727
  end
799
728
 
800
729
  ##
@@ -804,58 +733,41 @@ module Gcloud
804
733
  fail ArgumentError, "cannot find file #{file}"
805
734
  end
806
735
 
807
- ##
808
- # @private Determines if a resumable upload should be used.
809
- def resumable_upload? file
810
- ::File.size?(file).to_i > Upload.resumable_threshold
811
- end
812
-
813
- ##
814
- # Given nil, empty array, a gapi array of hashes, or any value, returns a
815
- # deeply dup'd and frozen array of simple hashes or values (not gapi
816
- # objects.)
817
- def deep_dup_and_freeze array
818
- return [].freeze if array.nil? || array.empty?
819
- array = Array(array.dup)
820
- array = array.map do |h|
821
- h = h.to_hash if h.respond_to? :to_hash
822
- h.dup.freeze
823
- end
824
- array.freeze
825
- end
826
-
827
736
  ##
828
737
  # Yielded to a block to accumulate changes for a patch request.
829
- class Updater
738
+ class Updater < Bucket
830
739
  attr_reader :updates
831
740
  ##
832
741
  # Create an Updater object.
833
- def initialize cors
834
- @cors = cors ? Array(cors.dup) : []
835
- @cors = @cors.map { |x| x.to_hash if x.respond_to? :to_hash }
836
- @updates = {}
742
+ def initialize gapi
743
+ @updates = []
744
+ @gapi = gapi
745
+ @cors_builder = nil
837
746
  end
838
747
 
839
- ATTRS = [:cors, :logging_bucket, :logging_prefix, :versioning,
840
- :website_main, :website_404]
748
+ def cors
749
+ # Same as Bucket#cors, but not frozen
750
+ @cors_builder ||= Bucket::Cors.from_gapi @gapi.cors_configurations
751
+ yield @cors_builder if block_given?
752
+ @cors_builder
753
+ end
841
754
 
842
- ATTRS.each do |attr|
843
- define_method "#{attr}=" do |arg|
844
- updates[attr] = arg
845
- end
755
+ ##
756
+ # @private Make sure any cors changes are saved
757
+ def check_for_mutable_cors!
758
+ return if @cors_builder.nil?
759
+ return unless @cors_builder.changed?
760
+ @gapi.cors_configurations = @cors_builder.to_gapi
761
+ patch_gapi! :cors_configurations
846
762
  end
847
763
 
764
+ protected
765
+
848
766
  ##
849
- # Return CORS for mutation. Also adds CORS to @updates so that it
850
- # is included in the patch request.
851
- def cors
852
- updates[:cors] ||= @cors
853
- if block_given?
854
- cors_builder = Bucket::Cors.new updates[:cors]
855
- yield cors_builder
856
- updates[:cors] = cors_builder if cors_builder.changed?
857
- end
858
- updates[:cors]
767
+ # Queue up all the updates instead of making them.
768
+ def patch_gapi! attribute
769
+ @updates << attribute
770
+ @updates.uniq!
859
771
  end
860
772
  end
861
773
  end