knife-essentials 0.8.4 → 0.8.5

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.
Files changed (38) hide show
  1. data/lib/chef/knife/delete_essentials.rb +37 -8
  2. data/lib/chef/knife/deps_essentials.rb +5 -5
  3. data/lib/chef/knife/diff_essentials.rb +9 -1
  4. data/lib/chef/knife/download_essentials.rb +1 -1
  5. data/lib/chef/knife/list_essentials.rb +5 -5
  6. data/lib/chef/knife/raw_essentials.rb +7 -2
  7. data/lib/chef/knife/show_essentials.rb +14 -4
  8. data/lib/chef/knife/upload_essentials.rb +1 -1
  9. data/lib/chef_fs/command_line.rb +18 -10
  10. data/lib/chef_fs/file_system.rb +4 -4
  11. data/lib/chef_fs/file_system/base_fs_object.rb +10 -10
  12. data/lib/chef_fs/file_system/chef_repository_file_system_root_dir.rb +1 -1
  13. data/lib/chef_fs/file_system/chef_server_root_dir.rb +0 -2
  14. data/lib/chef_fs/file_system/cookbook_dir.rb +17 -12
  15. data/lib/chef_fs/file_system/cookbooks_dir.rb +1 -1
  16. data/lib/chef_fs/file_system/data_bag_dir.rb +4 -3
  17. data/lib/chef_fs/file_system/data_bag_item.rb +1 -1
  18. data/lib/chef_fs/file_system/data_bags_dir.rb +2 -2
  19. data/lib/chef_fs/file_system/{operation_skipped_error.rb → default_environment_cannot_be_modified_error.rb} +8 -3
  20. data/lib/chef_fs/file_system/environments_dir.rb +5 -7
  21. data/lib/chef_fs/file_system/file_system_entry.rb +6 -6
  22. data/lib/chef_fs/file_system/must_delete_recursively_error.rb +4 -1
  23. data/lib/chef_fs/file_system/nodes_dir.rb +2 -2
  24. data/lib/chef_fs/file_system/nonexistent_fs_object.rb +0 -12
  25. data/lib/chef_fs/file_system/not_found_error.rb +4 -1
  26. data/lib/chef_fs/file_system/operation_not_allowed_error.rb +19 -1
  27. data/lib/chef_fs/file_system/rest_list_dir.rb +2 -2
  28. data/lib/chef_fs/file_system/rest_list_entry.rb +3 -3
  29. data/lib/chef_fs/knife.rb +5 -4
  30. data/lib/chef_fs/path_utils.rb +6 -4
  31. data/lib/chef_fs/version.rb +1 -1
  32. data/spec/integration/delete_spec.rb +684 -0
  33. data/spec/integration/diff_spec.rb +75 -1
  34. data/spec/integration/download_spec.rb +101 -4
  35. data/spec/integration/raw_spec.rb +171 -0
  36. data/spec/integration/show_spec.rb +124 -0
  37. data/spec/integration/upload_spec.rb +122 -13
  38. metadata +6 -3
@@ -99,6 +99,7 @@ module ChefFS
99
99
  container.add_child(CookbookFile.new(parts[parts.length-1], container, segment_file))
100
100
  end
101
101
  end
102
+ @children = @children.sort_by { |c| c.name }
102
103
  end
103
104
  @children
104
105
  end
@@ -107,16 +108,18 @@ module ChefFS
107
108
  exists?
108
109
  end
109
110
 
110
- def read
111
- # This will only be called if dir? is false, which means exists? is false.
112
- raise ChefFS::FileSystem::NotFoundError, path_for_printing
113
- end
114
-
115
111
  def delete(recurse)
116
112
  if recurse
117
- rest.delete_rest(api_path)
113
+ begin
114
+ rest.delete_rest(api_path)
115
+ rescue Net::HTTPServerException
116
+ if $!.response.code == "404"
117
+ raise ChefFS::FileSystem::NotFoundError.new(self, $!)
118
+ end
119
+ end
118
120
  else
119
- raise ChefFS::FileSystem::MustDeleteRecursivelyError.new, "#{path_for_printing} must be deleted recursively"
121
+ raise NotFoundError.new(self) if !exists?
122
+ raise MustDeleteRecursivelyError.new(self), "#{path_for_printing} must be deleted recursively"
120
123
  end
121
124
  end
122
125
 
@@ -133,8 +136,10 @@ module ChefFS
133
136
  return [ !exists?, nil, nil ]
134
137
  end
135
138
  are_same = true
136
- ChefFS::CommandLine::diff_entries(self, other, nil, :name_only) do
137
- are_same = false
139
+ ChefFS::CommandLine::diff_entries(self, other, nil, :name_only) do |type, old_entry, new_entry|
140
+ if [ :directory_to_file, :file_to_directory, :deleted, :added, :modified ].include?(type)
141
+ are_same = false
142
+ end
138
143
  end
139
144
  [ are_same, nil, nil ]
140
145
  end
@@ -154,7 +159,7 @@ module ChefFS
154
159
 
155
160
  # The negative (not found) response is cached
156
161
  if @could_not_get_chef_object
157
- raise ChefFS::FileSystem::NotFoundError.new(@could_not_get_chef_object), "#{path_for_printing} not found"
162
+ raise ChefFS::FileSystem::NotFoundError.new(self, @could_not_get_chef_object)
158
163
  end
159
164
 
160
165
  begin
@@ -173,7 +178,7 @@ module ChefFS
173
178
  rescue Net::HTTPServerException
174
179
  if $!.response.code == "404"
175
180
  @could_not_get_chef_object = $!
176
- raise ChefFS::FileSystem::NotFoundError.new(@could_not_get_chef_object), "#{path_for_printing} not found"
181
+ raise ChefFS::FileSystem::NotFoundError.new(self, @could_not_get_chef_object)
177
182
  else
178
183
  raise
179
184
  end
@@ -183,7 +188,7 @@ module ChefFS
183
188
  rescue Net::HTTPFatalError
184
189
  if $!.response.code == "500"
185
190
  @could_not_get_chef_object = $!
186
- raise ChefFS::FileSystem::NotFoundError.new(@could_not_get_chef_object), "#{path_for_printing} not found"
191
+ raise ChefFS::FileSystem::NotFoundError.new(self, @could_not_get_chef_object)
187
192
  else
188
193
  raise
189
194
  end
@@ -32,7 +32,7 @@ module ChefFS
32
32
  end
33
33
 
34
34
  def children
35
- @children ||= rest.get_rest(api_path).map { |key, value| CookbookDir.new(key, self, value) }
35
+ @children ||= rest.get_rest(api_path).map { |key, value| CookbookDir.new(key, self, value) }.sort_by { |c| c.name }
36
36
  end
37
37
 
38
38
  def create_child_from(other)
@@ -35,7 +35,7 @@ module ChefFS
35
35
 
36
36
  def read
37
37
  # This will only be called if dir? is false, which means exists? is false.
38
- raise ChefFS::FileSystem::NotFoundError, "#{path_for_printing} not found"
38
+ raise ChefFS::FileSystem::NotFoundError.new(self)
39
39
  end
40
40
 
41
41
  def exists?
@@ -61,13 +61,14 @@ module ChefFS
61
61
 
62
62
  def delete(recurse)
63
63
  if !recurse
64
- raise ChefFS::FileSystem::MustDeleteRecursivelyError.new, "#{path_for_printing} must be deleted recursively"
64
+ raise NotFoundError.new(self) if !exists?
65
+ raise MustDeleteRecursivelyError.new(self), "#{path_for_printing} must be deleted recursively"
65
66
  end
66
67
  begin
67
68
  rest.delete_rest(api_path)
68
69
  rescue Net::HTTPServerException
69
70
  if $!.response.code == "404"
70
- raise ChefFS::FileSystem::NotFoundError.new($!), "#{path_for_printing} not found"
71
+ raise ChefFS::FileSystem::NotFoundError.new(self, $!)
71
72
  end
72
73
  end
73
74
  end
@@ -46,7 +46,7 @@ module ChefFS
46
46
  rest.put_rest(api_path, json)
47
47
  rescue Net::HTTPServerException
48
48
  if $!.response.code == "404"
49
- raise ChefFS::FileSystem::NotFoundError.new($!), "#{path_for_printing} not found"
49
+ raise ChefFS::FileSystem::NotFoundError.new(self, $!)
50
50
  else
51
51
  raise
52
52
  end
@@ -33,12 +33,12 @@ module ChefFS
33
33
 
34
34
  def children
35
35
  begin
36
- @children ||= rest.get_rest(api_path).keys.map do |entry|
36
+ @children ||= rest.get_rest(api_path).keys.sort.map do |entry|
37
37
  DataBagDir.new(entry, self, true)
38
38
  end
39
39
  rescue Net::HTTPServerException
40
40
  if $!.response.code == "404"
41
- raise ChefFS::FileSystem::NotFoundError.new($!), "#{path_for_printing} not found"
41
+ raise ChefFS::FileSystem::NotFoundError.new(self, $!)
42
42
  else
43
43
  raise
44
44
  end
@@ -20,9 +20,14 @@ require 'chef_fs/file_system/operation_not_allowed_error'
20
20
 
21
21
  module ChefFS
22
22
  module FileSystem
23
- class OperationSkippedError < OperationNotAllowedError
24
- def initialize(operation, cause = nil)
25
- super(operation, cause)
23
+ class DefaultEnvironmentCannotBeModifiedError < OperationNotAllowedError
24
+ def initialize(operation, entry, cause = nil)
25
+ super(operation, entry, cause)
26
+ end
27
+
28
+ def reason
29
+ result = super
30
+ result + " (default environment cannot be modified)"
26
31
  end
27
32
  end
28
33
  end
@@ -19,7 +19,7 @@
19
19
  require 'chef_fs/file_system/base_fs_dir'
20
20
  require 'chef_fs/file_system/rest_list_entry'
21
21
  require 'chef_fs/file_system/not_found_error'
22
- require 'chef_fs/file_system/operation_skipped_error'
22
+ require 'chef_fs/file_system/default_environment_cannot_be_modified_error'
23
23
 
24
24
  module ChefFS
25
25
  module FileSystem
@@ -43,15 +43,13 @@ module ChefFS
43
43
  end
44
44
 
45
45
  def delete(recurse)
46
- Chef::Log.warn("The default environment (#{name}) cannot be deleted. Skipping.")
47
- raise NotFoundError, "Nonexistent #{path_for_printing}" if !exists?
48
- raise OperationSkippedError.new(:delete), "#{path_for_printing} cannot be deleted."
46
+ raise NotFoundError.new(self) if !exists?
47
+ raise DefaultEnvironmentCannotBeModifiedError.new(:delete, self), "#{path_for_printing} cannot be deleted."
49
48
  end
50
49
 
51
50
  def write(file_contents)
52
- Chef::Log.warn("The default environment (#{name}) cannot be deleted. Skipping.")
53
- raise NotFoundError, "Nonexistent #{path_for_printing}" if !exists?
54
- raise OperationSkippedError.new(:write), "#{path_for_printing} cannot be updated."
51
+ raise NotFoundError.new(self) if !exists?
52
+ raise DefaultEnvironmentCannotBeModifiedError.new(:write, self), "#{path_for_printing} cannot be updated."
55
53
  end
56
54
  end
57
55
  end
@@ -19,6 +19,7 @@
19
19
  require 'chef_fs/file_system/base_fs_dir'
20
20
  require 'chef_fs/file_system/rest_list_dir'
21
21
  require 'chef_fs/file_system/not_found_error'
22
+ require 'chef_fs/file_system/must_delete_recursively_error'
22
23
  require 'chef_fs/path_utils'
23
24
  require 'fileutils'
24
25
 
@@ -40,7 +41,7 @@ module ChefFS
40
41
  begin
41
42
  @children ||= Dir.entries(file_path).select { |entry| entry != '.' && entry != '..' }.map { |entry| FileSystemEntry.new(entry, self) }
42
43
  rescue Errno::ENOENT
43
- raise ChefFS::FileSystem::NotFoundError.new($!), "#{file_path} not found"
44
+ raise ChefFS::FileSystem::NotFoundError.new(self, $!)
44
45
  end
45
46
  end
46
47
 
@@ -60,11 +61,10 @@ module ChefFS
60
61
 
61
62
  def delete(recurse)
62
63
  if dir?
63
- if recurse
64
- FileUtils.rm_rf(file_path)
65
- else
66
- File.rmdir(file_path)
64
+ if !recurse
65
+ raise MustDeleteRecursivelyError.new(self, $!)
67
66
  end
67
+ FileUtils.rm_rf(file_path)
68
68
  else
69
69
  File.delete(file_path)
70
70
  end
@@ -74,7 +74,7 @@ module ChefFS
74
74
  begin
75
75
  File.open(file_path, "rb") {|f| f.read}
76
76
  rescue Errno::ENOENT
77
- raise ChefFS::FileSystem::NotFoundError.new($!), "#{file_path} not found"
77
+ raise ChefFS::FileSystem::NotFoundError.new(self, $!)
78
78
  end
79
79
  end
80
80
 
@@ -21,9 +21,12 @@ require 'chef_fs/file_system/file_system_error'
21
21
  module ChefFS
22
22
  module FileSystem
23
23
  class MustDeleteRecursivelyError < FileSystemError
24
- def initialize(cause = nil)
24
+ def initialize(entry, cause = nil)
25
25
  super(cause)
26
+ @entry = entry
26
27
  end
28
+
29
+ attr_reader :entry
27
30
  end
28
31
  end
29
32
  end
@@ -32,10 +32,10 @@ module ChefFS
32
32
  def children
33
33
  @children ||= begin
34
34
  env_api_path = environment ? "environments/#{environment}/#{api_path}" : api_path
35
- rest.get_rest(env_api_path).keys.map { |key| RestListEntry.new("#{key}.json", self, true) }
35
+ rest.get_rest(env_api_path).keys.sort.map { |key| RestListEntry.new("#{key}.json", self, true) }
36
36
  rescue Net::HTTPServerException
37
37
  if $!.response.code == "404"
38
- raise ChefFS::FileSystem::NotFoundError.new($!), "#{path_for_printing} not found"
38
+ raise ChefFS::FileSystem::NotFoundError.new(self, $!)
39
39
  else
40
40
  raise
41
41
  end
@@ -29,18 +29,6 @@ module ChefFS
29
29
  def exists?
30
30
  false
31
31
  end
32
-
33
- def read
34
- raise ChefFS::FileSystem::NotFoundError, "Nonexistent #{path_for_printing}"
35
- end
36
-
37
- def write(contents)
38
- raise ChefFS::FileSystem::NotFoundError, "Nonexistent #{path_for_printing}"
39
- end
40
-
41
- def delete(recurse)
42
- raise ChefFS::FileSystem::NotFoundError, "Nonexistent #{path_for_printing}"
43
- end
44
32
  end
45
33
  end
46
34
  end
@@ -21,9 +21,12 @@ require 'chef_fs/file_system/file_system_error'
21
21
  module ChefFS
22
22
  module FileSystem
23
23
  class NotFoundError < FileSystemError
24
- def initialize(cause = nil)
24
+ def initialize(entry, cause = nil)
25
25
  super(cause)
26
+ @entry = entry
26
27
  end
28
+
29
+ attr_reader :entry
27
30
  end
28
31
  end
29
32
  end
@@ -21,8 +21,26 @@ require 'chef_fs/file_system/file_system_error'
21
21
  module ChefFS
22
22
  module FileSystem
23
23
  class OperationNotAllowedError < FileSystemError
24
- def initialize(operation, cause = nil)
24
+ def initialize(operation, entry, cause = nil)
25
25
  super(cause)
26
+ @operation = operation
27
+ @entry = entry
28
+ end
29
+
30
+ attr_reader :operation
31
+ attr_reader :entry
32
+
33
+ def reason
34
+ case operation
35
+ when :delete
36
+ "cannot be deleted"
37
+ when :write
38
+ "cannot be updated"
39
+ when :create_child
40
+ "cannot have a child created under it"
41
+ when :read
42
+ "cannot be read"
43
+ end
26
44
  end
27
45
  end
28
46
  end
@@ -42,12 +42,12 @@ module ChefFS
42
42
 
43
43
  def children
44
44
  begin
45
- @children ||= rest.get_rest(api_path).keys.map do |key|
45
+ @children ||= rest.get_rest(api_path).keys.sort.map do |key|
46
46
  _make_child_entry("#{key}.json", true)
47
47
  end
48
48
  rescue Net::HTTPServerException
49
49
  if $!.response.code == "404"
50
- raise ChefFS::FileSystem::NotFoundError.new($!), "#{path_for_printing} not found"
50
+ raise ChefFS::FileSystem::NotFoundError.new(self, $!)
51
51
  else
52
52
  raise
53
53
  end
@@ -57,7 +57,7 @@ module ChefFS
57
57
  rest.delete_rest(api_path)
58
58
  rescue Net::HTTPServerException
59
59
  if $!.response.code == "404"
60
- raise ChefFS::FileSystem::NotFoundError.new($!), "#{path_for_printing} not found"
60
+ raise ChefFS::FileSystem::NotFoundError.new(self, $!)
61
61
  else
62
62
  raise
63
63
  end
@@ -74,7 +74,7 @@ module ChefFS
74
74
  rest.get_rest(api_path)
75
75
  rescue Net::HTTPServerException
76
76
  if $!.response.code == "404"
77
- raise ChefFS::FileSystem::NotFoundError.new($!), "#{path_for_printing} not found"
77
+ raise ChefFS::FileSystem::NotFoundError.new(self, $!)
78
78
  else
79
79
  raise
80
80
  end
@@ -110,7 +110,7 @@ module ChefFS
110
110
  rest.put_rest(api_path, json)
111
111
  rescue Net::HTTPServerException
112
112
  if $!.response.code == "404"
113
- raise ChefFS::FileSystem::NotFoundError.new($!), "#{path_for_printing} not found"
113
+ raise ChefFS::FileSystem::NotFoundError.new(self, $!)
114
114
  else
115
115
  raise
116
116
  end
data/lib/chef_fs/knife.rb CHANGED
@@ -124,7 +124,7 @@ module ChefFS
124
124
  realest_path = ChefFS::PathUtils.realest_path(path)
125
125
  if absolute_path[0,realest_path.length] == realest_path &&
126
126
  (absolute_path.length == realest_path.length ||
127
- absolute_path[realest_path.length] =~ /#{PathUtils.regexp_path_separator}/)
127
+ absolute_path[realest_path.length,1] =~ /#{PathUtils.regexp_path_separator}/)
128
128
  relative_path = ChefFS::PathUtils::relative_to(absolute_path, realest_path)
129
129
  return relative_path == '.' ? "/#{name}" : "/#{name}/#{relative_path}"
130
130
  end
@@ -148,13 +148,14 @@ module ChefFS
148
148
  end
149
149
 
150
150
  # Print the given server path, relative to the current directory
151
- def format_path(server_path)
151
+ def format_path(entry)
152
+ server_path = entry.path
152
153
  if base_path && server_path[0,base_path.length] == base_path
153
154
  if server_path == base_path
154
155
  return "."
155
- elsif server_path[base_path.length] == "/"
156
+ elsif server_path[base_path.length,1] == "/"
156
157
  return server_path[base_path.length + 1, server_path.length - base_path.length - 1]
157
- elsif base_path == "/" && server_path[0] == "/"
158
+ elsif base_path == "/" && server_path[0,1] == "/"
158
159
  return server_path[1, server_path.length - 1]
159
160
  end
160
161
  end
@@ -17,6 +17,7 @@
17
17
  #
18
18
 
19
19
  require 'chef_fs'
20
+ require 'pathname'
20
21
 
21
22
  module ChefFS
22
23
  class PathUtils
@@ -67,14 +68,15 @@ module ChefFS
67
68
  # PathUtils.realest_path('/x/*/z') == '/blarghle/*/z'
68
69
  # PathUtils.realest_path('/*/y/z') == '/*/y/z'
69
70
  def self.realest_path(path)
71
+ path = Pathname.new(path)
70
72
  begin
71
- File.realpath(path)
73
+ path.realpath.to_s
72
74
  rescue Errno::ENOENT
73
- dirname = File.dirname(path)
75
+ dirname = path.dirname
74
76
  if dirname
75
- PathUtils.join(realest_path(dirname), File.basename(path))
77
+ PathUtils.join(realest_path(dirname), path.basename.to_s)
76
78
  else
77
- path
79
+ path.to_s
78
80
  end
79
81
  end
80
82
  end
@@ -1,4 +1,4 @@
1
1
  module ChefFS
2
- VERSION = "0.8.4"
2
+ VERSION = "0.8.5"
3
3
  end
4
4
 
@@ -0,0 +1,684 @@
1
+ require 'support/integration_helper'
2
+ require 'chef/knife/delete_essentials'
3
+ require 'chef/knife/list_essentials'
4
+ require 'chef/knife/raw_essentials'
5
+
6
+ describe 'knife delete' do
7
+ extend IntegrationSupport
8
+ include KnifeSupport
9
+
10
+ let :everything do
11
+ <<EOM
12
+ /cookbooks
13
+ /cookbooks/x
14
+ /cookbooks/x/metadata.rb
15
+ /data_bags
16
+ /data_bags/x
17
+ /data_bags/x/y.json
18
+ /environments
19
+ /environments/_default.json
20
+ /environments/x.json
21
+ /roles
22
+ /roles/x.json
23
+ EOM
24
+ end
25
+
26
+ let :server_nothing do
27
+ <<EOM
28
+ /cookbooks
29
+ /data_bags
30
+ /environments
31
+ /environments/_default.json
32
+ /roles
33
+ EOM
34
+ end
35
+
36
+ let :nothing do
37
+ <<EOM
38
+ /cookbooks
39
+ /data_bags
40
+ /environments
41
+ /roles
42
+ EOM
43
+ end
44
+
45
+ when_the_chef_server "has one of each thing" do
46
+ client 'x', '{}'
47
+ cookbook 'x', '1.0.0', { 'metadata.rb' => 'version "1.0.0"' }
48
+ data_bag 'x', { 'y' => '{}' }
49
+ environment 'x', '{}'
50
+ node 'x', '{}'
51
+ role 'x', '{}'
52
+ user 'x', '{}'
53
+
54
+ when_the_repository 'also has one of each thing' do
55
+ file 'clients/x.json', {}
56
+ file 'cookbooks/x/metadata.rb', ''
57
+ file 'data_bags/x/y.json', {}
58
+ file 'environments/_default.json', {}
59
+ file 'environments/x.json', {}
60
+ file 'nodes/x.json', {}
61
+ file 'roles/x.json', {}
62
+ file 'users/x.json', {}
63
+
64
+ it 'knife delete /cookbooks/x fails' do
65
+ knife('delete /cookbooks/x').should_fail <<EOM
66
+ ERROR: /cookbooks/x (remote) must be deleted recursively! Pass -r to knife delete.
67
+ ERROR: /cookbooks/x (local) must be deleted recursively! Pass -r to knife delete.
68
+ EOM
69
+ knife('list -Rf /').should_succeed everything
70
+ knife('list -Rf --local /').should_succeed everything
71
+ end
72
+
73
+ it 'knife delete -r /cookbooks/x deletes x' do
74
+ knife('delete -r /cookbooks/x').should_succeed "Deleted /cookbooks/x\n"
75
+ knife('list -Rf /').should_succeed <<EOM
76
+ /cookbooks
77
+ /data_bags
78
+ /data_bags/x
79
+ /data_bags/x/y.json
80
+ /environments
81
+ /environments/_default.json
82
+ /environments/x.json
83
+ /roles
84
+ /roles/x.json
85
+ EOM
86
+ knife('list -Rf --local /').should_succeed <<EOM
87
+ /cookbooks
88
+ /data_bags
89
+ /data_bags/x
90
+ /data_bags/x/y.json
91
+ /environments
92
+ /environments/_default.json
93
+ /environments/x.json
94
+ /roles
95
+ /roles/x.json
96
+ EOM
97
+ end
98
+
99
+ it 'knife delete -r --local-only /cookbooks/x deletes x locally but not remotely' do
100
+ knife('delete -r --local-only /cookbooks/x').should_succeed "Deleted /cookbooks/x\n"
101
+ knife('list -Rf /').should_succeed everything
102
+ knife('list -Rf --local /').should_succeed <<EOM
103
+ /cookbooks
104
+ /data_bags
105
+ /data_bags/x
106
+ /data_bags/x/y.json
107
+ /environments
108
+ /environments/_default.json
109
+ /environments/x.json
110
+ /roles
111
+ /roles/x.json
112
+ EOM
113
+ end
114
+
115
+ it 'knife delete -r --remote-only /cookbooks/x deletes x remotely but not locally' do
116
+ knife('delete -r --remote-only /cookbooks/x').should_succeed "Deleted /cookbooks/x\n"
117
+ knife('list -Rf /').should_succeed <<EOM
118
+ /cookbooks
119
+ /data_bags
120
+ /data_bags/x
121
+ /data_bags/x/y.json
122
+ /environments
123
+ /environments/_default.json
124
+ /environments/x.json
125
+ /roles
126
+ /roles/x.json
127
+ EOM
128
+ knife('list -Rf --local /').should_succeed everything
129
+ end
130
+
131
+ # TODO delete empty data bag (particularly different on local side)
132
+ context 'with an empty data bag on both' do
133
+ data_bag 'empty', {}
134
+ directory 'data_bags/empty'
135
+ it 'knife delete /data_bags/empty fails but deletes local version' do
136
+ knife('delete /data_bags/empty').should_fail <<EOM
137
+ ERROR: /data_bags/empty (remote) must be deleted recursively! Pass -r to knife delete.
138
+ ERROR: /data_bags/empty (local) must be deleted recursively! Pass -r to knife delete.
139
+ EOM
140
+ knife('list -Rf /').should_succeed <<EOM
141
+ /cookbooks
142
+ /cookbooks/x
143
+ /cookbooks/x/metadata.rb
144
+ /data_bags
145
+ /data_bags/empty
146
+ /data_bags/x
147
+ /data_bags/x/y.json
148
+ /environments
149
+ /environments/_default.json
150
+ /environments/x.json
151
+ /roles
152
+ /roles/x.json
153
+ EOM
154
+ knife('list -Rf --local /').should_succeed <<EOM
155
+ /cookbooks
156
+ /cookbooks/x
157
+ /cookbooks/x/metadata.rb
158
+ /data_bags
159
+ /data_bags/empty
160
+ /data_bags/x
161
+ /data_bags/x/y.json
162
+ /environments
163
+ /environments/_default.json
164
+ /environments/x.json
165
+ /roles
166
+ /roles/x.json
167
+ EOM
168
+ end
169
+ end
170
+
171
+ it 'knife delete /data_bags/x fails' do
172
+ knife('delete /data_bags/x').should_fail <<EOM
173
+ ERROR: /data_bags/x (remote) must be deleted recursively! Pass -r to knife delete.
174
+ ERROR: /data_bags/x (local) must be deleted recursively! Pass -r to knife delete.
175
+ EOM
176
+ knife('list -Rf /').should_succeed everything
177
+ knife('list -Rf --local /').should_succeed everything
178
+ end
179
+
180
+ it 'knife delete -r /data_bags/x deletes x' do
181
+ knife('delete -r /data_bags/x').should_succeed "Deleted /data_bags/x\n"
182
+ knife('list -Rf /').should_succeed <<EOM
183
+ /cookbooks
184
+ /cookbooks/x
185
+ /cookbooks/x/metadata.rb
186
+ /data_bags
187
+ /environments
188
+ /environments/_default.json
189
+ /environments/x.json
190
+ /roles
191
+ /roles/x.json
192
+ EOM
193
+ knife('list -Rf --local /').should_succeed <<EOM
194
+ /cookbooks
195
+ /cookbooks/x
196
+ /cookbooks/x/metadata.rb
197
+ /data_bags
198
+ /environments
199
+ /environments/_default.json
200
+ /environments/x.json
201
+ /roles
202
+ /roles/x.json
203
+ EOM
204
+ end
205
+
206
+ it 'knife delete /environments/x.json deletes x' do
207
+ knife('delete /environments/x.json').should_succeed "Deleted /environments/x.json\n"
208
+ knife('list -Rf /').should_succeed <<EOM
209
+ /cookbooks
210
+ /cookbooks/x
211
+ /cookbooks/x/metadata.rb
212
+ /data_bags
213
+ /data_bags/x
214
+ /data_bags/x/y.json
215
+ /environments
216
+ /environments/_default.json
217
+ /roles
218
+ /roles/x.json
219
+ EOM
220
+ knife('list -Rf --local /').should_succeed <<EOM
221
+ /cookbooks
222
+ /cookbooks/x
223
+ /cookbooks/x/metadata.rb
224
+ /data_bags
225
+ /data_bags/x
226
+ /data_bags/x/y.json
227
+ /environments
228
+ /environments/_default.json
229
+ /roles
230
+ /roles/x.json
231
+ EOM
232
+ end
233
+
234
+ it 'knife delete /roles/x.json deletes x' do
235
+ knife('delete /roles/x.json').should_succeed "Deleted /roles/x.json\n"
236
+ knife('list -Rf /').should_succeed <<EOM
237
+ /cookbooks
238
+ /cookbooks/x
239
+ /cookbooks/x/metadata.rb
240
+ /data_bags
241
+ /data_bags/x
242
+ /data_bags/x/y.json
243
+ /environments
244
+ /environments/_default.json
245
+ /environments/x.json
246
+ /roles
247
+ EOM
248
+ knife('list -Rf --local /').should_succeed <<EOM
249
+ /cookbooks
250
+ /cookbooks/x
251
+ /cookbooks/x/metadata.rb
252
+ /data_bags
253
+ /data_bags/x
254
+ /data_bags/x/y.json
255
+ /environments
256
+ /environments/_default.json
257
+ /environments/x.json
258
+ /roles
259
+ EOM
260
+ end
261
+
262
+ it 'knife delete /environments/_default.json fails but still deletes the local copy' do
263
+ knife('delete /environments/_default.json').should_fail :stderr => "ERROR: /environments/_default.json (remote) cannot be deleted (default environment cannot be modified).\n", :stdout => "Deleted /environments/_default.json\n"
264
+ knife('list -Rf /').should_succeed everything
265
+ knife('list -Rf --local /').should_succeed <<EOM
266
+ /cookbooks
267
+ /cookbooks/x
268
+ /cookbooks/x/metadata.rb
269
+ /data_bags
270
+ /data_bags/x
271
+ /data_bags/x/y.json
272
+ /environments
273
+ /environments/x.json
274
+ /roles
275
+ /roles/x.json
276
+ EOM
277
+ end
278
+
279
+ it 'knife delete /environments/nonexistent.json fails' do
280
+ knife('delete /environments/nonexistent.json').should_fail "ERROR: /environments/nonexistent.json: No such file or directory\n"
281
+ knife('list -Rf /').should_succeed everything
282
+ knife('list -Rf --local /').should_succeed everything
283
+ end
284
+
285
+ it 'knife delete / fails' do
286
+ knife('delete /').should_fail <<EOM
287
+ ERROR: / (remote) cannot be deleted.
288
+ ERROR: / (local) cannot be deleted.
289
+ EOM
290
+ knife('list -Rf /').should_succeed everything
291
+ knife('list -Rf --local /').should_succeed everything
292
+ end
293
+
294
+ it 'knife delete -r /* fails' do
295
+ knife('delete -r /*').should_fail <<EOM
296
+ ERROR: / (remote) cannot be deleted.
297
+ ERROR: / (local) cannot be deleted.
298
+ ERROR: /cookbooks (remote) cannot be deleted.
299
+ ERROR: /cookbooks (local) cannot be deleted.
300
+ ERROR: /data_bags (remote) cannot be deleted.
301
+ ERROR: /data_bags (local) cannot be deleted.
302
+ ERROR: /environments (remote) cannot be deleted.
303
+ ERROR: /environments (local) cannot be deleted.
304
+ ERROR: /roles (remote) cannot be deleted.
305
+ ERROR: /roles (local) cannot be deleted.
306
+ EOM
307
+ knife('list -Rf /').should_succeed everything
308
+ knife('list -Rf --local /').should_succeed everything
309
+ end
310
+ end
311
+
312
+ when_the_repository 'has only top-level directories' do
313
+ directory 'clients'
314
+ directory 'cookbooks'
315
+ directory 'data_bags'
316
+ directory 'environments'
317
+ directory 'nodes'
318
+ directory 'roles'
319
+ directory 'users'
320
+
321
+ it 'knife delete /cookbooks/x fails' do
322
+ knife('delete /cookbooks/x').should_fail "ERROR: /cookbooks/x (remote) must be deleted recursively! Pass -r to knife delete.\n"
323
+ knife('list -Rf /').should_succeed everything
324
+ knife('list -Rf --local /').should_succeed nothing
325
+ end
326
+
327
+ it 'knife delete -r /cookbooks/x deletes x' do
328
+ knife('delete -r /cookbooks/x').should_succeed "Deleted /cookbooks/x\n"
329
+ knife('list -Rf /').should_succeed <<EOM
330
+ /cookbooks
331
+ /data_bags
332
+ /data_bags/x
333
+ /data_bags/x/y.json
334
+ /environments
335
+ /environments/_default.json
336
+ /environments/x.json
337
+ /roles
338
+ /roles/x.json
339
+ EOM
340
+ knife('list -Rf --local /').should_succeed nothing
341
+ end
342
+
343
+ it 'knife delete /data_bags/x fails' do
344
+ knife('delete /data_bags/x').should_fail "ERROR: /data_bags/x (remote) must be deleted recursively! Pass -r to knife delete.\n"
345
+ knife('list -Rf /').should_succeed everything
346
+ knife('list -Rf --local /').should_succeed nothing
347
+ end
348
+
349
+ it 'knife delete -r /data_bags/x deletes x' do
350
+ knife('delete -r /data_bags/x').should_succeed "Deleted /data_bags/x\n"
351
+ knife('list -Rf /').should_succeed <<EOM
352
+ /cookbooks
353
+ /cookbooks/x
354
+ /cookbooks/x/metadata.rb
355
+ /data_bags
356
+ /environments
357
+ /environments/_default.json
358
+ /environments/x.json
359
+ /roles
360
+ /roles/x.json
361
+ EOM
362
+ knife('list -Rf --local /').should_succeed nothing
363
+ end
364
+
365
+ it 'knife delete /environments/x.json deletes x' do
366
+ knife('delete /environments/x.json').should_succeed "Deleted /environments/x.json\n"
367
+ knife('list -Rf /').should_succeed <<EOM
368
+ /cookbooks
369
+ /cookbooks/x
370
+ /cookbooks/x/metadata.rb
371
+ /data_bags
372
+ /data_bags/x
373
+ /data_bags/x/y.json
374
+ /environments
375
+ /environments/_default.json
376
+ /roles
377
+ /roles/x.json
378
+ EOM
379
+ knife('list -Rf --local /').should_succeed nothing
380
+ end
381
+
382
+ it 'knife delete /roles/x.json deletes x' do
383
+ knife('delete /roles/x.json').should_succeed "Deleted /roles/x.json\n"
384
+ knife('list -Rf /').should_succeed <<EOM
385
+ /cookbooks
386
+ /cookbooks/x
387
+ /cookbooks/x/metadata.rb
388
+ /data_bags
389
+ /data_bags/x
390
+ /data_bags/x/y.json
391
+ /environments
392
+ /environments/_default.json
393
+ /environments/x.json
394
+ /roles
395
+ EOM
396
+ knife('list -Rf --local /').should_succeed nothing
397
+ end
398
+
399
+ it 'knife delete /environments/_default.json fails' do
400
+ knife('delete /environments/_default.json').should_fail "", :stderr => "ERROR: /environments/_default.json (remote) cannot be deleted (default environment cannot be modified).\n"
401
+ knife('list -Rf /').should_succeed everything
402
+ knife('list -Rf --local /').should_succeed nothing
403
+ end
404
+
405
+ it 'knife delete / fails' do
406
+ knife('delete /').should_fail "ERROR: / (remote) cannot be deleted.\nERROR: / (local) cannot be deleted.\n"
407
+ knife('list -Rf /').should_succeed everything
408
+ knife('list -Rf --local /').should_succeed nothing
409
+ end
410
+
411
+ it 'knife delete -r /* fails' do
412
+ knife('delete -r /*').should_fail <<EOM
413
+ ERROR: / (remote) cannot be deleted.
414
+ ERROR: / (local) cannot be deleted.
415
+ ERROR: /cookbooks (remote) cannot be deleted.
416
+ ERROR: /cookbooks (local) cannot be deleted.
417
+ ERROR: /data_bags (remote) cannot be deleted.
418
+ ERROR: /data_bags (local) cannot be deleted.
419
+ ERROR: /environments (remote) cannot be deleted.
420
+ ERROR: /environments (local) cannot be deleted.
421
+ ERROR: /roles (remote) cannot be deleted.
422
+ ERROR: /roles (local) cannot be deleted.
423
+ EOM
424
+ knife('list -Rf /').should_succeed everything
425
+ knife('list -Rf --local /').should_succeed nothing
426
+ end
427
+
428
+ it 'knife delete /environments/nonexistent.json fails' do
429
+ knife('delete /environments/nonexistent.json').should_fail "ERROR: /environments/nonexistent.json: No such file or directory\n"
430
+ knife('list -Rf /').should_succeed everything
431
+ knife('list -Rf --local /').should_succeed nothing
432
+ end
433
+
434
+ context 'and cwd is at the top level' do
435
+ cwd '.'
436
+ it 'knife delete fails' do
437
+ knife('delete').should_fail "FATAL: Must specify at least one argument. If you want to delete everything in this directory, type \"knife delete --recurse .\"\n", :stdout => /USAGE/
438
+ knife('list -Rf /').should_succeed <<EOM
439
+ cookbooks
440
+ cookbooks/x
441
+ cookbooks/x/metadata.rb
442
+ data_bags
443
+ data_bags/x
444
+ data_bags/x/y.json
445
+ environments
446
+ environments/_default.json
447
+ environments/x.json
448
+ roles
449
+ roles/x.json
450
+ EOM
451
+ knife('list -Rf --local /').should_succeed <<EOM
452
+ cookbooks
453
+ data_bags
454
+ environments
455
+ roles
456
+ EOM
457
+ end
458
+ end
459
+ end
460
+ end
461
+
462
+ when_the_chef_server 'is empty' do
463
+ when_the_repository 'has one of each thing' do
464
+ file 'clients/x.json', {}
465
+ file 'cookbooks/x/metadata.rb', ''
466
+ file 'data_bags/x/y.json', {}
467
+ file 'environments/_default.json', {}
468
+ file 'environments/x.json', {}
469
+ file 'nodes/x.json', {}
470
+ file 'roles/x.json', {}
471
+ file 'users/x.json', {}
472
+
473
+ it 'knife delete /cookbooks/x fails' do
474
+ knife('delete /cookbooks/x').should_fail "ERROR: /cookbooks/x (local) must be deleted recursively! Pass -r to knife delete.\n"
475
+ knife('list -Rf /').should_succeed server_nothing
476
+ knife('list -Rf --local /').should_succeed everything
477
+ end
478
+
479
+ it 'knife delete -r /cookbooks/x deletes x' do
480
+ knife('delete -r /cookbooks/x').should_succeed "Deleted /cookbooks/x\n"
481
+ knife('list -Rf /').should_succeed server_nothing
482
+ knife('list -Rf --local /').should_succeed <<EOM
483
+ /cookbooks
484
+ /data_bags
485
+ /data_bags/x
486
+ /data_bags/x/y.json
487
+ /environments
488
+ /environments/_default.json
489
+ /environments/x.json
490
+ /roles
491
+ /roles/x.json
492
+ EOM
493
+ end
494
+
495
+ it 'knife delete /data_bags/x fails' do
496
+ knife('delete /data_bags/x').should_fail "ERROR: /data_bags/x (local) must be deleted recursively! Pass -r to knife delete.\n"
497
+ knife('list -Rf /').should_succeed server_nothing
498
+ knife('list -Rf --local /').should_succeed everything
499
+ end
500
+
501
+ it 'knife delete -r /data_bags/x deletes x' do
502
+ knife('delete -r /data_bags/x').should_succeed "Deleted /data_bags/x\n"
503
+ knife('list -Rf /').should_succeed server_nothing
504
+ knife('list -Rf --local /').should_succeed <<EOM
505
+ /cookbooks
506
+ /cookbooks/x
507
+ /cookbooks/x/metadata.rb
508
+ /data_bags
509
+ /environments
510
+ /environments/_default.json
511
+ /environments/x.json
512
+ /roles
513
+ /roles/x.json
514
+ EOM
515
+ end
516
+
517
+ it 'knife delete /environments/x.json deletes x' do
518
+ knife('delete /environments/x.json').should_succeed "Deleted /environments/x.json\n"
519
+ knife('list -Rf /').should_succeed server_nothing
520
+ knife('list -Rf --local /').should_succeed <<EOM
521
+ /cookbooks
522
+ /cookbooks/x
523
+ /cookbooks/x/metadata.rb
524
+ /data_bags
525
+ /data_bags/x
526
+ /data_bags/x/y.json
527
+ /environments
528
+ /environments/_default.json
529
+ /roles
530
+ /roles/x.json
531
+ EOM
532
+ end
533
+
534
+ it 'knife delete /roles/x.json deletes x' do
535
+ knife('delete /roles/x.json').should_succeed "Deleted /roles/x.json\n"
536
+ knife('list -Rf /').should_succeed server_nothing
537
+ knife('list -Rf --local /').should_succeed <<EOM
538
+ /cookbooks
539
+ /cookbooks/x
540
+ /cookbooks/x/metadata.rb
541
+ /data_bags
542
+ /data_bags/x
543
+ /data_bags/x/y.json
544
+ /environments
545
+ /environments/_default.json
546
+ /environments/x.json
547
+ /roles
548
+ EOM
549
+ end
550
+
551
+ it 'knife delete /environments/_default.json fails but still deletes the local copy' do
552
+ knife('delete /environments/_default.json').should_fail :stderr => "ERROR: /environments/_default.json (remote) cannot be deleted (default environment cannot be modified).\n", :stdout => "Deleted /environments/_default.json\n"
553
+ knife('list -Rf /').should_succeed server_nothing
554
+ knife('list -Rf --local /').should_succeed <<EOM
555
+ /cookbooks
556
+ /cookbooks/x
557
+ /cookbooks/x/metadata.rb
558
+ /data_bags
559
+ /data_bags/x
560
+ /data_bags/x/y.json
561
+ /environments
562
+ /environments/x.json
563
+ /roles
564
+ /roles/x.json
565
+ EOM
566
+ end
567
+
568
+ it 'knife delete / fails' do
569
+ knife('delete /').should_fail "ERROR: / (remote) cannot be deleted.\nERROR: / (local) cannot be deleted.\n"
570
+ knife('list -Rf /').should_succeed server_nothing
571
+ knife('list -Rf --local /').should_succeed everything
572
+ end
573
+
574
+ it 'knife delete -r /* fails' do
575
+ knife('delete -r /*').should_fail <<EOM
576
+ ERROR: / (remote) cannot be deleted.
577
+ ERROR: / (local) cannot be deleted.
578
+ ERROR: /cookbooks (remote) cannot be deleted.
579
+ ERROR: /cookbooks (local) cannot be deleted.
580
+ ERROR: /data_bags (remote) cannot be deleted.
581
+ ERROR: /data_bags (local) cannot be deleted.
582
+ ERROR: /environments (remote) cannot be deleted.
583
+ ERROR: /environments (local) cannot be deleted.
584
+ ERROR: /roles (remote) cannot be deleted.
585
+ ERROR: /roles (local) cannot be deleted.
586
+ EOM
587
+ knife('list -Rf /').should_succeed server_nothing
588
+ knife('list -Rf --local /').should_succeed everything
589
+ end
590
+
591
+ it 'knife delete /environments/nonexistent.json fails' do
592
+ knife('delete /environments/nonexistent.json').should_fail "ERROR: /environments/nonexistent.json: No such file or directory\n"
593
+ knife('list -Rf /').should_succeed server_nothing
594
+ knife('list -Rf --local /').should_succeed everything
595
+ end
596
+
597
+ context 'and cwd is at the top level' do
598
+ cwd '.'
599
+ it 'knife delete fails' do
600
+ knife('delete').should_fail "FATAL: Must specify at least one argument. If you want to delete everything in this directory, type \"knife delete --recurse .\"\n", :stdout => /USAGE/
601
+ knife('list -Rf /').should_succeed <<EOM
602
+ cookbooks
603
+ data_bags
604
+ environments
605
+ environments/_default.json
606
+ roles
607
+ EOM
608
+ knife('list -Rf --local /').should_succeed <<EOM
609
+ cookbooks
610
+ cookbooks/x
611
+ cookbooks/x/metadata.rb
612
+ data_bags
613
+ data_bags/x
614
+ data_bags/x/y.json
615
+ environments
616
+ environments/_default.json
617
+ environments/x.json
618
+ roles
619
+ roles/x.json
620
+ EOM
621
+ end
622
+ end
623
+ end
624
+ end
625
+
626
+ when_the_repository 'has a cookbook' do
627
+ file 'cookbooks/x/metadata.rb', 'version "1.0.0"'
628
+ file 'cookbooks/x/onlyin1.0.0.rb', 'old_text'
629
+
630
+ when_the_chef_server 'has a later version for the cookbook' do
631
+ cookbook 'x', '1.0.0', { 'metadata.rb' => 'version "1.0.0"', 'onlyin1.0.0.rb' => '' }
632
+ cookbook 'x', '1.0.1', { 'metadata.rb' => 'version "1.0.1"', 'onlyin1.0.1.rb' => 'hi' }
633
+
634
+ # TODO this seems wrong
635
+ it 'knife delete /cookbooks/x deletes the latest version on the server and the local version' do
636
+ knife('delete -r /cookbooks/x').should_succeed "Deleted /cookbooks/x\n"
637
+ knife('raw /cookbooks/x').should_succeed(/1.0.0/)
638
+ knife('list --local /cookbooks').should_succeed ''
639
+ end
640
+ end
641
+
642
+ when_the_chef_server 'has an earlier version for the cookbook' do
643
+ cookbook 'x', '1.0.0', { 'metadata.rb' => 'version "1.0.0"', 'onlyin1.0.0.rb' => ''}
644
+ cookbook 'x', '0.9.9', { 'metadata.rb' => 'version "0.9.9"', 'onlyin0.9.9.rb' => 'hi' }
645
+
646
+ it 'knife delete /cookbooks/x deletes the latest version on the server and the local version' do
647
+ knife('delete -r /cookbooks/x').should_succeed "Deleted /cookbooks/x\n"
648
+ knife('raw /cookbooks/x').should_succeed(/0.9.9/)
649
+ knife('list --local /cookbooks').should_succeed ''
650
+ end
651
+ end
652
+
653
+ when_the_chef_server 'has a later version for the cookbook, and no current version' do
654
+ cookbook 'x', '1.0.1', { 'metadata.rb' => 'version "1.0.1"', 'onlyin1.0.1.rb' => 'hi' }
655
+
656
+ it 'knife delete /cookbooks/x deletes the server and client version of the cookbook' do
657
+ knife('delete -r /cookbooks/x').should_succeed "Deleted /cookbooks/x\n"
658
+ knife('raw /cookbooks/x').should_fail(/404/)
659
+ knife('list --local /cookbooks').should_succeed ''
660
+ end
661
+ end
662
+
663
+ when_the_chef_server 'has an earlier version for the cookbook, and no current version' do
664
+ cookbook 'x', '0.9.9', { 'metadata.rb' => 'version "0.9.9"', 'onlyin0.9.9.rb' => 'hi' }
665
+
666
+ it 'knife delete /cookbooks/x deletes the server and client version of the cookbook' do
667
+ knife('delete -r /cookbooks/x').should_succeed "Deleted /cookbooks/x\n"
668
+ knife('raw /cookbooks/x').should_fail(/404/)
669
+ knife('list --local /cookbooks').should_succeed ''
670
+ end
671
+ end
672
+ end
673
+
674
+ when_the_repository 'is empty' do
675
+ when_the_chef_server 'has two versions of a cookbook' do
676
+ cookbook 'x', '2.0.11', { 'metadata.rb' => 'version "2.0.11"' }
677
+ cookbook 'x', '11.0.0', { 'metadata.rb' => 'version "11.0.0"' }
678
+ it 'knife delete deletes the latest version' do
679
+ knife('delete -r /cookbooks/x').should_succeed "Deleted /cookbooks/x\n"
680
+ knife('raw /cookbooks/x').should_succeed /2.0.11/
681
+ end
682
+ end
683
+ end
684
+ end