knife-essentials 0.8.4 → 0.8.5

Sign up to get free protection for your applications and to get access to all the features.
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