knife-essentials 0.1.1 → 0.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -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