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.
- data/CHANGELOG.md +77 -0
- data/Gemfile +30 -0
- data/Gemfile.lock +80 -0
- data/LICENSE +202 -0
- data/README.md +71 -0
- data/Rakefile +42 -0
- data/bin/google-api +545 -0
- data/lib/compat/multi_json.rb +17 -0
- data/lib/google/api_client.rb +802 -0
- data/lib/google/api_client/batch.rb +296 -0
- data/lib/google/api_client/client_secrets.rb +106 -0
- data/lib/google/api_client/discovery.rb +19 -0
- data/lib/google/api_client/discovery/api.rb +287 -0
- data/lib/google/api_client/discovery/media.rb +77 -0
- data/lib/google/api_client/discovery/method.rb +369 -0
- data/lib/google/api_client/discovery/resource.rb +150 -0
- data/lib/google/api_client/discovery/schema.rb +119 -0
- data/lib/google/api_client/environment.rb +42 -0
- data/lib/google/api_client/errors.rb +49 -0
- data/lib/google/api_client/media.rb +172 -0
- data/lib/google/api_client/reference.rb +305 -0
- data/lib/google/api_client/result.rb +161 -0
- data/lib/google/api_client/service_account.rb +134 -0
- data/lib/google/api_client/version.rb +31 -0
- data/lib/google/inflection.rb +28 -0
- data/spec/fixtures/files/sample.txt +33 -0
- data/spec/google/api_client/batch_spec.rb +241 -0
- data/spec/google/api_client/discovery_spec.rb +670 -0
- data/spec/google/api_client/media_spec.rb +143 -0
- data/spec/google/api_client/result_spec.rb +185 -0
- data/spec/google/api_client/service_account_spec.rb +58 -0
- data/spec/google/api_client_spec.rb +139 -0
- data/spec/spec_helper.rb +7 -0
- data/tasks/gem.rake +97 -0
- data/tasks/git.rake +45 -0
- data/tasks/metrics.rake +22 -0
- data/tasks/spec.rake +57 -0
- data/tasks/wiki.rake +82 -0
- data/tasks/yard.rake +29 -0
- metadata +253 -0
data/Rakefile
ADDED
@@ -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 }
|
data/bin/google-api
ADDED
@@ -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!
|