knife-essentials 0.3.1 → 0.4

Sign up to get free protection for your applications and to get access to all the features.
@@ -12,12 +12,30 @@ class Chef
12
12
  :default => true,
13
13
  :description => "List directories recursively."
14
14
 
15
+ option :name_only,
16
+ :long => '--name-only',
17
+ :boolean => true,
18
+ :description => "Only show names of modified files."
19
+
20
+ option :name_status,
21
+ :long => '--name-status',
22
+ :boolean => true,
23
+ :description => "Only show names and statuses of modified files: Added, Deleted, Modified, and Type Changed."
24
+
25
+ common_options
26
+
15
27
  def run
28
+ if config[:name_only]
29
+ output_mode = :name_only
30
+ end
31
+ if config[:name_status]
32
+ output_mode = :name_status
33
+ end
16
34
  patterns = pattern_args_from(name_args.length > 0 ? name_args : [ "" ])
17
35
 
18
36
  # Get the matches (recursively)
19
37
  patterns.each do |pattern|
20
- ChefFS::CommandLine.diff(pattern, chef_fs, local_fs, config[:recurse] ? nil : 1) do |diff|
38
+ ChefFS::CommandLine.diff(pattern, chef_fs, local_fs, config[:recurse] ? nil : 1, output_mode) do |diff|
21
39
  puts diff
22
40
  end
23
41
  end
@@ -2,11 +2,11 @@ require 'chef_fs/diff'
2
2
 
3
3
  module ChefFS
4
4
  module CommandLine
5
- def self.diff(pattern, a_root, b_root, recurse_depth)
5
+ def self.diff(pattern, a_root, b_root, recurse_depth, output_mode)
6
6
  found_result = false
7
7
  ChefFS::Diff::diffable_leaves_from_pattern(pattern, a_root, b_root, recurse_depth) do |a_leaf, b_leaf|
8
8
  found_result = true
9
- diff = diff_leaves(a_leaf, b_leaf)
9
+ diff = diff_leaves(a_leaf, b_leaf, output_mode)
10
10
  yield diff if diff != ''
11
11
  end
12
12
  if !found_result && pattern.exact_path
@@ -17,27 +17,53 @@ module ChefFS
17
17
  private
18
18
 
19
19
  # Diff two known leaves (could be files or dirs)
20
- def self.diff_leaves(old_file, new_file)
20
+ def self.diff_leaves(old_file, new_file, output_mode)
21
21
  result = ''
22
22
  # If both are directories
23
23
  # If old is a directory and new is a file
24
24
  # If old is a directory and new does not exist
25
25
  if old_file.dir?
26
26
  if new_file.dir?
27
- result << "Common subdirectories: #{old_file.path}\n"
27
+ if output_mode != :name_only && output_mode != :name_status
28
+ result << "Common subdirectories: #{old_file.path}\n"
29
+ end
28
30
  elsif new_file.exists?
29
- result << "File #{new_file.path_for_printing} is a directory while file #{new_file.path_for_printing} is a regular file\n"
31
+ if output_mode == :name_only
32
+ result << "#{new_file.path_for_printing}\n"
33
+ elsif output_mode == :name_status
34
+ result << "T\t#{new_file.path_for_printing}\n"
35
+ else
36
+ result << "File #{new_file.path_for_printing} is a directory while file #{new_file.path_for_printing} is a regular file\n"
37
+ end
30
38
  elsif new_file.parent.can_have_child?(old_file.name, old_file.dir?)
31
- result << "Only in #{old_file.parent.path_for_printing}: #{old_file.name}\n"
39
+ if output_mode == :name_only
40
+ result << "#{new_file.path_for_printing}\n"
41
+ elsif output_mode == :name_status
42
+ result << "D\t#{new_file.path_for_printing}\n"
43
+ else
44
+ result << "Only in #{old_file.parent.path_for_printing}: #{old_file.name}\n"
45
+ end
32
46
  end
33
47
 
34
48
  # If new is a directory and old does not exist
35
49
  # If new is a directory and old is a file
36
50
  elsif new_file.dir?
37
51
  if old_file.exists?
38
- result << "File #{old_file.path_for_printing} is a regular file while file #{old_file.path_for_printing} is a directory\n"
52
+ if output_mode == :name_only
53
+ result << "#{new_file.path_for_printing}\n"
54
+ elsif output_mode == :name_status
55
+ result << "T\t#{new_file.path_for_printing}\n"
56
+ else
57
+ result << "File #{old_file.path_for_printing} is a regular file while file #{old_file.path_for_printing} is a directory\n"
58
+ end
39
59
  elsif old_file.parent.can_have_child?(new_file.name, new_file.dir?)
40
- result << "Only in #{new_file.parent.path_for_printing}: #{new_file.name}\n"
60
+ if output_mode == :name_only
61
+ result << "#{new_file.path_for_printing}\n"
62
+ elsif output_mode == :name_status
63
+ result << "A\t#{new_file.path_for_printing}\n"
64
+ else
65
+ result << "Only in #{new_file.parent.path_for_printing}: #{new_file.name}\n"
66
+ end
41
67
  end
42
68
 
43
69
  else
@@ -45,7 +71,7 @@ module ChefFS
45
71
  different, old_value, new_value = ChefFS::Diff::diff_files(old_file, new_file)
46
72
  if different
47
73
  # If one of the files doesn't exist, we only want to print the diff if the
48
- # other file *could be synced*.
74
+ # other file *could be uploaded/downloaded*.
49
75
  if !old_value && !old_file.parent.can_have_child?(new_file.name, new_file.dir?)
50
76
  return result
51
77
  end
@@ -53,20 +79,32 @@ module ChefFS
53
79
  return result
54
80
  end
55
81
 
56
- old_path = old_file.path_for_printing
57
- new_path = new_file.path_for_printing
58
- result << "diff --knife #{old_path} #{new_path}\n"
59
- if !old_value
60
- result << "new file\n"
61
- old_path = "/dev/null"
62
- old_value = ''
63
- end
64
- if !new_value
65
- result << "deleted file\n"
66
- new_path = "/dev/null"
67
- new_value = ''
82
+ if output_mode == :name_only
83
+ result << "#{new_file.path_for_printing}\n"
84
+ elsif output_mode == :name_status
85
+ if !old_value
86
+ result << "A\t#{new_file.path_for_printing}\n"
87
+ elsif !new_value
88
+ result << "D\t#{new_file.path_for_printing}\n"
89
+ else
90
+ result << "M\t#{new_file.path_for_printing}\n"
91
+ end
92
+ else
93
+ old_path = old_file.path_for_printing
94
+ new_path = new_file.path_for_printing
95
+ result << "diff --knife #{old_path} #{new_path}\n"
96
+ if !old_value
97
+ result << "new file\n"
98
+ old_path = "/dev/null"
99
+ old_value = ''
100
+ end
101
+ if !new_value
102
+ result << "deleted file\n"
103
+ new_path = "/dev/null"
104
+ new_value = ''
105
+ end
106
+ result << diff_text(old_path, new_path, old_value, new_value)
68
107
  end
69
- result << diff_text(old_path, new_path, old_value, new_value)
70
108
  end
71
109
  end
72
110
  return result
@@ -61,20 +61,20 @@ module ChefFS
61
61
  new_value = read_file_value(new_file) if new_value == :not_retrieved
62
62
 
63
63
  return false if old_value == new_value
64
- return false if old_value && new_value && !context_aware_diff(old_file, new_file, old_value, new_value)
64
+ return false if old_value && new_value && context_aware_diff(old_file, new_file, old_value, new_value) == false
65
65
  return [ true, old_value, new_value ]
66
66
  end
67
67
 
68
68
  def self.context_aware_diff(old_file, new_file, old_value, new_value)
69
- # TODO handle errors in reading JSON
70
69
  if old_file.content_type == :json || new_file.content_type == :json
71
- new_value = Chef::JSONCompat.from_json(new_value).to_hash
72
- old_value = Chef::JSONCompat.from_json(old_value).to_hash
73
-
74
- old_value != new_value
75
- else
76
- true
70
+ begin
71
+ new_value = Chef::JSONCompat.from_json(new_value).to_hash
72
+ old_value = Chef::JSONCompat.from_json(old_value).to_hash
73
+ return old_value != new_value
74
+ rescue JSON::ParserError
75
+ end
77
76
  end
77
+ return nil
78
78
  end
79
79
 
80
80
  # Gets all common leaves, recursively, starting from the results of
@@ -7,12 +7,13 @@ require 'chef_fs/file_system/nodes_dir'
7
7
  module ChefFS
8
8
  module FileSystem
9
9
  class ChefServerRootDir < BaseFSDir
10
- def initialize(root_name, config)
10
+ def initialize(root_name, chef_config, repo_mode)
11
11
  super("", nil)
12
- @chef_server_url = config[:chef_server_url]
13
- @chef_username = config[:node_name]
14
- @chef_private_key = config[:client_key]
15
- @environment = config[:environment]
12
+ @chef_server_url = chef_config[:chef_server_url]
13
+ @chef_username = chef_config[:node_name]
14
+ @chef_private_key = chef_config[:client_key]
15
+ @environment = chef_config[:environment]
16
+ @repo_mode = repo_mode
16
17
  @root_name = root_name
17
18
  end
18
19
 
@@ -20,6 +21,7 @@ module ChefFS
20
21
  attr_reader :chef_username
21
22
  attr_reader :chef_private_key
22
23
  attr_reader :environment
24
+ attr_reader :repo_mode
23
25
 
24
26
  def rest
25
27
  Chef::REST.new(chef_server_url, chef_username, chef_private_key)
@@ -38,15 +40,21 @@ module ChefFS
38
40
  end
39
41
 
40
42
  def children
41
- @children ||= [
42
- RestListDir.new("clients", self),
43
- CookbooksDir.new(self),
44
- DataBagsDir.new(self),
45
- RestListDir.new("environments", self),
46
- NodesDir.new(self),
47
- RestListDir.new("roles", self),
48
- # RestListDir.new("sandboxes", self)
49
- ]
43
+ @children ||= begin
44
+ result = [
45
+ CookbooksDir.new(self),
46
+ DataBagsDir.new(self),
47
+ RestListDir.new("environments", self),
48
+ RestListDir.new("roles", self)
49
+ ]
50
+ if repo_mode == 'everything'
51
+ result += [
52
+ RestListDir.new("clients", self),
53
+ NodesDir.new(self)
54
+ ]
55
+ end
56
+ result.sort_by { |child| child.name }
57
+ end
50
58
  end
51
59
  end
52
60
  end
@@ -1,7 +1,5 @@
1
1
  require 'chef_fs/file_system/base_fs_dir'
2
2
 
3
- # TODO: take environment into account
4
-
5
3
  module ChefFS
6
4
  module FileSystem
7
5
  class CookbookSubdir < BaseFSDir
@@ -6,12 +6,19 @@ require 'chef/config'
6
6
 
7
7
  module ChefFS
8
8
  class Knife < Chef::Knife
9
+ def self.common_options
10
+ option :repo_mode,
11
+ :long => '--repo-mode MODE',
12
+ :default => "default",
13
+ :description => "Specifies the local repository layout. Values: default or full"
14
+ end
15
+
9
16
  def base_path
10
17
  @base_path ||= "/" + ChefFS::PathUtils::relative_to(File.absolute_path(Dir.pwd), chef_repo)
11
18
  end
12
19
 
13
20
  def chef_fs
14
- @chef_fs ||= ChefFS::FileSystem::ChefServerRootDir.new("remote", Chef::Config)
21
+ @chef_fs ||= ChefFS::FileSystem::ChefServerRootDir.new("remote", Chef::Config, config[:repo_mode])
15
22
  end
16
23
 
17
24
  def chef_repo
@@ -1,4 +1,4 @@
1
1
  module ChefFS
2
- VERSION = "0.3.1"
2
+ VERSION = "0.4"
3
3
  end
4
4
 
@@ -136,7 +136,7 @@ describe ChefFS::Diff do
136
136
  end
137
137
  it 'ChefFS::CommandLine.diff(/)' do
138
138
  results = []
139
- ChefFS::CommandLine.diff(pattern('/'), a, b, nil) do |diff|
139
+ ChefFS::CommandLine.diff(pattern('/'), a, b, nil, nil) do |diff|
140
140
  results << diff.gsub(/\s+\d\d\d\d-\d\d-\d\d\s\d?\d:\d\d:\d\d\.\d{9} -\d\d\d\d/, ' DATE')
141
141
  end
142
142
  results.should =~ [
@@ -212,7 +212,7 @@ new file
212
212
  end
213
213
  it 'ChefFS::CommandLine.diff(/both_dirs)' do
214
214
  results = []
215
- ChefFS::CommandLine.diff(pattern('/both_dirs'), a, b, nil) do |diff|
215
+ ChefFS::CommandLine.diff(pattern('/both_dirs'), a, b, nil, nil) do |diff|
216
216
  results << diff.gsub(/\s+\d\d\d\d-\d\d-\d\d\s\d?\d:\d\d:\d\d\.\d{9} -\d\d\d\d/, ' DATE')
217
217
  end
218
218
  results.should =~ [
@@ -254,7 +254,7 @@ new file
254
254
  end
255
255
  it 'ChefFS::CommandLine.diff(/) with depth 1' do
256
256
  results = []
257
- ChefFS::CommandLine.diff(pattern('/'), a, b, 1) do |diff|
257
+ ChefFS::CommandLine.diff(pattern('/'), a, b, 1, nil) do |diff|
258
258
  results << diff.gsub(/\s+\d\d\d\d-\d\d-\d\d\s\d?\d:\d\d:\d\d\.\d{9} -\d\d\d\d/, ' DATE')
259
259
  end
260
260
  results.should =~ [
@@ -288,7 +288,7 @@ new file
288
288
  end
289
289
  it 'ChefFS::CommandLine.diff(/*_*) with depth 0' do
290
290
  results = []
291
- ChefFS::CommandLine.diff(pattern('/*_*'), a, b, 0) do |diff|
291
+ ChefFS::CommandLine.diff(pattern('/*_*'), a, b, 0, nil) do |diff|
292
292
  results << diff.gsub(/\s+\d\d\d\d-\d\d-\d\d\s\d?\d:\d\d:\d\d\.\d{9} -\d\d\d\d/, ' DATE')
293
293
  end
294
294
  results.should =~ [
@@ -320,5 +320,57 @@ new file
320
320
  +b_only_file
321
321
  ' ]
322
322
  end
323
+ it 'ChefFS::CommandLine.diff(/) in name-only mode' do
324
+ results = []
325
+ ChefFS::CommandLine.diff(pattern('/'), a, b, nil, :name_only) do |diff|
326
+ results << diff.gsub(/\s+\d\d\d\d-\d\d-\d\d\s\d?\d:\d\d:\d\d\.\d{9} -\d\d\d\d/, ' DATE')
327
+ end
328
+ results.should =~ [
329
+ "b/both_dirs/sub_both_files_different\n",
330
+ "b/both_dirs/sub_dirs_empty_in_b_filled_in_a/subsub\n",
331
+ "b/both_dirs/sub_dirs_empty_in_a_filled_in_b/subsub\n",
332
+ "b/both_dirs/sub_a_only_dir\n",
333
+ "b/both_dirs/sub_a_only_file\n",
334
+ "b/both_dirs/sub_b_only_dir\n",
335
+ "b/both_dirs/sub_b_only_file\n",
336
+ "b/both_dirs/sub_dir_in_a_file_in_b\n",
337
+ "b/both_dirs/sub_file_in_a_dir_in_b\n",
338
+ "b/both_files_different\n",
339
+ "b/dirs_empty_in_b_filled_in_a/subsub\n",
340
+ "b/dirs_empty_in_a_filled_in_b/subsub\n",
341
+ "b/a_only_dir\n",
342
+ "b/a_only_file\n",
343
+ "b/b_only_dir\n",
344
+ "b/b_only_file\n",
345
+ "b/dir_in_a_file_in_b\n",
346
+ "b/file_in_a_dir_in_b\n"
347
+ ]
348
+ end
349
+ it 'ChefFS::CommandLine.diff(/) in name-status mode' do
350
+ results = []
351
+ ChefFS::CommandLine.diff(pattern('/'), a, b, nil, :name_status) do |diff|
352
+ results << diff.gsub(/\s+\d\d\d\d-\d\d-\d\d\s\d?\d:\d\d:\d\d\.\d{9} -\d\d\d\d/, ' DATE')
353
+ end
354
+ results.should =~ [
355
+ "M\tb/both_dirs/sub_both_files_different\n",
356
+ "D\tb/both_dirs/sub_dirs_empty_in_b_filled_in_a/subsub\n",
357
+ "A\tb/both_dirs/sub_dirs_empty_in_a_filled_in_b/subsub\n",
358
+ "D\tb/both_dirs/sub_a_only_dir\n",
359
+ "D\tb/both_dirs/sub_a_only_file\n",
360
+ "A\tb/both_dirs/sub_b_only_dir\n",
361
+ "A\tb/both_dirs/sub_b_only_file\n",
362
+ "T\tb/both_dirs/sub_dir_in_a_file_in_b\n",
363
+ "T\tb/both_dirs/sub_file_in_a_dir_in_b\n",
364
+ "M\tb/both_files_different\n",
365
+ "D\tb/dirs_empty_in_b_filled_in_a/subsub\n",
366
+ "A\tb/dirs_empty_in_a_filled_in_b/subsub\n",
367
+ "D\tb/a_only_dir\n",
368
+ "D\tb/a_only_file\n",
369
+ "A\tb/b_only_dir\n",
370
+ "A\tb/b_only_file\n",
371
+ "T\tb/dir_in_a_file_in_b\n",
372
+ "T\tb/file_in_a_dir_in_b\n"
373
+ ]
374
+ end
323
375
  end
324
376
  end
@@ -22,7 +22,7 @@ describe ChefFS::FileSystem::ChefServerRootDir do
22
22
  endpoint_leaf.exists?.should be_true
23
23
  end
24
24
  it 'read returns content' do
25
- @rest.should_receive(:get_rest).with("#{endpoint_name}/#{endpoint_leaf_name}/environments/env").once.and_return(
25
+ @rest.should_receive(:get_rest).with("#{endpoint_name}/#{endpoint_leaf_name}").once.and_return(
26
26
  {
27
27
  'a' => 'b'
28
28
  })
@@ -101,7 +101,7 @@ describe ChefFS::FileSystem::ChefServerRootDir do
101
101
  nonexistent_child.dir?.should be_false
102
102
  end
103
103
  it 'read returns NotFoundError' do
104
- @rest.should_receive(:get_rest).with("#{endpoint_name}/blah/environments/env").once.and_raise(Net::HTTPServerException.new(nil,Net::HTTPResponse.new(nil,'404',nil)))
104
+ @rest.should_receive(:get_rest).with("#{endpoint_name}/blah").once.and_raise(Net::HTTPServerException.new(nil,Net::HTTPResponse.new(nil,'404',nil)))
105
105
  expect { nonexistent_child.read }.to raise_error(ChefFS::FileSystem::NotFoundError)
106
106
  end
107
107
  end
@@ -112,9 +112,8 @@ describe ChefFS::FileSystem::ChefServerRootDir do
112
112
  {
113
113
  :chef_server_url => 'url',
114
114
  :node_name => 'username',
115
- :client_key => 'key',
116
- :environment => 'env'
117
- })
115
+ :client_key => 'key'
116
+ }, 'everything')
118
117
  }
119
118
  before(:each) do
120
119
  @rest = double("rest")
@@ -7,9 +7,9 @@ describe ChefFS::FileSystem::CookbooksDir do
7
7
  {
8
8
  :chef_server_url => 'url',
9
9
  :node_name => 'username',
10
- :client_key => 'key',
11
- :environment => 'env'
12
- })
10
+ :client_key => 'key'
11
+ },
12
+ 'everything')
13
13
  }
14
14
  let(:cookbooks_dir) { root_dir.child('cookbooks') }
15
15
  let(:should_list_cookbooks) do
@@ -6,9 +6,8 @@ describe ChefFS::FileSystem::DataBagsDir do
6
6
  {
7
7
  :chef_server_url => 'url',
8
8
  :node_name => 'username',
9
- :client_key => 'key',
10
- :environment => 'env'
11
- })
9
+ :client_key => 'key'
10
+ }, 'everything')
12
11
  }
13
12
  let(:data_bags_dir) { root_dir.child('data_bags') }
14
13
  let(:should_list_data_bags) do
@@ -73,7 +72,7 @@ describe ChefFS::FileSystem::DataBagsDir do
73
72
  data_bag_item.path_for_printing.should == "remote/data_bags/#{data_bag_dir_name}/#{data_bag_item_name}"
74
73
  end
75
74
  it 'reads correctly' do
76
- @rest.should_receive(:get_rest).with("data/#{data_bag_dir_name}/#{data_bag_item_short_name}/environments/env").once.and_return({
75
+ @rest.should_receive(:get_rest).with("data/#{data_bag_dir_name}/#{data_bag_item_short_name}").once.and_return({
77
76
  'a' => 'b'
78
77
  })
79
78
  data_bag_item.read.should == '{
@@ -155,7 +154,7 @@ describe ChefFS::FileSystem::DataBagsDir do
155
154
  nonexistent_child.dir?.should be_false
156
155
  end
157
156
  it 'read returns NotFoundError' do
158
- @rest.should_receive(:get_rest).with("data/#{data_bag_dir_name}/blah/environments/env").once.and_raise(Net::HTTPServerException.new(nil,Net::HTTPResponse.new(nil,'404',nil)))
157
+ @rest.should_receive(:get_rest).with("data/#{data_bag_dir_name}/blah").once.and_raise(Net::HTTPServerException.new(nil,Net::HTTPResponse.new(nil,'404',nil)))
159
158
  expect { nonexistent_child.read }.to raise_error(ChefFS::FileSystem::NotFoundError)
160
159
  end
161
160
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: knife-essentials
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.1
4
+ version: '0.4'
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors: