knife-essentials 0.9.8 → 1.0.0.beta1

Sign up to get free protection for your applications and to get access to all the features.
@@ -38,7 +38,7 @@ class Chef
38
38
  error = false
39
39
  if config[:remote_only]
40
40
  pattern_args.each do |pattern|
41
- ChefFS::FileSystem.list(chef_fs, pattern) do |result|
41
+ ChefFS::FileSystem.list(chef_fs, pattern).each do |result|
42
42
  if delete_result(result)
43
43
  error = true
44
44
  end
@@ -46,7 +46,7 @@ class Chef
46
46
  end
47
47
  elsif config[:local_only]
48
48
  pattern_args.each do |pattern|
49
- ChefFS::FileSystem.list(local_fs, pattern) do |result|
49
+ ChefFS::FileSystem.list(local_fs, pattern).each do |result|
50
50
  if delete_result(result)
51
51
  error = true
52
52
  end
@@ -54,7 +54,7 @@ class Chef
54
54
  end
55
55
  else
56
56
  pattern_args.each do |pattern|
57
- ChefFS::FileSystem.list_pairs(pattern, chef_fs, local_fs) do |chef_result, local_result|
57
+ ChefFS::FileSystem.list_pairs(pattern, chef_fs, local_fs).each do |chef_result, local_result|
58
58
  if delete_result(chef_result, local_result)
59
59
  error = true
60
60
  end
@@ -36,7 +36,7 @@ class Chef
36
36
  @root = config[:remote] ? chef_fs : local_fs
37
37
  dependencies = {}
38
38
  pattern_args.each do |pattern|
39
- ChefFS::FileSystem.list(@root, pattern) do |entry|
39
+ ChefFS::FileSystem.list(@root, pattern).each do |entry|
40
40
  if config[:tree]
41
41
  print_dependencies_tree(entry, dependencies)
42
42
  else
@@ -20,7 +20,7 @@ class Chef
20
20
  # Get the matches (recursively)
21
21
  error = false
22
22
  pattern_args.each do |pattern|
23
- ChefFS::FileSystem.list(config[:local] ? local_fs : chef_fs, pattern) do |result|
23
+ ChefFS::FileSystem.list(config[:local] ? local_fs : chef_fs, pattern).each do |result|
24
24
  if result.dir?
25
25
  ui.error "#{format_path(result)}: is a directory" if pattern.exact_path
26
26
  error = true
@@ -43,21 +43,28 @@ class Chef
43
43
  patterns = name_args.length == 0 ? [""] : name_args
44
44
 
45
45
  # Get the matches (recursively)
46
- results = []
47
- dir_results = []
48
- pattern_args_from(patterns).each do |pattern|
49
- ChefFS::FileSystem.list(config[:local] ? local_fs : chef_fs, pattern) do |result|
50
- if result.dir? && !config[:bare_directories]
51
- dir_results += add_dir_result(result)
52
- elsif result.exists?
53
- results << result
54
- elsif pattern.exact_path
55
- ui.error "#{format_path(result)}: No such file or directory"
56
- self.exit_code = 1
57
- end
46
+ all_results = parallelize(pattern_args_from(patterns), :flatten => true) do |pattern|
47
+ pattern_results = ChefFS::FileSystem.list(config[:local] ? local_fs : chef_fs, pattern)
48
+ if pattern_results.first && !pattern_results.first.exists? && pattern.exact_path
49
+ ui.error "#{format_path(pattern_results.first)}: No such file or directory"
50
+ self.exit_code = 1
58
51
  end
52
+ pattern_results
59
53
  end
60
54
 
55
+ # Process directories
56
+ if !config[:bare_directories]
57
+ dir_results = parallelize(all_results.select { |result| result.dir? }, :flatten => true) do |result|
58
+ add_dir_result(result)
59
+ end.to_a
60
+ else
61
+ dir_results = []
62
+ end
63
+
64
+ # Process all other results
65
+ results = all_results.select { |result| result.exists? && (!result.dir? || config[:bare_directories]) }.to_a
66
+
67
+ # Flatten out directory results if necessary
61
68
  if config[:flat]
62
69
  dir_results.each do |result, children|
63
70
  results += children
@@ -65,9 +72,11 @@ class Chef
65
72
  dir_results = []
66
73
  end
67
74
 
75
+ # Sort by path for happy output
68
76
  results = results.sort_by { |result| result.path }
69
77
  dir_results = dir_results.sort_by { |result| result[0].path }
70
78
 
79
+ # Print!
71
80
  if results.length == 0 && dir_results.length == 1
72
81
  results = dir_results[0][1]
73
82
  dir_results = []
@@ -98,11 +107,8 @@ class Chef
98
107
 
99
108
  result = [ [ result, children ] ]
100
109
  if config[:recursive]
101
- children.each do |child|
102
- if child.dir?
103
- result += add_dir_result(child)
104
- end
105
- end
110
+ child_dirs = children.select { |child| child.dir? }
111
+ result += parallelize(child_dirs, :flatten => true) { |child| add_dir_result(child) }.to_a
106
112
  end
107
113
  result
108
114
  end
@@ -19,26 +19,33 @@ class Chef
19
19
  def run
20
20
  # Get the matches (recursively)
21
21
  error = false
22
- pattern_args.each do |pattern|
23
- ChefFS::FileSystem.list(config[:local] ? local_fs : chef_fs, pattern) do |result|
24
- if result.dir?
25
- ui.error "#{format_path(result)}: is a directory" if pattern.exact_path
22
+ entry_values = parallelize(pattern_args, :flatten => true) do |pattern|
23
+ parallelize(ChefFS::FileSystem.list(config[:local] ? local_fs : chef_fs, pattern)) do |entry|
24
+ if entry.dir?
25
+ ui.error "#{format_path(entry)}: is a directory" if pattern.exact_path
26
26
  error = true
27
+ nil
27
28
  else
28
29
  begin
29
- value = result.read
30
- output "#{format_path(result)}:"
31
- output(format_for_display(value))
30
+ [entry, entry.read]
32
31
  rescue ChefFS::FileSystem::OperationNotAllowedError => e
33
32
  ui.error "#{format_path(e.entry)}: #{e.reason}."
34
33
  error = true
34
+ nil
35
35
  rescue ChefFS::FileSystem::NotFoundError => e
36
36
  ui.error "#{format_path(e.entry)}: No such file or directory"
37
37
  error = true
38
+ nil
38
39
  end
39
40
  end
40
41
  end
41
42
  end
43
+ entry_values.each do |entry, value|
44
+ if entry
45
+ output "#{format_path(entry)}:"
46
+ output(format_for_display(value))
47
+ end
48
+ end
42
49
  if error
43
50
  exit 1
44
51
  end
@@ -74,7 +74,7 @@ class Chef
74
74
  # Get the matches (recursively)
75
75
  files = []
76
76
  pattern_args_from(get_patterns).each do |pattern|
77
- ChefFS::FileSystem.list(config[:local] ? local_fs : chef_fs, pattern) do |result|
77
+ ChefFS::FileSystem.list(config[:local] ? local_fs : chef_fs, pattern).each do |result|
78
78
  if result.dir?
79
79
  # TODO option to include directories
80
80
  ui.warn "#{format_path(result)}: is a directory. Will not run #{command} on it."
@@ -30,7 +30,7 @@ module ChefFS
30
30
 
31
31
  get_content = (output_mode != :name_only && output_mode != :name_status)
32
32
  found_match = false
33
- diff(pattern, a_root, b_root, recurse_depth, get_content) do |type, old_entry, new_entry, old_value, new_value, error|
33
+ diff(pattern, a_root, b_root, recurse_depth, get_content).each do |type, old_entry, new_entry, old_value, new_value, error|
34
34
  found_match = true unless type == :both_nonexistent
35
35
  old_path = format_path.call(old_entry)
36
36
  new_path = format_path.call(new_entry)
@@ -124,112 +124,128 @@ module ChefFS
124
124
  error
125
125
  end
126
126
 
127
- def self.diff(pattern, a_root, b_root, recurse_depth, get_content)
128
- ChefFS::FileSystem.list_pairs(pattern, a_root, b_root) do |a, b|
129
- diff_entries(a, b, recurse_depth, get_content) do |diff|
130
- yield diff
131
- end
127
+ def self.diff(pattern, old_root, new_root, recurse_depth, get_content)
128
+ ChefFS::Parallelizer.parallelize(ChefFS::FileSystem.list_pairs(pattern, old_root, new_root), :flatten => true) do |old_entry, new_entry|
129
+ diff_entries(old_entry, new_entry, recurse_depth, get_content)
132
130
  end
133
131
  end
134
132
 
135
133
  # Diff two known entries (could be files or dirs)
136
134
  def self.diff_entries(old_entry, new_entry, recurse_depth, get_content)
137
- begin
138
- # If both are directories
139
- if old_entry.dir?
140
- if new_entry.dir?
141
- if recurse_depth == 0
142
- yield [ :common_subdirectories, old_entry, new_entry ]
143
- else
144
- ChefFS::FileSystem.child_pairs(old_entry, new_entry).each do |old_child,new_child|
145
- diff_entries(old_child, new_child,
146
- recurse_depth ? recurse_depth - 1 : nil, get_content) do |diff|
147
- yield diff
148
- end
149
- end
135
+ # If both are directories
136
+ if old_entry.dir?
137
+ if new_entry.dir?
138
+ if recurse_depth == 0
139
+ return [ [ :common_subdirectories, old_entry, new_entry ] ]
140
+ else
141
+ return ChefFS::Parallelizer.parallelize(ChefFS::FileSystem.child_pairs(old_entry, new_entry), :flatten => true) do |old_child, new_child|
142
+ ChefFS::CommandLine.diff_entries(old_child, new_child, recurse_depth ? recurse_depth - 1 : nil, get_content)
150
143
  end
144
+ end
151
145
 
152
146
  # If old is a directory and new is a file
153
- elsif new_entry.exists?
154
- yield [ :directory_to_file, old_entry, new_entry ]
147
+ elsif new_entry.exists?
148
+ return [ [ :directory_to_file, old_entry, new_entry ] ]
155
149
 
156
150
  # If old is a directory and new does not exist
157
- elsif new_entry.parent.can_have_child?(old_entry.name, old_entry.dir?)
158
- yield [ :deleted, old_entry, new_entry ]
159
- end
151
+ elsif new_entry.parent.can_have_child?(old_entry.name, old_entry.dir?)
152
+ return [ [ :deleted, old_entry, new_entry ] ]
160
153
 
161
- # If new is a directory and old is a file
162
- elsif new_entry.dir?
163
- if old_entry.exists?
164
- yield [ :file_to_directory, old_entry, new_entry ]
154
+ # If the new entry does not and *cannot* exist, report that.
155
+ else
156
+ return [ [ :new_cannot_upload, old_entry, new_entry ] ]
157
+ end
158
+
159
+ # If new is a directory and old is a file
160
+ elsif new_entry.dir?
161
+ if old_entry.exists?
162
+ return [ [ :file_to_directory, old_entry, new_entry ] ]
165
163
 
166
164
  # If new is a directory and old does not exist
167
- elsif old_entry.parent.can_have_child?(new_entry.name, new_entry.dir?)
168
- yield [ :added, old_entry, new_entry ]
169
- end
165
+ elsif old_entry.parent.can_have_child?(new_entry.name, new_entry.dir?)
166
+ return [ [ :added, old_entry, new_entry ] ]
170
167
 
171
- # Neither is a directory, so they are diffable with file diff
168
+ # If the new entry does not and *cannot* exist, report that.
172
169
  else
173
- are_same, old_value, new_value = ChefFS::FileSystem.compare(old_entry, new_entry)
174
- if are_same
175
- if old_value == :none
176
- yield [ :both_nonexistent, old_entry, new_entry ]
177
- else
178
- yield [ :same, old_entry, new_entry ]
179
- end
170
+ return [ [ :old_cannot_upload, old_entry, new_entry ] ]
171
+ end
172
+
173
+ # Neither is a directory, so they are diffable with file diff
174
+ else
175
+ are_same, old_value, new_value = ChefFS::FileSystem.compare(old_entry, new_entry)
176
+ if are_same
177
+ if old_value == :none
178
+ return [ [ :both_nonexistent, old_entry, new_entry ] ]
180
179
  else
181
- if old_value == :none
182
- old_exists = false
183
- elsif old_value.nil?
184
- old_exists = old_entry.exists?
185
- else
186
- old_exists = true
187
- end
180
+ return [ [ :same, old_entry, new_entry ] ]
181
+ end
182
+ else
183
+ if old_value == :none
184
+ old_exists = false
185
+ elsif old_value.nil?
186
+ old_exists = old_entry.exists?
187
+ else
188
+ old_exists = true
189
+ end
188
190
 
189
- if new_value == :none
190
- new_exists = false
191
- elsif new_value.nil?
192
- new_exists = new_entry.exists?
193
- else
194
- new_exists = true
195
- end
191
+ if new_value == :none
192
+ new_exists = false
193
+ elsif new_value.nil?
194
+ new_exists = new_entry.exists?
195
+ else
196
+ new_exists = true
197
+ end
196
198
 
197
- # If one of the files doesn't exist, we only want to print the diff if the
198
- # other file *could be uploaded/downloaded*.
199
- if !old_exists && !old_entry.parent.can_have_child?(new_entry.name, new_entry.dir?)
200
- yield [ :old_cannot_upload, old_entry, new_entry ]
201
- return
202
- end
203
- if !new_exists && !new_entry.parent.can_have_child?(old_entry.name, old_entry.dir?)
204
- yield [ :new_cannot_upload, old_entry, new_entry ]
205
- return
206
- end
199
+ # If one of the files doesn't exist, we only want to print the diff if the
200
+ # other file *could be uploaded/downloaded*.
201
+ if !old_exists && !old_entry.parent.can_have_child?(new_entry.name, new_entry.dir?)
202
+ return [ [ :old_cannot_upload, old_entry, new_entry ] ]
203
+ end
204
+ if !new_exists && !new_entry.parent.can_have_child?(old_entry.name, old_entry.dir?)
205
+ return [ [ :new_cannot_upload, old_entry, new_entry ] ]
206
+ end
207
207
 
208
- if get_content
209
- # If we haven't read the values yet, get them now so that they can be diffed
210
- begin
211
- old_value = old_entry.read if old_value.nil?
212
- rescue ChefFS::FileSystem::NotFoundError
213
- old_value = :none
214
- end
215
- begin
216
- new_value = new_entry.read if new_value.nil?
217
- rescue ChefFS::FileSystem::NotFoundError
218
- new_value = :none
219
- end
208
+ if get_content
209
+ # If we haven't read the values yet, get them now so that they can be diffed
210
+ begin
211
+ old_value = old_entry.read if old_value.nil?
212
+ rescue ChefFS::FileSystem::NotFoundError
213
+ old_value = :none
220
214
  end
221
-
222
- if old_value == :none || (old_value == nil && !old_entry.exists?)
223
- yield [ :added, old_entry, new_entry, old_value, new_value ]
224
- elsif new_value == :none
225
- yield [ :deleted, old_entry, new_entry, old_value, new_value ]
226
- else
227
- yield [ :modified, old_entry, new_entry, old_value, new_value ]
215
+ begin
216
+ new_value = new_entry.read if new_value.nil?
217
+ rescue ChefFS::FileSystem::NotFoundError
218
+ new_value = :none
228
219
  end
229
220
  end
221
+
222
+ if old_value == :none || (old_value == nil && !old_entry.exists?)
223
+ return [ [ :added, old_entry, new_entry, old_value, new_value ] ]
224
+ elsif new_value == :none
225
+ return [ [ :deleted, old_entry, new_entry, old_value, new_value ] ]
226
+ else
227
+ return [ [ :modified, old_entry, new_entry, old_value, new_value ] ]
228
+ end
230
229
  end
231
- rescue ChefFS::FileSystem::FileSystemError => e
232
- yield [ :error, old_entry, new_entry, nil, nil, e ]
230
+ end
231
+ rescue ChefFS::FileSystem::FileSystemError => e
232
+ return [ [ :error, old_entry, new_entry, nil, nil, e ] ]
233
+ end
234
+
235
+ class Differ
236
+ def initialize(old_entry, new_entry, recurse_depth, get_content)
237
+ @old_entry = old_entry
238
+ @new_entry = new_entry
239
+ @recurse_depth = recurse_depth
240
+ @get_content = get_content
241
+ end
242
+
243
+ attr_reader :old_entry
244
+ attr_reader :new_entry
245
+ attr_reader :recurse_depth
246
+ attr_reader :get_content
247
+
248
+ def each
233
249
  end
234
250
  end
235
251
 
@@ -20,39 +20,59 @@ require 'chef_fs/path_utils'
20
20
  require 'chef_fs/file_system/default_environment_cannot_be_modified_error'
21
21
  require 'chef_fs/file_system/operation_failed_error'
22
22
  require 'chef_fs/file_system/operation_not_allowed_error'
23
+ require 'chef_fs/parallelizer'
23
24
 
24
25
  module ChefFS
25
26
  module FileSystem
26
- # Yields a list of all things under (and including) this entry that match the
27
+ # Returns a list of all things under (and including) this entry that match the
27
28
  # given pattern.
28
29
  #
29
30
  # ==== Attributes
30
31
  #
31
- # * +entry+ - Entry to start listing under
32
+ # * +root+ - Entry to start listing under
32
33
  # * +pattern+ - ChefFS::FilePattern to match children under
33
34
  #
34
- def self.list(entry, pattern, &block)
35
- # Include self in results if it matches
36
- if pattern.match?(entry.path)
37
- block.call(entry)
35
+ def self.list(root, pattern)
36
+ Lister.new(root, pattern)
37
+ end
38
+
39
+ class Lister
40
+ include Enumerable
41
+
42
+ def initialize(root, pattern)
43
+ @root = root
44
+ @pattern = pattern
38
45
  end
39
46
 
40
- if pattern.could_match_children?(entry.path)
41
- # If it's possible that our children could match, descend in and add matches.
42
- exact_child_name = pattern.exact_child_name_under(entry.path)
47
+ attr_reader :root
48
+ attr_reader :pattern
43
49
 
44
- # If we've got an exact name, don't bother listing children; just grab the
45
- # child with the given name.
46
- if exact_child_name
47
- exact_child = entry.child(exact_child_name)
48
- if exact_child
49
- list(exact_child, pattern, &block)
50
- end
50
+ def each(&block)
51
+ list_from(root, &block)
52
+ end
53
+
54
+ def list_from(entry, &block)
55
+ # Include self in results if it matches
56
+ if pattern.match?(entry.path)
57
+ block.call(entry)
58
+ end
59
+
60
+ if pattern.could_match_children?(entry.path)
61
+ # If it's possible that our children could match, descend in and add matches.
62
+ exact_child_name = pattern.exact_child_name_under(entry.path)
63
+
64
+ # If we've got an exact name, don't bother listing children; just grab the
65
+ # child with the given name.
66
+ if exact_child_name
67
+ exact_child = entry.child(exact_child_name)
68
+ if exact_child
69
+ list_from(exact_child, &block)
70
+ end
51
71
 
52
- # Otherwise, go through all children and find any matches
53
- elsif entry.dir?
54
- entry.children.each do |child|
55
- list(child, pattern, &block)
72
+ # Otherwise, go through all children and find any matches
73
+ elsif entry.dir?
74
+ results = Parallelizer::parallelize(entry.children, :flatten => true) { |child| ChefFS::FileSystem.list(child, pattern) }
75
+ results.each(&block)
56
76
  end
57
77
  end
58
78
  end
@@ -118,7 +138,7 @@ module ChefFS
118
138
  def self.copy_to(pattern, src_root, dest_root, recurse_depth, options, ui, format_path)
119
139
  found_result = false
120
140
  error = false
121
- list_pairs(pattern, src_root, dest_root) do |src, dest|
141
+ parallel_do(list_pairs(pattern, src_root, dest_root)) do |src, dest|
122
142
  found_result = true
123
143
  new_dest_parent = get_or_create_parent(dest, options, ui, format_path)
124
144
  child_error = copy_entries(src, dest, new_dest_parent, recurse_depth, options, ui, format_path)
@@ -142,26 +162,44 @@ module ChefFS
142
162
  #
143
163
  # ==== Example
144
164
  #
145
- # ChefFS::FileSystem.list_pairs(FilePattern.new('**x.txt', a_root, b_root)) do |a, b|
165
+ # ChefFS::FileSystem.list_pairs(FilePattern.new('**x.txt', a_root, b_root)).each do |a, b|
146
166
  # ...
147
167
  # end
148
168
  #
149
169
  def self.list_pairs(pattern, a_root, b_root)
150
- # Make sure everything on the server is also on the filesystem, and diff
151
- found_paths = Set.new
152
- ChefFS::FileSystem.list(a_root, pattern) do |a|
153
- found_paths << a.path
154
- b = ChefFS::FileSystem.resolve_path(b_root, a.path)
155
- yield [ a, b ]
170
+ PairLister.new(pattern, a_root, b_root)
171
+ end
172
+
173
+ class PairLister
174
+ include Enumerable
175
+
176
+ def initialize(pattern, a_root, b_root)
177
+ @pattern = pattern
178
+ @a_root = a_root
179
+ @b_root = b_root
156
180
  end
157
181
 
158
- # Check the outer regex pattern to see if it matches anything on the
159
- # filesystem that isn't on the server
160
- ChefFS::FileSystem.list(b_root, pattern) do |b|
161
- if !found_paths.include?(b.path)
162
- a = ChefFS::FileSystem.resolve_path(a_root, b.path)
182
+ attr_reader :pattern
183
+ attr_reader :a_root
184
+ attr_reader :b_root
185
+
186
+ def each
187
+ # Make sure everything on the server is also on the filesystem, and diff
188
+ found_paths = Set.new
189
+ ChefFS::FileSystem.list(a_root, pattern).each do |a|
190
+ found_paths << a.path
191
+ b = ChefFS::FileSystem.resolve_path(b_root, a.path)
163
192
  yield [ a, b ]
164
193
  end
194
+
195
+ # Check the outer regex pattern to see if it matches anything on the
196
+ # filesystem that isn't on the server
197
+ ChefFS::FileSystem.list(b_root, pattern).each do |b|
198
+ if !found_paths.include?(b.path)
199
+ a = ChefFS::FileSystem.resolve_path(a_root, b.path)
200
+ yield [ a, b ]
201
+ end
202
+ end
165
203
  end
166
204
  end
167
205
 
@@ -204,6 +242,7 @@ module ChefFS
204
242
  are_same, b_value, a_value = b.compare_to(a)
205
243
  end
206
244
  if are_same.nil?
245
+ # TODO these reads can be parallelized
207
246
  begin
208
247
  a_value = a.read if a_value.nil?
209
248
  rescue ChefFS::FileSystem::NotFoundError
@@ -276,7 +315,7 @@ module ChefFS
276
315
  end
277
316
  # Directory creation is recursive.
278
317
  if recurse_depth != 0
279
- src_entry.children.each do |src_child|
318
+ parallel_do(src_entry.children) do |src_child|
280
319
  new_dest_child = new_dest_dir.child(src_child.name)
281
320
  child_error = copy_entries(src_child, new_dest_child, new_dest_dir, recurse_depth ? recurse_depth - 1 : recurse_depth, options, ui, format_path)
282
321
  error ||= child_error
@@ -313,7 +352,7 @@ module ChefFS
313
352
  if dest_entry.dir?
314
353
  # If both are directories, recurse into their children
315
354
  if recurse_depth != 0
316
- child_pairs(src_entry, dest_entry).each do |src_child, dest_child|
355
+ parallel_do(child_pairs(src_entry, dest_entry)) do |src_child, dest_child|
317
356
  child_error = copy_entries(src_child, dest_child, dest_entry, recurse_depth ? recurse_depth - 1 : recurse_depth, options, ui, format_path)
318
357
  error ||= child_error
319
358
  end
@@ -376,5 +415,8 @@ module ChefFS
376
415
  return parent
377
416
  end
378
417
 
418
+ def self.parallel_do(enum, options = {}, &block)
419
+ ChefFS::Parallelizer.parallelize(enum, options, &block).to_a
420
+ end
379
421
  end
380
422
  end