ssc 0.1 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +14 -0
- data/Gemfile.lock +39 -0
- data/README.rdoc +22 -0
- data/Rakefile +53 -0
- data/VERSION +1 -0
- data/bin/ssc +4 -231
- data/lib/directory_manager.rb +194 -0
- data/lib/handlers/all.rb +33 -0
- data/lib/handlers/appliance.rb +74 -0
- data/lib/handlers/file.rb +102 -0
- data/lib/handlers/helper.rb +79 -0
- data/lib/handlers/package.rb +153 -0
- data/lib/handlers/repository.rb +109 -0
- data/lib/handlers/template.rb +25 -0
- data/lib/ssc.rb +18 -0
- data/test/handlers/test_appliance.rb +20 -0
- data/test/handlers/test_helper.rb +45 -0
- data/test/handlers/test_repository.rb +20 -0
- data/test/handlers/test_template.rb +27 -0
- data/test/helper.rb +19 -0
- data/test/test_argument_parser.rb +55 -0
- data/test/test_directory_manager.rb +40 -0
- data/test/test_ssc.rb +39 -0
- metadata +147 -31
- data/README +0 -1
- data/lib/appliancehandler.rb +0 -69
- data/lib/buildhandler.rb +0 -125
- data/lib/checkouthandler.rb +0 -322
- data/lib/commandhandler.rb +0 -38
- data/lib/request.rb +0 -29
data/lib/checkouthandler.rb
DELETED
@@ -1,322 +0,0 @@
|
|
1
|
-
#!/usr/bin/env ruby
|
2
|
-
|
3
|
-
require 'commandhandler'
|
4
|
-
|
5
|
-
class CheckoutHandler < CommandHandler
|
6
|
-
def self.checkout args, images
|
7
|
-
appliance = get_appliance_from_args_or_config args
|
8
|
-
# Get appliance
|
9
|
-
r = Request.new
|
10
|
-
r.method = "GET"
|
11
|
-
r.call = "appliances/#{appliance}"
|
12
|
-
s = doRequest(r)
|
13
|
-
appliancexml =XML::Smart.string( s )
|
14
|
-
id = appliancexml.find("appliance/id").first.to_s
|
15
|
-
base_system = appliancexml.find("appliance/basesystem").first.to_s
|
16
|
-
puts "Checkout '#{appliancexml.find("appliance/name").first.to_s}'\n"
|
17
|
-
|
18
|
-
FileUtils.mkdir_p id
|
19
|
-
[ ".ssc", ".ssc/files", ".ssc/rpms", "files", "rpms", "images"].each do |d|
|
20
|
-
FileUtils.mkdir_p id + "/" + d
|
21
|
-
end
|
22
|
-
|
23
|
-
XML::Smart.modify("#{id}/.ssc/appliance.config","<checkout/>") { |doc|
|
24
|
-
node = doc.root.add("appliance_id", id)
|
25
|
-
node = doc.root.add("appliance_name", appliancexml.find("appliance/name").first.to_s)
|
26
|
-
node = doc.root.add("base_system", appliancexml.find("appliance/basesystem").first.to_s)
|
27
|
-
}
|
28
|
-
|
29
|
-
# Get files
|
30
|
-
r = Request.new
|
31
|
-
r.method = "GET"
|
32
|
-
r.call = "files/?appliance_id=#{appliance}"
|
33
|
-
s = doRequest(r)
|
34
|
-
|
35
|
-
filesxml = XML::Smart.string( s )
|
36
|
-
filesxml.find("files/file").each do |f|
|
37
|
-
filename = f.find("filename").first.to_s
|
38
|
-
fileid = f.find("id").first.to_s
|
39
|
-
path = "#{id}/files/#{filename}"
|
40
|
-
puts " Downloading '#{filename}'"
|
41
|
-
|
42
|
-
download_file "#{base_url}/files/#{fileid}/data", path
|
43
|
-
FileUtils.cp path, "#{id}/.ssc/files/#{filename}.orig"
|
44
|
-
download_file "#{base_url}/files/#{fileid}", "#{id}/.ssc/files/#{filename}.config"
|
45
|
-
XML::Smart.modify("#{id}/.ssc/files/#{filename}.config") do |doc|
|
46
|
-
node = doc.find("/file").first
|
47
|
-
node.add("state", "synched")
|
48
|
-
end
|
49
|
-
end
|
50
|
-
|
51
|
-
# Get rpms
|
52
|
-
r = Request.new
|
53
|
-
r.method = "GET"
|
54
|
-
r.call = "rpms?base_system=#{base_system}"
|
55
|
-
s = doRequest(r)
|
56
|
-
|
57
|
-
rpmsxml = XML::Smart.string( s )
|
58
|
-
rpmsxml.find("rpms/rpm").each do |rpm|
|
59
|
-
filename = rpm.find("filename").first.to_s
|
60
|
-
fileid = rpm.find("id").first.to_s
|
61
|
-
path = "#{id}/rpms/#{filename}"
|
62
|
-
puts " Downloading '#{filename}'"
|
63
|
-
|
64
|
-
download_file "#{base_url}/rpms/#{fileid}/data", path
|
65
|
-
FileUtils.cp path, "#{id}/.ssc/rpms/#{filename}.orig"
|
66
|
-
download_file "#{base_url}/rpms/#{fileid}", "#{id}/.ssc/rpms/#{filename}.config"
|
67
|
-
XML::Smart.modify("#{id}/.ssc/rpms/#{filename}.config") do |doc|
|
68
|
-
node = doc.find("/rpm").first
|
69
|
-
node.add("state", "synched")
|
70
|
-
end
|
71
|
-
end
|
72
|
-
|
73
|
-
if images
|
74
|
-
appliancexml.find("appliance/builds/build").each do |build|
|
75
|
-
url = build.find("download_url").first.to_s
|
76
|
-
puts " Downloading image '#{File.basename(url)}'"
|
77
|
-
download_file url, "#{id}/images/#{File.basename(url)}"
|
78
|
-
end
|
79
|
-
else
|
80
|
-
puts " Skipped downloading images (change with -i)'"
|
81
|
-
end
|
82
|
-
end
|
83
|
-
|
84
|
-
def self.status
|
85
|
-
appliance_config = XML::Smart.open(".ssc/appliance.config")
|
86
|
-
id = appliance_config.find("/checkout/appliance_id").first.to_s
|
87
|
-
name = appliance_config.find("/checkout/appliance_name").first.to_s
|
88
|
-
|
89
|
-
show_files = false
|
90
|
-
unknown_files = Array.new
|
91
|
-
added_files = Array.new
|
92
|
-
modified_files = Array.new
|
93
|
-
removed_files = Array.new
|
94
|
-
Dir.entries("files").each do |file|
|
95
|
-
if [".", ".."].include?(file) then next end
|
96
|
-
if File.exists?(".ssc/files/#{file}.config")
|
97
|
-
xml = XML::Smart.open(".ssc/files/#{file}.config")
|
98
|
-
status = xml.find("file/state").first.to_s
|
99
|
-
if status == "added"
|
100
|
-
added_files << file
|
101
|
-
show_files = true
|
102
|
-
elsif status == "synched"
|
103
|
-
oldmd5 = `md5sum .ssc/files/#{file}.orig`.split[0]
|
104
|
-
md5 = `md5sum files/#{file}`.split[0]
|
105
|
-
if md5 == oldmd5
|
106
|
-
next
|
107
|
-
elsif md5 != oldmd5
|
108
|
-
modified_files << file
|
109
|
-
show_files = true
|
110
|
-
end
|
111
|
-
end
|
112
|
-
else
|
113
|
-
unknown_files << file
|
114
|
-
show_files = true
|
115
|
-
end
|
116
|
-
end
|
117
|
-
Dir.entries(".ssc/files").each do |file|
|
118
|
-
if [".", ".."].include?(file) then next end
|
119
|
-
unless file =~ /.*.config$/ then next end
|
120
|
-
xml = XML::Smart.open(".ssc/files/#{file}")
|
121
|
-
if xml.find("file/state").first.to_s == "removed"
|
122
|
-
removed_files << file.sub(/(.*).config$/, "\\1")
|
123
|
-
show_files = true
|
124
|
-
end
|
125
|
-
end
|
126
|
-
|
127
|
-
show_rpms = false
|
128
|
-
unknown_rpms = Array.new
|
129
|
-
added_rpms = Array.new
|
130
|
-
modified_rpms = Array.new
|
131
|
-
removed_rpms = Array.new
|
132
|
-
Dir.entries("rpms").each do |file|
|
133
|
-
if [".", ".."].include?(file) then next end
|
134
|
-
if File.exists?(".ssc/rpms/#{file}.config")
|
135
|
-
xml = XML::Smart.open(".ssc/rpms/#{file}.config")
|
136
|
-
status = xml.find("rpm/state").first.to_s
|
137
|
-
if status == "added"
|
138
|
-
added_rpms << file
|
139
|
-
show_rpms = true
|
140
|
-
elsif status == "synched"
|
141
|
-
oldmd5 = `md5sum .ssc/rpms/#{file}.orig`.split[0]
|
142
|
-
md5 = `md5sum rpms/#{file}`.split[0]
|
143
|
-
if md5 == oldmd5
|
144
|
-
next
|
145
|
-
elsif md5 != oldmd5
|
146
|
-
modified_rpms << file
|
147
|
-
show_rpms = true
|
148
|
-
end
|
149
|
-
end
|
150
|
-
else
|
151
|
-
unknown_rpms << file
|
152
|
-
show_rpms = true
|
153
|
-
end
|
154
|
-
end
|
155
|
-
Dir.entries(".ssc/rpms").each do |file|
|
156
|
-
if [".", ".."].include?(file) then next end
|
157
|
-
unless file =~ /.*.config$/ then next end
|
158
|
-
xml = XML::Smart.open(".ssc/rpms/#{file}")
|
159
|
-
if xml.find("rpm/state").first.to_s == "removed"
|
160
|
-
removed_rpms << file.sub(/(.*).config$/, "\\1")
|
161
|
-
show_rpms = true
|
162
|
-
end
|
163
|
-
end
|
164
|
-
|
165
|
-
puts "Status of #{name} (#{id}):"
|
166
|
-
if show_files
|
167
|
-
puts " Overlay files:"
|
168
|
-
unknown_files.each {|f| puts " ? #{f}"}
|
169
|
-
modified_files.each {|f| puts " M #{f}"}
|
170
|
-
added_files.each {|f| puts " A #{f}"}
|
171
|
-
removed_files.each {|f| puts " D #{f}"}
|
172
|
-
end
|
173
|
-
if show_rpms
|
174
|
-
puts " RPMs:"
|
175
|
-
unknown_rpms.each {|f| puts " ? #{f}"}
|
176
|
-
modified_rpms.each {|f| puts " M #{f}"}
|
177
|
-
added_rpms.each {|f| puts " A #{f}"}
|
178
|
-
removed_rpms.each {|f| puts " D #{f}"}
|
179
|
-
end
|
180
|
-
unless show_files or show_rpms
|
181
|
-
puts "Nothing changed."
|
182
|
-
end
|
183
|
-
end
|
184
|
-
|
185
|
-
def self.commit
|
186
|
-
appliance = get_appliance_from_args_or_config nil
|
187
|
-
appliance_config = XML::Smart.open(".ssc/appliance.config")
|
188
|
-
base = appliance_config.find("checkout/base_system").first.to_s
|
189
|
-
|
190
|
-
Dir.entries(".ssc/rpms").each do |file|
|
191
|
-
next unless file =~ /.config$/
|
192
|
-
config = XML::Smart.open(".ssc/rpms/" + file)
|
193
|
-
filename = file.gsub(/(.*).config$/, "\\1")
|
194
|
-
status = config.find("rpm/state").first.to_s
|
195
|
-
|
196
|
-
if (status == "added")
|
197
|
-
puts "Uploading #{filename}"
|
198
|
-
s = `curl -u #{$username}:#{$password} -XPOST -F\"file=@#{"rpms/" + filename}\" http://#{$username}:#{$password}@#{$server_name}/#{$api_prefix}/rpms?base_system=#{base} 2> /dev/null`
|
199
|
-
xml = XML::Smart.string(s)
|
200
|
-
id = xml.find("rpm/id").first.to_s unless xml.find("rpm/id").length == 0
|
201
|
-
if id
|
202
|
-
FileUtils.cp "rpms/#{filename}", ".ssc/rpms/#{filename}.orig"
|
203
|
-
download_file "#{base_url}/rpms/#{id}", ".ssc/rpms/#{filename}.config"
|
204
|
-
end
|
205
|
-
elsif (status == "removed")
|
206
|
-
puts "Removing #{filename}"
|
207
|
-
id = config.find("rpm/id").first.to_s
|
208
|
-
r = Request.new
|
209
|
-
r.method = "DELETE"
|
210
|
-
r.call = "rpms/#{id}"
|
211
|
-
doRequest(r)
|
212
|
-
FileUtils.rm ".ssc/rpms/#{filename}.orig"
|
213
|
-
FileUtils.rm ".ssc/rpms/#{filename}.config"
|
214
|
-
else
|
215
|
-
oldmd5 = `md5sum .ssc/rpms/#{filename}.orig`.split[0]
|
216
|
-
md5 = `md5sum rpms/#{filename}`.split[0]
|
217
|
-
if (status == "synched" and md5 != oldmd5)
|
218
|
-
id = config.find("rpm/id").first.to_s
|
219
|
-
puts "Updating #{filename}"
|
220
|
-
`curl -u #{$username}:#{$password} -XPUT -F\"file=@#{"rpms/" + filename}\" http://#{$username}:#{$password}@#{$server_name}/#{$api_prefix}/rpms/#{id}/data 2> /dev/null`
|
221
|
-
download_file "#{base_url}/rpms/#{id}", ".ssc/rpms/#{filename}.config"
|
222
|
-
end
|
223
|
-
end
|
224
|
-
end
|
225
|
-
Dir.entries(".ssc/files").each do |file|
|
226
|
-
next unless file =~ /.config$/
|
227
|
-
config = XML::Smart.open(".ssc/files/" + file)
|
228
|
-
filename = file.gsub(/(.*).config$/, "\\1")
|
229
|
-
status = config.find("file/state").first.to_s
|
230
|
-
|
231
|
-
if (status == "added")
|
232
|
-
puts "Uploading #{filename}"
|
233
|
-
s = `curl -u #{$username}:#{$password} -XPOST -F\"file=@#{"files/" + filename}\" http://#{$username}:#{$password}@#{$server_name}/#{$api_prefix}/files?appliance_id=#{appliance} 2> /dev/null`
|
234
|
-
xml = XML::Smart.string(s)
|
235
|
-
id = xml.find("file/id").first.to_s unless xml.find("file/id").length == 0
|
236
|
-
if id
|
237
|
-
FileUtils.cp "files/#{filename}", ".ssc/files/#{filename}.orig"
|
238
|
-
download_file "#{base_url}/files/#{id}", ".ssc/files/#{filename}.config"
|
239
|
-
end
|
240
|
-
elsif (status == "removed")
|
241
|
-
puts "Removing #{filename}"
|
242
|
-
id = config.find("file/id").first.to_s
|
243
|
-
r = Request.new
|
244
|
-
r.method = "DELETE"
|
245
|
-
r.call = "files/#{id}"
|
246
|
-
doRequest(r)
|
247
|
-
FileUtils.rm ".ssc/files/#{filename}.orig"
|
248
|
-
FileUtils.rm ".ssc/files/#{filename}.config"
|
249
|
-
else
|
250
|
-
oldmd5 = `md5sum .ssc/files/#{filename}.orig`.split[0]
|
251
|
-
md5 = `md5sum files/#{filename}`.split[0]
|
252
|
-
if ((status == "synched" or status == "modified") and md5 != oldmd5)
|
253
|
-
id = config.find("file/id").first.to_s
|
254
|
-
puts "Updating #{filename}"
|
255
|
-
`curl -u #{$username}:#{$password} -XPUT -F\"file=@#{"files/" + filename}\" http://#{$username}:#{$password}@#{$server_name}/#{$api_prefix}/files/#{id}/data 2> /dev/null`
|
256
|
-
download_file "#{base_url}/files/#{id}", ".ssc/files/#{filename}.config"
|
257
|
-
end
|
258
|
-
end
|
259
|
-
end
|
260
|
-
end
|
261
|
-
|
262
|
-
def self.add args
|
263
|
-
filename = args[1]
|
264
|
-
unless File.exists?(filename)
|
265
|
-
STDERR.puts "File '#{filename}' does not exist."
|
266
|
-
return 1
|
267
|
-
end
|
268
|
-
path = File.expand_path(filename)
|
269
|
-
basename = File.basename(path)
|
270
|
-
if path =~ /.*\/rpms\/#{basename}/
|
271
|
-
if File.exists?(".ssc/rpms/#{basename}.config")
|
272
|
-
STDERR.puts "File '#{filename}' already belongs to the checkout."
|
273
|
-
return 1
|
274
|
-
end
|
275
|
-
XML::Smart.modify(".ssc/rpms/#{basename}.config","<rpm/>") { |doc|
|
276
|
-
node = doc.root.add("state", "added")
|
277
|
-
}
|
278
|
-
elsif path =~ /.*\/files\/#{basename}/
|
279
|
-
if File.exists?(".ssc/files/#{basename}.config")
|
280
|
-
STDERR.puts "File '#{filename}' already belongs to the checkout."
|
281
|
-
return 1
|
282
|
-
end
|
283
|
-
XML::Smart.modify(".ssc/files/#{basename}.config","<file/>") { |doc|
|
284
|
-
node = doc.root.add("state", "added")
|
285
|
-
}
|
286
|
-
else
|
287
|
-
STDERR.puts "Only files in /rpms and /files can be added."
|
288
|
-
return 1
|
289
|
-
end
|
290
|
-
end
|
291
|
-
|
292
|
-
def self.remove args
|
293
|
-
filename = args[1]
|
294
|
-
path = File.expand_path(filename)
|
295
|
-
basename = File.basename(path)
|
296
|
-
if path =~ /.*\/rpms\/#{basename}/
|
297
|
-
type = "rpm"
|
298
|
-
elsif path =~ /.*\/files\/#{basename}/
|
299
|
-
type = "file"
|
300
|
-
else
|
301
|
-
STDERR.puts "Only files in /rpms and /files can be removed."
|
302
|
-
return 1
|
303
|
-
end
|
304
|
-
unless File.exists?(".ssc/#{type}s/#{basename}.config")
|
305
|
-
STDERR.puts "The file does not belong to the checkout and can not be removed."
|
306
|
-
return 1
|
307
|
-
end
|
308
|
-
|
309
|
-
XML::Smart.modify(".ssc/#{type}s/#{basename}.config") { |doc|
|
310
|
-
nodes = doc.find("#{type}/state")
|
311
|
-
if( nodes.first.to_s == "added" )
|
312
|
-
FileUtils.rm "#{type}s/#{basename}"
|
313
|
-
FileUtils.rm ".ssc/#{type}s/#{basename}.config"
|
314
|
-
else
|
315
|
-
nodes.delete_at!(0)
|
316
|
-
doc.root.add("state", "removed")
|
317
|
-
end
|
318
|
-
}
|
319
|
-
FileUtils.rm filename
|
320
|
-
end
|
321
|
-
|
322
|
-
end
|
data/lib/commandhandler.rb
DELETED
@@ -1,38 +0,0 @@
|
|
1
|
-
#!/usr/bin/env ruby
|
2
|
-
|
3
|
-
require 'request.rb'
|
4
|
-
|
5
|
-
|
6
|
-
class CommandHandler
|
7
|
-
def self.doRequest r
|
8
|
-
xml, success = r.go
|
9
|
-
if success
|
10
|
-
return xml
|
11
|
-
else
|
12
|
-
handle_error xml
|
13
|
-
end
|
14
|
-
end
|
15
|
-
|
16
|
-
def self.handle_error s
|
17
|
-
xml = XML::Smart.string(s)
|
18
|
-
if xml.find("/error/code").length > 0
|
19
|
-
STDERR.puts "Error '#{xml.find("/error/code").first.to_s}' occured.\nMessage: #{xml.find("/error/message").first.to_s}"
|
20
|
-
else
|
21
|
-
STDERR.puts "Server returned: #{s}"
|
22
|
-
end
|
23
|
-
exit 1
|
24
|
-
end
|
25
|
-
|
26
|
-
def self.download_file url, target
|
27
|
-
uri = URI.parse(url)
|
28
|
-
request = Net::HTTP::Get.new(uri.request_uri)
|
29
|
-
request.basic_auth($username, $password)
|
30
|
-
Net::HTTP.start(uri.host, uri.port) do |http|
|
31
|
-
http.read_timeout = 45
|
32
|
-
response = http.request(request)
|
33
|
-
open(target, "wb") do |file|
|
34
|
-
file.write(response.body)
|
35
|
-
end
|
36
|
-
end
|
37
|
-
end
|
38
|
-
end
|
data/lib/request.rb
DELETED
@@ -1,29 +0,0 @@
|
|
1
|
-
class Request
|
2
|
-
attr_accessor :method, :call, :data
|
3
|
-
|
4
|
-
def go
|
5
|
-
uri = URI.parse("#{base_url}/#{call}")
|
6
|
-
request = nil
|
7
|
-
if method == "GET"
|
8
|
-
request = Net::HTTP::Get.new(uri.request_uri)
|
9
|
-
elsif method == "POST"
|
10
|
-
request = Net::HTTP::Post.new(uri.request_uri)
|
11
|
-
request.set_form_data(data, ";") unless data.nil?
|
12
|
-
elsif method == "DELETE"
|
13
|
-
request = Net::HTTP::Delete.new(uri.request_uri)
|
14
|
-
end
|
15
|
-
request.basic_auth($username, $password)
|
16
|
-
begin
|
17
|
-
Net::HTTP.start(uri.host, uri.port) do |http|
|
18
|
-
http.read_timeout = 45
|
19
|
-
response = http.request(request)
|
20
|
-
unless( response.kind_of? Net::HTTPSuccess )
|
21
|
-
return [response.body, false]
|
22
|
-
end
|
23
|
-
return [response.body, true]
|
24
|
-
end
|
25
|
-
rescue => e
|
26
|
-
return ["Error: #{e.to_s}", false]
|
27
|
-
end
|
28
|
-
end
|
29
|
-
end
|