ssc 0.3.0 → 0.4.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/README.rdoc +3 -3
- data/VERSION +1 -1
- data/lib/directory_manager.rb +9 -2
- data/lib/handlers/all.rb +1 -1
- data/lib/handlers/build.rb +1 -1
- data/lib/handlers/file.rb +63 -25
- data/ssc.gemspec +3 -3
- data/test/integration/test_file.rb +77 -6
- data/test/unit/test_directory_manager.rb +60 -0
- metadata +4 -4
data/README.rdoc
CHANGED
@@ -15,9 +15,9 @@ This is the new version of the the Suse Studio command line client. Built as a p
|
|
15
15
|
|
16
16
|
=== Command Listing
|
17
17
|
|
18
|
-
ssc checkout --appliance-id=N --password=PASSWORD --username=USERNAME # checkout the latest changes to an appliance
|
19
|
-
ssc commit --appliance-id=N --password=PASSWORD --username=USERNAME # commit changes to studio
|
20
|
-
ssc status --appliance-id=N --password=PASSWORD --username=USERNAME # show status of the appliance
|
18
|
+
ssc checkout --appliance-id=N --password=PASSWORD --username=USERNAME # checkout the latest changes to an appliance
|
19
|
+
ssc commit --appliance-id=N --password=PASSWORD --username=USERNAME # commit changes to studio
|
20
|
+
ssc status --appliance-id=N --password=PASSWORD --username=USERNAME # show status of the appliance
|
21
21
|
|
22
22
|
ssc appliance # manage appliances
|
23
23
|
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.4.0
|
data/lib/directory_manager.rb
CHANGED
@@ -98,13 +98,13 @@ module SSC
|
|
98
98
|
file_params= options.slice(:permissions, :group, :owner).merge(:path => file_path)
|
99
99
|
push("add", {file_name => file_params})
|
100
100
|
end
|
101
|
-
|
101
|
+
destination_path
|
102
102
|
end
|
103
103
|
|
104
104
|
def is_uploaded?(file_name)
|
105
105
|
read
|
106
106
|
list= @parsed_file["list"].select{|i| i.keys[0] == file_name}
|
107
|
-
list
|
107
|
+
list[0][file_name]["id"] if list.length > 0
|
108
108
|
end
|
109
109
|
|
110
110
|
end
|
@@ -141,6 +141,13 @@ module SSC
|
|
141
141
|
def valid?
|
142
142
|
Dir.exists?(@path) && File.exists?(File.join(@path, '.sscrc'))
|
143
143
|
end
|
144
|
+
|
145
|
+
class << self
|
146
|
+
def show_file(relative_path)
|
147
|
+
path= File.join(@path, relative_path)
|
148
|
+
File.read(path)
|
149
|
+
end
|
150
|
+
end
|
144
151
|
end
|
145
152
|
end
|
146
153
|
end
|
data/lib/handlers/all.rb
CHANGED
data/lib/handlers/build.rb
CHANGED
@@ -8,7 +8,7 @@ module SSC
|
|
8
8
|
require_appliance_id
|
9
9
|
method_option :image_type, :type => :string
|
10
10
|
def build
|
11
|
-
|
11
|
+
require_appliance_directory do |appliance, files|
|
12
12
|
if appliance.status.state != "ok"
|
13
13
|
raise Thor::Error, "Appliance is not OK. Please fix before building.\n#{appliance.status.issues.join("\n")}\n"
|
14
14
|
else
|
data/lib/handlers/file.rb
CHANGED
@@ -49,8 +49,8 @@ module SSC
|
|
49
49
|
require_appliance_id
|
50
50
|
allow_remote_option
|
51
51
|
def remove(file_name)
|
52
|
-
|
53
|
-
file_id=
|
52
|
+
file_list= FileListFile.new
|
53
|
+
file_id= file_list.is_uploaded?(file_name)
|
54
54
|
if options.remote? && file_id
|
55
55
|
begin
|
56
56
|
StudioApi::File.find(file_id).destroy
|
@@ -61,8 +61,8 @@ module SSC
|
|
61
61
|
elsif options.remote? && !file_id
|
62
62
|
raise Thor::Error, "File '#{file_name}' not found"
|
63
63
|
else
|
64
|
-
|
65
|
-
|
64
|
+
file_list.push('remove', {file_name => nil})
|
65
|
+
file_list.save
|
66
66
|
say "File '#{file_name}' marked for removal"
|
67
67
|
end
|
68
68
|
end
|
@@ -70,51 +70,89 @@ module SSC
|
|
70
70
|
desc 'file show FILE_NAME', 'show the contents of the file'
|
71
71
|
require_appliance_id
|
72
72
|
allow_remote_option
|
73
|
+
method_option :file_id, :type => :string
|
73
74
|
def show(file_name)
|
74
75
|
if options.remote?
|
75
|
-
|
76
|
-
|
77
|
-
|
76
|
+
begin
|
77
|
+
require_appliance_directory do |appliance, files|
|
78
|
+
id= files[:file_list].is_uploaded?(file_name)
|
79
|
+
if id
|
80
|
+
response= StudioApi::File.find(id)
|
81
|
+
say response.content
|
82
|
+
else
|
83
|
+
say "File hasn't been uploaded.\nLocal Copy:", :red
|
84
|
+
say ApplianceDirectory.show_file(File.join('files',file_name))
|
85
|
+
end
|
86
|
+
end
|
87
|
+
rescue ApplianceDirectoryError
|
88
|
+
if options.file_id
|
89
|
+
say StudioApi::File.find(options.file_id).content
|
90
|
+
else
|
91
|
+
files= StudioApi::File.find(:all)
|
92
|
+
files= files.select {|f| f.filename == file_name}
|
93
|
+
raise Thor::Error, "File not found or ambiguous file name " unless files.length == 1
|
94
|
+
say files[0].content
|
95
|
+
end
|
96
|
+
end
|
78
97
|
else
|
79
|
-
say show_file(file_name)
|
98
|
+
say ApplianceDirectory.show_file(File.join('files', file_name))
|
80
99
|
end
|
81
100
|
end
|
82
101
|
|
83
102
|
desc 'file diff FILE_NAME', 'show the diff of the remote file and the local one'
|
84
103
|
require_appliance_id
|
85
104
|
def diff(file_name)
|
86
|
-
|
87
|
-
id=
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
begin
|
105
|
+
require_appliance_directory do |appliance, files|
|
106
|
+
id= files[:file_list].is_uploaded?(file_name)
|
107
|
+
raise Thor::Error, "File hasn't been uploaded" unless id
|
108
|
+
response= StudioApi::File.find(id)
|
109
|
+
remote_content= response.content
|
110
|
+
local_file= File.join(Dir.pwd, 'files', file_name)
|
94
111
|
tempfile=Tempfile.new('ssc_file')
|
95
|
-
tempfile.write(
|
96
|
-
say find_diff(tempfile.path,
|
112
|
+
tempfile.write(remote_content)
|
113
|
+
say find_diff(tempfile.path, local_file)
|
97
114
|
tempfile.close; tempfile.unlink
|
98
|
-
rescue Errno::ENOENT
|
99
|
-
say "diff not installed", :red
|
100
115
|
end
|
116
|
+
rescue ApplianceDirectoryError
|
117
|
+
raise Thor::Error, "diff can only be performed in the appliance directory"
|
101
118
|
end
|
102
119
|
|
103
120
|
desc 'file list', 'show all overlay files'
|
104
121
|
require_appliance_id
|
105
122
|
allow_remote_option
|
106
123
|
def list
|
107
|
-
|
108
|
-
|
124
|
+
require_appliance_directory do |appliance, files|
|
125
|
+
file_list= files[:file_list]
|
126
|
+
out= if options.remote? || file_list.empty_list?
|
109
127
|
response= StudioApi::File.find(:all, :params => {:appliance_id => appliance.id})
|
110
|
-
response.collect do |file|
|
111
|
-
{file.filename => {"id" => file.id, "path" => file.path}}
|
128
|
+
response= response.collect do |file|
|
129
|
+
item= {file.filename => {"id" => file.id, "path" => file.path}}
|
130
|
+
file_list.push('list', item)
|
112
131
|
end
|
132
|
+
file_list.save
|
133
|
+
response
|
113
134
|
else
|
114
|
-
|
135
|
+
file_list["list"]
|
115
136
|
end
|
116
137
|
say out.to_yaml
|
117
138
|
end
|
139
|
+
rescue ApplianceDirectoryError
|
140
|
+
require_appliance do |appliance|
|
141
|
+
print_table StudioApi::File.find(:all, :params => {:appliance_id => appliance.id}).collect do |file|
|
142
|
+
[file.id, File.join(file.path, file.filename)]
|
143
|
+
end
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
private
|
148
|
+
|
149
|
+
def get_file_list(appliance_id)
|
150
|
+
end
|
151
|
+
|
152
|
+
def find_diff(file1, file2)
|
153
|
+
`diff #{file1} #{file2}`
|
154
|
+
rescue Errno::ENOENT
|
155
|
+
raise Thor::Error, "'diff' not installed"
|
118
156
|
end
|
119
157
|
end
|
120
158
|
end
|
data/ssc.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{ssc}
|
8
|
-
s.version = "0.
|
8
|
+
s.version = "0.4.0"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Ratan Sebastian"]
|
12
|
-
s.date = %q{2011-08-
|
12
|
+
s.date = %q{2011-08-31}
|
13
13
|
s.default_executable = %q{ssc}
|
14
14
|
s.description = %q{Command-line client for Suse Studio}
|
15
15
|
s.email = %q{rjsvaljean@gmail.com}
|
@@ -46,7 +46,7 @@ Gem::Specification.new do |s|
|
|
46
46
|
s.licenses = ["MIT"]
|
47
47
|
s.require_paths = ["lib"]
|
48
48
|
s.rubygems_version = %q{1.3.7}
|
49
|
-
s.summary = %q{Command-line client for Suse Studio}
|
49
|
+
s.summary = %q{Command-line client for Suse Studio.}
|
50
50
|
|
51
51
|
if s.respond_to? :specification_version then
|
52
52
|
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
@@ -1,6 +1,9 @@
|
|
1
1
|
require 'helper'
|
2
2
|
|
3
3
|
class TestOverlayFile < Test::Unit::TestCase
|
4
|
+
|
5
|
+
include SSC::DirectoryManager
|
6
|
+
|
4
7
|
context "file" do
|
5
8
|
setup do
|
6
9
|
@client= SSC::Client.new
|
@@ -10,7 +13,7 @@ class TestOverlayFile < Test::Unit::TestCase
|
|
10
13
|
StudioApi::Appliance.stubs(:clone).returns(@default_mock_appliance)
|
11
14
|
@client.invoke('s_s_c:handler:appliance:create', ['test_appliance'], {:source_id => 1234}.merge(@auth_params))
|
12
15
|
@default_mock_package= StudioApi::Package.new('test_package', :version => '1', :repository_id => 9876)
|
13
|
-
StudioApi::Appliance.stubs(:find).
|
16
|
+
StudioApi::Appliance.stubs(:find).returns(@default_mock_appliance)
|
14
17
|
end
|
15
18
|
context "add" do
|
16
19
|
setup do
|
@@ -25,7 +28,7 @@ class TestOverlayFile < Test::Unit::TestCase
|
|
25
28
|
should "upload file and create a new file locally" do
|
26
29
|
StudioApi::File.expects(:upload).returns(stub(:id => 1))
|
27
30
|
mock_file_list= mock()
|
28
|
-
|
31
|
+
FileListFile.stubs(:new).returns(mock_file_list)
|
29
32
|
mock_file_list.expects(:initiate_file).with(@test_file_path, anything)
|
30
33
|
@client.invoke('s_s_c:handler:overlay_file:add', [@test_file_path], {:remote => true, :appliance_id => 5678})
|
31
34
|
end
|
@@ -33,7 +36,7 @@ class TestOverlayFile < Test::Unit::TestCase
|
|
33
36
|
context "when the remote flag is not set" do
|
34
37
|
should "just add the file to the file_list in the add section" do
|
35
38
|
mock_file_list= mock()
|
36
|
-
|
39
|
+
FileListFile.stubs(:new).returns(mock_file_list)
|
37
40
|
mock_file_list.expects(:initiate_file).with(@test_file_path, anything)
|
38
41
|
@client.invoke('s_s_c:handler:overlay_file:add', [@test_file_path], {:appliance_id => 5678})
|
39
42
|
end
|
@@ -42,7 +45,7 @@ class TestOverlayFile < Test::Unit::TestCase
|
|
42
45
|
context "when not in the appliance directory" do
|
43
46
|
setup do
|
44
47
|
Dir.chdir('..') if File.exist?('./.sscrc')
|
45
|
-
|
48
|
+
ApplianceDirectory.any_instance.stubs(:valid).returns(false)
|
46
49
|
end
|
47
50
|
context "when the remote flag is set" do
|
48
51
|
should "just upload the file" do
|
@@ -56,7 +59,7 @@ class TestOverlayFile < Test::Unit::TestCase
|
|
56
59
|
context "remove" do
|
57
60
|
context "when the remote flag is set" do
|
58
61
|
should "destroy the file remotely" do
|
59
|
-
|
62
|
+
FileListFile.any_instance.stubs(:is_uploaded?).returns(:id)
|
60
63
|
mock_file_object= mock()
|
61
64
|
mock_file_object.expects(:destroy)
|
62
65
|
StudioApi::File.expects(:find).with(:id).returns(mock_file_object)
|
@@ -70,11 +73,79 @@ class TestOverlayFile < Test::Unit::TestCase
|
|
70
73
|
mock_file_list.stubs(:is_uploaded?).returns(:id)
|
71
74
|
mock_file_list.expects(:push).with('remove', has_key('test_file'))
|
72
75
|
mock_file_list.expects(:save)
|
73
|
-
|
76
|
+
FileListFile.stubs(:new).returns(mock_file_list)
|
74
77
|
@client.invoke('s_s_c:handler:overlay_file:remove', ["test_file"], {})
|
75
78
|
end
|
76
79
|
end
|
77
80
|
end
|
81
|
+
context "show" do
|
82
|
+
context "when not in the appliance directory" do
|
83
|
+
setup do
|
84
|
+
Dir.chdir('..') if File.exists?('.sscrc')
|
85
|
+
end
|
86
|
+
context "and when the remote flag is set with the file_id option" do
|
87
|
+
should "show the file using the file_id" do
|
88
|
+
StudioApi::File.expects(:find).with(1).returns(stub(:content => ''))
|
89
|
+
@client.invoke('s_s_c:handler:overlay_file:show', ['test_file'], @appliance_params.merge({:remote => true, :file_id => 1}))
|
90
|
+
end
|
91
|
+
end
|
92
|
+
context "and when the remote flag is set without the file_id option" do
|
93
|
+
should "show the file using the file_name" do
|
94
|
+
StudioApi::File.expects(:find).with(:all).returns([stub(:content => '', :filename => 'test_file')])
|
95
|
+
@client.invoke('s_s_c:handler:overlay_file:show', ['test_file'], @appliance_params.merge({:remote => true}))
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
context "when in the appliance directory" do
|
100
|
+
setup do
|
101
|
+
Dir.chdir('test_appliance') if Dir.exists?('test_appliance')
|
102
|
+
end
|
103
|
+
context "and when the remote flag is set" do
|
104
|
+
should "show the file if file has been uploaded" do
|
105
|
+
FileListFile.any_instance.stubs(:is_uploaded?).returns(:id)
|
106
|
+
StudioApi::File.expects(:find).with(:id).returns(stub(:content => ''))
|
107
|
+
@client.invoke('s_s_c:handler:overlay_file:show', ['test_file'], @appliance_params.merge({:remote => true}))
|
108
|
+
end
|
109
|
+
|
110
|
+
should "show the local file if the file hasn't been uploaded" do
|
111
|
+
FileListFile.any_instance.stubs(:is_uploaded?).returns(nil)
|
112
|
+
ApplianceDirectory.expects(:show_file).with('files/test_file')
|
113
|
+
@client.invoke('s_s_c:handler:overlay_file:show', ['test_file'], @appliance_params.merge({:remote => true}))
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
context "diff" do
|
120
|
+
context "when in the appliance directory" do
|
121
|
+
setup do
|
122
|
+
Dir.chdir('test_appliance') if Dir.exists?('test_appliance')
|
123
|
+
File.open('files/test_file', 'w') {|f| f.write('test')}
|
124
|
+
end
|
125
|
+
should "show the diff of the two files" do
|
126
|
+
FileListFile.any_instance.expects(:is_uploaded?).returns(:id)
|
127
|
+
StudioApi::File.expects(:find).with(:id).returns(stub(:content => ''))
|
128
|
+
@client.invoke('s_s_c:handler:overlay_file:diff', ['test_file'], @appliance_params)
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
context "list" do
|
134
|
+
context "when in an appliance directory" do
|
135
|
+
setup do
|
136
|
+
Dir.chdir('test_appliance') if Dir.exists?('test_appliance')
|
137
|
+
end
|
138
|
+
should "list the files and save to the file list file" do
|
139
|
+
FileListFile.any_instance.stubs(:empty_list? => true, :push => {}, :[] => {})
|
140
|
+
mock_file= StudioApi::File.new(:path => 'path', :id => 1,
|
141
|
+
:filename => 'filename')
|
142
|
+
StudioApi::File.expects(:find).with(:all, anything).returns([mock_file])
|
143
|
+
@client.invoke('s_s_c:handler:overlay_file:list', [], @appliance_params)
|
144
|
+
end
|
145
|
+
end
|
146
|
+
context "when not in an appliance directory" do
|
147
|
+
end
|
148
|
+
end
|
78
149
|
end
|
79
150
|
|
80
151
|
|
@@ -1,5 +1,49 @@
|
|
1
1
|
require 'helper'
|
2
2
|
|
3
|
+
class TestFileListFile < Test::Unit::TestCase
|
4
|
+
include SSC::DirectoryManager
|
5
|
+
|
6
|
+
def setup
|
7
|
+
@file_list_file= FileListFile.new
|
8
|
+
@data = {"list" => [{'file2' => {'path' => '/file/path'}},
|
9
|
+
{'file1' => {'id' => 1,
|
10
|
+
'path' => '/file/path',
|
11
|
+
'owner' => 'root',
|
12
|
+
'group' => 'root' }}],
|
13
|
+
"add" => [],
|
14
|
+
"remove" => []}
|
15
|
+
@file_list_file.instance_variable_set('@parsed_file', @data)
|
16
|
+
end
|
17
|
+
|
18
|
+
context "#pop" do
|
19
|
+
should "reformat the file list hash" do
|
20
|
+
assert_equal({:name=>"file1", :full_path=>"/file/path",
|
21
|
+
:params=>{"owner"=>"root", "group"=>"root"}},
|
22
|
+
@file_list_file.pop('list'))
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
context "#initiate_file" do
|
27
|
+
should "create a file and make an entry in the file_list file" do
|
28
|
+
FileUtils.mkdir_p('files')
|
29
|
+
File.open('test_file', 'w') {|f| f.write('test')}
|
30
|
+
@file_list_file.initiate_file('test_file', {'key' => 'value'})
|
31
|
+
assert File.exists? 'files/test_file'
|
32
|
+
FileUtils.rm_rf('files')
|
33
|
+
FileUtils.rm('test_file')
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
context "#is_uploaded?" do
|
38
|
+
should "return the id if the file is uploaded" do
|
39
|
+
assert_equal 1, @file_list_file.is_uploaded?('file1')
|
40
|
+
end
|
41
|
+
should "return false if file is not uploaded" do
|
42
|
+
assert_equal nil, @file_list_file.is_uploaded?('file2')
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
3
47
|
class TestDirectoryManager < Test::Unit::TestCase
|
4
48
|
include SSC::DirectoryManager
|
5
49
|
|
@@ -40,6 +84,9 @@ class TestDirectoryManager < Test::Unit::TestCase
|
|
40
84
|
assert_equal 4, @file.pop('add')
|
41
85
|
assert !@file.instance_variable_get('@parsed_file')["add"].include?(4)
|
42
86
|
end
|
87
|
+
should "return nil if the section is empty" do
|
88
|
+
assert_equal nil, @file.pop("empty_section")
|
89
|
+
end
|
43
90
|
end
|
44
91
|
|
45
92
|
context "#push" do
|
@@ -58,6 +105,19 @@ class TestDirectoryManager < Test::Unit::TestCase
|
|
58
105
|
end
|
59
106
|
end
|
60
107
|
|
108
|
+
context "#[]" do
|
109
|
+
context "when the section exists" do
|
110
|
+
should "return the list from the section" do
|
111
|
+
assert @file["add"] == [{"sub" => {1 => "one", 2 => "two"}}, 2, 3, 4]
|
112
|
+
end
|
113
|
+
end
|
114
|
+
context "when the section does not exist" do
|
115
|
+
should "return a empty list" do
|
116
|
+
assert @file["empty_section"] == []
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
61
121
|
context "#read" do
|
62
122
|
should "return the parsed contents of the file if the file is available" do
|
63
123
|
assert @file.read.is_a?(Hash)
|
metadata
CHANGED
@@ -4,9 +4,9 @@ version: !ruby/object:Gem::Version
|
|
4
4
|
prerelease: false
|
5
5
|
segments:
|
6
6
|
- 0
|
7
|
-
-
|
7
|
+
- 4
|
8
8
|
- 0
|
9
|
-
version: 0.
|
9
|
+
version: 0.4.0
|
10
10
|
platform: ruby
|
11
11
|
authors:
|
12
12
|
- Ratan Sebastian
|
@@ -14,7 +14,7 @@ autorequire:
|
|
14
14
|
bindir: bin
|
15
15
|
cert_chain: []
|
16
16
|
|
17
|
-
date: 2011-08-
|
17
|
+
date: 2011-08-31 00:00:00 +02:00
|
18
18
|
default_executable: ssc
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|
@@ -179,6 +179,6 @@ rubyforge_project:
|
|
179
179
|
rubygems_version: 1.3.7
|
180
180
|
signing_key:
|
181
181
|
specification_version: 3
|
182
|
-
summary: Command-line client for Suse Studio
|
182
|
+
summary: Command-line client for Suse Studio.
|
183
183
|
test_files: []
|
184
184
|
|