ghost_google-api-client 0.4.7.1

Sign up to get free protection for your applications and to get access to all the features.
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!