addax 0.10.0
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/Rakefile +16 -0
- data/VERSION +1 -0
- data/bin/addax +7 -0
- data/lib/addax.rb +80 -0
- data/lib/addax/commands.rb +236 -0
- metadata +119 -0
data/Rakefile
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
begin
|
2
|
+
require 'jeweler'
|
3
|
+
Jeweler::Tasks.new do |gemspec|
|
4
|
+
gemspec.name = "addax"
|
5
|
+
gemspec.summary = "Command-line tool for accessing TIMA-SLS's ADDAX webservice."
|
6
|
+
gemspec.email = "guillaume.godetbar@gmail.com"
|
7
|
+
gemspec.homepage = "http://tima-sls.imag.fr/addax"
|
8
|
+
gemspec.authors = ["Guillaume Godet-Bar"]
|
9
|
+
gemspec.files = FileList["lib/**/*", "bin/*", "Rakefile", "VERSION"]
|
10
|
+
gemspec.executables = ['addax']
|
11
|
+
gemspec.add_dependency 'rest-client'
|
12
|
+
gemspec.add_dependency 'json'
|
13
|
+
end
|
14
|
+
rescue LoadError
|
15
|
+
puts "Jeweler not available. Install it with: gem install jeweler"
|
16
|
+
end
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.10.0
|
data/bin/addax
ADDED
data/lib/addax.rb
ADDED
@@ -0,0 +1,80 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'rest_client'
|
4
|
+
require 'json'
|
5
|
+
require 'readline'
|
6
|
+
require 'base64'
|
7
|
+
require 'tempfile'
|
8
|
+
require 'pp'
|
9
|
+
|
10
|
+
require File.join(File.dirname(__FILE__), 'addax/commands')
|
11
|
+
|
12
|
+
module Addax
|
13
|
+
USAGE = <<END
|
14
|
+
Addax, a command line tool for connecting with the Addax Webservice.
|
15
|
+
|
16
|
+
Usage
|
17
|
+
|
18
|
+
addax <Action>
|
19
|
+
|
20
|
+
Actions
|
21
|
+
|
22
|
+
[list | l] <object_type> - lists all available objects, which should be either 'oses|operating_systems', 'drivers', 'platforms'
|
23
|
+
<object_type> <id> - displays the data associated with the object instance, e.g. 'addax driver 1'
|
24
|
+
[fetch | f] <object_type> <id> <path> - returns the file associated with a driver or a platform
|
25
|
+
[generate | g] <id> <path> - downloads the generated sources for the driver associated with <id> into <path>
|
26
|
+
[create | c] <object_type> <param>=<value> [<param>=<value>]*
|
27
|
+
- creates a new instance of the object type, with the list of parameters provided.
|
28
|
+
[update | u] <object_type> <id> <param>=<value> [<param>=<value>]*
|
29
|
+
- modifies the object identified by <id> with the list of parameters provided.
|
30
|
+
[destroy | d] [-f] <object_type> <id> - destroys the object identified by <id>. -f to destroy without asking for confirmation.
|
31
|
+
|
32
|
+
END
|
33
|
+
|
34
|
+
SERVER_URL = 'http://tima-sls.imag.fr/addax'
|
35
|
+
|
36
|
+
class Exec
|
37
|
+
|
38
|
+
def initialize(args)
|
39
|
+
@args = args
|
40
|
+
end
|
41
|
+
|
42
|
+
def parse!
|
43
|
+
begin
|
44
|
+
parse
|
45
|
+
rescue ArgumentError
|
46
|
+
$stderr.puts USAGE
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def parse
|
51
|
+
if ARGV.size == 2 && %w(l list).include?(ARGV[0]) && %w(operating_systems oses platforms drivers strategies).include?(ARGV[1])
|
52
|
+
Addax::Commands.list(ARGV[1])
|
53
|
+
elsif ARGV.size == 2 && %w(operating_system os driver platform).include?(ARGV[0])
|
54
|
+
Addax::Commands.show(ARGV[0], ARGV[1])
|
55
|
+
elsif ARGV.size == 3 && %w(g generate).include?(ARGV[0])
|
56
|
+
Addax::Commands.generate(ARGV[1], ARGV[2])
|
57
|
+
elsif ARGV.size > 2 && %w(c create).include?(ARGV[0]) && %w(operating_system os platform driver).include?(ARGV[1])
|
58
|
+
Addax::Commands.send("create_#{ARGV[1]}".to_sym, ARGV[2..-1])
|
59
|
+
elsif ARGV.size == 4 && %w(f fetch).include?(ARGV[0]) && %w(driver platform).include?(ARGV[1])
|
60
|
+
Addax::Commands.send("fetch_#{ARGV[1]}".to_sym, ARGV[2], ARGV[3])
|
61
|
+
elsif ARGV.size > 3 && %w(u update).include?(ARGV[0]) && %w(operating_system os platform driver).include?(ARGV[1])
|
62
|
+
Addax::Commands.update(ARGV[1], ARGV[2], ARGV[3..-1])
|
63
|
+
elsif ARGV.size >= 3 && %w(d destroy).include?(ARGV[0])
|
64
|
+
if ARGV[1] == '-f'
|
65
|
+
Addax::Commands.destroy(ARGV[2], ARGV[3])
|
66
|
+
else
|
67
|
+
begin
|
68
|
+
puts "Please confirm that you wish to destroy this resource (Y/n)"
|
69
|
+
line = Readline.readline()
|
70
|
+
end while !%w(Y n).include?(line)
|
71
|
+
if line == 'Y'
|
72
|
+
Addax::Commands.destroy(ARGV[1], ARGV[2])
|
73
|
+
end
|
74
|
+
end
|
75
|
+
else
|
76
|
+
raise ArgumentError
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
@@ -0,0 +1,236 @@
|
|
1
|
+
module Addax
|
2
|
+
module Commands
|
3
|
+
|
4
|
+
OUTPUTS = {
|
5
|
+
:generic_error => "ERROR. Something went wrong with the server.",
|
6
|
+
:not_found => "ERROR. Resource not found.",
|
7
|
+
:platform_data_missing => "ERROR. Platform data file (format: zip) is missing.",
|
8
|
+
:created_resource => "Successfully created resource.",
|
9
|
+
:updated_resource => "Successfully updated resource.",
|
10
|
+
:destroyed_resource => "Successfully destroyed resource.",
|
11
|
+
:security_tokens_error => "ERROR. Could not fetch security tokens from the server."
|
12
|
+
}
|
13
|
+
|
14
|
+
def self.list(type)
|
15
|
+
type = type == 'oses' ? 'operating_systems' : type
|
16
|
+
begin
|
17
|
+
response = RestClient.get "#{SERVER_URL}/#{type}.json"
|
18
|
+
rescue => e
|
19
|
+
abort OUTPUTS[:generic_error]
|
20
|
+
else
|
21
|
+
format(response.body)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.show(model, id)
|
26
|
+
type = type == 'os' ? 'operating_system' : type
|
27
|
+
begin
|
28
|
+
response = RestClient.get "#{SERVER_URL}/#{model}s/#{id}.json"
|
29
|
+
rescue => e
|
30
|
+
case e.response.code
|
31
|
+
when 404 then
|
32
|
+
abort OUTPUTS[:not_found]
|
33
|
+
else
|
34
|
+
abort OUTPUTS[:generic_error]
|
35
|
+
end
|
36
|
+
else
|
37
|
+
format(response.body)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def self.generate(driver_id, file_path)
|
42
|
+
begin
|
43
|
+
response = RestClient.post "#{SERVER_URL}/drivers/#{driver_id}/generate_sources", {}
|
44
|
+
rescue => e
|
45
|
+
case e.response.code
|
46
|
+
when 404 then
|
47
|
+
abort OUTPUTS[:not_found]
|
48
|
+
else
|
49
|
+
abort OUTPUTS[:generic_error]
|
50
|
+
end
|
51
|
+
else
|
52
|
+
file_name = response.headers[:content_disposition].scan(/filename="(.+)"/)[0][0] + ".zip"
|
53
|
+
File.open File.join(file_path, file_name), "w" do |f|
|
54
|
+
f.write(response.body)
|
55
|
+
end
|
56
|
+
puts "File was written to #{File.join(file_path, file_name)}"
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def self.fetch_driver(object_id, file_path)
|
61
|
+
begin
|
62
|
+
response = RestClient.get "#{SERVER_URL}/drivers/#{object_id}/show_attachment"
|
63
|
+
rescue => e
|
64
|
+
case e.response.code
|
65
|
+
when 404 then
|
66
|
+
abort OUTPUTS[:not_found]
|
67
|
+
else
|
68
|
+
abort OUTPUTS[:generic_error]
|
69
|
+
end
|
70
|
+
else
|
71
|
+
file_name = response.headers[:content_disposition].scan(/filename="(.+)"/)[0][0] + ".xml"
|
72
|
+
File.open File.join(file_path, file_name), "w" do |f|
|
73
|
+
f.write(response.body)
|
74
|
+
end
|
75
|
+
puts "File was written to #{File.join file_path, file_name}"
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
def self.fetch_platform(object_id, file_path)
|
80
|
+
abort "ERROR: Platform data fetch not implemented yet!"
|
81
|
+
end
|
82
|
+
|
83
|
+
def self.create_platform(params)
|
84
|
+
param_hash = normalize_params(params)
|
85
|
+
|
86
|
+
authenticity_token, cookie = security_tokens
|
87
|
+
|
88
|
+
# The params should at least have a platform_data param
|
89
|
+
platform_data = param_hash.delete(:platform_data)
|
90
|
+
unless platform_data
|
91
|
+
abort OUTPUTS[:platform_data_missing]
|
92
|
+
end
|
93
|
+
|
94
|
+
begin
|
95
|
+
load_platform_data_response = RestClient.post "#{SERVER_URL}/platforms/load_file.json",
|
96
|
+
{:platform_data => File.new(platform_data, 'rb'), :authenticity_token => authenticity_token},
|
97
|
+
{:cookies => cookie}
|
98
|
+
rescue => e
|
99
|
+
abort OUTPUTS[:generic_error] + '\n' + format_error(e.response.body)
|
100
|
+
end
|
101
|
+
|
102
|
+
encoded_cache_name = load_platform_data_response.body
|
103
|
+
|
104
|
+
if param_hash[:root_component]
|
105
|
+
begin
|
106
|
+
create_platform_response = RestClient.post "#{SERVER_URL}/platforms.json?cache=#{encoded_cache_name}",
|
107
|
+
{:platform => param_hash, :authenticity_token => authenticity_token},
|
108
|
+
{:cookies => cookie}
|
109
|
+
rescue => e
|
110
|
+
abort OUTPUTS[:generic_error] + '\n' + format_error(e.response.body)
|
111
|
+
else
|
112
|
+
puts OUTPUTS[:created_resource]
|
113
|
+
format(create_platform_response.body)
|
114
|
+
end
|
115
|
+
else
|
116
|
+
abort "ERROR: Root component choice not yet implemented!"
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
def self.create_driver(params)
|
121
|
+
param_hash = normalize_params(params)
|
122
|
+
|
123
|
+
authenticity_token, cookie = security_tokens
|
124
|
+
|
125
|
+
begin
|
126
|
+
response = RestClient.post "#{SERVER_URL}/drivers.json",
|
127
|
+
{:driver => param_hash, :authenticity_token => authenticity_token},
|
128
|
+
{:cookies => cookie}
|
129
|
+
rescue => e
|
130
|
+
abort OUTPUTS[:generic_error] + '\n' + format_error(e.response.body)
|
131
|
+
else
|
132
|
+
puts OUTPUTS[:updated_resource]
|
133
|
+
format(response.body)
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
def self.create_operating_system(params)
|
138
|
+
param_hash = normalize_params(params)
|
139
|
+
|
140
|
+
authenticity_token, cookie = security_tokens
|
141
|
+
|
142
|
+
begin
|
143
|
+
response = RestClient.post "#{SERVER_URL}/operating_systems.json",
|
144
|
+
{:operating_system => param_hash,:authenticity_token => authenticity_token},
|
145
|
+
{:cookies => cookie}
|
146
|
+
rescue => e
|
147
|
+
abort OUTPUTS[:generic_error] + '\n' + format_error(e.response.body)
|
148
|
+
else
|
149
|
+
puts OUTPUTS[:created_resource]
|
150
|
+
format(response.body)
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
def self.update(object_type, object_id, params)
|
155
|
+
object_type = object_type == "os" ? "operating_system" : object_type
|
156
|
+
param_hash = normalize_params(params)
|
157
|
+
|
158
|
+
begin
|
159
|
+
response = RestClient.put "#{SERVER_URL}/#{object_type}s/#{object_id}.json",
|
160
|
+
{object_type.to_sym => param_hash}
|
161
|
+
rescue => e
|
162
|
+
abort OUTPUTS[:generic_error] + '\n' + format_error(e.response.body)
|
163
|
+
else
|
164
|
+
puts OUTPUTS[:updated_resource]
|
165
|
+
format(response.body)
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
def self.destroy(object_type, object_id)
|
170
|
+
authenticity_token, cookie = security_tokens
|
171
|
+
begin
|
172
|
+
response = RestClient.delete "#{SERVER_URL}/#{object_type}s/#{object_id}.json", {:cookies => cookie}
|
173
|
+
rescue => e
|
174
|
+
case e.response.code
|
175
|
+
when 404 then
|
176
|
+
abort OUTPUTS[:not_found]
|
177
|
+
else
|
178
|
+
abort OUTPUTS[:generic_error]
|
179
|
+
end
|
180
|
+
else
|
181
|
+
puts OUTPUTS[:destroyed_resource]
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
185
|
+
class << self
|
186
|
+
alias :create_os :create_operating_system
|
187
|
+
end
|
188
|
+
|
189
|
+
private
|
190
|
+
def self.security_tokens
|
191
|
+
begin
|
192
|
+
new_response = RestClient.get "#{SERVER_URL}/drivers/new.html" # Any form would do
|
193
|
+
rescue => e
|
194
|
+
abort OUTPUTS[:security_tokens_error]
|
195
|
+
else
|
196
|
+
authenticity_token = new_response.body.scan(/<meta name="csrf-token" content="(.*)"\/>/)[0][0]
|
197
|
+
cookie = new_response.cookies
|
198
|
+
[authenticity_token, cookie]
|
199
|
+
end
|
200
|
+
end
|
201
|
+
|
202
|
+
def self.normalize_params(param_array)
|
203
|
+
param_hash = param_array.inject({}){|acc, p| pieces = p.split('='); acc[pieces[0].to_sym] = pieces[1]; acc}
|
204
|
+
param_hash.delete(:id)
|
205
|
+
param_hash.delete(:created_at)
|
206
|
+
param_hash.delete(:updated_at)
|
207
|
+
|
208
|
+
param_hash
|
209
|
+
end
|
210
|
+
|
211
|
+
def self.format(json)
|
212
|
+
content = json.is_a?(String) ? JSON::parse(json) : json
|
213
|
+
if content.is_a?(Array)
|
214
|
+
content.each do |el|
|
215
|
+
format(el)
|
216
|
+
end
|
217
|
+
else
|
218
|
+
puts content.values[0].delete('name') + ":"
|
219
|
+
data = content.values[0]
|
220
|
+
data.each do |k, v|
|
221
|
+
puts "\t" + k + ": " + v.to_s #.gsub('_', ' ').capitalize + ": " + v.to_s
|
222
|
+
end
|
223
|
+
|
224
|
+
end
|
225
|
+
end
|
226
|
+
|
227
|
+
def self.format_error(json)
|
228
|
+
content = json.is_a?(String) ? JSON::parse(json) : json
|
229
|
+
if content.is_a?(Hash)
|
230
|
+
content.collect do |k, v|
|
231
|
+
"\t" + k + ' ' + v
|
232
|
+
end.join('\n')
|
233
|
+
end
|
234
|
+
end
|
235
|
+
end
|
236
|
+
end
|
metadata
ADDED
@@ -0,0 +1,119 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: addax
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease: false
|
5
|
+
segments:
|
6
|
+
- 0
|
7
|
+
- 10
|
8
|
+
- 0
|
9
|
+
version: 0.10.0
|
10
|
+
platform: ruby
|
11
|
+
authors:
|
12
|
+
- Guillaume Godet-Bar
|
13
|
+
autorequire:
|
14
|
+
bindir: bin
|
15
|
+
cert_chain: []
|
16
|
+
|
17
|
+
date: 2011-02-15 00:00:00 +01:00
|
18
|
+
default_executable: addax
|
19
|
+
dependencies:
|
20
|
+
- !ruby/object:Gem::Dependency
|
21
|
+
name: json
|
22
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
23
|
+
none: false
|
24
|
+
requirements:
|
25
|
+
- - ">="
|
26
|
+
- !ruby/object:Gem::Version
|
27
|
+
segments:
|
28
|
+
- 0
|
29
|
+
version: "0"
|
30
|
+
type: :runtime
|
31
|
+
prerelease: false
|
32
|
+
version_requirements: *id001
|
33
|
+
- !ruby/object:Gem::Dependency
|
34
|
+
name: rest-client
|
35
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
36
|
+
none: false
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
segments:
|
41
|
+
- 0
|
42
|
+
version: "0"
|
43
|
+
type: :runtime
|
44
|
+
prerelease: false
|
45
|
+
version_requirements: *id002
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: rest-client
|
48
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ">="
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
segments:
|
54
|
+
- 0
|
55
|
+
version: "0"
|
56
|
+
type: :runtime
|
57
|
+
prerelease: false
|
58
|
+
version_requirements: *id003
|
59
|
+
- !ruby/object:Gem::Dependency
|
60
|
+
name: json
|
61
|
+
requirement: &id004 !ruby/object:Gem::Requirement
|
62
|
+
none: false
|
63
|
+
requirements:
|
64
|
+
- - ">="
|
65
|
+
- !ruby/object:Gem::Version
|
66
|
+
segments:
|
67
|
+
- 0
|
68
|
+
version: "0"
|
69
|
+
type: :runtime
|
70
|
+
prerelease: false
|
71
|
+
version_requirements: *id004
|
72
|
+
description:
|
73
|
+
email: guillaume.godetbar@gmail.com
|
74
|
+
executables:
|
75
|
+
- addax
|
76
|
+
extensions: []
|
77
|
+
|
78
|
+
extra_rdoc_files: []
|
79
|
+
|
80
|
+
files:
|
81
|
+
- Rakefile
|
82
|
+
- VERSION
|
83
|
+
- bin/addax
|
84
|
+
- lib/addax.rb
|
85
|
+
- lib/addax/commands.rb
|
86
|
+
has_rdoc: true
|
87
|
+
homepage: http://tima-sls.imag.fr/addax
|
88
|
+
licenses: []
|
89
|
+
|
90
|
+
post_install_message:
|
91
|
+
rdoc_options: []
|
92
|
+
|
93
|
+
require_paths:
|
94
|
+
- lib
|
95
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
96
|
+
none: false
|
97
|
+
requirements:
|
98
|
+
- - ">="
|
99
|
+
- !ruby/object:Gem::Version
|
100
|
+
segments:
|
101
|
+
- 0
|
102
|
+
version: "0"
|
103
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
104
|
+
none: false
|
105
|
+
requirements:
|
106
|
+
- - ">="
|
107
|
+
- !ruby/object:Gem::Version
|
108
|
+
segments:
|
109
|
+
- 0
|
110
|
+
version: "0"
|
111
|
+
requirements: []
|
112
|
+
|
113
|
+
rubyforge_project:
|
114
|
+
rubygems_version: 1.3.7
|
115
|
+
signing_key:
|
116
|
+
specification_version: 3
|
117
|
+
summary: Command-line tool for accessing TIMA-SLS's ADDAX webservice.
|
118
|
+
test_files: []
|
119
|
+
|