knife-essentials 0.8.1 → 0.8.2

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.
@@ -3,7 +3,7 @@ require 'chef_fs/file_system'
3
3
 
4
4
  class Chef
5
5
  class Knife
6
- remove_const(:Delete) if const_defined?(:Delete) # override Chef's version
6
+ remove_const(:Delete) if const_defined?(:Delete) && Delete.name == 'Chef::Knife::Delete' # override Chef's version
7
7
  class Delete < ::ChefFS::Knife
8
8
  ChefFS = ::ChefFS
9
9
  banner "knife delete [PATTERN1 ... PATTERNn]"
@@ -67,9 +67,9 @@ class Chef
67
67
  end
68
68
  end
69
69
  if deleted_any
70
- puts "Deleted #{format_path(results[0].path)}"
70
+ output("Deleted #{format_path(results[0].path)}")
71
71
  else
72
- STDERR.puts "#{format_path(results[0].path)}: No such file or directory"
72
+ ui.error "#{format_path(results[0].path)}: No such file or directory"
73
73
  end
74
74
  end
75
75
  end
@@ -3,7 +3,7 @@ require 'chef_fs/file_system'
3
3
 
4
4
  class Chef
5
5
  class Knife
6
- remove_const(:Deps) if const_defined?(:Deps) # override Chef's version
6
+ remove_const(:Deps) if const_defined?(:Deps) && Deps.name == 'Chef::Knife::Deps' # override Chef's version
7
7
  class Deps < ::ChefFS::Knife
8
8
  ChefFS = ::ChefFS
9
9
  banner "knife deps PATTERN1 [PATTERNn]"
@@ -23,9 +23,11 @@ class Chef
23
23
  :boolean => true,
24
24
  :description => "List dependencies on the server instead of the local filesystem"
25
25
 
26
+ attr_accessor :exit_code
27
+
26
28
  def run
27
- if config[:tree] && config[:recurse]
28
- STDERR.puts "--recurse requires --tree"
29
+ if config[:recurse] == false && !config[:tree]
30
+ ui.error "--no-recurse requires --tree"
29
31
  exit(1)
30
32
  end
31
33
  config[:recurse] = true if config[:recurse].nil?
@@ -41,6 +43,7 @@ class Chef
41
43
  end
42
44
  end
43
45
  end
46
+ exit exit_code if exit_code
44
47
  end
45
48
 
46
49
  def print_flattened_dependencies(entry, dependencies)
@@ -50,14 +53,14 @@ class Chef
50
53
  child_entry = ChefFS::FileSystem.resolve_path(@root, child)
51
54
  print_flattened_dependencies(child_entry, dependencies)
52
55
  end
53
- puts format_path(entry.path)
56
+ output format_path(entry.path)
54
57
  end
55
58
  end
56
59
 
57
60
  def print_dependencies_tree(entry, dependencies, printed = {}, depth = 0)
58
61
  dependencies[entry.path] = get_dependencies(entry) if !dependencies[entry.path]
59
- puts "#{' '*depth}#{format_path(entry.path)}"
60
- if !printed[entry.path] && (config[:recurse] || depth <= 1)
62
+ output "#{' '*depth}#{format_path(entry.path)}"
63
+ if !printed[entry.path] && (config[:recurse] || depth == 0)
61
64
  printed[entry.path] = true
62
65
  dependencies[entry.path].each do |child|
63
66
  child_entry = ChefFS::FileSystem.resolve_path(@root, child)
@@ -70,18 +73,25 @@ class Chef
70
73
  begin
71
74
  object = entry.chef_object
72
75
  rescue ChefFS::FileSystem::NotFoundError
73
- STDERR.puts "#{result.path_for_printing}: No such file or directory"
76
+ ui.error "#{format_path(entry.path)}: No such file or directory"
77
+ self.exit_code = 2
74
78
  return []
75
79
  end
76
80
  if !object
77
- STDERR.puts "ERROR: #{entry} is not a Chef object!"
81
+ # If it's not a Chef object, it has no deps
78
82
  return []
79
83
  end
80
84
 
81
85
  if object.is_a?(Chef::CookbookVersion)
82
86
  return object.metadata.dependencies.keys.map { |cookbook| "/cookbooks/#{cookbook}"}
83
87
  elsif object.is_a?(Chef::Node)
84
- return [ "/environments/#{object.chef_environment}.json" ] + dependencies_from_runlist(object.run_list)
88
+ result = []
89
+ # /environments/_default.json is an annoying dependency, since you
90
+ # can't upload it anyway
91
+ if object.chef_environment != '_default'
92
+ result << "/environments/#{object.chef_environment}.json"
93
+ end
94
+ return result + dependencies_from_runlist(object.run_list)
85
95
  elsif object.is_a?(Chef::Role)
86
96
  result = []
87
97
  object.env_run_lists.each_pair do |env,run_list|
@@ -3,7 +3,7 @@ require 'chef_fs/command_line'
3
3
 
4
4
  class Chef
5
5
  class Knife
6
- remove_const(:Diff) if const_defined?(:Diff) # override Chef's version
6
+ remove_const(:Diff) if const_defined?(:Diff) && Diff.name == 'Chef::Knife::Diff' # override Chef's version
7
7
  class Diff < ::ChefFS::Knife
8
8
  ChefFS = ::ChefFS
9
9
  banner "knife diff PATTERNS"
@@ -38,7 +38,7 @@ class Chef
38
38
  # Get the matches (recursively)
39
39
  patterns.each do |pattern|
40
40
  ChefFS::CommandLine.diff(pattern, chef_fs, local_fs, config[:recurse] ? nil : 1, output_mode) do |diff|
41
- puts diff
41
+ output diff
42
42
  end
43
43
  end
44
44
  end
@@ -3,7 +3,7 @@ require 'chef_fs/command_line'
3
3
 
4
4
  class Chef
5
5
  class Knife
6
- remove_const(:Download) if const_defined?(:Download) # override Chef's version
6
+ remove_const(:Download) if const_defined?(:Download) && Download.name == 'Chef::Knife::Download' # override Chef's version
7
7
  class Download < ::ChefFS::Knife
8
8
  ChefFS = ::ChefFS
9
9
  banner "knife download PATTERNS"
@@ -43,7 +43,7 @@ class Chef
43
43
  end
44
44
 
45
45
  pattern_args.each do |pattern|
46
- ChefFS::FileSystem.copy_to(pattern, chef_fs, local_fs, config[:recurse] ? nil : 1, config)
46
+ ChefFS::FileSystem.copy_to(pattern, chef_fs, local_fs, config[:recurse] ? nil : 1, config, ui)
47
47
  end
48
48
  end
49
49
  end
@@ -3,7 +3,7 @@ require 'chef_fs/file_system'
3
3
 
4
4
  class Chef
5
5
  class Knife
6
- remove_const(:List) if const_defined?(:List) # override Chef's version
6
+ remove_const(:List) if const_defined?(:List) && List.name == 'Chef::Knife::List' # override Chef's version
7
7
  class List < ::ChefFS::Knife
8
8
  ChefFS = ::ChefFS
9
9
  banner "knife list [-dR] [PATTERN1 ... PATTERNn]"
@@ -13,15 +13,29 @@ class Chef
13
13
  option :recursive,
14
14
  :short => '-R',
15
15
  :boolean => true,
16
- :description => "List directories recursively."
16
+ :description => "List directories recursively"
17
17
  option :bare_directories,
18
18
  :short => '-d',
19
19
  :boolean => true,
20
- :description => "When directories match the pattern, do not show the directories' children."
20
+ :description => "When directories match the pattern, do not show the directories' children"
21
21
  option :local,
22
22
  :long => '--local',
23
23
  :boolean => true,
24
24
  :description => "List local directory instead of remote"
25
+ option :flat,
26
+ :long => '--flat',
27
+ :boolean => true,
28
+ :description => "Show a list of filenames rather than the prettified ls-like output normally produced"
29
+ option :one_column,
30
+ :short => '-1',
31
+ :boolean => true,
32
+ :description => "Show only one column of results"
33
+ option :trailing_slashes,
34
+ :short => '-p',
35
+ :boolean => true,
36
+ :description => "Show trailing slashes after directories"
37
+
38
+ attr_accessor :exit_code
25
39
 
26
40
  def run
27
41
  patterns = name_args.length == 0 ? [""] : name_args
@@ -36,11 +50,19 @@ class Chef
36
50
  elsif result.exists?
37
51
  results << result
38
52
  elsif pattern.exact_path
39
- STDERR.puts "#{format_path(result.path)}: No such file or directory"
53
+ ui.error "#{format_path(result.path)}: No such file or directory"
54
+ self.exit_code = 1
40
55
  end
41
56
  end
42
57
  end
43
58
 
59
+ if config[:flat]
60
+ dir_results.each do |result, children|
61
+ results += children
62
+ end
63
+ dir_results = []
64
+ end
65
+
44
66
  results = results.sort_by { |result| result.path }
45
67
  dir_results = dir_results.sort_by { |result| result[0].path }
46
68
 
@@ -50,18 +72,25 @@ class Chef
50
72
  end
51
73
 
52
74
  print_result_paths results
75
+ printed_something = results.length > 0
53
76
  dir_results.each do |result, children|
54
- puts ""
55
- puts "#{format_path(result.path)}:"
56
- print_results(children.map { |result| result.name }.sort, "")
77
+ if printed_something
78
+ output ""
79
+ else
80
+ printed_something = true
81
+ end
82
+ output "#{format_path(result.path)}:"
83
+ print_results(children.map { |result| maybe_add_slash(result.name, result.dir?) }.sort, "")
57
84
  end
85
+
86
+ exit self.exit_code if self.exit_code
58
87
  end
59
88
 
60
89
  def add_dir_result(result)
61
90
  begin
62
91
  children = result.children.sort_by { |child| child.name }
63
92
  rescue ChefFS::FileSystem::NotFoundError
64
- STDERR.puts "#{format_path(result.path)}: No such file or directory"
93
+ ui.error "#{format_path(result.path)}: No such file or directory"
65
94
  return []
66
95
  end
67
96
 
@@ -76,38 +105,41 @@ class Chef
76
105
  result
77
106
  end
78
107
 
79
- def list_dirs_recursive(children)
80
- results = children.select { |child| child.dir? }.to_a
81
- results.each do |child|
82
- results += list_dirs_recursive(child.children)
83
- end
84
- results
85
- end
86
-
87
108
  def print_result_paths(results, indent = "")
88
- print_results(results.map { |result| format_path(result.path) }, indent)
109
+ print_results(results.map { |result| maybe_add_slash(format_path(result.path), result.dir?) }, indent)
89
110
  end
90
111
 
91
112
  def print_results(results, indent)
92
113
  return if results.length == 0
93
114
 
94
115
  print_space = results.map { |result| result.length }.max + 2
95
- # TODO: tput cols is not cross platform
96
- columns = $stdout.isatty ? Integer(`tput cols`) : 0
97
- current_column = 0
116
+ if config[:one_column] || !stdout.isatty
117
+ columns = 0
118
+ else
119
+ # TODO: tput cols is not cross platform
120
+ columns = Integer(`tput cols`)
121
+ end
122
+ current_line = ''
98
123
  results.each do |result|
99
- if current_column != 0 && current_column + print_space > columns
100
- puts ""
101
- current_column = 0
124
+ if current_line.length > 0 && current_line.length + print_space > columns
125
+ output current_line.rstrip
126
+ current_line = ''
102
127
  end
103
- if current_column == 0
104
- print indent
105
- current_column += indent.length
128
+ if current_line.length == 0
129
+ current_line << indent
106
130
  end
107
- print result + (' ' * (print_space - result.length))
108
- current_column += print_space
131
+ current_line << result
132
+ current_line << (' ' * (print_space - result.length))
133
+ end
134
+ output current_line.rstrip if current_line.length > 0
135
+ end
136
+
137
+ def maybe_add_slash(path, is_dir)
138
+ if config[:trailing_slashes] && is_dir
139
+ "#{path}/"
140
+ else
141
+ path
109
142
  end
110
- puts ""
111
143
  end
112
144
  end
113
145
  end
@@ -2,7 +2,7 @@ require 'json'
2
2
 
3
3
  class Chef
4
4
  class Knife
5
- remove_const(:Raw) if const_defined?(:Raw) # override Chef's version
5
+ remove_const(:Raw) if const_defined?(:Raw) && Raw.name == 'Chef::Knife::Raw' # override Chef's version
6
6
  class Raw < Chef::Knife
7
7
  ChefFS = ::ChefFS
8
8
  banner "knife raw REQUEST_PATH"
@@ -11,13 +11,13 @@ class Chef
11
11
  :long => '--method METHOD',
12
12
  :short => '-m METHOD',
13
13
  :default => "GET",
14
- :description => "Request method (GET, POST, PUT or DELETE)"
14
+ :description => "Request method (GET, POST, PUT or DELETE). Default: GET"
15
15
 
16
16
  option :pretty,
17
17
  :long => '--[no-]pretty',
18
18
  :boolean => true,
19
19
  :default => true,
20
- :description => "Pretty-print JSON output"
20
+ :description => "Pretty-print JSON output. Default: true"
21
21
 
22
22
  option :input,
23
23
  :long => '--input FILE',
@@ -41,7 +41,7 @@ class Chef
41
41
  data = IO.read(config[:input])
42
42
  end
43
43
  chef_rest = Chef::REST.new(Chef::Config[:chef_server_url])
44
- puts api_request(chef_rest, config[:method].to_sym, chef_rest.create_url(name_args[0]), {}, data)
44
+ output api_request(chef_rest, config[:method].to_sym, chef_rest.create_url(name_args[0]), {}, data)
45
45
  end
46
46
 
47
47
  ACCEPT_ENCODING = "Accept-Encoding".freeze
@@ -87,7 +87,7 @@ class Chef
87
87
  msg << (exception["error"].respond_to?(:join) ? exception["error"].join(", ") : exception["error"].to_s)
88
88
  Chef::Log.info(msg)
89
89
  end
90
- puts response.body
90
+ output response.body
91
91
  response.error!
92
92
  end
93
93
  end
@@ -3,7 +3,7 @@ require 'chef_fs/file_system'
3
3
 
4
4
  class Chef
5
5
  class Knife
6
- remove_const(:Show) if const_defined?(:Show) # override Chef's version
6
+ remove_const(:Show) if const_defined?(:Show) && Show.name == 'Chef::Knife::Show' # override Chef's version
7
7
  class Show < ::ChefFS::Knife
8
8
  ChefFS = ::ChefFS
9
9
  banner "knife show [PATTERN1 ... PATTERNn]"
@@ -20,14 +20,14 @@ class Chef
20
20
  pattern_args.each do |pattern|
21
21
  ChefFS::FileSystem.list(config[:local] ? local_fs : chef_fs, pattern) do |result|
22
22
  if result.dir?
23
- STDERR.puts "#{result.path_for_printing}: is a directory" if pattern.exact_path
23
+ ui.error "#{result.path_for_printing}: is a directory" if pattern.exact_path
24
24
  else
25
25
  begin
26
26
  value = result.read
27
- puts "#{result.path_for_printing}:"
27
+ output "#{result.path_for_printing}:"
28
28
  output(format_for_display(value))
29
29
  rescue ChefFS::FileSystem::NotFoundError
30
- STDERR.puts "#{result.path_for_printing}: No such file or directory"
30
+ ui.error "#{result.path_for_printing}: No such file or directory"
31
31
  end
32
32
  end
33
33
  end
@@ -3,7 +3,7 @@ require 'chef_fs/command_line'
3
3
 
4
4
  class Chef
5
5
  class Knife
6
- remove_const(:Upload) if const_defined?(:Upload) # override Chef's version
6
+ remove_const(:Upload) if const_defined?(:Upload) && Upload.name == 'Chef::Knife::Upload' # override Chef's version
7
7
  class Upload < ::ChefFS::Knife
8
8
  ChefFS = ::ChefFS
9
9
  banner "knife upload PATTERNS"
@@ -43,7 +43,7 @@ class Chef
43
43
  end
44
44
 
45
45
  pattern_args.each do |pattern|
46
- ChefFS::FileSystem.copy_to(pattern, local_fs, chef_fs, config[:recurse] ? nil : 1, config)
46
+ ChefFS::FileSystem.copy_to(pattern, local_fs, chef_fs, config[:recurse] ? nil : 1, config, ui)
47
47
  end
48
48
  end
49
49
  end
@@ -34,7 +34,7 @@ module ChefFS
34
34
  block.call(entry)
35
35
  end
36
36
 
37
- if entry.dir? && pattern.could_match_children?(entry.path)
37
+ if pattern.could_match_children?(entry.path)
38
38
  # If it's possible that our children could match, descend in and add matches.
39
39
  exact_child_name = pattern.exact_child_name_under(entry.path)
40
40
 
@@ -47,7 +47,7 @@ module ChefFS
47
47
  end
48
48
 
49
49
  # Otherwise, go through all children and find any matches
50
- else
50
+ elsif entry.dir?
51
51
  entry.children.each do |child|
52
52
  list(child, pattern, &block)
53
53
  end
@@ -112,15 +112,15 @@ module ChefFS
112
112
  # puts message
113
113
  # end
114
114
  #
115
- def self.copy_to(pattern, src_root, dest_root, recurse_depth, options)
115
+ def self.copy_to(pattern, src_root, dest_root, recurse_depth, options, ui)
116
116
  found_result = false
117
117
  list_pairs(pattern, src_root, dest_root) do |src, dest|
118
118
  found_result = true
119
- new_dest_parent = get_or_create_parent(dest, options)
120
- copy_entries(src, dest, new_dest_parent, recurse_depth, options)
119
+ new_dest_parent = get_or_create_parent(dest, options, ui)
120
+ copy_entries(src, dest, new_dest_parent, recurse_depth, options, ui)
121
121
  end
122
122
  if !found_result && pattern.exact_path
123
- puts "#{pattern}: No such file or directory on remote or local"
123
+ ui.error "#{pattern}: No such file or directory on remote or local"
124
124
  end
125
125
  end
126
126
 
@@ -215,7 +215,7 @@ module ChefFS
215
215
  private
216
216
 
217
217
  # Copy two entries (could be files or dirs)
218
- def self.copy_entries(src_entry, dest_entry, new_dest_parent, recurse_depth, options)
218
+ def self.copy_entries(src_entry, dest_entry, new_dest_parent, recurse_depth, options, ui)
219
219
  # A NOTE about this algorithm:
220
220
  # There are cases where this algorithm does too many network requests.
221
221
  # knife upload with a specific filename will first check if the file
@@ -232,10 +232,10 @@ module ChefFS
232
232
  # If we would not have uploaded it, we will not purge it.
233
233
  if src_entry.parent.can_have_child?(dest_entry.name, dest_entry.dir?)
234
234
  if options[:dry_run]
235
- puts "Would delete #{dest_entry.path_for_printing}"
235
+ ui.output "Would delete #{dest_entry.path_for_printing}"
236
236
  else
237
237
  dest_entry.delete(true)
238
- puts "Deleted extra entry #{dest_entry.path_for_printing} (purge is on)"
238
+ ui.output "Deleted extra entry #{dest_entry.path_for_printing} (purge is on)"
239
239
  end
240
240
  else
241
241
  Chef::Log.info("Not deleting extra entry #{dest_entry.path_for_printing} (purge is off)")
@@ -247,35 +247,35 @@ module ChefFS
247
247
  # If the entry can do a copy directly from filesystem, do that.
248
248
  if new_dest_parent.respond_to?(:create_child_from)
249
249
  if options[:dry_run]
250
- puts "Would create #{dest_entry.path_for_printing}"
250
+ ui.output "Would create #{dest_entry.path_for_printing}"
251
251
  else
252
252
  new_dest_parent.create_child_from(src_entry)
253
- puts "Created #{dest_entry.path_for_printing}"
253
+ ui.output "Created #{dest_entry.path_for_printing}"
254
254
  end
255
255
  return
256
256
  end
257
257
 
258
258
  if src_entry.dir?
259
259
  if options[:dry_run]
260
- puts "Would create #{dest_entry.path_for_printing}"
260
+ ui.output "Would create #{dest_entry.path_for_printing}"
261
261
  new_dest_dir = new_dest_parent.child(src_entry.name)
262
262
  else
263
263
  new_dest_dir = new_dest_parent.create_child(src_entry.name, nil)
264
- puts "Created #{dest_entry.path_for_printing}/"
264
+ ui.output "Created #{dest_entry.path_for_printing}/"
265
265
  end
266
266
  # Directory creation is recursive.
267
267
  if recurse_depth != 0
268
268
  src_entry.children.each do |src_child|
269
269
  new_dest_child = new_dest_dir.child(src_child.name)
270
- copy_entries(src_child, new_dest_child, new_dest_dir, recurse_depth ? recurse_depth - 1 : recurse_depth, options)
270
+ copy_entries(src_child, new_dest_child, new_dest_dir, recurse_depth ? recurse_depth - 1 : recurse_depth, options, ui)
271
271
  end
272
272
  end
273
273
  else
274
274
  if options[:dry_run]
275
- puts "Would create #{dest_entry.path_for_printing}"
275
+ ui.output "Would create #{dest_entry.path_for_printing}"
276
276
  else
277
277
  new_dest_parent.create_child(src_entry.name, src_entry.read)
278
- puts "Created #{dest_entry.path_for_printing}"
278
+ ui.output "Created #{dest_entry.path_for_printing}"
279
279
  end
280
280
  end
281
281
  end
@@ -287,10 +287,10 @@ module ChefFS
287
287
  if dest_entry.respond_to?(:copy_from)
288
288
  if options[:force] || compare(src_entry, dest_entry)[0] == false
289
289
  if options[:dry_run]
290
- puts "Would update #{dest_entry.path_for_printing}"
290
+ ui.output "Would update #{dest_entry.path_for_printing}"
291
291
  else
292
292
  dest_entry.copy_from(src_entry)
293
- puts "Updated #{dest_entry.path_for_printing}"
293
+ ui.output "Updated #{dest_entry.path_for_printing}"
294
294
  end
295
295
  end
296
296
  return
@@ -302,17 +302,17 @@ module ChefFS
302
302
  # If both are directories, recurse into their children
303
303
  if recurse_depth != 0
304
304
  child_pairs(src_entry, dest_entry).each do |src_child, dest_child|
305
- copy_entries(src_child, dest_child, dest_entry, recurse_depth ? recurse_depth - 1 : recurse_depth, options)
305
+ copy_entries(src_child, dest_child, dest_entry, recurse_depth ? recurse_depth - 1 : recurse_depth, options, ui)
306
306
  end
307
307
  end
308
308
  else
309
309
  # If they are different types.
310
- Chef::Log.error("File #{dest_entry.path_for_printing} is a directory while file #{dest_entry.path_for_printing} is a regular file\n")
310
+ ui.error("File #{dest_entry.path_for_printing} is a directory while file #{dest_entry.path_for_printing} is a regular file\n")
311
311
  return
312
312
  end
313
313
  else
314
314
  if dest_entry.dir?
315
- Chef::Log.error("File #{dest_entry.path_for_printing} is a directory while file #{dest_entry.path_for_printing} is a regular file\n")
315
+ ui.error("File #{dest_entry.path_for_printing} is a directory while file #{dest_entry.path_for_printing} is a regular file\n")
316
316
  return
317
317
  else
318
318
 
@@ -326,11 +326,11 @@ module ChefFS
326
326
  end
327
327
  if should_copy
328
328
  if options[:dry_run]
329
- puts "Would update #{dest_entry.path_for_printing}"
329
+ ui.output "Would update #{dest_entry.path_for_printing}"
330
330
  else
331
331
  src_value = src_entry.read if src_value.nil?
332
332
  dest_entry.write(src_value)
333
- puts "Updated #{dest_entry.path_for_printing}"
333
+ ui.output "Updated #{dest_entry.path_for_printing}"
334
334
  end
335
335
  end
336
336
  end
@@ -338,15 +338,15 @@ module ChefFS
338
338
  end
339
339
  end
340
340
 
341
- def self.get_or_create_parent(entry, options)
341
+ def self.get_or_create_parent(entry, options, ui)
342
342
  parent = entry.parent
343
343
  if parent && !parent.exists?
344
- parent_parent = get_or_create_parent(entry.parent, options)
344
+ parent_parent = get_or_create_parent(entry.parent, options, ui)
345
345
  if options[:dry_run]
346
- puts "Would create #{parent.path_for_printing}"
346
+ ui.output "Would create #{parent.path_for_printing}"
347
347
  else
348
348
  parent = parent_parent.create_child(parent.name, true)
349
- puts "Created #{parent.path_for_printing}"
349
+ ui.output "Created #{parent.path_for_printing}"
350
350
  end
351
351
  end
352
352
  return parent