knife-essentials 0.5.4 → 0.6

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.
@@ -40,10 +40,6 @@ module ChefFS
40
40
  true
41
41
  end
42
42
 
43
- def content_type
44
- :text
45
- end
46
-
47
43
  def child(name)
48
44
  NonexistentFSObject.new(name, self)
49
45
  end
@@ -55,6 +51,43 @@ module ChefFS
55
51
  false
56
52
  end
57
53
 
54
+ # Override this if you have a special comparison algorithm that can tell
55
+ # you whether this entry is the same as another--either a quicker or a
56
+ # more reliable one. Callers will use this to decide whether to upload,
57
+ # download or diff an object.
58
+ #
59
+ # You should not override this if you're going to do the standard
60
+ # +self.read == other.read+. If you return +nil+, the caller will call
61
+ # +other.compare_to(you)+ instead. Give them a chance :)
62
+ #
63
+ # ==== Parameters
64
+ #
65
+ # * +other+ - the entry to compare to
66
+ #
67
+ # ==== Returns
68
+ #
69
+ # * +[ are_same, value, other_value ]+
70
+ # +are_same+ may be +true+, +false+ or +nil+ (which means "don't know").
71
+ # +value+ and +other_value+ must either be the text of +self+ or +other+,
72
+ # +:none+ (if the entry does not exist or has no value) or +nil+ if the
73
+ # value was not retrieved.
74
+ # * +nil+ if a definitive answer cannot be had and nothing was retrieved.
75
+ #
76
+ # ==== Example
77
+ #
78
+ # are_same, value, other_value = entry.compare_to(other)
79
+ # if are_same.nil?
80
+ # are_same, other_value, value = other.compare_to(entry)
81
+ # end
82
+ # if are_same.nil?
83
+ # value = entry.read if value.nil?
84
+ # other_value = entry.read if other_value.nil?
85
+ # are_same = (value == other_value)
86
+ # end
87
+ def compare_to(other)
88
+ return nil
89
+ end
90
+
58
91
  # Important directory attributes: name, parent, path, root
59
92
  # Overridable attributes: dir?, child(name), path_for_printing
60
93
  # Abstract: read, write, delete, children
@@ -1,10 +1,17 @@
1
1
  require 'chef_fs/file_system/file_system_entry'
2
2
  require 'chef/cookbook/chefignore'
3
+ require 'chef/cookbook/cookbook_version_loader'
4
+ require 'chef/node'
5
+ require 'chef/role'
6
+ require 'chef/environment'
7
+ require 'chef/data_bag_item'
8
+ require 'chef/client'
3
9
 
4
10
  module ChefFS
5
11
  module FileSystem
6
12
  # ChefRepositoryFileSystemEntry works just like FileSystemEntry,
7
13
  # except it pretends files in /cookbooks/chefignore don't exist
14
+ # and it can inflate Chef objects
8
15
  class ChefRepositoryFileSystemEntry < FileSystemEntry
9
16
  def initialize(name, parent, file_path = nil)
10
17
  super(name, parent, file_path)
@@ -14,6 +21,24 @@ module ChefFS
14
21
  end
15
22
  end
16
23
 
24
+ attr_reader :chefignore
25
+
26
+ def chef_object
27
+ begin
28
+ if parent.path == "/cookbooks"
29
+ loader = Chef::Cookbook::CookbookVersionLoader.new(file_path, parent.chefignore)
30
+ loader.load_cookbooks
31
+ return loader.cookbook_version
32
+ end
33
+
34
+ # Otherwise the information to inflate the object, is in the file (json_class).
35
+ return Chef::JSONCompat.from_json(read)
36
+ rescue
37
+ Chef::Log.error("Could not read #{path_for_printing} into a Chef object: #{$!}")
38
+ end
39
+ nil
40
+ end
41
+
17
42
  def children
18
43
  @children ||= Dir.entries(file_path).select { |entry| entry != '.' && entry != '..' && !ignored?(entry) }
19
44
  .map { |entry| ChefRepositoryFileSystemEntry.new(entry, self) }
@@ -3,6 +3,7 @@ require 'chef_fs/file_system/cookbook_subdir'
3
3
  require 'chef_fs/file_system/cookbook_file'
4
4
  require 'chef_fs/file_system/not_found_error'
5
5
  require 'chef/cookbook_version'
6
+ require 'chef/cookbook_uploader'
6
7
 
7
8
  module ChefFS
8
9
  module FileSystem
@@ -49,7 +50,8 @@ module ChefFS
49
50
  def can_have_child?(name, is_dir)
50
51
  # A cookbook's root may not have directories unless they are segment directories
51
52
  if is_dir
52
- return name != 'root_files' && COOKBOOK_SEGMENT_INFO.keys.any? { |segment| segment.to_s == name }
53
+ return name != 'root_files' &&
54
+ COOKBOOK_SEGMENT_INFO.keys.any? { |segment| segment.to_s == name }
53
55
  end
54
56
  true
55
57
  end
@@ -57,6 +59,7 @@ module ChefFS
57
59
  def children
58
60
  if @children.nil?
59
61
  @children = []
62
+ manifest = chef_object.manifest
60
63
  COOKBOOK_SEGMENT_INFO.each do |segment, segment_info|
61
64
  next unless manifest.has_key?(segment)
62
65
 
@@ -99,32 +102,63 @@ module ChefFS
99
102
  !!@versions
100
103
  end
101
104
 
105
+ def compare_to(other)
106
+ are_same = true
107
+ ChefFS::CommandLine::diff_entries(self, other, nil, :name_only) do
108
+ are_same = false
109
+ end
110
+ [ are_same, nil, nil ]
111
+ end
112
+
113
+ def copy_from(other)
114
+ other_cookbook_version = other.chef_object
115
+ # TODO this only works on the file system. And it can't be broken into
116
+ # pieces.
117
+ begin
118
+ Chef::CookbookUploader.new(other_cookbook_version, other.parent.file_path).upload_cookbook
119
+ rescue Net::HTTPServerException => e
120
+ case e.response.code
121
+ when "409"
122
+ ui.error "Version #{cookbook.version} of cookbook #{cookbook.name} is frozen. Use --force to override."
123
+ Log.debug(e)
124
+ raise Exceptions::CookbookFrozen
125
+ else
126
+ raise
127
+ end
128
+ end
129
+ end
130
+
102
131
  def rest
103
132
  parent.rest
104
133
  end
105
134
 
106
- private
135
+ def chef_object
136
+ # We cheat and cache here, because it seems like a good idea to keep
137
+ # the cookbook view consistent with the directory structure.
138
+ return @chef_object if @chef_object
107
139
 
108
- def manifest
109
140
  # The negative (not found) response is cached
110
- if @could_not_get_manifest
111
- raise ChefFS::FileSystem::NotFoundError.new(@could_not_get_manifest), "#{path_for_printing} not found"
141
+ if @could_not_get_chef_object
142
+ raise ChefFS::FileSystem::NotFoundError.new(@could_not_get_chef_object), "#{path_for_printing} not found"
112
143
  end
113
144
 
114
145
  begin
115
146
  # We want to fail fast, for now, because of the 500 issue :/
116
- # This will make things worse for parallelism, a little.
147
+ # This will make things worse for parallelism, a little, because
148
+ # Chef::Config is global and this could affect other requests while
149
+ # this request is going on. (We're not parallel yet, but we will be.)
150
+ # Chef bug http://tickets.opscode.com/browse/CHEF-3066
117
151
  old_retry_count = Chef::Config[:http_retry_count]
118
152
  begin
119
153
  Chef::Config[:http_retry_count] = 0
120
- @manifest ||= rest.get_rest(api_path).manifest
154
+ @chef_object ||= rest.get_rest(api_path)
121
155
  ensure
122
156
  Chef::Config[:http_retry_count] = old_retry_count
123
157
  end
124
158
  rescue Net::HTTPServerException
125
159
  if $!.response.code == "404"
126
- @could_not_get_manifest = $!
127
- raise ChefFS::FileSystem::NotFoundError.new(@could_not_get_manifest), "#{path_for_printing} not found"
160
+ @could_not_get_chef_object = $!
161
+ raise ChefFS::FileSystem::NotFoundError.new(@could_not_get_chef_object), "#{path_for_printing} not found"
128
162
  else
129
163
  raise
130
164
  end
@@ -133,8 +167,8 @@ module ChefFS
133
167
  # Remove this when that bug is fixed.
134
168
  rescue Net::HTTPFatalError
135
169
  if $!.response.code == "500"
136
- @could_not_get_manifest = $!
137
- raise ChefFS::FileSystem::NotFoundError.new(@could_not_get_manifest), "#{path_for_printing} not found"
170
+ @could_not_get_chef_object = $!
171
+ raise ChefFS::FileSystem::NotFoundError.new(@could_not_get_chef_object), "#{path_for_printing} not found"
138
172
  else
139
173
  raise
140
174
  end
@@ -1,4 +1,5 @@
1
1
  require 'chef_fs/file_system/base_fs_object'
2
+ require 'digest/md5'
2
3
 
3
4
  module ChefFS
4
5
  module FileSystem
@@ -27,6 +28,31 @@ module ChefFS
27
28
  def rest
28
29
  parent.rest
29
30
  end
31
+
32
+ def compare_to(other)
33
+ other_value = nil
34
+ if other.respond_to?(:checksum)
35
+ other_checksum = other.checksum
36
+ else
37
+ begin
38
+ other_value = other.read
39
+ rescue ChefFS::FileSystem::NotFoundError
40
+ other_value = :none
41
+ end
42
+ other_checksum = calc_checksum(other_value)
43
+ end
44
+ [ checksum == other_checksum, nil, other_value ]
45
+ end
46
+
47
+ private
48
+
49
+ def calc_checksum(value)
50
+ begin
51
+ Digest::MD5.hexdigest(value)
52
+ rescue ChefFS::FileSystem::NotFoundError
53
+ nil
54
+ end
55
+ end
30
56
  end
31
57
  end
32
58
  end
@@ -50,14 +50,14 @@ module ChefFS
50
50
 
51
51
  def read
52
52
  begin
53
- IO.read(file_path)
53
+ File.open(file_path, "rb") {|f| f.read}
54
54
  rescue Errno::ENOENT
55
55
  raise ChefFS::FileSystem::NotFoundError.new($!), "#{file_path} not found"
56
56
  end
57
57
  end
58
58
 
59
59
  def write(content)
60
- File.open(file_path, 'w') do |file|
60
+ File.open(file_path, 'wb') do |file|
61
61
  file.write(content)
62
62
  end
63
63
  end
@@ -43,8 +43,13 @@ module ChefFS
43
43
  end
44
44
 
45
45
  def read
46
+ Chef::JSONCompat.to_json_pretty(chef_object.to_hash)
47
+ end
48
+
49
+ def chef_object
46
50
  begin
47
- Chef::JSONCompat.to_json_pretty(rest.get_rest(api_path).to_hash)
51
+ # REST will inflate the Chef object using json_class
52
+ rest.get_rest(api_path)
48
53
  rescue Net::HTTPServerException
49
54
  if $!.response.code == "404"
50
55
  raise ChefFS::FileSystem::NotFoundError.new($!), "#{path_for_printing} not found"
@@ -54,12 +59,19 @@ module ChefFS
54
59
  end
55
60
  end
56
61
 
57
- def rest
58
- parent.rest
62
+ def compare_to(other)
63
+ begin
64
+ other_value = other.read
65
+ rescue ChefFS::FileSystem::NotFoundError
66
+ return [ nil, nil, :none ]
67
+ end
68
+ value = chef_object.to_hash
69
+ are_same = (value == Chef::JSONCompat.from_json(other_value, :create_additions => false))
70
+ [ are_same, Chef::JSONCompat.to_json_pretty(value), other_value ]
59
71
  end
60
72
 
61
- def content_type
62
- :json
73
+ def rest
74
+ parent.rest
63
75
  end
64
76
 
65
77
  def write(file_contents)
@@ -1,4 +1,4 @@
1
1
  module ChefFS
2
- VERSION = "0.5.4"
2
+ VERSION = "0.6"
3
3
  end
4
4
 
@@ -1,9 +1,8 @@
1
- require 'support/file_system_support'
2
- require 'chef_fs/diff'
1
+ require 'support/spec_helper'
3
2
  require 'chef_fs/file_pattern'
4
3
  require 'chef_fs/command_line'
5
4
 
6
- describe ChefFS::Diff do
5
+ describe 'diff' do
7
6
  include FileSystemSupport
8
7
 
9
8
  context 'with two filesystems with all types of difference' do
@@ -61,79 +60,6 @@ describe ChefFS::Diff do
61
60
  :file_in_a_dir_in_b => {}
62
61
  }, /cannot_be_in_b/)
63
62
  }
64
- it 'diffable_leaves' do
65
- diffable_leaves_should_yield_paths(a, b, nil,
66
- %w(
67
- /both_dirs/sub_both_dirs/subsub
68
- /both_dirs/sub_both_files
69
- /both_dirs/sub_both_files_different
70
- /both_dirs/sub_dirs_empty_in_b_filled_in_a/subsub
71
- /both_dirs/sub_dirs_empty_in_a_filled_in_b/subsub
72
- /both_dirs/sub_a_only_dir
73
- /both_dirs/sub_a_only_file
74
- /both_dirs/sub_b_only_dir
75
- /both_dirs/sub_b_only_file
76
- /both_dirs/sub_dir_in_a_file_in_b
77
- /both_dirs/sub_file_in_a_dir_in_b
78
- /both_files
79
- /both_files_different
80
- /dirs_empty_in_b_filled_in_a/subsub
81
- /dirs_empty_in_a_filled_in_b/subsub
82
- /dirs_in_a_cannot_be_in_b
83
- /dirs_in_b_cannot_be_in_a
84
- /file_in_a_cannot_be_in_b
85
- /file_in_b_cannot_be_in_a
86
- /a_only_dir
87
- /a_only_file
88
- /b_only_dir
89
- /b_only_file
90
- /dir_in_a_file_in_b
91
- /file_in_a_dir_in_b
92
- ))
93
- end
94
- it 'diffable_leaves_from_pattern(/**file*)' do
95
- diffable_leaves_from_pattern_should_yield_paths(pattern('/**file*'), a, b, nil,
96
- %w(
97
- /both_dirs/sub_both_files
98
- /both_dirs/sub_both_files_different
99
- /both_dirs/sub_a_only_file
100
- /both_dirs/sub_b_only_file
101
- /both_dirs/sub_dir_in_a_file_in_b
102
- /both_dirs/sub_file_in_a_dir_in_b
103
- /both_files
104
- /both_files_different
105
- /file_in_a_cannot_be_in_b
106
- /file_in_b_cannot_be_in_a
107
- /a_only_file
108
- /b_only_file
109
- /dir_in_a_file_in_b
110
- /file_in_a_dir_in_b
111
- ))
112
- end
113
- it 'diffable_leaves_from_pattern(/*dir*)' do
114
- diffable_leaves_from_pattern_should_yield_paths(pattern('/*dir*'), a, b, nil,
115
- %w(
116
- /both_dirs/sub_both_dirs/subsub
117
- /both_dirs/sub_both_files
118
- /both_dirs/sub_both_files_different
119
- /both_dirs/sub_dirs_empty_in_b_filled_in_a/subsub
120
- /both_dirs/sub_dirs_empty_in_a_filled_in_b/subsub
121
- /both_dirs/sub_a_only_dir
122
- /both_dirs/sub_a_only_file
123
- /both_dirs/sub_b_only_dir
124
- /both_dirs/sub_b_only_file
125
- /both_dirs/sub_dir_in_a_file_in_b
126
- /both_dirs/sub_file_in_a_dir_in_b
127
- /dirs_empty_in_b_filled_in_a/subsub
128
- /dirs_empty_in_a_filled_in_b/subsub
129
- /dirs_in_a_cannot_be_in_b
130
- /dirs_in_b_cannot_be_in_a
131
- /a_only_dir
132
- /b_only_dir
133
- /dir_in_a_file_in_b
134
- /file_in_a_dir_in_b
135
- ))
136
- end
137
63
  it 'ChefFS::CommandLine.diff(/)' do
138
64
  results = []
139
65
  ChefFS::CommandLine.diff(pattern('/'), a, b, nil, nil) do |diff|
@@ -373,4 +299,4 @@ new file
373
299
  ]
374
300
  end
375
301
  end
376
- end
302
+ end
@@ -1,3 +1,4 @@
1
+ require 'support/spec_helper'
1
2
  require 'chef_fs/file_pattern'
2
3
 
3
4
  describe ChefFS::FilePattern do
@@ -487,7 +488,7 @@ describe ChefFS::FilePattern do
487
488
  # - ?, *, characters, **
488
489
 
489
490
  # could_match_children?
490
- #
491
+ #
491
492
  #
492
493
  #
493
494
  #
@@ -504,4 +505,4 @@ describe ChefFS::FilePattern do
504
505
  end
505
506
 
506
507
  # Exercise the different methods to their maximum
507
- end
508
+ end
@@ -1,3 +1,4 @@
1
+ require 'support/spec_helper'
1
2
  require 'chef_fs/file_system/chef_server_root_dir'
2
3
 
3
4
  describe ChefFS::FileSystem::ChefServerRootDir do
@@ -1,3 +1,4 @@
1
+ require 'support/spec_helper'
1
2
  require 'chef_fs/file_system/chef_server_root_dir'
2
3
  require 'chef_fs/file_system'
3
4
 
@@ -546,4 +547,4 @@ describe ChefFS::FileSystem::CookbooksDir do
546
547
  end
547
548
  end
548
549
 
549
- end
550
+ end
@@ -1,3 +1,4 @@
1
+ require 'support/spec_helper'
1
2
  require 'chef_fs/file_system/chef_server_root_dir'
2
3
 
3
4
  describe ChefFS::FileSystem::DataBagsDir do
@@ -198,4 +199,4 @@ describe ChefFS::FileSystem::DataBagsDir do
198
199
  end
199
200
  end
200
201
 
201
- end
202
+ end