knife-essentials 0.2.1 → 0.3
Sign up to get free protection for your applications and to get access to all the features.
- data/README.rdoc +9 -0
- data/lib/chef/knife/download.rb +32 -0
- data/lib/chef_fs/diff.rb +17 -8
- data/lib/chef_fs/file_system.rb +108 -0
- data/lib/chef_fs/file_system/file_system_entry.rb +32 -3
- data/lib/chef_fs/version.rb +1 -1
- metadata +2 -1
data/README.rdoc
CHANGED
@@ -7,6 +7,7 @@ to manipulate Chef using a common set of verbs that work on *everything*
|
|
7
7
|
that is stored in the Chef server.
|
8
8
|
|
9
9
|
knife diff cookbooks/*apache*
|
10
|
+
knife download roles data_bags cookbooks/emacs
|
10
11
|
knife list data_bags/users
|
11
12
|
knife show roles/*base*
|
12
13
|
|
@@ -53,6 +54,7 @@ This plugin builds a Ruby Gem (but has not yet been released to RubyGems). To i
|
|
53
54
|
chef_fs installs a number of useful knife verbs, including:
|
54
55
|
|
55
56
|
knife diff [pattern1 pattern2 ...]
|
57
|
+
knife download [pattern1 pattern2 ...]
|
56
58
|
knife list [pattern1 pattern2 ...]
|
57
59
|
knife show [pattern2 pattern2 ...]
|
58
60
|
|
@@ -81,6 +83,13 @@ To run the knife plugin functionality, install a version of Chef > 0.10.10:
|
|
81
83
|
Diffs objects on the server against files in the local repository. Output is similar to
|
82
84
|
+git diff+.
|
83
85
|
|
86
|
+
== knife download
|
87
|
+
|
88
|
+
knife download [pattern1 pattern2 ...]
|
89
|
+
|
90
|
+
Downloads objects from the server to your local repository. Pass --purge to delete local
|
91
|
+
files and directories which do not exist on the server.
|
92
|
+
|
84
93
|
== knife list
|
85
94
|
|
86
95
|
knife list [pattern1 pattern2 ...]
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require 'chef_fs/knife'
|
2
|
+
require 'chef_fs/command_line'
|
3
|
+
|
4
|
+
class Chef
|
5
|
+
class Knife
|
6
|
+
class Download < ChefFS::Knife
|
7
|
+
banner "download PATTERNS"
|
8
|
+
|
9
|
+
option :recurse,
|
10
|
+
:long => '--[no-]recurse',
|
11
|
+
:boolean => true,
|
12
|
+
:default => true,
|
13
|
+
:description => "List directories recursively."
|
14
|
+
|
15
|
+
option :purge,
|
16
|
+
:long => '--[no-]purge',
|
17
|
+
:boolean => true,
|
18
|
+
:default => false,
|
19
|
+
:description => "Delete matching local files and directories that do not exist remotely."
|
20
|
+
|
21
|
+
def run
|
22
|
+
patterns = pattern_args_from(name_args.length > 0 ? name_args : [ "" ])
|
23
|
+
|
24
|
+
# Get the matches (recursively)
|
25
|
+
patterns.each do |pattern|
|
26
|
+
ChefFS::FileSystem.copy_to(pattern, chef_fs, local_fs, config[:recurse] ? nil : 1, config[:purge])
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
data/lib/chef_fs/diff.rb
CHANGED
@@ -12,7 +12,7 @@ module ChefFS
|
|
12
12
|
Digest::MD5.hexdigest(value)
|
13
13
|
end
|
14
14
|
|
15
|
-
def self.
|
15
|
+
def self.diff_files_quick(old_file, new_file)
|
16
16
|
#
|
17
17
|
# Short-circuit expensive comparison (could be an extra network
|
18
18
|
# request) if a pre-calculated checksum is there
|
@@ -42,7 +42,16 @@ module ChefFS
|
|
42
42
|
end
|
43
43
|
|
44
44
|
# If the checksums are the same, they are the same. Return.
|
45
|
-
return false if old_checksum == new_checksum
|
45
|
+
return [ false, old_value, new_value ] if old_checksum == new_checksum
|
46
|
+
end
|
47
|
+
|
48
|
+
return [ nil, old_value, new_value ]
|
49
|
+
end
|
50
|
+
|
51
|
+
def self.diff_files(old_file, new_file)
|
52
|
+
different, old_value, new_value = diff_files_quick(old_file, new_file)
|
53
|
+
if different != nil
|
54
|
+
return different
|
46
55
|
end
|
47
56
|
|
48
57
|
#
|
@@ -87,8 +96,8 @@ module ChefFS
|
|
87
96
|
ChefFS::FileSystem.list(a_root, pattern) do |a|
|
88
97
|
found_paths << a.path
|
89
98
|
b = ChefFS::FileSystem.resolve_path(b_root, a.path)
|
90
|
-
diffable_leaves(a, b, recurse_depth) do |a_leaf, b_leaf|
|
91
|
-
yield [ a_leaf, b_leaf ]
|
99
|
+
diffable_leaves(a, b, recurse_depth) do |a_leaf, b_leaf, leaf_recurse_depth|
|
100
|
+
yield [ a_leaf, b_leaf, leaf_recurse_depth ]
|
92
101
|
end
|
93
102
|
end
|
94
103
|
|
@@ -97,7 +106,7 @@ module ChefFS
|
|
97
106
|
ChefFS::FileSystem.list(b_root, pattern) do |b|
|
98
107
|
if !found_paths.include?(b.path)
|
99
108
|
a = ChefFS::FileSystem.resolve_path(a_root, b.path)
|
100
|
-
yield [ a, b ]
|
109
|
+
yield [ a, b, recurse_depth ]
|
101
110
|
end
|
102
111
|
end
|
103
112
|
end
|
@@ -126,15 +135,15 @@ module ChefFS
|
|
126
135
|
a_children_names = Set.new
|
127
136
|
a.children.each do |a_child|
|
128
137
|
a_children_names << a_child.name
|
129
|
-
diffable_leaves(a_child, b.child(a_child.name), recurse_depth ? recurse_depth - 1 : nil) do |a_leaf, b_leaf|
|
130
|
-
yield [ a_leaf, b_leaf ]
|
138
|
+
diffable_leaves(a_child, b.child(a_child.name), recurse_depth ? recurse_depth - 1 : nil) do |a_leaf, b_leaf, leaf_recurse_depth|
|
139
|
+
yield [ a_leaf, b_leaf, leaf_recurse_depth ]
|
131
140
|
end
|
132
141
|
end
|
133
142
|
|
134
143
|
# Check b for children that aren't in a
|
135
144
|
b.children.each do |b_child|
|
136
145
|
if !a_children_names.include?(b_child.name)
|
137
|
-
yield [ a.child(b_child.name), b_child ]
|
146
|
+
yield [ a.child(b_child.name), b_child, recurse_depth ]
|
138
147
|
end
|
139
148
|
end
|
140
149
|
return
|
data/lib/chef_fs/file_system.rb
CHANGED
@@ -1,7 +1,12 @@
|
|
1
1
|
require 'chef_fs/path_utils'
|
2
|
+
require 'chef_fs/diff'
|
2
3
|
|
3
4
|
module ChefFS
|
4
5
|
module FileSystem
|
6
|
+
def self.copy_to(pattern, src_root, dest_root)
|
7
|
+
|
8
|
+
end
|
9
|
+
|
5
10
|
# Yields a list of all things under (and including) this entry that match the
|
6
11
|
# given pattern.
|
7
12
|
#
|
@@ -64,6 +69,109 @@ module ChefFS
|
|
64
69
|
end
|
65
70
|
result
|
66
71
|
end
|
72
|
+
|
73
|
+
# Copy everything matching the given pattern from src to dest.
|
74
|
+
#
|
75
|
+
# After this method completes, everything in dest matching the
|
76
|
+
# given pattern will look identical to src.
|
77
|
+
#
|
78
|
+
# ==== Attributes
|
79
|
+
#
|
80
|
+
# * +pattern+ - ChefFS::FilePattern to match children under
|
81
|
+
# * +src_root+ - the root from which things will be copied
|
82
|
+
# * +dest_root+ - the root to which things will be copied
|
83
|
+
# * +recurse_depth+ - the maximum depth to copy things. +nil+
|
84
|
+
# means infinite depth. 0 means no recursion.
|
85
|
+
# * +purge+ - if +true+, items in +dest+ that are not in +src+
|
86
|
+
# will be deleted from +dest+. If +false+, these items will
|
87
|
+
# be left alone.
|
88
|
+
#
|
89
|
+
# ==== Examples
|
90
|
+
#
|
91
|
+
# ChefFS::FileSystem.copy_to(FilePattern.new('/cookbooks', chef_fs, local_fs, nil, true)
|
92
|
+
#
|
93
|
+
def self.copy_to(pattern, src_root, dest_root, recurse_depth, purge)
|
94
|
+
found_result = false
|
95
|
+
# Find things we might want to copy
|
96
|
+
ChefFS::Diff::diffable_leaves_from_pattern(pattern, src_root, dest_root, recurse_depth) do |src_leaf, dest_leaf, child_recurse_depth|
|
97
|
+
found_result = true
|
98
|
+
copy_leaves(src_leaf, dest_leaf, child_recurse_depth, purge)
|
99
|
+
end
|
100
|
+
if !found_result && pattern.exact_path
|
101
|
+
yield "#{pattern}: No such file or directory on remote or local"
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
private
|
106
|
+
|
107
|
+
# Copy two known leaves (could be files or dirs)
|
108
|
+
def self.copy_leaves(src_entry, dest_entry, recurse_depth, purge)
|
109
|
+
# A NOTE about this algorithm:
|
110
|
+
# There are cases where this algorithm does too many network requests.
|
111
|
+
# knife upload with a specific filename will first check if the file
|
112
|
+
# exists (a "dir" in the parent) before deciding whether to POST or
|
113
|
+
# PUT it. If we just tried PUT (or POST) and then tried the other if
|
114
|
+
# the conflict failed, we wouldn't need to check existence.
|
115
|
+
# On the other hand, we may already have DONE the request, in which
|
116
|
+
# case we shouldn't waste time trying PUT if we know the file doesn't
|
117
|
+
# exist.
|
118
|
+
# Will need to decide how that works with checksums, though.
|
119
|
+
|
120
|
+
if !src_entry.exists?
|
121
|
+
if purge
|
122
|
+
# If we would not have uploaded it, we will not purge it.
|
123
|
+
if src_entry.parent.can_have_child?(dest_entry.name, dest_entry.dir?)
|
124
|
+
Chef::Log.info("Deleting extra entry #{dest_entry.path_for_printing} (purge is on)")
|
125
|
+
dest_entry.delete
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
elsif !dest_entry.exists?
|
130
|
+
if dest_entry.parent.can_have_child?(src_entry.name, src_entry.dir?)
|
131
|
+
if src_entry.dir?
|
132
|
+
Chef::Log.info("Creating #{dest_entry.path_for_printing}/")
|
133
|
+
new_dest_dir = dest_entry.parent.create_child(src_entry.name, nil)
|
134
|
+
# Directory creation is recursive.
|
135
|
+
if recurse_depth != 0
|
136
|
+
src_entry.children.each do |src_child|
|
137
|
+
new_dest_child = new_dest_dir.child(src_child.name)
|
138
|
+
copy_leaves(src_child, new_dest_child, recurse_depth ? recurse_depth - 1 : recurse_depth, purge)
|
139
|
+
end
|
140
|
+
end
|
141
|
+
else
|
142
|
+
Chef::Log.info("Creating #{dest_entry.path_for_printing}")
|
143
|
+
dest_entry.parent.create_child(src_entry.name, src_entry.read)
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
else
|
148
|
+
# Both exist.
|
149
|
+
# If they are different types, log an error.
|
150
|
+
if src_entry.dir?
|
151
|
+
if dest_entry.dir?
|
152
|
+
# If they are both directories, we'll end up recursing later.
|
153
|
+
else
|
154
|
+
# If they are different types.
|
155
|
+
Chef::Log.error("File #{dest_entry.path_for_printing} is a directory while file #{dest_entry.path_for_printing} is a regular file\n")
|
156
|
+
return
|
157
|
+
end
|
158
|
+
else
|
159
|
+
if dest_entry.dir?
|
160
|
+
Chef::Log.error("File #{dest_entry.path_for_printing} is a directory while file #{dest_entry.path_for_printing} is a regular file\n")
|
161
|
+
return
|
162
|
+
else
|
163
|
+
# Both are files! Copy them unless we're sure they are the same.
|
164
|
+
different, src_value, dest_value = ChefFS::Diff.diff_files_quick(src_entry, dest_entry)
|
165
|
+
if different || different == nil
|
166
|
+
Chef::Log.info("Copying #{src_entry.path_for_printing} to #{dest_entry.path_for_printing}")
|
167
|
+
src_value = src_entry.read if src_value == :not_retrieved
|
168
|
+
dest_entry.write(src_value)
|
169
|
+
end
|
170
|
+
end
|
171
|
+
end
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
67
175
|
end
|
68
176
|
end
|
69
177
|
|
@@ -2,6 +2,7 @@ require 'chef_fs/file_system/base_fs_dir'
|
|
2
2
|
require 'chef_fs/file_system/rest_list_dir'
|
3
3
|
require 'chef_fs/file_system/not_found_error'
|
4
4
|
require 'chef_fs/path_utils'
|
5
|
+
require 'fileutils'
|
5
6
|
|
6
7
|
module ChefFS
|
7
8
|
module FileSystem
|
@@ -18,18 +19,46 @@ module ChefFS
|
|
18
19
|
end
|
19
20
|
|
20
21
|
def children
|
21
|
-
|
22
|
+
begin
|
23
|
+
@children ||= Dir.entries(file_path).select { |entry| entry != '.' && entry != '..' }.map { |entry| FileSystemEntry.new(entry, self) }
|
24
|
+
rescue Errno::ENOENT
|
25
|
+
raise ChefFS::FileSystem::NotFoundError.new($!), "#{file_path} not found"
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def create_child(child_name, file_contents=nil)
|
30
|
+
result = FileSystemEntry.new(child_name, self)
|
31
|
+
if file_contents
|
32
|
+
result.write(file_contents)
|
33
|
+
else
|
34
|
+
Dir.mkdir(result.file_path)
|
35
|
+
end
|
36
|
+
result
|
22
37
|
end
|
23
38
|
|
24
39
|
def dir?
|
25
40
|
File.directory?(file_path)
|
26
41
|
end
|
27
42
|
|
43
|
+
def delete
|
44
|
+
if dir?
|
45
|
+
FileUtils.rm_rf(file_path)
|
46
|
+
else
|
47
|
+
File.delete(file_path)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
28
51
|
def read
|
29
52
|
begin
|
30
53
|
IO.read(file_path)
|
31
|
-
rescue
|
32
|
-
raise ChefFS::FileSystem::NotFoundError.new($!), "#{
|
54
|
+
rescue Errno::ENOENT
|
55
|
+
raise ChefFS::FileSystem::NotFoundError.new($!), "#{file_path} not found"
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def write(content)
|
60
|
+
File.open(file_path, 'w') do |file|
|
61
|
+
file.write(content)
|
33
62
|
end
|
34
63
|
end
|
35
64
|
end
|
data/lib/chef_fs/version.rb
CHANGED
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.
|
4
|
+
version: '0.3'
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -23,6 +23,7 @@ files:
|
|
23
23
|
- README.rdoc
|
24
24
|
- Rakefile
|
25
25
|
- lib/chef/knife/diff.rb
|
26
|
+
- lib/chef/knife/download.rb
|
26
27
|
- lib/chef/knife/list.rb
|
27
28
|
- lib/chef/knife/show.rb
|
28
29
|
- lib/chef_fs/command_line.rb
|