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
@@ -11,18 +11,17 @@ class Chef
11
11
  common_options
12
12
 
13
13
  option :recurse,
14
+ :short => '-r',
14
15
  :long => '--[no-]recurse',
15
16
  :boolean => true,
16
17
  :default => false,
17
18
  :description => "Delete directories recursively."
18
19
  option :remote_only,
19
- :short => '-R',
20
20
  :long => '--remote-only',
21
21
  :boolean => true,
22
22
  :default => false,
23
23
  :description => "Only delete the remote copy (leave the local copy)."
24
24
  option :local_only,
25
- :short => '-L',
26
25
  :long => '--local-only',
27
26
  :boolean => true,
28
27
  :default => false,
@@ -36,41 +35,71 @@ class Chef
36
35
  end
37
36
 
38
37
  # Get the matches (recursively)
38
+ error = false
39
39
  if config[:remote_only]
40
40
  pattern_args.each do |pattern|
41
41
  ChefFS::FileSystem.list(chef_fs, pattern) do |result|
42
- delete_result(result)
42
+ if delete_result(result)
43
+ error = true
44
+ end
43
45
  end
44
46
  end
45
47
  elsif config[:local_only]
46
48
  pattern_args.each do |pattern|
47
49
  ChefFS::FileSystem.list(local_fs, pattern) do |result|
48
- delete_result(result)
50
+ if delete_result(result)
51
+ error = true
52
+ end
49
53
  end
50
54
  end
51
55
  else
52
56
  pattern_args.each do |pattern|
53
57
  ChefFS::FileSystem.list_pairs(pattern, chef_fs, local_fs) do |chef_result, local_result|
54
- delete_result(chef_result, local_result)
58
+ if delete_result(chef_result, local_result)
59
+ error = true
60
+ end
55
61
  end
56
62
  end
57
63
  end
64
+
65
+ if error
66
+ exit 1
67
+ end
68
+ end
69
+
70
+ def format_path_with_root(entry)
71
+ root = entry.root == chef_fs ? " (remote)" : " (local)"
72
+ "#{format_path(entry)}#{root}"
58
73
  end
59
74
 
60
75
  def delete_result(*results)
61
76
  deleted_any = false
77
+ found_any = false
78
+ error = false
62
79
  results.each do |result|
63
80
  begin
64
81
  result.delete(config[:recurse])
65
82
  deleted_any = true
83
+ found_any = true
66
84
  rescue ChefFS::FileSystem::NotFoundError
85
+ # This is not an error unless *all* of them were not found
86
+ rescue ChefFS::FileSystem::MustDeleteRecursivelyError => e
87
+ ui.error "#{format_path_with_root(e.entry)} must be deleted recursively! Pass -r to knife delete."
88
+ found_any = true
89
+ error = true
90
+ rescue ChefFS::FileSystem::OperationNotAllowedError => e
91
+ ui.error "#{format_path_with_root(e.entry)} #{e.reason}."
92
+ found_any = true
93
+ error = true
67
94
  end
68
95
  end
69
96
  if deleted_any
70
- output("Deleted #{format_path(results[0].path)}")
71
- else
72
- ui.error "#{format_path(results[0].path)}: No such file or directory"
97
+ output("Deleted #{format_path(results[0])}")
98
+ elsif !found_any
99
+ ui.error "#{format_path(results[0])}: No such file or directory"
100
+ error = true
73
101
  end
102
+ error
74
103
  end
75
104
  end
76
105
  end
@@ -54,13 +54,13 @@ class Chef
54
54
  child_entry = ChefFS::FileSystem.resolve_path(@root, child)
55
55
  print_flattened_dependencies(child_entry, dependencies)
56
56
  end
57
- output format_path(entry.path)
57
+ output format_path(entry)
58
58
  end
59
59
  end
60
60
 
61
61
  def print_dependencies_tree(entry, dependencies, printed = {}, depth = 0)
62
62
  dependencies[entry.path] = get_dependencies(entry) if !dependencies[entry.path]
63
- output "#{' '*depth}#{format_path(entry.path)}"
63
+ output "#{' '*depth}#{format_path(entry)}"
64
64
  if !printed[entry.path] && (config[:recurse] || depth == 0)
65
65
  printed[entry.path] = true
66
66
  dependencies[entry.path].each do |child|
@@ -104,13 +104,13 @@ class Chef
104
104
  result
105
105
 
106
106
  elsif !entry.exists?
107
- raise ChefFS::FileSystem::NotFoundError, "Nonexistent #{entry.path_for_printing}"
107
+ raise ChefFS::FileSystem::NotFoundError.new(entry)
108
108
 
109
109
  else
110
110
  []
111
111
  end
112
- rescue ChefFS::FileSystem::NotFoundError
113
- ui.error "#{format_path(entry.path)}: No such file or directory"
112
+ rescue ChefFS::FileSystem::NotFoundError => e
113
+ ui.error "#{format_path(e.entry)}: No such file or directory"
114
114
  self.exit_code = 2
115
115
  []
116
116
  end
@@ -36,10 +36,18 @@ class Chef
36
36
  patterns = pattern_args_from(name_args.length > 0 ? name_args : [ "" ])
37
37
 
38
38
  # Get the matches (recursively)
39
+ error = false
39
40
  patterns.each do |pattern|
40
- ChefFS::CommandLine.diff_print(pattern, chef_fs, local_fs, config[:recurse] ? nil : 1, output_mode, proc { |entry| format_path(entry.path) } ) do |diff|
41
+ found_match = ChefFS::CommandLine.diff_print(pattern, chef_fs, local_fs, config[:recurse] ? nil : 1, output_mode, proc { |entry| format_path(entry) } ) do |diff|
41
42
  stdout.print diff
42
43
  end
44
+ if !found_match
45
+ ui.error "#{pattern}: No such file or directory on remote or local"
46
+ error = true
47
+ end
48
+ end
49
+ if error
50
+ exit 1
43
51
  end
44
52
  end
45
53
  end
@@ -44,7 +44,7 @@ class Chef
44
44
 
45
45
  error = false
46
46
  pattern_args.each do |pattern|
47
- error ||= ChefFS::FileSystem.copy_to(pattern, chef_fs, local_fs, config[:recurse] ? nil : 1, config, ui, proc { |entry| format_path(entry.path) })
47
+ error ||= ChefFS::FileSystem.copy_to(pattern, chef_fs, local_fs, config[:recurse] ? nil : 1, config, ui, proc { |entry| format_path(entry) })
48
48
  end
49
49
  if error
50
50
  exit 1
@@ -51,7 +51,7 @@ class Chef
51
51
  elsif result.exists?
52
52
  results << result
53
53
  elsif pattern.exact_path
54
- ui.error "#{format_path(result.path)}: No such file or directory"
54
+ ui.error "#{format_path(result)}: No such file or directory"
55
55
  self.exit_code = 1
56
56
  end
57
57
  end
@@ -80,7 +80,7 @@ class Chef
80
80
  else
81
81
  printed_something = true
82
82
  end
83
- output "#{format_path(result.path)}:"
83
+ output "#{format_path(result)}:"
84
84
  print_results(children.map { |result| maybe_add_slash(result.name, result.dir?) }.sort, "")
85
85
  end
86
86
 
@@ -90,8 +90,8 @@ class Chef
90
90
  def add_dir_result(result)
91
91
  begin
92
92
  children = result.children.sort_by { |child| child.name }
93
- rescue ChefFS::FileSystem::NotFoundError
94
- ui.error "#{format_path(result.path)}: No such file or directory"
93
+ rescue ChefFS::FileSystem::NotFoundError => e
94
+ ui.error "#{format_path(e.entry)}: No such file or directory"
95
95
  return []
96
96
  end
97
97
 
@@ -107,7 +107,7 @@ class Chef
107
107
  end
108
108
 
109
109
  def print_result_paths(results, indent = "")
110
- print_results(results.map { |result| maybe_add_slash(format_path(result.path), result.dir?) }, indent)
110
+ print_results(results.map { |result| maybe_add_slash(format_path(result), result.dir?) }, indent)
111
111
  end
112
112
 
113
113
  def print_results(results, indent)
@@ -40,7 +40,13 @@ class Chef
40
40
  data = IO.read(config[:input])
41
41
  end
42
42
  chef_rest = Chef::REST.new(Chef::Config[:chef_server_url])
43
- output api_request(chef_rest, config[:method].to_sym, chef_rest.create_url(name_args[0]), {}, data)
43
+ begin
44
+ output api_request(chef_rest, config[:method].to_sym, chef_rest.create_url(name_args[0]), {}, data)
45
+ rescue Net::HTTPServerException => e
46
+ ui.error "Server responded with error #{e.response.code} \"#{e.response.message}\""
47
+ ui.error "Error Body: #{e.response.body}" if e.response.body && e.response.body != ''
48
+ exit 1
49
+ end
44
50
  end
45
51
 
46
52
  ACCEPT_ENCODING = "Accept-Encoding".freeze
@@ -86,7 +92,6 @@ class Chef
86
92
  msg << (exception["error"].respond_to?(:join) ? exception["error"].join(", ") : exception["error"].to_s)
87
93
  Chef::Log.info(msg)
88
94
  end
89
- output response.body
90
95
  response.error!
91
96
  end
92
97
  end
@@ -1,5 +1,6 @@
1
1
  require 'chef_fs/knife'
2
2
  require 'chef_fs/file_system'
3
+ require 'chef_fs/file_system/not_found_error'
3
4
 
4
5
  class Chef
5
6
  class Knife
@@ -17,21 +18,30 @@ class Chef
17
18
 
18
19
  def run
19
20
  # Get the matches (recursively)
21
+ error = false
20
22
  pattern_args.each do |pattern|
21
23
  ChefFS::FileSystem.list(config[:local] ? local_fs : chef_fs, pattern) do |result|
22
24
  if result.dir?
23
- ui.error "#{result.path_for_printing}: is a directory" if pattern.exact_path
25
+ ui.error "#{format_path(result)}: is a directory" if pattern.exact_path
26
+ error = true
24
27
  else
25
28
  begin
26
29
  value = result.read
27
- output "#{result.path_for_printing}:"
30
+ output "#{format_path(result)}:"
28
31
  output(format_for_display(value))
29
- rescue ChefFS::FileSystem::NotFoundError
30
- ui.error "#{result.path_for_printing}: No such file or directory"
32
+ rescue ChefFS::FileSystem::OperationNotAllowedError => e
33
+ ui.error "#{format_path(e.entry)}: #{e.reason}."
34
+ error = true
35
+ rescue ChefFS::FileSystem::NotFoundError => e
36
+ ui.error "#{format_path(e.entry)}: No such file or directory"
37
+ error = true
31
38
  end
32
39
  end
33
40
  end
34
41
  end
42
+ if error
43
+ exit 1
44
+ end
35
45
  end
36
46
  end
37
47
  end
@@ -44,7 +44,7 @@ class Chef
44
44
 
45
45
  error = false
46
46
  pattern_args.each do |pattern|
47
- error ||= ChefFS::FileSystem.copy_to(pattern, local_fs, chef_fs, config[:recurse] ? nil : 1, config, ui, proc { |entry| format_path(entry.path) })
47
+ error ||= ChefFS::FileSystem.copy_to(pattern, local_fs, chef_fs, config[:recurse] ? nil : 1, config, ui, proc { |entry| format_path(entry) })
48
48
  end
49
49
  if error
50
50
  exit 1
@@ -27,7 +27,9 @@ module ChefFS
27
27
  end
28
28
 
29
29
  get_content = (output_mode != :name_only && output_mode != :name_status)
30
+ found_match = false
30
31
  diff(pattern, a_root, b_root, recurse_depth, get_content) do |type, old_entry, new_entry, old_value, new_value|
32
+ found_match = true unless type == :both_nonexistent
31
33
  old_path = format_path.call(old_entry)
32
34
  new_path = format_path.call(new_entry)
33
35
 
@@ -90,21 +92,22 @@ module ChefFS
90
92
  elsif output_mode == :name_status
91
93
  yield "M\t#{new_path}\n"
92
94
  end
95
+ when :both_nonexistent
96
+ when :added_cannot_upload
97
+ when :deleted_cannot_download
98
+ when :same
99
+ # Skip these silently
93
100
  end
94
101
  end
95
102
  end
103
+ found_match
96
104
  end
97
105
 
98
106
  def self.diff(pattern, a_root, b_root, recurse_depth, get_content)
99
- found_result = false
100
107
  ChefFS::FileSystem.list_pairs(pattern, a_root, b_root) do |a, b|
101
- existed = diff_entries(a, b, recurse_depth, get_content) do |diff|
108
+ diff_entries(a, b, recurse_depth, get_content) do |diff|
102
109
  yield diff
103
110
  end
104
- found_result = true if existed
105
- end
106
- if !found_result && pattern.exact_path
107
- yield "#{pattern}: No such file or directory on remote or local"
108
111
  end
109
112
  end
110
113
 
@@ -147,7 +150,11 @@ module ChefFS
147
150
  else
148
151
  are_same, old_value, new_value = ChefFS::FileSystem.compare(old_entry, new_entry)
149
152
  if are_same
150
- return old_value != :none
153
+ if old_value == :none
154
+ yield [ :both_nonexistent, old_entry, new_entry ]
155
+ else
156
+ yield [ :same, old_entry, new_entry ]
157
+ end
151
158
  else
152
159
  if old_value == :none
153
160
  old_exists = false
@@ -168,10 +175,12 @@ module ChefFS
168
175
  # If one of the files doesn't exist, we only want to print the diff if the
169
176
  # other file *could be uploaded/downloaded*.
170
177
  if !old_exists && !old_entry.parent.can_have_child?(new_entry.name, new_entry.dir?)
171
- return true
178
+ yield [ :old_cannot_upload, old_entry, new_entry ]
179
+ return
172
180
  end
173
181
  if !new_exists && !new_entry.parent.can_have_child?(old_entry.name, old_entry.dir?)
174
- return true
182
+ yield [ :new_cannot_upload, old_entry, new_entry ]
183
+ return
175
184
  end
176
185
 
177
186
  if get_content
@@ -197,7 +206,6 @@ module ChefFS
197
206
  end
198
207
  end
199
208
  end
200
- return true
201
209
  end
202
210
 
203
211
  private
@@ -17,7 +17,7 @@
17
17
  #
18
18
 
19
19
  require 'chef_fs/path_utils'
20
- require 'chef_fs/file_system/operation_skipped_error'
20
+ require 'chef_fs/file_system/default_environment_cannot_be_modified_error'
21
21
  require 'chef_fs/file_system/operation_not_allowed_error'
22
22
 
23
23
  module ChefFS
@@ -348,10 +348,10 @@ module ChefFS
348
348
  end
349
349
  end
350
350
  end
351
- rescue OperationSkippedError
352
- # If it was simply skipped, a warning has already been printed.
351
+ rescue DefaultEnvironmentCannotBeModifiedError => e
352
+ ui.warn "#{format_path.call(e.entry)} #{e.reason}."
353
353
  rescue OperationNotAllowedError => e
354
- ui.error e.message
354
+ ui.error "#{format_path.call(e.entry)} #{e.reason}."
355
355
  error = true
356
356
  end
357
357
  error
@@ -99,13 +99,13 @@ module ChefFS
99
99
 
100
100
  # Override children to report your *actual* list of children as an array.
101
101
  def children
102
- raise NotFoundError, "Nonexistent #{path_for_printing}" if !exists?
102
+ raise NotFoundError.new(self) if !exists?
103
103
  []
104
104
  end
105
105
 
106
106
  # Expand this entry into a chef object (Chef::Role, ::Node, etc.)
107
107
  def chef_object
108
- raise NotFoundError, "Nonexistent #{path_for_printing}" if !exists?
108
+ raise NotFoundError.new(self) if !exists?
109
109
  nil
110
110
  end
111
111
 
@@ -116,15 +116,15 @@ module ChefFS
116
116
  # your entry class, and will be called without actually reading the
117
117
  # file_contents. This is used for knife upload /cookbooks/cookbookname.
118
118
  def create_child(name, file_contents)
119
- raise NotFoundError, "Nonexistent #{path_for_printing}" if !exists?
120
- raise OperationNotAllowedError.new(:create_child), "#{path_for_printing} cannot have a child created under it."
119
+ raise NotFoundError.new(self) if !exists?
120
+ raise OperationNotAllowedError.new(:create_child, self)
121
121
  end
122
122
 
123
123
  # Delete this item, possibly recursively. Entries MUST NOT delete a
124
124
  # directory unless recurse is true.
125
125
  def delete(recurse)
126
- raise NotFoundError, "Nonexistent #{path_for_printing}" if !exists?
127
- raise OperationNotAllowedError.new(:delete), "#{path_for_printing} cannot be deleted."
126
+ raise NotFoundError.new(self) if !exists?
127
+ raise OperationNotAllowedError.new(:delete, self)
128
128
  end
129
129
 
130
130
  # Ask whether this entry is a directory. If not, it is a file.
@@ -158,14 +158,14 @@ module ChefFS
158
158
 
159
159
  # Read the contents of this file entry.
160
160
  def read
161
- raise NotFoundError, "Nonexistent #{path_for_printing}" if !exists?
162
- raise OperationNotAllowedError.new(:read), "#{path_for_printing} cannot be read."
161
+ raise NotFoundError.new(self) if !exists?
162
+ raise OperationNotAllowedError.new(:read, self)
163
163
  end
164
164
 
165
165
  # Write the contents of this file entry.
166
166
  def write(file_contents)
167
- raise NotFoundError, "Nonexistent #{path_for_printing}" if !exists?
168
- raise OperationNotAllowedError.new(:write), "#{path_for_printing} cannot be updated."
167
+ raise NotFoundError.new(self) if !exists?
168
+ raise OperationNotAllowedError.new(:write, self)
169
169
  end
170
170
 
171
171
  # Important directory attributes: name, parent, path, root
@@ -37,7 +37,7 @@ module ChefFS
37
37
  attr_reader :child_paths
38
38
 
39
39
  def children
40
- @children ||= child_paths.keys.map { |name| make_child_entry(name) }.select { |child| !child.nil? }
40
+ @children ||= child_paths.keys.sort.map { |name| make_child_entry(name) }.select { |child| !child.nil? }
41
41
  end
42
42
 
43
43
  def can_have_child?(name, is_dir)
@@ -76,8 +76,6 @@ module ChefFS
76
76
  result.sort_by { |child| child.name }
77
77
  end
78
78
  end
79
-
80
- # Yeah, sorry, I'm not putting delete on this thing.
81
79
  end
82
80
  end
83
81
  end