cure-google-api-client 0.8.7.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.
Files changed (62) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +178 -0
  3. data/Gemfile +9 -0
  4. data/LICENSE +202 -0
  5. data/README.md +218 -0
  6. data/Rakefile +41 -0
  7. data/google-api-client.gemspec +43 -0
  8. data/lib/cacerts.pem +2183 -0
  9. data/lib/compat/multi_json.rb +19 -0
  10. data/lib/google/api_client.rb +750 -0
  11. data/lib/google/api_client/auth/compute_service_account.rb +28 -0
  12. data/lib/google/api_client/auth/file_storage.rb +59 -0
  13. data/lib/google/api_client/auth/installed_app.rb +126 -0
  14. data/lib/google/api_client/auth/jwt_asserter.rb +126 -0
  15. data/lib/google/api_client/auth/key_utils.rb +93 -0
  16. data/lib/google/api_client/auth/pkcs12.rb +41 -0
  17. data/lib/google/api_client/auth/storage.rb +102 -0
  18. data/lib/google/api_client/auth/storages/file_store.rb +58 -0
  19. data/lib/google/api_client/auth/storages/redis_store.rb +54 -0
  20. data/lib/google/api_client/batch.rb +326 -0
  21. data/lib/google/api_client/charset.rb +33 -0
  22. data/lib/google/api_client/client_secrets.rb +179 -0
  23. data/lib/google/api_client/discovery.rb +19 -0
  24. data/lib/google/api_client/discovery/api.rb +310 -0
  25. data/lib/google/api_client/discovery/media.rb +77 -0
  26. data/lib/google/api_client/discovery/method.rb +363 -0
  27. data/lib/google/api_client/discovery/resource.rb +156 -0
  28. data/lib/google/api_client/discovery/schema.rb +117 -0
  29. data/lib/google/api_client/environment.rb +42 -0
  30. data/lib/google/api_client/errors.rb +65 -0
  31. data/lib/google/api_client/gzip.rb +28 -0
  32. data/lib/google/api_client/logging.rb +32 -0
  33. data/lib/google/api_client/media.rb +259 -0
  34. data/lib/google/api_client/railtie.rb +18 -0
  35. data/lib/google/api_client/reference.rb +27 -0
  36. data/lib/google/api_client/request.rb +350 -0
  37. data/lib/google/api_client/result.rb +255 -0
  38. data/lib/google/api_client/service.rb +233 -0
  39. data/lib/google/api_client/service/batch.rb +110 -0
  40. data/lib/google/api_client/service/request.rb +144 -0
  41. data/lib/google/api_client/service/resource.rb +40 -0
  42. data/lib/google/api_client/service/result.rb +162 -0
  43. data/lib/google/api_client/service/simple_file_store.rb +151 -0
  44. data/lib/google/api_client/service/stub_generator.rb +61 -0
  45. data/lib/google/api_client/service_account.rb +21 -0
  46. data/lib/google/api_client/version.rb +26 -0
  47. data/spec/google/api_client/auth/storage_spec.rb +122 -0
  48. data/spec/google/api_client/auth/storages/file_store_spec.rb +40 -0
  49. data/spec/google/api_client/auth/storages/redis_store_spec.rb +70 -0
  50. data/spec/google/api_client/batch_spec.rb +248 -0
  51. data/spec/google/api_client/client_secrets_spec.rb +53 -0
  52. data/spec/google/api_client/discovery_spec.rb +708 -0
  53. data/spec/google/api_client/gzip_spec.rb +98 -0
  54. data/spec/google/api_client/media_spec.rb +178 -0
  55. data/spec/google/api_client/request_spec.rb +29 -0
  56. data/spec/google/api_client/result_spec.rb +207 -0
  57. data/spec/google/api_client/service_account_spec.rb +169 -0
  58. data/spec/google/api_client/service_spec.rb +618 -0
  59. data/spec/google/api_client/simple_file_store_spec.rb +133 -0
  60. data/spec/google/api_client_spec.rb +352 -0
  61. data/spec/spec_helper.rb +66 -0
  62. metadata +339 -0
@@ -0,0 +1,117 @@
1
+ # Copyright 2010 Google Inc.
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 'time'
17
+ require 'multi_json'
18
+ require 'compat/multi_json'
19
+ require 'base64'
20
+ require 'autoparse'
21
+ require 'addressable/uri'
22
+ require 'addressable/template'
23
+
24
+ require 'active_support/inflector'
25
+ require 'google/api_client/errors'
26
+
27
+
28
+ module Google
29
+ class APIClient
30
+ ##
31
+ # @api private
32
+ module Schema
33
+ def self.parse(api, schema_data)
34
+ # This method is super-long, but hard to break up due to the
35
+ # unavoidable dependence on closures and execution context.
36
+ schema_name = schema_data['id']
37
+
38
+ # Due to an oversight, schema IDs may not be URI references.
39
+ # TODO(bobaman): Remove this code once this has been resolved.
40
+ schema_uri = (
41
+ api.document_base +
42
+ (schema_name[0..0] != '#' ? '#' + schema_name : schema_name)
43
+ )
44
+
45
+ # Due to an oversight, schema IDs may not be URI references.
46
+ # TODO(bobaman): Remove this whole lambda once this has been resolved.
47
+ reformat_references = lambda do |data|
48
+ # This code is not particularly efficient due to recursive traversal
49
+ # and excess object creation, but this hopefully shouldn't be an
50
+ # issue since it should only be called only once per schema per
51
+ # process.
52
+ if data.kind_of?(Hash) &&
53
+ data['$ref'] && !data['$ref'].kind_of?(Hash)
54
+ if data['$ref'].respond_to?(:to_str)
55
+ reference = data['$ref'].to_str
56
+ else
57
+ raise TypeError, "Expected String, got #{data['$ref'].class}"
58
+ end
59
+ reference = '#' + reference if reference[0..0] != '#'
60
+ data.merge({
61
+ '$ref' => reference
62
+ })
63
+ elsif data.kind_of?(Hash)
64
+ data.inject({}) do |accu, (key, value)|
65
+ if value.kind_of?(Hash)
66
+ accu[key] = reformat_references.call(value)
67
+ else
68
+ accu[key] = value
69
+ end
70
+ accu
71
+ end
72
+ else
73
+ data
74
+ end
75
+ end
76
+ schema_data = reformat_references.call(schema_data)
77
+
78
+ if schema_name
79
+ api_name_string = ActiveSupport::Inflector.camelize(api.name)
80
+ api_version_string = ActiveSupport::Inflector.camelize(api.version).gsub('.', '_')
81
+ # This is for compatibility with Ruby 1.8.7.
82
+ # TODO(bobaman) Remove this when we eventually stop supporting 1.8.7.
83
+ args = []
84
+ args << false if Class.method(:const_defined?).arity != 1
85
+ if Google::APIClient::Schema.const_defined?(api_name_string, *args)
86
+ api_name = Google::APIClient::Schema.const_get(
87
+ api_name_string, *args
88
+ )
89
+ else
90
+ api_name = Google::APIClient::Schema.const_set(
91
+ api_name_string, Module.new
92
+ )
93
+ end
94
+ if api_name.const_defined?(api_version_string, *args)
95
+ api_version = api_name.const_get(api_version_string, *args)
96
+ else
97
+ api_version = api_name.const_set(api_version_string, Module.new)
98
+ end
99
+ if api_version.const_defined?(schema_name, *args)
100
+ schema_class = api_version.const_get(schema_name, *args)
101
+ end
102
+ end
103
+
104
+ # It's possible the schema has already been defined. If so, don't
105
+ # redefine it. This means that reloading a schema which has already
106
+ # been loaded into memory is not possible.
107
+ unless schema_class
108
+ schema_class = AutoParse.generate(schema_data, :uri => schema_uri)
109
+ if schema_name
110
+ api_version.const_set(schema_name, schema_class)
111
+ end
112
+ end
113
+ return schema_class
114
+ end
115
+ end
116
+ end
117
+ end
@@ -0,0 +1,42 @@
1
+ # Copyright 2010 Google Inc.
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
+ module Google
17
+ class APIClient
18
+ module ENV
19
+ OS_VERSION = begin
20
+ if RUBY_PLATFORM =~ /mswin|win32|mingw|bccwin|cygwin/
21
+ # TODO(bobaman)
22
+ # Confirm that all of these Windows environments actually have access
23
+ # to the `ver` command.
24
+ `ver`.sub(/\s*\[Version\s*/, '/').sub(']', '').strip
25
+ elsif RUBY_PLATFORM =~ /darwin/i
26
+ "Mac OS X/#{`sw_vers -productVersion`}"
27
+ elsif RUBY_PLATFORM == 'java'
28
+ # Get the information from java system properties to avoid spawning a
29
+ # sub-process, which is not friendly in some contexts (web servers).
30
+ require 'java'
31
+ name = java.lang.System.getProperty('os.name')
32
+ version = java.lang.System.getProperty('os.version')
33
+ "#{name}/#{version}"
34
+ else
35
+ `uname -sr`.sub(' ', '/')
36
+ end
37
+ rescue Exception
38
+ RUBY_PLATFORM
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,65 @@
1
+ # Copyright 2010 Google Inc.
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
+ module Google
17
+ class APIClient
18
+ ##
19
+ # An error which is raised when there is an unexpected response or other
20
+ # transport error that prevents an operation from succeeding.
21
+ class TransmissionError < StandardError
22
+ attr_reader :result
23
+ def initialize(message = nil, result = nil)
24
+ super(message)
25
+ @result = result
26
+ end
27
+ end
28
+
29
+ ##
30
+ # An exception that is raised if a redirect is required
31
+ #
32
+ class RedirectError < TransmissionError
33
+ end
34
+
35
+ ##
36
+ # An exception that is raised if a method is called with missing or
37
+ # invalid parameter values.
38
+ class ValidationError < StandardError
39
+ end
40
+
41
+ ##
42
+ # A 4xx class HTTP error occurred.
43
+ class ClientError < TransmissionError
44
+ end
45
+
46
+ ##
47
+ # A 401 HTTP error occurred.
48
+ class AuthorizationError < ClientError
49
+ end
50
+
51
+ ##
52
+ # A 5xx class HTTP error occurred.
53
+ class ServerError < TransmissionError
54
+ end
55
+
56
+ ##
57
+ # An exception that is raised if an ID token could not be validated.
58
+ class InvalidIDTokenError < StandardError
59
+ end
60
+
61
+ # Error class for problems in batch requests.
62
+ class BatchError < StandardError
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,28 @@
1
+ require 'faraday'
2
+ require 'zlib'
3
+
4
+ module Google
5
+ class APIClient
6
+ class Gzip < Faraday::Response::Middleware
7
+ include Google::APIClient::Logging
8
+
9
+ def on_complete(env)
10
+ encoding = env[:response_headers]['content-encoding'].to_s.downcase
11
+ case encoding
12
+ when 'gzip'
13
+ logger.debug { "Decompressing gzip encoded response (#{env[:body].length} bytes)" }
14
+ env[:body] = Zlib::GzipReader.new(StringIO.new(env[:body])).read
15
+ env[:response_headers].delete('content-encoding')
16
+ logger.debug { "Decompressed (#{env[:body].length} bytes)" }
17
+ when 'deflate'
18
+ logger.debug{ "Decompressing deflate encoded response (#{env[:body].length} bytes)" }
19
+ env[:body] = Zlib::Inflate.inflate(env[:body])
20
+ env[:response_headers].delete('content-encoding')
21
+ logger.debug { "Decompressed (#{env[:body].length} bytes)" }
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
27
+
28
+ Faraday::Response.register_middleware :gzip => Google::APIClient::Gzip
@@ -0,0 +1,32 @@
1
+ require 'logger'
2
+
3
+ module Google
4
+ class APIClient
5
+
6
+ class << self
7
+ ##
8
+ # Logger for the API client
9
+ #
10
+ # @return [Logger] logger instance.
11
+ attr_accessor :logger
12
+ end
13
+
14
+ self.logger = Logger.new(STDOUT)
15
+ self.logger.level = Logger::WARN
16
+
17
+ ##
18
+ # Module to make accessing the logger simpler
19
+ module Logging
20
+ ##
21
+ # Logger for the API client
22
+ #
23
+ # @return [Logger] logger instance.
24
+ def logger
25
+ Google::APIClient.logger
26
+ end
27
+ end
28
+
29
+ end
30
+
31
+
32
+ end
@@ -0,0 +1,259 @@
1
+ # Copyright 2010 Google Inc.
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
+ require 'google/api_client/reference'
15
+
16
+ module Google
17
+ class APIClient
18
+ ##
19
+ # Uploadable media support. Holds an IO stream & content type.
20
+ #
21
+ # @see Faraday::UploadIO
22
+ # @example
23
+ # media = Google::APIClient::UploadIO.new('mymovie.m4v', 'video/mp4')
24
+ class UploadIO < Faraday::UploadIO
25
+
26
+ # @return [Fixnum] Size of chunks to upload. Default is nil, meaning upload the entire file in a single request
27
+ attr_accessor :chunk_size
28
+
29
+ ##
30
+ # Get the length of the stream
31
+ #
32
+ # @return [Fixnum]
33
+ # Length of stream, in bytes
34
+ def length
35
+ io.respond_to?(:length) ? io.length : File.size(local_path)
36
+ end
37
+ end
38
+
39
+ ##
40
+ # Wraps an input stream and limits data to a given range
41
+ #
42
+ # @example
43
+ # chunk = Google::APIClient::RangedIO.new(io, 0, 1000)
44
+ class RangedIO
45
+ ##
46
+ # Bind an input stream to a specific range.
47
+ #
48
+ # @param [IO] io
49
+ # Source input stream
50
+ # @param [Fixnum] offset
51
+ # Starting offset of the range
52
+ # @param [Fixnum] length
53
+ # Length of range
54
+ def initialize(io, offset, length)
55
+ @io = io
56
+ @offset = offset
57
+ @length = length
58
+ self.rewind
59
+ end
60
+
61
+ ##
62
+ # @see IO#read
63
+ def read(amount = nil, buf = nil)
64
+ buffer = buf || ''
65
+ if amount.nil?
66
+ size = @length - @pos
67
+ done = ''
68
+ elsif amount == 0
69
+ size = 0
70
+ done = ''
71
+ else
72
+ size = [@length - @pos, amount].min
73
+ done = nil
74
+ end
75
+
76
+ if size > 0
77
+ result = @io.read(size)
78
+ result.force_encoding("BINARY") if result.respond_to?(:force_encoding)
79
+ buffer << result if result
80
+ @pos = @pos + size
81
+ end
82
+
83
+ if buffer.length > 0
84
+ buffer
85
+ else
86
+ done
87
+ end
88
+ end
89
+
90
+ ##
91
+ # @see IO#rewind
92
+ def rewind
93
+ self.pos = 0
94
+ end
95
+
96
+ ##
97
+ # @see IO#pos
98
+ def pos
99
+ @pos
100
+ end
101
+
102
+ ##
103
+ # @see IO#pos=
104
+ def pos=(pos)
105
+ @pos = pos
106
+ @io.pos = @offset + pos
107
+ end
108
+ end
109
+
110
+ ##
111
+ # Resumable uploader.
112
+ #
113
+ class ResumableUpload < Request
114
+ # @return [Fixnum] Max bytes to send in a single request
115
+ attr_accessor :chunk_size
116
+
117
+ ##
118
+ # Creates a new uploader.
119
+ #
120
+ # @param [Hash] options
121
+ # Request options
122
+ def initialize(options={})
123
+ super options
124
+ self.uri = options[:uri]
125
+ self.http_method = :put
126
+ @offset = options[:offset] || 0
127
+ @complete = false
128
+ @expired = false
129
+ end
130
+
131
+ ##
132
+ # Sends all remaining chunks to the server
133
+ #
134
+ # @deprecated Pass the instance to {Google::APIClient#execute} instead
135
+ #
136
+ # @param [Google::APIClient] api_client
137
+ # API Client instance to use for sending
138
+ def send_all(api_client)
139
+ result = nil
140
+ until complete?
141
+ result = send_chunk(api_client)
142
+ break unless result.status == 308
143
+ end
144
+ return result
145
+ end
146
+
147
+
148
+ ##
149
+ # Sends the next chunk to the server
150
+ #
151
+ # @deprecated Pass the instance to {Google::APIClient#execute} instead
152
+ #
153
+ # @param [Google::APIClient] api_client
154
+ # API Client instance to use for sending
155
+ def send_chunk(api_client)
156
+ return api_client.execute(self)
157
+ end
158
+
159
+ ##
160
+ # Check if upload is complete
161
+ #
162
+ # @return [TrueClass, FalseClass]
163
+ # Whether or not the upload complete successfully
164
+ def complete?
165
+ return @complete
166
+ end
167
+
168
+ ##
169
+ # Check if the upload URL expired (upload not completed in alotted time.)
170
+ # Expired uploads must be restarted from the beginning
171
+ #
172
+ # @return [TrueClass, FalseClass]
173
+ # Whether or not the upload has expired and can not be resumed
174
+ def expired?
175
+ return @expired
176
+ end
177
+
178
+ ##
179
+ # Check if upload is resumable. That is, neither complete nor expired
180
+ #
181
+ # @return [TrueClass, FalseClass] True if upload can be resumed
182
+ def resumable?
183
+ return !(self.complete? or self.expired?)
184
+ end
185
+
186
+ ##
187
+ # Convert to an HTTP request. Returns components in order of method, URI,
188
+ # request headers, and body
189
+ #
190
+ # @api private
191
+ #
192
+ # @return [Array<(Symbol, Addressable::URI, Hash, [#read,#to_str])>]
193
+ def to_http_request
194
+ if @complete
195
+ raise Google::APIClient::ClientError, "Upload already complete"
196
+ elsif @offset.nil?
197
+ self.headers.update({
198
+ 'Content-Length' => "0",
199
+ 'Content-Range' => "bytes */#{media.length}" })
200
+ else
201
+ start_offset = @offset
202
+ remaining = self.media.length - start_offset
203
+ chunk_size = self.media.chunk_size || self.chunk_size || self.media.length
204
+ content_length = [remaining, chunk_size].min
205
+ chunk = RangedIO.new(self.media.io, start_offset, content_length)
206
+ end_offset = start_offset + content_length - 1
207
+ self.headers.update({
208
+ 'Content-Length' => "#{content_length}",
209
+ 'Content-Type' => self.media.content_type,
210
+ 'Content-Range' => "bytes #{start_offset}-#{end_offset}/#{media.length}" })
211
+ self.body = chunk
212
+ end
213
+ super
214
+ end
215
+
216
+ ##
217
+ # Check the result from the server, updating the offset and/or location
218
+ # if available.
219
+ #
220
+ # @api private
221
+ #
222
+ # @param [Faraday::Response] response
223
+ # HTTP response
224
+ #
225
+ # @return [Google::APIClient::Result]
226
+ # Processed API response
227
+ def process_http_response(response)
228
+ case response.status
229
+ when 200...299
230
+ @complete = true
231
+ when 308
232
+ range = response.headers['range']
233
+ if range
234
+ @offset = range.scan(/\d+/).collect{|x| Integer(x)}.last + 1
235
+ end
236
+ if response.headers['location']
237
+ self.uri = response.headers['location']
238
+ end
239
+ when 400...499
240
+ @expired = true
241
+ when 500...599
242
+ # Invalidate the offset to mark it needs to be queried on the
243
+ # next request
244
+ @offset = nil
245
+ end
246
+ return Google::APIClient::Result.new(self, response)
247
+ end
248
+
249
+ ##
250
+ # Hashified verison of the API request
251
+ #
252
+ # @return [Hash]
253
+ def to_hash
254
+ super.merge(:offset => @offset)
255
+ end
256
+
257
+ end
258
+ end
259
+ end