knife-essentials 0.1.1 → 0.2

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.
@@ -52,7 +52,7 @@ class Chef
52
52
  def add_dir_result(result)
53
53
  begin
54
54
  children = result.children.sort_by { |child| child.name }
55
- rescue ChefFS::FileSystem::NotFoundException
55
+ rescue ChefFS::FileSystem::NotFoundError
56
56
  STDERR.puts "#{format_path(result.path)}: No such file or directory"
57
57
  return []
58
58
  end
@@ -17,7 +17,7 @@ class Chef
17
17
  value = result.read
18
18
  puts "#{format_path(result.path)}:"
19
19
  output(format_for_display(result.read))
20
- rescue ChefFS::FileSystem::NotFoundException
20
+ rescue ChefFS::FileSystem::NotFoundError
21
21
  STDERR.puts "#{format_path(result.path)}: No such file or directory" if pattern.exact_path
22
22
  end
23
23
  end
@@ -27,7 +27,7 @@ module ChefFS
27
27
  result << "Common subdirectories: #{old_file.path}\n"
28
28
  elsif new_file.exists?
29
29
  result << "File #{new_file.path_for_printing} is a directory while file #{new_file.path_for_printing} is a regular file\n"
30
- else
30
+ elsif new_file.parent.can_have_child?(old_file.name, old_file.dir?)
31
31
  result << "Only in #{old_file.parent.path_for_printing}: #{old_file.name}\n"
32
32
  end
33
33
 
@@ -36,7 +36,7 @@ module ChefFS
36
36
  elsif new_file.dir?
37
37
  if old_file.exists?
38
38
  result << "File #{old_file.path_for_printing} is a regular file while file #{old_file.path_for_printing} is a directory\n"
39
- else
39
+ elsif old_file.parent.can_have_child?(new_file.name, new_file.dir?)
40
40
  result << "Only in #{new_file.parent.path_for_printing}: #{new_file.name}\n"
41
41
  end
42
42
 
@@ -44,6 +44,15 @@ module ChefFS
44
44
  # Neither is a directory, so they are diffable with file diff
45
45
  different, old_value, new_value = ChefFS::Diff::diff_files(old_file, new_file)
46
46
  if different
47
+ # If one of the files doesn't exist, we only want to print the diff if the
48
+ # other file *could be synced*.
49
+ if !old_value && !old_file.parent.can_have_child?(new_file.name, new_file.dir?)
50
+ return result
51
+ end
52
+ if !new_value && !new_file.parent.can_have_child?(old_file.name, old_file.dir?)
53
+ return result
54
+ end
55
+
47
56
  old_path = old_file.path_for_printing
48
57
  new_path = new_file.path_for_printing
49
58
  result << "diff --knife #{old_path} #{new_path}\n"
@@ -149,7 +149,7 @@ module ChefFS
149
149
  def self.read_file_value(file)
150
150
  begin
151
151
  return file.read
152
- rescue ChefFS::FileSystem::NotFoundException
152
+ rescue ChefFS::FileSystem::NotFoundError
153
153
  return nil
154
154
  end
155
155
  end
@@ -17,6 +17,10 @@ module ChefFS
17
17
  children.select { |child| child.name == name }.first || NonexistentFSObject.new(name, self)
18
18
  end
19
19
 
20
+ def can_have_child?(name, is_dir)
21
+ true
22
+ end
23
+
20
24
  # Abstract: children
21
25
  end
22
26
  end
@@ -44,6 +44,17 @@ module ChefFS
44
44
  :text
45
45
  end
46
46
 
47
+ def child(name)
48
+ NonexistentFSObject.new(name, self)
49
+ end
50
+
51
+ # Override can_have_child? to report whether a given file *could* be added
52
+ # to this directory. (Some directories can't have subdirs, some can only have .json
53
+ # files, etc.)
54
+ def can_have_child?(name, is_dir)
55
+ false
56
+ end
57
+
47
58
  # Important directory attributes: name, parent, path, root
48
59
  # Overridable attributes: dir?, child(name), path_for_printing
49
60
  # Abstract: read, write, delete, children
@@ -0,0 +1,46 @@
1
+ require 'chef_fs/file_system/file_system_entry'
2
+ require 'chef/cookbook/chefignore'
3
+
4
+ module ChefFS
5
+ module FileSystem
6
+ # ChefRepositoryFileSystemEntry works just like FileSystemEntry,
7
+ # except it pretends files in /cookbooks/chefignore don't exist
8
+ class ChefRepositoryFileSystemEntry < FileSystemEntry
9
+ def initialize(name, parent, file_path = nil)
10
+ super(name, parent, file_path)
11
+ # Load /cookbooks/chefignore
12
+ if name == "cookbooks" && path == "/cookbooks" # We check name first because it's a faster fail than path
13
+ @chefignore = Chef::Cookbook::Chefignore.new(self.file_path)
14
+ end
15
+ end
16
+
17
+ def children
18
+ @children ||= Dir.entries(file_path).select { |entry| entry != '.' && entry != '..' && !ignored?(entry) }
19
+ .map { |entry| ChefRepositoryFileSystemEntry.new(entry, self) }
20
+ end
21
+
22
+ attr_reader :chefignore
23
+
24
+ private
25
+
26
+ def ignored?(child_name)
27
+ ignorer = self
28
+ begin
29
+ if ignorer.chefignore
30
+ # Grab the path from entry to child
31
+ path_to_child = child_name
32
+ child = self
33
+ while child != ignorer
34
+ path_to_child = PathUtils.join(child.name, path_to_child)
35
+ child = child.parent
36
+ end
37
+ # Check whether that relative path is ignored
38
+ return ignorer.chefignore.ignored?(path_to_child)
39
+ end
40
+ ignorer = ignorer.parent
41
+ end while ignorer
42
+ end
43
+
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,11 @@
1
+ require 'chef_fs/file_system/chef_repository_file_system_entry'
2
+
3
+ module ChefFS
4
+ module FileSystem
5
+ class ChefRepositoryFileSystemRootDir < ChefRepositoryFileSystemEntry
6
+ def initialize(file_path)
7
+ super("", nil, file_path)
8
+ end
9
+ end
10
+ end
11
+ end
@@ -29,7 +29,11 @@ module ChefFS
29
29
  end
30
30
 
31
31
  def path_for_printing
32
- @root_name
32
+ "#{@root_name}/"
33
+ end
34
+
35
+ def can_have_child?(name, is_dir)
36
+ is_dir && children.any? { |child| child.name == name }
33
37
  end
34
38
 
35
39
  def children
@@ -1,6 +1,7 @@
1
1
  require 'chef_fs/file_system/rest_list_dir'
2
2
  require 'chef_fs/file_system/cookbook_subdir'
3
3
  require 'chef_fs/file_system/cookbook_file'
4
+ require 'chef_fs/file_system/not_found_error'
4
5
  require 'chef/cookbook_version'
5
6
 
6
7
  module ChefFS
@@ -13,6 +14,18 @@ module ChefFS
13
14
 
14
15
  attr_reader :versions
15
16
 
17
+ COOKBOOK_SEGMENT_INFO = {
18
+ :attributes => { :ruby_only => true },
19
+ :definitions => { :ruby_only => true },
20
+ :recipes => { :ruby_only => true },
21
+ :libraries => { :ruby_only => true },
22
+ :templates => { :recursive => true },
23
+ :files => { :recursive => true },
24
+ :resources => { :ruby_only => true, :recursive => true },
25
+ :providers => { :ruby_only => true, :recursive => true },
26
+ :root_files => { }
27
+ }
28
+
16
29
  def add_child(child)
17
30
  @children << child
18
31
  end
@@ -22,23 +35,42 @@ module ChefFS
22
35
  end
23
36
 
24
37
  def child(name)
25
- children.select { |child| child.name == name }.first || NonexistentFSObject.new(name, self)
38
+ # Since we're ignoring the rules and doing a network request here,
39
+ # we need to make sure we don't rethrow the exception. (child(name)
40
+ # is not supposed to fail.)
41
+ begin
42
+ result = children.select { |child| child.name == name }.first
43
+ return result if result
44
+ rescue ChefFS::FileSystem::NotFoundError
45
+ end
46
+ return NonexistentFSObject.new(name, self)
47
+ end
48
+
49
+ def can_have_child?(name, is_dir)
50
+ # A cookbook's root may not have directories unless they are segment directories
51
+ if is_dir
52
+ return name != 'root_files' && COOKBOOK_SEGMENT_INFO.keys.any? { |segment| segment.to_s == name }
53
+ end
54
+ true
26
55
  end
27
56
 
28
57
  def children
29
58
  if @children.nil?
30
59
  @children = []
31
- Chef::CookbookVersion::COOKBOOK_SEGMENTS.each do |segment|
60
+ COOKBOOK_SEGMENT_INFO.each do |segment, segment_info|
32
61
  next unless manifest.has_key?(segment)
62
+
63
+ # Go through each file in the manifest for the segment, and
64
+ # add cookbook subdirs and files for it.
33
65
  manifest[segment].each do |segment_file|
34
- parts = segment_file['path'].split('/')
66
+ parts = segment_file[:path].split('/')
35
67
  # Get or create the path to the file
36
68
  container = self
37
69
  parts[0,parts.length-1].each do |part|
38
70
  old_container = container
39
71
  container = old_container.children.select { |child| part == child.name }.first
40
72
  if !container
41
- container = CookbookSubdir.new(part, old_container)
73
+ container = CookbookSubdir.new(part, old_container, segment_info[:ruby_only], segment_info[:recursive])
42
74
  old_container.add_child(container)
43
75
  end
44
76
  end
@@ -56,7 +88,7 @@ module ChefFS
56
88
 
57
89
  def read
58
90
  # This will only be called if dir? is false, which means exists? is false.
59
- raise ChefFS::FileSystem::NotFoundException, path_for_printing
91
+ raise ChefFS::FileSystem::NotFoundError, path_for_printing
60
92
  end
61
93
 
62
94
  def exists?
@@ -74,11 +106,35 @@ module ChefFS
74
106
  private
75
107
 
76
108
  def manifest
109
+ # 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"
112
+ end
113
+
77
114
  begin
78
- @manifest ||= rest.get_rest(api_path).manifest
115
+ # We want to fail fast, for now, because of the 500 issue :/
116
+ # This will make things worse for parallelism, a little.
117
+ old_retry_count = Chef::Config[:http_retry_count]
118
+ begin
119
+ Chef::Config[:http_retry_count] = 0
120
+ @manifest ||= rest.get_rest(api_path).manifest
121
+ ensure
122
+ Chef::Config[:http_retry_count] = old_retry_count
123
+ end
79
124
  rescue Net::HTTPServerException
80
125
  if $!.response.code == "404"
81
- raise ChefFS::FileSystem::NotFoundException, $!
126
+ @could_not_get_manifest = $!
127
+ raise ChefFS::FileSystem::NotFoundError.new(@could_not_get_manifest), "#{path_for_printing} not found"
128
+ else
129
+ raise
130
+ end
131
+
132
+ # Chef bug http://tickets.opscode.com/browse/CHEF-3066 ... instead of 404 we get 500 right now.
133
+ # Remove this when that bug is fixed.
134
+ rescue Net::HTTPFatalError
135
+ if $!.response.code == "500"
136
+ @could_not_get_manifest = $!
137
+ raise ChefFS::FileSystem::NotFoundError.new(@could_not_get_manifest), "#{path_for_printing} not found"
82
138
  else
83
139
  raise
84
140
  end
@@ -18,9 +18,9 @@ module ChefFS
18
18
  old_sign_on_redirect = rest.sign_on_redirect
19
19
  rest.sign_on_redirect = false
20
20
  begin
21
- rest.get_rest(file['url'])
21
+ rest.get_rest(file[:url])
22
22
  ensure
23
- rest.sign_on_redirect = true
23
+ rest.sign_on_redirect = old_sign_on_redirect
24
24
  end
25
25
  end
26
26
 
@@ -5,9 +5,11 @@ require 'chef_fs/file_system/base_fs_dir'
5
5
  module ChefFS
6
6
  module FileSystem
7
7
  class CookbookSubdir < BaseFSDir
8
- def initialize(name, parent)
8
+ def initialize(name, parent, ruby_only, recursive)
9
9
  super(name, parent)
10
10
  @children = []
11
+ @ruby_only = ruby_only
12
+ @recursive = recursive
11
13
  end
12
14
 
13
15
  attr_reader :versions
@@ -17,6 +19,15 @@ module ChefFS
17
19
  @children << child
18
20
  end
19
21
 
22
+ def can_have_child?(name, is_dir)
23
+ if is_dir
24
+ return false if !@recursive
25
+ else
26
+ return false if @ruby_only && name !~ /\.rb$/
27
+ end
28
+ true
29
+ end
30
+
20
31
  def rest
21
32
  parent.rest
22
33
  end
@@ -16,6 +16,10 @@ module ChefFS
16
16
  def children
17
17
  @children ||= rest.get_rest(api_path).map { |key, value| CookbookDir.new(key, self, value) }
18
18
  end
19
+
20
+ def can_have_child?(name, is_dir)
21
+ is_dir
22
+ end
19
23
  end
20
24
  end
21
25
  end
@@ -1,5 +1,6 @@
1
1
  require 'chef_fs/file_system/base_fs_dir'
2
2
  require 'chef_fs/file_system/rest_list_entry'
3
+ require 'chef_fs/file_system/not_found_error'
3
4
 
4
5
  # TODO: take environment into account
5
6
 
@@ -17,7 +18,7 @@ module ChefFS
17
18
 
18
19
  def read
19
20
  # This will only be called if dir? is false, which means exists? is false.
20
- raise ChefFS::FileSystem::NotFoundException, path_for_printing
21
+ raise ChefFS::FileSystem::NotFoundError, "#{path_for_printing} not found"
21
22
  end
22
23
 
23
24
  def exists?
@@ -18,6 +18,10 @@ module ChefFS
18
18
  def children
19
19
  @children ||= rest.get_rest(api_path).keys.map { |entry| DataBagDir.new(entry, self, true) }
20
20
  end
21
+
22
+ def can_have_child?(name, is_dir)
23
+ is_dir
24
+ end
21
25
  end
22
26
  end
23
27
  end
@@ -1,5 +1,6 @@
1
1
  require 'chef_fs/file_system/base_fs_dir'
2
2
  require 'chef_fs/file_system/rest_list_dir'
3
+ require 'chef_fs/file_system/not_found_error'
3
4
  require 'chef_fs/path_utils'
4
5
 
5
6
  module ChefFS
@@ -17,7 +18,7 @@ module ChefFS
17
18
  end
18
19
 
19
20
  def children
20
- @children ||= Dir.entries(file_path).select { |entry| entry[0] != "." }.map { |entry| FileSystemEntry.new(entry, self) }
21
+ @children ||= Dir.entries(file_path).select { |entry| entry != '.' && entry != '..' }.map { |entry| FileSystemEntry.new(entry, self) }
21
22
  end
22
23
 
23
24
  def dir?
@@ -27,8 +28,8 @@ module ChefFS
27
28
  def read
28
29
  begin
29
30
  IO.read(file_path)
30
- rescue IONotFoundException # TODO real exception
31
- raise NotFoundException, $!
31
+ rescue IONotFoundError # TODO real exception
32
+ raise ChefFS::FileSystem::NotFoundError.new($!), "#{path_for_printing} not found"
32
33
  end
33
34
  end
34
35
  end
@@ -1,4 +1,5 @@
1
1
  require 'chef_fs/file_system/base_fs_object'
2
+ require 'chef_fs/file_system/not_found_error'
2
3
 
3
4
  module ChefFS
4
5
  module FileSystem
@@ -11,12 +12,8 @@ module ChefFS
11
12
  false
12
13
  end
13
14
 
14
- def child(name)
15
- NonexistentFSObject.new(name, self)
16
- end
17
-
18
15
  def read
19
- raise ChefFS::FileSystem::NotFoundException, "Nonexistent object"
16
+ raise ChefFS::FileSystem::NotFoundError, "Nonexistent #{path_for_printing}"
20
17
  end
21
18
  end
22
19
  end
@@ -0,0 +1,11 @@
1
+ module ChefFS
2
+ module FileSystem
3
+ class NotFoundError < StandardError
4
+ def initialize(cause = nil)
5
+ @cause = cause
6
+ end
7
+
8
+ attr_reader :cause
9
+ end
10
+ end
11
+ end
@@ -1,5 +1,6 @@
1
1
  require 'chef_fs/file_system/base_fs_dir'
2
2
  require 'chef_fs/file_system/rest_list_entry'
3
+ require 'chef_fs/file_system/not_found_error'
3
4
 
4
5
  # TODO: take environment into account
5
6
 
@@ -18,12 +19,16 @@ module ChefFS
18
19
  result || RestListEntry.new(name, self)
19
20
  end
20
21
 
22
+ def can_have_child?(name, is_dir)
23
+ name =~ /\.json$/ && !is_dir
24
+ end
25
+
21
26
  def children
22
27
  begin
23
28
  @children ||= rest.get_rest(api_path).keys.map { |key| RestListEntry.new("#{key}.json", self, true) }
24
29
  rescue Net::HTTPServerException
25
30
  if $!.response.code == "404"
26
- raise ChefFS::FileSystem::NotFoundException, $!
31
+ raise ChefFS::FileSystem::NotFoundError.new($!), "#{path_for_printing} not found"
27
32
  else
28
33
  raise
29
34
  end