ghost_google-api-client 0.4.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 (40) hide show
  1. data/CHANGELOG.md +77 -0
  2. data/Gemfile +30 -0
  3. data/Gemfile.lock +80 -0
  4. data/LICENSE +202 -0
  5. data/README.md +71 -0
  6. data/Rakefile +42 -0
  7. data/bin/google-api +545 -0
  8. data/lib/compat/multi_json.rb +17 -0
  9. data/lib/google/api_client.rb +802 -0
  10. data/lib/google/api_client/batch.rb +296 -0
  11. data/lib/google/api_client/client_secrets.rb +106 -0
  12. data/lib/google/api_client/discovery.rb +19 -0
  13. data/lib/google/api_client/discovery/api.rb +287 -0
  14. data/lib/google/api_client/discovery/media.rb +77 -0
  15. data/lib/google/api_client/discovery/method.rb +369 -0
  16. data/lib/google/api_client/discovery/resource.rb +150 -0
  17. data/lib/google/api_client/discovery/schema.rb +119 -0
  18. data/lib/google/api_client/environment.rb +42 -0
  19. data/lib/google/api_client/errors.rb +49 -0
  20. data/lib/google/api_client/media.rb +172 -0
  21. data/lib/google/api_client/reference.rb +305 -0
  22. data/lib/google/api_client/result.rb +161 -0
  23. data/lib/google/api_client/service_account.rb +134 -0
  24. data/lib/google/api_client/version.rb +31 -0
  25. data/lib/google/inflection.rb +28 -0
  26. data/spec/fixtures/files/sample.txt +33 -0
  27. data/spec/google/api_client/batch_spec.rb +241 -0
  28. data/spec/google/api_client/discovery_spec.rb +670 -0
  29. data/spec/google/api_client/media_spec.rb +143 -0
  30. data/spec/google/api_client/result_spec.rb +185 -0
  31. data/spec/google/api_client/service_account_spec.rb +58 -0
  32. data/spec/google/api_client_spec.rb +139 -0
  33. data/spec/spec_helper.rb +7 -0
  34. data/tasks/gem.rake +97 -0
  35. data/tasks/git.rake +45 -0
  36. data/tasks/metrics.rake +22 -0
  37. data/tasks/spec.rake +57 -0
  38. data/tasks/wiki.rake +82 -0
  39. data/tasks/yard.rake +29 -0
  40. metadata +253 -0
@@ -0,0 +1,42 @@
1
+ lib_dir = File.expand_path('../lib', __FILE__)
2
+ $LOAD_PATH.unshift(lib_dir)
3
+ $LOAD_PATH.uniq!
4
+
5
+ require 'rubygems'
6
+ require 'rake'
7
+
8
+ require File.join(File.dirname(__FILE__), 'lib/google/api_client', 'version')
9
+
10
+ PKG_DISPLAY_NAME = 'Google API Client'
11
+ PKG_NAME = PKG_DISPLAY_NAME.downcase.gsub(/\s/, '-')
12
+ PKG_VERSION = Google::APIClient::VERSION::STRING
13
+ PKG_FILE_NAME = "#{PKG_NAME}-#{PKG_VERSION}"
14
+ PKG_HOMEPAGE = 'http://code.google.com/p/google-api-ruby-client/'
15
+
16
+ RELEASE_NAME = "REL #{PKG_VERSION}"
17
+
18
+ PKG_AUTHOR = "Bob Aman"
19
+ PKG_AUTHOR_EMAIL = "bobaman@google.com"
20
+ PKG_SUMMARY = 'Package Summary'
21
+ PKG_DESCRIPTION = <<-TEXT
22
+ The Google API Ruby Client makes it trivial to discover and access supported
23
+ APIs.
24
+ TEXT
25
+
26
+ PKG_FILES = FileList[
27
+ 'lib/**/*', 'spec/**/*', 'vendor/**/*',
28
+ 'tasks/**/*', 'website/**/*',
29
+ '[A-Z]*', 'Rakefile'
30
+ ].exclude(/database\.yml/).exclude(/[_\.]git$/)
31
+
32
+ RCOV_ENABLED = !!(RUBY_PLATFORM != 'java' && RUBY_VERSION =~ /^1\.8/)
33
+ if RCOV_ENABLED
34
+ task :default => 'spec:rcov'
35
+ else
36
+ task :default => 'spec'
37
+ end
38
+
39
+ WINDOWS = (RUBY_PLATFORM =~ /mswin|win32|mingw|bccwin|cygwin/) rescue false
40
+ SUDO = WINDOWS ? '' : ('sudo' unless ENV['SUDOLESS'])
41
+
42
+ Dir['tasks/**/*.rake'].each { |rake| load rake }
@@ -0,0 +1,545 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ bin_dir = File.expand_path("..", __FILE__)
4
+ lib_dir = File.expand_path("../lib", bin_dir)
5
+
6
+ $LOAD_PATH.unshift(lib_dir)
7
+ $LOAD_PATH.uniq!
8
+
9
+ OAUTH_SERVER_PORT = 12736
10
+
11
+ require 'rubygems'
12
+ require 'optparse'
13
+
14
+ gem 'faraday', '~> 0.8.1'
15
+ require 'faraday'
16
+ require 'faraday/utils'
17
+
18
+ require 'webrick'
19
+ require 'google/api_client/version'
20
+ require 'google/api_client'
21
+
22
+ ARGV.unshift('--help') if ARGV.empty?
23
+
24
+ module Google
25
+ class APIClient
26
+ class CLI
27
+ # Used for oauth login
28
+ class OAuthVerifierServlet < WEBrick::HTTPServlet::AbstractServlet
29
+ attr_reader :verifier
30
+
31
+ def do_GET(request, response)
32
+ $verifier ||= Addressable::URI.unencode_component(
33
+ request.request_uri.to_s[/\?.*oauth_verifier=([^&$]+)(&|$)/, 1] ||
34
+ request.request_uri.to_s[/\?.*code=([^&$]+)(&|$)/, 1]
35
+ )
36
+ response.status = WEBrick::HTTPStatus::RC_ACCEPTED
37
+ # This javascript will auto-close the tab after the
38
+ # verifier is obtained.
39
+ response.body = <<-HTML
40
+ <html>
41
+ <head>
42
+ <script>
43
+ function closeWindow() {
44
+ window.open('', '_self', '');
45
+ window.close();
46
+ }
47
+ setTimeout(closeWindow, 10);
48
+ </script>
49
+ </head>
50
+ <body>
51
+ You may close this window.
52
+ </body>
53
+ </html>
54
+ HTML
55
+ # Eww, hack!
56
+ server = self.instance_variable_get('@server')
57
+ server.stop if server
58
+ end
59
+ end
60
+
61
+ # Initialize with default parameter values
62
+ def initialize(argv)
63
+ @options = {
64
+ :command => 'execute',
65
+ :rpcname => nil,
66
+ :verbose => false
67
+ }
68
+ @argv = argv.clone
69
+ if @argv.first =~ /^[a-z0-9][a-z0-9_-]*$/i
70
+ self.options[:command] = @argv.shift
71
+ end
72
+ if @argv.first =~ /^[a-z0-9_-]+\.[a-z0-9_\.-]+$/i
73
+ self.options[:rpcname] = @argv.shift
74
+ end
75
+ end
76
+
77
+ attr_reader :options
78
+ attr_reader :argv
79
+
80
+ def command
81
+ return self.options[:command]
82
+ end
83
+
84
+ def rpcname
85
+ return self.options[:rpcname]
86
+ end
87
+
88
+ def parser
89
+ @parser ||= OptionParser.new do |opts|
90
+ opts.banner = "Usage: google-api " +
91
+ "(execute <rpcname> | [command]) [options] [-- <parameters>]"
92
+
93
+ opts.separator "\nAvailable options:"
94
+
95
+ opts.on(
96
+ "--scope <scope>", String, "Set the OAuth scope") do |s|
97
+ options[:scope] = s
98
+ end
99
+ opts.on(
100
+ "--client-id <key>", String,
101
+ "Set the OAuth client id or key") do |k|
102
+ options[:client_credential_key] = k
103
+ end
104
+ opts.on(
105
+ "--client-secret <secret>", String,
106
+ "Set the OAuth client secret") do |s|
107
+ options[:client_credential_secret] = s
108
+ end
109
+ opts.on(
110
+ "--api <name>", String,
111
+ "Perform discovery on API") do |s|
112
+ options[:api] = s
113
+ end
114
+ opts.on(
115
+ "--api-version <id>", String,
116
+ "Select api version") do |id|
117
+ options[:version] = id
118
+ end
119
+ opts.on(
120
+ "--content-type <format>", String,
121
+ "Content-Type for request") do |f|
122
+ # Resolve content type shortcuts
123
+ case f
124
+ when 'json'
125
+ f = 'application/json'
126
+ when 'xml'
127
+ f = 'application/xml'
128
+ when 'atom'
129
+ f = 'application/atom+xml'
130
+ when 'rss'
131
+ f = 'application/rss+xml'
132
+ end
133
+ options[:content_type] = f
134
+ end
135
+ opts.on(
136
+ "-u", "--uri <uri>", String,
137
+ "Sets the URI to perform a request against") do |u|
138
+ options[:uri] = u
139
+ end
140
+ opts.on(
141
+ "--discovery-uri <uri>", String,
142
+ "Sets the URI to perform discovery") do |u|
143
+ options[:discovery_uri] = u
144
+ end
145
+ opts.on(
146
+ "-m", "--method <method>", String,
147
+ "Sets the HTTP method to use for the request") do |m|
148
+ options[:http_method] = m
149
+ end
150
+ opts.on(
151
+ "--requestor-id <email>", String,
152
+ "Sets the email address of the requestor") do |e|
153
+ options[:requestor_id] = e
154
+ end
155
+
156
+ opts.on("-v", "--verbose", "Run verbosely") do |v|
157
+ options[:verbose] = v
158
+ end
159
+ opts.on("-h", "--help", "Show this message") do
160
+ puts opts
161
+ exit
162
+ end
163
+ opts.on("--version", "Show version") do
164
+ puts "google-api-client (#{Google::APIClient::VERSION::STRING})"
165
+ exit
166
+ end
167
+
168
+ opts.separator(
169
+ "\nAvailable commands:\n" +
170
+ " oauth-1-login Log a user into an API with OAuth 1.0a\n" +
171
+ " oauth-2-login Log a user into an API with OAuth 2.0 d10\n" +
172
+ " list List the methods available for an API\n" +
173
+ " execute Execute a method on the API\n" +
174
+ " irb Start an interactive client session"
175
+ )
176
+ end
177
+ end
178
+
179
+ def parse!
180
+ self.parser.parse!(self.argv)
181
+ symbol = self.command.gsub(/-/, "_").to_sym
182
+ if !COMMANDS.include?(symbol)
183
+ STDERR.puts("Invalid command: #{self.command}")
184
+ exit(1)
185
+ end
186
+ self.send(symbol)
187
+ end
188
+
189
+ def client
190
+ gem 'signet', '~> 0.4.0'
191
+ require 'signet/oauth_1/client'
192
+ require 'yaml'
193
+ require 'irb'
194
+ config_file = File.expand_path('~/.google-api.yaml')
195
+ authorization = nil
196
+ if File.exist?(config_file)
197
+ config = open(config_file, 'r') { |file| YAML.load(file.read) }
198
+ else
199
+ config = {}
200
+ end
201
+ if config["mechanism"]
202
+ authorization = config["mechanism"].to_sym
203
+ end
204
+
205
+ client = Google::APIClient.new(:authorization => authorization)
206
+
207
+ case authorization
208
+ when :oauth_1
209
+ if client.authorization &&
210
+ !client.authorization.kind_of?(Signet::OAuth1::Client)
211
+ STDERR.puts(
212
+ "Unexpected authorization mechanism: " +
213
+ "#{client.authorization.class}"
214
+ )
215
+ exit(1)
216
+ end
217
+ config = open(config_file, 'r') { |file| YAML.load(file.read) }
218
+ client.authorization.client_credential_key =
219
+ config["client_credential_key"]
220
+ client.authorization.client_credential_secret =
221
+ config["client_credential_secret"]
222
+ client.authorization.token_credential_key =
223
+ config["token_credential_key"]
224
+ client.authorization.token_credential_secret =
225
+ config["token_credential_secret"]
226
+ when :oauth_2
227
+ if client.authorization &&
228
+ !client.authorization.kind_of?(Signet::OAuth2::Client)
229
+ STDERR.puts(
230
+ "Unexpected authorization mechanism: " +
231
+ "#{client.authorization.class}"
232
+ )
233
+ exit(1)
234
+ end
235
+ config = open(config_file, 'r') { |file| YAML.load(file.read) }
236
+ client.authorization.scope = options[:scope]
237
+ client.authorization.client_id = config["client_id"]
238
+ client.authorization.client_secret = config["client_secret"]
239
+ client.authorization.access_token = config["access_token"]
240
+ client.authorization.refresh_token = config["refresh_token"]
241
+ else
242
+ # Dunno?
243
+ end
244
+
245
+ if options[:discovery_uri]
246
+ if options[:api] && options[:version]
247
+ client.register_discovery_uri(
248
+ options[:api], options[:version], options[:discovery_uri]
249
+ )
250
+ else
251
+ STDERR.puts(
252
+ 'Cannot register a discovery URI without ' +
253
+ 'specifying an API and version.'
254
+ )
255
+ exit(1)
256
+ end
257
+ end
258
+
259
+ return client
260
+ end
261
+
262
+ def api_version(api_name, version)
263
+ v = version
264
+ if !version
265
+ if client.preferred_version(api_name)
266
+ v = client.preferred_version(api_name).version
267
+ else
268
+ v = 'v1'
269
+ end
270
+ end
271
+ return v
272
+ end
273
+
274
+ COMMANDS = [
275
+ :oauth_1_login,
276
+ :oauth_2_login,
277
+ :list,
278
+ :execute,
279
+ :irb,
280
+ :fuzz
281
+ ]
282
+
283
+ def oauth_1_login
284
+ gem 'signet', '~> 0.4.0'
285
+ require 'signet/oauth_1/client'
286
+ require 'launchy'
287
+ require 'yaml'
288
+ if options[:client_credential_key] &&
289
+ options[:client_credential_secret]
290
+ config = {
291
+ "mechanism" => "oauth_1",
292
+ "scope" => options[:scope],
293
+ "client_credential_key" => options[:client_credential_key],
294
+ "client_credential_secret" => options[:client_credential_secret],
295
+ "token_credential_key" => nil,
296
+ "token_credential_secret" => nil
297
+ }
298
+ config_file = File.expand_path('~/.google-api.yaml')
299
+ open(config_file, 'w') { |file| file.write(YAML.dump(config)) }
300
+ exit(0)
301
+ else
302
+ $verifier = nil
303
+ server = WEBrick::HTTPServer.new(
304
+ :Port => OAUTH_SERVER_PORT,
305
+ :Logger => WEBrick::Log.new,
306
+ :AccessLog => WEBrick::Log.new
307
+ )
308
+ server.logger.level = 0
309
+ trap("INT") { server.shutdown }
310
+
311
+ server.mount("/", OAuthVerifierServlet)
312
+
313
+ oauth_client = Signet::OAuth1::Client.new(
314
+ :temporary_credential_uri =>
315
+ 'https://www.google.com/accounts/OAuthGetRequestToken',
316
+ :authorization_uri =>
317
+ 'https://www.google.com/accounts/OAuthAuthorizeToken',
318
+ :token_credential_uri =>
319
+ 'https://www.google.com/accounts/OAuthGetAccessToken',
320
+ :client_credential_key => 'anonymous',
321
+ :client_credential_secret => 'anonymous',
322
+ :callback => "http://localhost:#{OAUTH_SERVER_PORT}/"
323
+ )
324
+ oauth_client.fetch_temporary_credential!(:additional_parameters => {
325
+ :scope => options[:scope],
326
+ :xoauth_displayname => 'Google API Client'
327
+ })
328
+
329
+ # Launch browser
330
+ Launchy::Browser.run(oauth_client.authorization_uri.to_s)
331
+
332
+ server.start
333
+ oauth_client.fetch_token_credential!(:verifier => $verifier)
334
+ config = {
335
+ "scope" => options[:scope],
336
+ "client_credential_key" =>
337
+ oauth_client.client_credential_key,
338
+ "client_credential_secret" =>
339
+ oauth_client.client_credential_secret,
340
+ "token_credential_key" =>
341
+ oauth_client.token_credential_key,
342
+ "token_credential_secret" =>
343
+ oauth_client.token_credential_secret
344
+ }
345
+ config_file = File.expand_path('~/.google-api.yaml')
346
+ open(config_file, 'w') { |file| file.write(YAML.dump(config)) }
347
+ exit(0)
348
+ end
349
+ end
350
+
351
+ def oauth_2_login
352
+ gem 'signet', '~> 0.4.0'
353
+ require 'signet/oauth_2/client'
354
+ require 'launchy'
355
+ require 'yaml'
356
+ if !options[:client_credential_key] ||
357
+ !options[:client_credential_secret]
358
+ STDERR.puts('No client ID and secret supplied.')
359
+ exit(1)
360
+ end
361
+ if options[:access_token]
362
+ config = {
363
+ "mechanism" => "oauth_2",
364
+ "scope" => options[:scope],
365
+ "client_id" => options[:client_credential_key],
366
+ "client_secret" => options[:client_credential_secret],
367
+ "access_token" => options[:access_token],
368
+ "refresh_token" => options[:refresh_token]
369
+ }
370
+ config_file = File.expand_path('~/.google-api.yaml')
371
+ open(config_file, 'w') { |file| file.write(YAML.dump(config)) }
372
+ exit(0)
373
+ else
374
+ $verifier = nil
375
+ logger = WEBrick::Log.new
376
+ logger.level = 0
377
+ server = WEBrick::HTTPServer.new(
378
+ :Port => OAUTH_SERVER_PORT,
379
+ :Logger => logger,
380
+ :AccessLog => logger
381
+ )
382
+ trap("INT") { server.shutdown }
383
+
384
+ server.mount("/", OAuthVerifierServlet)
385
+
386
+ oauth_client = Signet::OAuth2::Client.new(
387
+ :authorization_uri =>
388
+ 'https://www.google.com/accounts/o8/oauth2/authorization',
389
+ :token_credential_uri =>
390
+ 'https://www.google.com/accounts/o8/oauth2/token',
391
+ :client_id => options[:client_credential_key],
392
+ :client_secret => options[:client_credential_secret],
393
+ :redirect_uri => "http://localhost:#{OAUTH_SERVER_PORT}/",
394
+ :scope => options[:scope]
395
+ )
396
+
397
+ # Launch browser
398
+ Launchy.open(oauth_client.authorization_uri.to_s)
399
+
400
+ server.start
401
+ oauth_client.code = $verifier
402
+ oauth_client.fetch_access_token!
403
+ config = {
404
+ "mechanism" => "oauth_2",
405
+ "scope" => options[:scope],
406
+ "client_id" => oauth_client.client_id,
407
+ "client_secret" => oauth_client.client_secret,
408
+ "access_token" => oauth_client.access_token,
409
+ "refresh_token" => oauth_client.refresh_token
410
+ }
411
+ config_file = File.expand_path('~/.google-api.yaml')
412
+ open(config_file, 'w') { |file| file.write(YAML.dump(config)) }
413
+ exit(0)
414
+ end
415
+ end
416
+
417
+ def list
418
+ api_name = options[:api]
419
+ unless api_name
420
+ STDERR.puts('No API name supplied.')
421
+ exit(1)
422
+ end
423
+ client = Google::APIClient.new(:authorization => nil)
424
+ if options[:discovery_uri]
425
+ if options[:api] && options[:version]
426
+ client.register_discovery_uri(
427
+ options[:api], options[:version], options[:discovery_uri]
428
+ )
429
+ else
430
+ STDERR.puts(
431
+ 'Cannot register a discovery URI without ' +
432
+ 'specifying an API and version.'
433
+ )
434
+ exit(1)
435
+ end
436
+ end
437
+ version = api_version(api_name, options[:version])
438
+ api = client.discovered_api(api_name, version)
439
+ rpcnames = api.to_h.keys
440
+ puts rpcnames.sort.join("\n")
441
+ exit(0)
442
+ end
443
+
444
+ def execute
445
+ client = self.client
446
+
447
+ # Setup HTTP request data
448
+ request_body = ''
449
+ input_streams, _, _ = IO.select([STDIN], [], [], 0)
450
+ request_body = STDIN.read || '' if input_streams
451
+ headers = []
452
+ if options[:content_type]
453
+ headers << ['Content-Type', options[:content_type]]
454
+ elsif request_body
455
+ # Default to JSON
456
+ headers << ['Content-Type', 'application/json']
457
+ end
458
+
459
+ if options[:uri]
460
+ # Make request with URI manually specified
461
+ uri = Addressable::URI.parse(options[:uri])
462
+ if uri.relative?
463
+ STDERR.puts('URI may not be relative.')
464
+ exit(1)
465
+ end
466
+ if options[:requestor_id]
467
+ uri.query_values = uri.query_values.merge(
468
+ 'xoauth_requestor_id' => options[:requestor_id]
469
+ )
470
+ end
471
+ method = options[:http_method]
472
+ method ||= request_body == '' ? 'GET' : 'POST'
473
+ method.upcase!
474
+ request = [method, uri.to_str, headers, [request_body]]
475
+ request = client.generate_authenticated_request(:request => request)
476
+ response = client.transmit(request)
477
+ puts response.body
478
+ exit(0)
479
+ else
480
+ # Make request with URI generated from template and parameters
481
+ if !self.rpcname
482
+ STDERR.puts('No rpcname supplied.')
483
+ exit(1)
484
+ end
485
+ api_name = options[:api] || self.rpcname[/^([^\.]+)\./, 1]
486
+ version = api_version(api_name, options[:version])
487
+ api = client.discovered_api(api_name, version)
488
+ method = api.to_h[self.rpcname]
489
+ if !method
490
+ STDERR.puts(
491
+ "Method #{self.rpcname} does not exist for " +
492
+ "#{api_name}-#{version}."
493
+ )
494
+ exit(1)
495
+ end
496
+ parameters = self.argv.inject({}) do |accu, pair|
497
+ name, value = pair.split('=', 2)
498
+ accu[name] = value
499
+ accu
500
+ end
501
+ if options[:requestor_id]
502
+ parameters['xoauth_requestor_id'] = options[:requestor_id]
503
+ end
504
+ begin
505
+ result = client.execute(
506
+ :api_method => method,
507
+ :parameters => parameters,
508
+ :merged_body => request_body,
509
+ :headers => headers
510
+ )
511
+ puts result.response.body
512
+ exit(0)
513
+ rescue ArgumentError => e
514
+ puts e.message
515
+ exit(1)
516
+ end
517
+ end
518
+ end
519
+
520
+ def irb
521
+ $client = self.client
522
+ # Otherwise IRB will misinterpret command-line options
523
+ ARGV.clear
524
+ IRB.start(__FILE__)
525
+ end
526
+
527
+ def fuzz
528
+ STDERR.puts('API fuzzing not yet supported.')
529
+ if self.rpcname
530
+ # Fuzz just one method
531
+ else
532
+ # Fuzz the entire API
533
+ end
534
+ exit(1)
535
+ end
536
+
537
+ def help
538
+ puts self.parser
539
+ exit(0)
540
+ end
541
+ end
542
+ end
543
+ end
544
+
545
+ Google::APIClient::CLI.new(ARGV).parse!