knife-essentials 0.8.1 → 0.8.2

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