knife-essentials 0.4 → 0.5

Sign up to get free protection for your applications and to get access to all the features.
@@ -6,6 +6,8 @@ class Chef
6
6
  class Diff < ChefFS::Knife
7
7
  banner "diff PATTERNS"
8
8
 
9
+ common_options
10
+
9
11
  option :recurse,
10
12
  :long => '--[no-]recurse',
11
13
  :boolean => true,
@@ -22,8 +24,6 @@ class Chef
22
24
  :boolean => true,
23
25
  :description => "Only show names and statuses of modified files: Added, Deleted, Modified, and Type Changed."
24
26
 
25
- common_options
26
-
27
27
  def run
28
28
  if config[:name_only]
29
29
  output_mode = :name_only
@@ -6,6 +6,8 @@ class Chef
6
6
  class Download < ChefFS::Knife
7
7
  banner "download PATTERNS"
8
8
 
9
+ common_options
10
+
9
11
  option :recurse,
10
12
  :long => '--[no-]recurse',
11
13
  :boolean => true,
@@ -18,12 +20,25 @@ class Chef
18
20
  :default => false,
19
21
  :description => "Delete matching local files and directories that do not exist remotely."
20
22
 
23
+ option :force,
24
+ :long => '--[no-]force',
25
+ :boolean => true,
26
+ :default => false,
27
+ :description => "Force upload of files even if they match (quicker and harmless, but doesn't print out what it changed)"
28
+
29
+ option :dry_run,
30
+ :long => '--dry-run',
31
+ :short => '-n',
32
+ :boolean => true,
33
+ :default => false,
34
+ :description => "Don't take action, only print what would happen"
35
+
21
36
  def run
22
37
  patterns = pattern_args_from(name_args.length > 0 ? name_args : [ "" ])
23
38
 
24
39
  # Get the matches (recursively)
25
40
  patterns.each do |pattern|
26
- ChefFS::FileSystem.copy_to(pattern, chef_fs, local_fs, config[:recurse] ? nil : 1, config[:purge])
41
+ ChefFS::FileSystem.copy_to(pattern, chef_fs, local_fs, config[:recurse] ? nil : 1, config)
27
42
  end
28
43
  end
29
44
  end
@@ -6,6 +6,8 @@ class Chef
6
6
  class List < ChefFS::Knife
7
7
  banner "list [-dR] [PATTERN1 ... PATTERNn]"
8
8
 
9
+ common_options
10
+
9
11
  option :recursive,
10
12
  :short => '-R',
11
13
  :boolean => true,
@@ -6,6 +6,8 @@ class Chef
6
6
  class Show < ChefFS::Knife
7
7
  banner "show [PATTERN1 ... PATTERNn]"
8
8
 
9
+ common_options
10
+
9
11
  def run
10
12
  # Get the matches (recursively)
11
13
  pattern_args.each do |pattern|
@@ -0,0 +1,47 @@
1
+ require 'chef_fs/knife'
2
+ require 'chef_fs/command_line'
3
+
4
+ class Chef
5
+ class Knife
6
+ class Upload < ChefFS::Knife
7
+ banner "upload PATTERNS"
8
+
9
+ common_options
10
+
11
+ option :recurse,
12
+ :long => '--[no-]recurse',
13
+ :boolean => true,
14
+ :default => true,
15
+ :description => "List directories recursively."
16
+
17
+ option :purge,
18
+ :long => '--[no-]purge',
19
+ :boolean => true,
20
+ :default => false,
21
+ :description => "Delete matching local files and directories that do not exist remotely."
22
+
23
+ option :force,
24
+ :long => '--[no-]force',
25
+ :boolean => true,
26
+ :default => false,
27
+ :description => "Force upload of files even if they match (quicker and harmless, but doesn't print out what it changed)"
28
+
29
+ option :dry_run,
30
+ :long => '--dry-run',
31
+ :short => '-n',
32
+ :boolean => true,
33
+ :default => false,
34
+ :description => "Don't take action, only print what would happen"
35
+
36
+ def run
37
+ patterns = pattern_args_from(name_args.length > 0 ? name_args : [ "" ])
38
+
39
+ # Get the matches (recursively)
40
+ patterns.each do |pattern|
41
+ ChefFS::FileSystem.copy_to(pattern, local_fs, chef_fs, config[:recurse] ? nil : 1, config)
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
47
+
@@ -42,7 +42,7 @@ module ChefFS
42
42
  # the entry at the end of the path.
43
43
  #
44
44
  # ==== Attributes
45
- #
45
+ #
46
46
  # * +entry+ - the entry to start looking under. Relative
47
47
  # paths will be resolved from here.
48
48
  # * +path+ - the path to resolve. If it starts with +/+,
@@ -72,26 +72,32 @@ module ChefFS
72
72
  # given pattern will look identical to src.
73
73
  #
74
74
  # ==== Attributes
75
- #
75
+ #
76
76
  # * +pattern+ - ChefFS::FilePattern to match children under
77
77
  # * +src_root+ - the root from which things will be copied
78
78
  # * +dest_root+ - the root to which things will be copied
79
79
  # * +recurse_depth+ - the maximum depth to copy things. +nil+
80
80
  # means infinite depth. 0 means no recursion.
81
- # * +purge+ - if +true+, items in +dest+ that are not in +src+
81
+ # * +options+ - hash of options:
82
+ # - +purge+ - if +true+, items in +dest+ that are not in +src+
82
83
  # will be deleted from +dest+. If +false+, these items will
83
84
  # be left alone.
85
+ # - +force+ - if +true+, matching files are always copied from
86
+ # +src+ to +dest+. If +false+, they will only be copied if
87
+ # actually different (which will take time to determine).
88
+ # - +dry_run+ - if +true+, action will not actually be taken;
89
+ # things will be printed out instead.
84
90
  #
85
91
  # ==== Examples
86
92
  #
87
93
  # ChefFS::FileSystem.copy_to(FilePattern.new('/cookbooks', chef_fs, local_fs, nil, true)
88
94
  #
89
- def self.copy_to(pattern, src_root, dest_root, recurse_depth, purge)
95
+ def self.copy_to(pattern, src_root, dest_root, recurse_depth, options)
90
96
  found_result = false
91
97
  # Find things we might want to copy
92
98
  ChefFS::Diff::diffable_leaves_from_pattern(pattern, src_root, dest_root, recurse_depth) do |src_leaf, dest_leaf, child_recurse_depth|
93
99
  found_result = true
94
- copy_leaves(src_leaf, dest_leaf, child_recurse_depth, purge)
100
+ copy_leaves(src_leaf, dest_leaf, child_recurse_depth, options)
95
101
  end
96
102
  if !found_result && pattern.exact_path
97
103
  yield "#{pattern}: No such file or directory on remote or local"
@@ -101,7 +107,7 @@ module ChefFS
101
107
  private
102
108
 
103
109
  # Copy two known leaves (could be files or dirs)
104
- def self.copy_leaves(src_entry, dest_entry, recurse_depth, purge)
110
+ def self.copy_leaves(src_entry, dest_entry, recurse_depth, options)
105
111
  # A NOTE about this algorithm:
106
112
  # There are cases where this algorithm does too many network requests.
107
113
  # knife upload with a specific filename will first check if the file
@@ -114,11 +120,15 @@ module ChefFS
114
120
  # Will need to decide how that works with checksums, though.
115
121
 
116
122
  if !src_entry.exists?
117
- if purge
123
+ if options[:purge]
118
124
  # If we would not have uploaded it, we will not purge it.
119
125
  if src_entry.parent.can_have_child?(dest_entry.name, dest_entry.dir?)
120
- dest_entry.delete
121
- puts "Delete extra entry #{dest_entry.path_for_printing} (purge is on)"
126
+ if options[:dry_run]
127
+ puts "Would delete #{dest_entry.path_for_printing}"
128
+ else
129
+ dest_entry.delete
130
+ puts "Delete extra entry #{dest_entry.path_for_printing} (purge is on)"
131
+ end
122
132
  else
123
133
  Chef::Log.info("Not deleting extra entry #{dest_entry.path_for_printing} (purge is off)")
124
134
  end
@@ -127,18 +137,27 @@ module ChefFS
127
137
  elsif !dest_entry.exists?
128
138
  if dest_entry.parent.can_have_child?(src_entry.name, src_entry.dir?)
129
139
  if src_entry.dir?
130
- new_dest_dir = dest_entry.parent.create_child(src_entry.name, nil)
131
- puts "Created #{dest_entry.path_for_printing}/"
140
+ if options[:dry_run]
141
+ puts "Would create #{dest_entry.path_for_printing}"
142
+ new_dest_dir = dest_entry.parent.child(src_entry.name)
143
+ else
144
+ new_dest_dir = dest_entry.parent.create_child(src_entry.name, nil)
145
+ puts "Created #{dest_entry.path_for_printing}/"
146
+ end
132
147
  # Directory creation is recursive.
133
148
  if recurse_depth != 0
134
149
  src_entry.children.each do |src_child|
135
150
  new_dest_child = new_dest_dir.child(src_child.name)
136
- copy_leaves(src_child, new_dest_child, recurse_depth ? recurse_depth - 1 : recurse_depth, purge)
151
+ copy_leaves(src_child, new_dest_child, recurse_depth ? recurse_depth - 1 : recurse_depth, options)
137
152
  end
138
153
  end
139
154
  else
140
- dest_entry.parent.create_child(src_entry.name, src_entry.read)
141
- puts "Created #{dest_entry.path_for_printing}"
155
+ if options[:dry_run]
156
+ puts "Would create #{dest_entry.path_for_printing}"
157
+ else
158
+ dest_entry.parent.create_child(src_entry.name, src_entry.read)
159
+ puts "Created #{dest_entry.path_for_printing}"
160
+ end
142
161
  end
143
162
  end
144
163
 
@@ -159,11 +178,24 @@ module ChefFS
159
178
  return
160
179
  else
161
180
  # Both are files! Copy them unless we're sure they are the same.
162
- different, src_value, dest_value = ChefFS::Diff.diff_files_quick(src_entry, dest_entry)
163
- if different || different == nil
181
+ if options[:force]
182
+ should_copy = true
183
+ src_value = src_entry.read
184
+ else
185
+ should_copy, src_value, dest_value = ChefFS::Diff.diff_files(src_entry, dest_entry)
164
186
  src_value = src_entry.read if src_value == :not_retrieved
165
- dest_entry.write(src_value)
166
- puts "Updated #{dest_entry.path_for_printing}"
187
+ if should_copy == nil
188
+ should_copy = true
189
+ end
190
+ end
191
+ if should_copy
192
+ if options[:dry_run]
193
+ puts "Would update #{dest_entry.path_for_printing}"
194
+ else
195
+ src_value = src_entry.read if src_value == :not_retrieved
196
+ dest_entry.write(src_value)
197
+ puts "Updated #{dest_entry.path_for_printing}"
198
+ end
167
199
  end
168
200
  end
169
201
  end
@@ -20,6 +20,17 @@ module ChefFS
20
20
  def can_have_child?(name, is_dir)
21
21
  is_dir
22
22
  end
23
+
24
+ def create_child(name, file_contents)
25
+ begin
26
+ rest.post_rest(api_path, { 'name' => name })
27
+ rescue Net::HTTPServerException
28
+ if $!.response.code != "409"
29
+ raise
30
+ end
31
+ end
32
+ DataBagDir.new(name, self, true)
33
+ end
23
34
  end
24
35
  end
25
36
  end
@@ -33,6 +33,18 @@ module ChefFS
33
33
  end
34
34
  end
35
35
 
36
+ def create_child(name, file_contents)
37
+ json = Chef::JSONCompat.from_json(file_contents).to_hash
38
+ base_name = name[0,name.length-5]
39
+ if json.include?('name') && json['name'] != base_name
40
+ raise "Name in #{path_for_printing}/#{name} must be '#{base_name}' (is '#{json['name']}')"
41
+ elsif json.include?('id') && json['id'] != base_name
42
+ raise "Name in #{path_for_printing}/#{name} must be '#{base_name}' (is '#{json['id']}')"
43
+ end
44
+ rest.post_rest(api_path, json)
45
+ RestListEntry.new(name, self, true)
46
+ end
47
+
36
48
  def environment
37
49
  parent.environment
38
50
  end
@@ -62,8 +62,23 @@ module ChefFS
62
62
  :json
63
63
  end
64
64
 
65
- def write(contents)
66
- rest.put_rest(api_path, contents)
65
+ def write(file_contents)
66
+ json = Chef::JSONCompat.from_json(file_contents).to_hash
67
+ base_name = name[0,name.length-5]
68
+ if json.include?('name') && json['name'] != base_name
69
+ raise "Name in #{path_for_printing}/#{name} must be '#{base_name}' (is '#{json['name']}')"
70
+ elsif json.include?('id') && json['id'] != base_name
71
+ raise "Name in #{path_for_printing}/#{name} must be '#{base_name}' (is '#{json['id']}')"
72
+ end
73
+ begin
74
+ rest.put_rest(api_path, json)
75
+ rescue Net::HTTPServerException
76
+ if $!.response.code == "404"
77
+ raise ChefFS::FileSystem::NotFoundError.new($!), "#{path_for_printing} not found"
78
+ else
79
+ raise
80
+ end
81
+ end
67
82
  end
68
83
  end
69
84
  end
@@ -1,4 +1,4 @@
1
1
  module ChefFS
2
- VERSION = "0.4"
2
+ VERSION = "0.5"
3
3
  end
4
4
 
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'
4
+ version: '0.5'
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-04-29 00:00:00.000000000Z
12
+ date: 2012-05-10 00:00:00.000000000Z
13
13
  dependencies: []
14
14
  description: Universal knife verbs that work with your Chef repository
15
15
  email: jkeiser@opscode.com
@@ -26,6 +26,7 @@ files:
26
26
  - lib/chef/knife/download.rb
27
27
  - lib/chef/knife/list.rb
28
28
  - lib/chef/knife/show.rb
29
+ - lib/chef/knife/upload.rb
29
30
  - lib/chef_fs/command_line.rb
30
31
  - lib/chef_fs/diff.rb
31
32
  - lib/chef_fs/file_pattern.rb