ssc 0.3.0 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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.3.0
1
+ 0.4.0
@@ -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
- destination_file
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.length > 0 ? list[0]["id"].to_i : nil
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
@@ -12,7 +12,7 @@ module SSC
12
12
 
13
13
  include Helper
14
14
 
15
- API_URL= 'https://susestudio.com/api/v1/user'
15
+ API_URL= 'https://susestudio.com/api/v2/user'
16
16
 
17
17
  def initialize(*args)
18
18
  super
@@ -8,7 +8,7 @@ module SSC
8
8
  require_appliance_id
9
9
  method_option :image_type, :type => :string
10
10
  def build
11
- require_appliance_dir do |appliance, files|
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
@@ -49,8 +49,8 @@ module SSC
49
49
  require_appliance_id
50
50
  allow_remote_option
51
51
  def remove(file_name)
52
- @file_list= FileListFile.new
53
- file_id= @file_list.is_uploaded?(file_name)
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
- @file_list.push('remove', {file_name => nil})
65
- @file_list.save
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
- id= find_file_id(file_name)
76
- response= StudioApi::File.find(id)
77
- say response.content
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
- begin
87
- id= find_file_id(file_name)
88
- file_content= StudioApi::File.find(id).content
89
- rescue
90
- say "unable to connect or not in appliance directory", :red
91
- end
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(file_content)
96
- say find_diff(tempfile.path, full_local_file_path(file_name))
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
- require_appliance do |appliance|
108
- out= if options.remote? || file_list_empty?
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
- list_local_files
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
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{ssc}
8
- s.version = "0.3.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-15}
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).with(5678).returns(@default_mock_appliance)
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
- SSC::DirectoryManager::FileListFile.stubs(:new).returns(mock_file_list)
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
- SSC::DirectoryManager::FileListFile.stubs(:new).returns(mock_file_list)
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
- SSC::DirectoryManager::ApplianceDirectory.any_instance.stubs(:valid).returns(false)
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
- SSC::DirectoryManager::FileListFile.any_instance.stubs(:is_uploaded?).returns(:id)
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
- SSC::DirectoryManager::FileListFile.stubs(:new).returns(mock_file_list)
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
- - 3
7
+ - 4
8
8
  - 0
9
- version: 0.3.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-15 00:00:00 +02:00
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