google-api-client 0.1.0 → 0.1.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.
data/CHANGELOG CHANGED
@@ -1,3 +1,7 @@
1
+ == 0.1.1
2
+
3
+ * substantial improvements to the command line interface
4
+
1
5
  == 0.1.0
2
6
 
3
7
  * initial release
data/bin/google-api CHANGED
@@ -10,96 +10,28 @@ OAUTH_SERVER_PORT = 12736
10
10
 
11
11
  require 'rubygems'
12
12
  require 'optparse'
13
+ require 'httpadapter'
14
+ require 'webrick'
13
15
  require 'google/api_client/version'
14
16
  require 'google/api_client'
15
17
 
16
18
  ARGV.unshift('--help') if ARGV.empty?
17
19
 
18
- command = 'execute'
19
- options = {}
20
- OptionParser.new do |opts|
21
- opts.banner =
22
- "Usage: google-api <rpcname> [options] -- <parameters>\n" +
23
- " or: google-api --oauth-login=<scope> [options]\n" +
24
- " or: google-api --interactive=<service> [options]\n" +
25
- " or: google-api --fuzz [options]"
20
+ module Google
21
+ class APIClient
22
+ class CLI
23
+ # Used for oauth login
24
+ class OAuthVerifierServlet < WEBrick::HTTPServlet::AbstractServlet
25
+ attr_reader :verifier
26
26
 
27
- opts.separator ""
28
-
29
- opts.on(
30
- "--oauth-login <scope>", String, "Authorize for the scope") do |s|
31
- if command != 'execute'
32
- STDERR.puts("Ambiguous command: #{command}")
33
- exit(1)
34
- end
35
- command = 'oauth-login'
36
- options[:scope] = s
37
- end
38
- opts.on(
39
- "-s", "--service <name>", String, "Perform discovery on service") do |s|
40
- options[:service_name] = s
41
- end
42
- opts.on(
43
- "-i", "--interactive <name>", String, "Start interactive session") do |s|
44
- if command != 'execute'
45
- STDERR.puts("Ambiguous command: #{command}")
46
- exit(1)
47
- end
48
- command = 'interactive'
49
- options[:service_name] = s
50
- end
51
- opts.on(
52
- "--service-version <id>", String, "Select service version") do |id|
53
- options[:service_version] = id
54
- end
55
- opts.on(
56
- "--content-type <format>", String, "Content-Type for request") do |f|
57
- # Resolve content type shortcuts
58
- case f
59
- when 'json'
60
- f = 'application/json'
61
- when 'xml'
62
- f = 'application/xml'
63
- when 'atom'
64
- f = 'application/atom+xml'
65
- when 'rss'
66
- f = 'application/rss+xml'
67
- end
68
- options[:content_type] = f
69
- end
70
- opts.on("--fuzz [rpcname]", String, "Fuzz an API or endpoint") do |rpcname|
71
- if command != 'execute'
72
- STDERR.puts("Ambiguous command: #{command}")
73
- exit(1)
74
- end
75
- command = 'fuzz'
76
- options[:fuzz] = rpcname
77
- end
78
-
79
- opts.on_tail("-v", "--verbose", "Run verbosely") do |v|
80
- options[:verbose] = v
81
- end
82
- opts.on_tail("-h", "--help", "Show this message") do
83
- puts opts
84
- exit
85
- end
86
- opts.on_tail("--version", "Show version") do
87
- puts "google-api-client (#{Google::APIClient::VERSION::STRING})"
88
- exit
89
- end
90
- end.parse!
91
-
92
- if command == 'oauth-login' # Guard to keep start-up time short
93
- require 'webrick'
94
- # Used for oauth login
95
- class OAuthVerifierServlet < WEBrick::HTTPServlet::AbstractServlet
96
- def do_GET(request, response)
97
- $verifier ||= Addressable::URI.unencode_component(
98
- request.request_uri.to_s[/\?.*oauth_verifier=([^&$]+)(&|$)/, 1]
99
- )
100
- response.status = WEBrick::HTTPStatus::RC_ACCEPTED
101
- # This javascript will auto-close the tab after the verifier is obtained.
102
- response.body = <<-HTML
27
+ def do_GET(request, response)
28
+ $verifier ||= Addressable::URI.unencode_component(
29
+ request.request_uri.to_s[/\?.*oauth_verifier=([^&$]+)(&|$)/, 1]
30
+ )
31
+ response.status = WEBrick::HTTPStatus::RC_ACCEPTED
32
+ # This javascript will auto-close the tab after the
33
+ # verifier is obtained.
34
+ response.body = <<-HTML
103
35
  <html>
104
36
  <head>
105
37
  <script>
@@ -115,181 +47,303 @@ if command == 'oauth-login' # Guard to keep start-up time short
115
47
  </body>
116
48
  </html>
117
49
  HTML
118
- self.instance_variable_get('@server').stop
119
- end
120
- end
121
- end
50
+ # Eww, hack!
51
+ server = self.instance_variable_get('@server')
52
+ server.stop if server
53
+ end
54
+ end
122
55
 
123
- def oauth_login(options={})
124
- require 'signet/oauth_1/client'
125
- require 'launchy'
126
- require 'yaml'
127
- $verifier = nil
128
- logger = WEBrick::Log.new('/dev/null') # TODO(bobaman): Cross-platform?
129
- server = WEBrick::HTTPServer.new(
130
- :Port => OAUTH_SERVER_PORT,
131
- :Logger => logger,
132
- :AccessLog => logger
133
- )
134
- trap("INT") { server.shutdown }
56
+ # Initialize with default parameter values
57
+ def initialize(argv)
58
+ @options = {
59
+ :command => 'execute',
60
+ :rpcname => nil,
61
+ :verbose => false
62
+ }
63
+ @argv = argv.clone
64
+ if @argv.first =~ /^[a-z0-9][a-z0-9_-]*$/i
65
+ self.options[:command] = @argv.shift
66
+ end
67
+ if @argv.first =~ /^[a-z0-9_-]+\.[a-z0-9_\.-]+$/i
68
+ self.options[:rpcname] = @argv.shift
69
+ end
70
+ end
135
71
 
136
- server.mount("/", OAuthVerifierServlet)
72
+ attr_reader :options
73
+ attr_reader :argv
137
74
 
138
- oauth_client = Signet::OAuth1::Client.new(
139
- :temporary_credential_uri =>
140
- 'https://www.google.com/accounts/OAuthGetRequestToken',
141
- :authorization_uri =>
142
- 'https://www.google.com/accounts/OAuthAuthorizeToken',
143
- :token_credential_uri =>
144
- 'https://www.google.com/accounts/OAuthGetAccessToken',
145
- :client_credential_key => 'anonymous',
146
- :client_credential_secret => 'anonymous',
147
- :callback => "http://localhost:#{OAUTH_SERVER_PORT}/"
148
- )
149
- scope = options[:scope]
150
- # Special cases
151
- case scope
152
- when "https://www.googleapis.com/auth/buzz",
153
- "https://www.googleapis.com/auth/buzz.readonly"
154
- oauth_client.authorization_uri =
155
- 'https://www.google.com/buzz/api/auth/OAuthAuthorizeToken?' +
156
- "domain=#{oauth_client.client_credential_key}&" +
157
- "scope=#{scope}&" +
158
- "xoauth_displayname=Google%20API%20Client"
159
- end
160
- oauth_client.fetch_temporary_credential!(:additional_parameters => {
161
- :scope => scope,
162
- :xoauth_displayname => 'Google API Client'
163
- })
75
+ def command
76
+ return self.options[:command]
77
+ end
164
78
 
165
- # Launch browser
166
- Launchy::Browser.run(oauth_client.authorization_uri.to_s)
79
+ def rpcname
80
+ return self.options[:rpcname]
81
+ end
167
82
 
168
- server.start
169
- oauth_client.fetch_token_credential!(:verifier => $verifier)
170
- config = {
171
- "scope" => scope,
172
- "client_credential_key" => oauth_client.client_credential_key,
173
- "client_credential_secret" => oauth_client.client_credential_secret,
174
- "token_credential_key" => oauth_client.token_credential_key,
175
- "token_credential_secret" => oauth_client.token_credential_secret
176
- }
177
- config_file = File.expand_path('~/.google-api.yaml')
178
- open(config_file, 'w') { |file| file.write(YAML.dump(config)) }
179
- exit(0)
180
- end
83
+ def parser
84
+ @parser ||= OptionParser.new do |opts|
85
+ opts.banner = "Usage: google-api " +
86
+ "(execute <rpcname> | [command]) [options] [-- <parameters>]"
181
87
 
182
- def execute(options={})
183
- require 'signet/oauth_1/client'
184
- require 'yaml'
185
- config_file = File.expand_path('~/.google-api.yaml')
186
- signed = File.exist?(config_file)
187
- rpcname = ARGV.detect { |p| p =~ /^[a-z0-9_-]+\.[a-z0-9_\.-]+$/i }
188
- if rpcname
189
- ARGV.delete(rpcname)
190
- else
191
- STDERR.puts('Could not find rpcname.')
192
- exit(1)
193
- end
194
- service_name = options[:service_name] || rpcname[/^([^\.]+)\./, 1]
195
- client = Google::APIClient.new(
196
- :service => service_name,
197
- :authorization => :oauth_1
198
- )
199
- if signed
200
- if !client.authorization.kind_of?(Signet::OAuth1::Client)
201
- STDERR.puts(
202
- "Unexpected authorization mechanism: #{client.authorization.class}"
203
- )
204
- exit(1)
205
- end
206
- config = open(config_file, 'r') { |file| YAML.load(file.read) }
207
- client.authorization.client_credential_key =
208
- config["client_credential_key"]
209
- client.authorization.client_credential_secret =
210
- config["client_credential_secret"]
211
- client.authorization.token_credential_key =
212
- config["token_credential_key"]
213
- client.authorization.token_credential_secret =
214
- config["token_credential_secret"]
215
- end
216
- service_version =
217
- options[:service_version] ||
218
- client.latest_service_version(service_name).version
219
- service = client.discovered_service(service_name, service_version)
220
- method = service.to_h[rpcname]
221
- if !method
222
- STDERR.puts(
223
- "Method #{rpcname} does not exist for " +
224
- "#{service_name}-#{service_version}."
225
- )
226
- exit(1)
227
- end
228
- parameters = ARGV.inject({}) do |accu, pair|
229
- name, value = pair.split('=', 2)
230
- accu[name] = value
231
- accu
232
- end
233
- request_body = ''
234
- input_streams, _, _ = IO.select([STDIN], [], [], 0)
235
- request_body = STDIN.read || '' if input_streams
236
- headers = []
237
- if options[:content_type]
238
- headers << ['Content-Type', options[:content_type]]
239
- elsif request_body
240
- # Default to JSON
241
- headers << ['Content-Type', 'application/json']
242
- end
243
- response = client.execute(
244
- method, parameters, request_body, headers, {:signed => signed}
245
- )
246
- status, headers, body = response
247
- puts body
248
- exit(0)
249
- end
88
+ opts.separator "\nAvailable options:"
250
89
 
251
- def interactive(options={})
252
- require 'signet/oauth_1/client'
253
- require 'yaml'
254
- config_file = File.expand_path('~/.google-api.yaml')
255
- signed = File.exist?(config_file)
90
+ opts.on(
91
+ "--scope <scope>", String, "Set the OAuth scope") do |s|
92
+ options[:scope] = s
93
+ end
94
+ opts.on(
95
+ "-s", "--service <name>", String,
96
+ "Perform discovery on service") do |s|
97
+ options[:service_name] = s
98
+ end
99
+ opts.on(
100
+ "--service-version <id>", String,
101
+ "Select service version") do |id|
102
+ options[:service_version] = id
103
+ end
104
+ opts.on(
105
+ "--content-type <format>", String,
106
+ "Content-Type for request") do |f|
107
+ # Resolve content type shortcuts
108
+ case f
109
+ when 'json'
110
+ f = 'application/json'
111
+ when 'xml'
112
+ f = 'application/xml'
113
+ when 'atom'
114
+ f = 'application/atom+xml'
115
+ when 'rss'
116
+ f = 'application/rss+xml'
117
+ end
118
+ options[:content_type] = f
119
+ end
256
120
 
257
- $client = Google::APIClient.new(
258
- :service => options[:service_name],
259
- :authorization => (signed ? :oauth_1 : nil)
260
- )
121
+ opts.on("-v", "--verbose", "Run verbosely") do |v|
122
+ options[:verbose] = v
123
+ end
124
+ opts.on("-h", "--help", "Show this message") do
125
+ puts opts
126
+ exit
127
+ end
128
+ opts.on("--version", "Show version") do
129
+ puts "google-api-client (#{Google::APIClient::VERSION::STRING})"
130
+ exit
131
+ end
261
132
 
262
- if signed
263
- if $client.authorization &&
264
- !$client.authorization.kind_of?(Signet::OAuth1::Client)
265
- STDERR.puts(
266
- "Unexpected authorization mechanism: #{$client.authorization.class}"
267
- )
268
- exit(1)
269
- end
270
- config = open(config_file, 'r') { |file| YAML.load(file.read) }
271
- $client.authorization.client_credential_key =
272
- config["client_credential_key"]
273
- $client.authorization.client_credential_secret =
274
- config["client_credential_secret"]
275
- $client.authorization.token_credential_key =
276
- config["token_credential_key"]
277
- $client.authorization.token_credential_secret =
278
- config["token_credential_secret"]
279
- end
133
+ opts.separator(
134
+ "\nAvailable commands:\n" +
135
+ " oauth-login Log a user into an API\n" +
136
+ " list List the methods available for a service\n" +
137
+ " execute Execute a method on the API\n" +
138
+ " irb Start an interactive client session"
139
+ )
140
+ end
141
+ end
280
142
 
281
- require 'irb'
282
- IRB.start(__FILE__)
283
- end
143
+ def parse!
144
+ self.parser.parse!(self.argv)
145
+ self.send(self.command.gsub(/-/, "_").to_sym)
146
+ end
147
+
148
+ def oauth_login
149
+ require 'signet/oauth_1/client'
150
+ require 'launchy'
151
+ require 'yaml'
152
+ $verifier = nil
153
+ logger = WEBrick::Log.new('/dev/null') # TODO(bobaman): Cross-platform?
154
+ server = WEBrick::HTTPServer.new(
155
+ :Port => OAUTH_SERVER_PORT,
156
+ :Logger => logger,
157
+ :AccessLog => logger
158
+ )
159
+ trap("INT") { server.shutdown }
160
+
161
+ server.mount("/", OAuthVerifierServlet)
284
162
 
285
- def fuzz(options={})
286
- STDERR.puts('API fuzzing not yet supported.')
287
- if rpcname
288
- # Fuzz just one method
289
- else
290
- # Fuzz the entire API
163
+ oauth_client = Signet::OAuth1::Client.new(
164
+ :temporary_credential_uri =>
165
+ 'https://www.google.com/accounts/OAuthGetRequestToken',
166
+ :authorization_uri =>
167
+ 'https://www.google.com/accounts/OAuthAuthorizeToken',
168
+ :token_credential_uri =>
169
+ 'https://www.google.com/accounts/OAuthGetAccessToken',
170
+ :client_credential_key => 'anonymous',
171
+ :client_credential_secret => 'anonymous',
172
+ :callback => "http://localhost:#{OAUTH_SERVER_PORT}/"
173
+ )
174
+ scope = options[:scope]
175
+ # Special cases
176
+ case scope
177
+ when "https://www.googleapis.com/auth/buzz",
178
+ "https://www.googleapis.com/auth/buzz.readonly"
179
+ oauth_client.authorization_uri =
180
+ 'https://www.google.com/buzz/api/auth/OAuthAuthorizeToken?' +
181
+ "domain=#{oauth_client.client_credential_key}&" +
182
+ "scope=#{scope}&" +
183
+ "xoauth_displayname=Google%20API%20Client"
184
+ end
185
+ oauth_client.fetch_temporary_credential!(:additional_parameters => {
186
+ :scope => scope,
187
+ :xoauth_displayname => 'Google API Client'
188
+ })
189
+
190
+ # Launch browser
191
+ Launchy::Browser.run(oauth_client.authorization_uri.to_s)
192
+
193
+ server.start
194
+ oauth_client.fetch_token_credential!(:verifier => $verifier)
195
+ config = {
196
+ "scope" => scope,
197
+ "client_credential_key" => oauth_client.client_credential_key,
198
+ "client_credential_secret" => oauth_client.client_credential_secret,
199
+ "token_credential_key" => oauth_client.token_credential_key,
200
+ "token_credential_secret" => oauth_client.token_credential_secret
201
+ }
202
+ config_file = File.expand_path('~/.google-api.yaml')
203
+ open(config_file, 'w') { |file| file.write(YAML.dump(config)) }
204
+ exit(0)
205
+ end
206
+
207
+ def list
208
+ service_name = options[:service_name]
209
+ client = Google::APIClient.new(
210
+ :service => service_name,
211
+ :authorization => nil
212
+ )
213
+ service_version =
214
+ options[:service_version] ||
215
+ client.latest_service_version(service_name).version
216
+ service = client.discovered_service(service_name, service_version)
217
+ rpcnames = service.to_h.keys
218
+ puts rpcnames.sort.join("\n")
219
+ exit(0)
220
+ end
221
+
222
+ def execute
223
+ require 'signet/oauth_1/client'
224
+ require 'yaml'
225
+ config_file = File.expand_path('~/.google-api.yaml')
226
+ signed = File.exist?(config_file)
227
+ if !self.rpcname
228
+ STDERR.puts('No rpcname supplied.')
229
+ exit(1)
230
+ end
231
+ service_name = options[:service_name] || self.rpcname[/^([^\.]+)\./, 1]
232
+ client = Google::APIClient.new(
233
+ :service => service_name,
234
+ :authorization => :oauth_1
235
+ )
236
+ if signed
237
+ if !client.authorization.kind_of?(Signet::OAuth1::Client)
238
+ STDERR.puts(
239
+ "Unexpected authorization mechanism: " +
240
+ "#{client.authorization.class}"
241
+ )
242
+ exit(1)
243
+ end
244
+ config = open(config_file, 'r') { |file| YAML.load(file.read) }
245
+ client.authorization.client_credential_key =
246
+ config["client_credential_key"]
247
+ client.authorization.client_credential_secret =
248
+ config["client_credential_secret"]
249
+ client.authorization.token_credential_key =
250
+ config["token_credential_key"]
251
+ client.authorization.token_credential_secret =
252
+ config["token_credential_secret"]
253
+ end
254
+ service_version =
255
+ options[:service_version] ||
256
+ client.latest_service_version(service_name).version
257
+ service = client.discovered_service(service_name, service_version)
258
+ method = service.to_h[self.rpcname]
259
+ if !method
260
+ STDERR.puts(
261
+ "Method #{self.rpcname} does not exist for " +
262
+ "#{service_name}-#{service_version}."
263
+ )
264
+ exit(1)
265
+ end
266
+ parameters = self.argv.inject({}) do |accu, pair|
267
+ name, value = pair.split('=', 2)
268
+ accu[name] = value
269
+ accu
270
+ end
271
+ request_body = ''
272
+ input_streams, _, _ = IO.select([STDIN], [], [], 0)
273
+ request_body = STDIN.read || '' if input_streams
274
+ headers = []
275
+ if options[:content_type]
276
+ headers << ['Content-Type', options[:content_type]]
277
+ elsif request_body
278
+ # Default to JSON
279
+ headers << ['Content-Type', 'application/json']
280
+ end
281
+ begin
282
+ response = client.execute(
283
+ method, parameters, request_body, headers, {:signed => signed}
284
+ )
285
+ status, headers, body = response
286
+ puts body
287
+ exit(0)
288
+ rescue ArgumentError => e
289
+ puts e.message
290
+ exit(1)
291
+ end
292
+ end
293
+
294
+ def irb
295
+ require 'signet/oauth_1/client'
296
+ require 'yaml'
297
+ require 'irb'
298
+ config_file = File.expand_path('~/.google-api.yaml')
299
+ signed = File.exist?(config_file)
300
+
301
+ $client = Google::APIClient.new(
302
+ :service => options[:service_name],
303
+ :authorization => (signed ? :oauth_1 : nil)
304
+ )
305
+
306
+ if signed
307
+ if $client.authorization &&
308
+ !$client.authorization.kind_of?(Signet::OAuth1::Client)
309
+ STDERR.puts(
310
+ "Unexpected authorization mechanism: " +
311
+ "#{$client.authorization.class}"
312
+ )
313
+ exit(1)
314
+ end
315
+ config = open(config_file, 'r') { |file| YAML.load(file.read) }
316
+ $client.authorization.client_credential_key =
317
+ config["client_credential_key"]
318
+ $client.authorization.client_credential_secret =
319
+ config["client_credential_secret"]
320
+ $client.authorization.token_credential_key =
321
+ config["token_credential_key"]
322
+ $client.authorization.token_credential_secret =
323
+ config["token_credential_secret"]
324
+ end
325
+
326
+ # Otherwise IRB will misinterpret command-line options
327
+ ARGV.clear
328
+ IRB.start(__FILE__)
329
+ end
330
+
331
+ def fuzz
332
+ STDERR.puts('API fuzzing not yet supported.')
333
+ if self.rpcname
334
+ # Fuzz just one method
335
+ else
336
+ # Fuzz the entire API
337
+ end
338
+ exit(1)
339
+ end
340
+
341
+ def help
342
+ puts self.parser
343
+ exit(0)
344
+ end
345
+ end
291
346
  end
292
- exit(1)
293
347
  end
294
348
 
295
- self.send(command.gsub(/-/, "_").to_sym, options)
349
+ Google::APIClient::CLI.new(ARGV).parse!
@@ -17,7 +17,7 @@ module Google
17
17
  module VERSION
18
18
  MAJOR = 0
19
19
  MINOR = 1
20
- TINY = 0
20
+ TINY = 1
21
21
 
22
22
  STRING = [MAJOR, MINOR, TINY].join('.')
23
23
  end
@@ -14,6 +14,7 @@
14
14
 
15
15
  require 'httpadapter'
16
16
  require 'json'
17
+ require 'stringio'
17
18
 
18
19
  require 'google/api_client/discovery'
19
20
 
data/tasks/spec.rake CHANGED
@@ -18,6 +18,7 @@ namespace :spec do
18
18
  end
19
19
  t.rcov_opts = [
20
20
  '--exclude', 'spec',
21
+ '--exclude', '\\.rvm\\/gems',
21
22
  '--exclude', '1\\.8\\/gems',
22
23
  '--exclude', '1\\.9\\/gems'
23
24
  ]
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: google-api-client
3
3
  version: !ruby/object:Gem::Version
4
- hash: 27
4
+ hash: 25
5
5
  prerelease: false
6
6
  segments:
7
7
  - 0
8
8
  - 1
9
- - 0
10
- version: 0.1.0
9
+ - 1
10
+ version: 0.1.1
11
11
  platform: ruby
12
12
  authors: []
13
13
 
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2010-10-13 00:00:00 -07:00
18
+ date: 2010-10-21 00:00:00 -07:00
19
19
  default_executable:
20
20
  dependencies:
21
21
  - !ruby/object:Gem::Dependency