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.
- data/lib/chef/knife/raw.rb +3 -4
- data/lib/chef/sandbox_uploader.rb +208 -0
- data/lib/chef_fs/command_line.rb +90 -50
- data/lib/chef_fs/file_system.rb +123 -17
- data/lib/chef_fs/file_system/base_fs_object.rb +37 -4
- data/lib/chef_fs/file_system/chef_repository_file_system_entry.rb +25 -0
- data/lib/chef_fs/file_system/cookbook_dir.rb +45 -11
- data/lib/chef_fs/file_system/cookbook_file.rb +26 -0
- data/lib/chef_fs/file_system/file_system_entry.rb +2 -2
- data/lib/chef_fs/file_system/rest_list_entry.rb +17 -5
- data/lib/chef_fs/version.rb +1 -1
- data/spec/chef_fs/diff_spec.rb +3 -77
- data/spec/chef_fs/file_pattern_spec.rb +3 -2
- data/spec/chef_fs/file_system/chef_server_root_dir_spec.rb +1 -0
- data/spec/chef_fs/file_system/cookbooks_dir_spec.rb +2 -1
- data/spec/chef_fs/file_system/data_bags_dir_spec.rb +2 -1
- data/spec/chef_fs/file_system_spec.rb +1 -1
- data/spec/support/file_system_support.rb +0 -22
- data/spec/support/spec_helper.rb +8 -0
- metadata +4 -3
- data/lib/chef_fs/diff.rb +0 -167
@@ -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' &&
|
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
|
-
|
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 @
|
111
|
-
raise ChefFS::FileSystem::NotFoundError.new(@
|
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
|
-
@
|
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
|
-
@
|
127
|
-
raise ChefFS::FileSystem::NotFoundError.new(@
|
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
|
-
@
|
137
|
-
raise ChefFS::FileSystem::NotFoundError.new(@
|
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
|
-
|
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, '
|
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
|
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
|
58
|
-
|
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
|
62
|
-
|
73
|
+
def rest
|
74
|
+
parent.rest
|
63
75
|
end
|
64
76
|
|
65
77
|
def write(file_contents)
|
data/lib/chef_fs/version.rb
CHANGED
data/spec/chef_fs/diff_spec.rb
CHANGED
@@ -1,9 +1,8 @@
|
|
1
|
-
require '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
|
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
|