Module: Chef::ChefFS::CommandLine

Defined in:
lib/chef/chef_fs/command_line.rb

Class Method Summary collapse

Class Method Details

.diff(pattern, a_root, b_root, recurse_depth, output_mode) ⇒ Object



24
25
26
27
28
29
30
31
32
33
34
35
# File 'lib/chef/chef_fs/command_line.rb', line 24

def self.diff(pattern, a_root, b_root, recurse_depth, output_mode)
  found_result = false
  Chef::ChefFS::FileSystem.list_pairs(pattern, a_root, b_root) do |a, b|
    existed = diff_entries(a, b, recurse_depth, output_mode) do |diff|
      yield diff
    end
    found_result = true if existed
  end
  if !found_result && pattern.exact_path
    yield "#{pattern}: No such file or directory on remote or local"
  end
end

.diff_entries(old_entry, new_entry, recurse_depth, output_mode) ⇒ Object

Diff two known entries (could be files or dirs)



38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
# File 'lib/chef/chef_fs/command_line.rb', line 38

def self.diff_entries(old_entry, new_entry, recurse_depth, output_mode)
  # If both are directories
  if old_entry.dir?
    if new_entry.dir?
      if recurse_depth == 0
        if output_mode != :name_only && output_mode != :name_status
          yield "Common subdirectories: #{old_entry.path}\n"
        end
      else
        Chef::ChefFS::FileSystem.child_pairs(old_entry, new_entry).each do |old_child,new_child|
          diff_entries(old_child, new_child,
                       recurse_depth ? recurse_depth - 1 : nil, output_mode) do |diff|
            yield diff
          end
        end
      end

  # If old is a directory and new is a file
    elsif new_entry.exists?
      if output_mode == :name_only
        yield "#{new_entry.path_for_printing}\n"
      elsif output_mode == :name_status
        yield "T\t#{new_entry.path_for_printing}\n"
      else
        yield "File #{new_entry.path_for_printing} is a directory while file #{new_entry.path_for_printing} is a regular file\n"
      end

  # If old is a directory and new does not exist
    elsif new_entry.parent.can_have_child?(old_entry.name, old_entry.dir?)
      if output_mode == :name_only
        yield "#{new_entry.path_for_printing}\n"
      elsif output_mode == :name_status
        yield "D\t#{new_entry.path_for_printing}\n"
      else
        yield "Only in #{old_entry.parent.path_for_printing}: #{old_entry.name}\n"
      end
    end

  # If new is a directory and old is a file
  elsif new_entry.dir?
    if old_entry.exists?
      if output_mode == :name_only
        yield "#{new_entry.path_for_printing}\n"
      elsif output_mode == :name_status
        yield "T\t#{new_entry.path_for_printing}\n"
      else
        yield "File #{old_entry.path_for_printing} is a regular file while file #{old_entry.path_for_printing} is a directory\n"
      end

  # If new is a directory and old does not exist
    elsif old_entry.parent.can_have_child?(new_entry.name, new_entry.dir?)
      if output_mode == :name_only
        yield "#{new_entry.path_for_printing}\n"
      elsif output_mode == :name_status
        yield "A\t#{new_entry.path_for_printing}\n"
      else
        yield "Only in #{new_entry.parent.path_for_printing}: #{new_entry.name}\n"
      end
    end

  # Neither is a directory, so they are diffable with file diff
  else
    are_same, old_value, new_value = Chef::ChefFS::FileSystem.compare(old_entry, new_entry)
    if are_same
      return old_value != :none
    else
      if old_value == :none
        old_exists = false
      elsif old_value.nil?
        old_exists = old_entry.exists?
      else
        old_exists = true
      end
      if new_value == :none
        new_exists = false
      elsif new_value.nil?
        new_exists = new_entry.exists?
      else
        new_exists = true
      end

      # If one of the files doesn't exist, we only want to print the diff if the
      # other file *could be uploaded/downloaded*.
      if !old_exists && !old_entry.parent.can_have_child?(new_entry.name, new_entry.dir?)
        return true
      end
      if !new_exists && !new_entry.parent.can_have_child?(old_entry.name, old_entry.dir?)
        return true
      end

      if output_mode == :name_only
        yield "#{new_entry.path_for_printing}\n"
      elsif output_mode == :name_status
        if old_value == :none || (old_value == nil && !old_entry.exists?)
          yield "A\t#{new_entry.path_for_printing}\n"
        elsif new_value == :none
          yield "D\t#{new_entry.path_for_printing}\n"
        else
          yield "M\t#{new_entry.path_for_printing}\n"
        end
      else
        # If we haven't read the values yet, get them now.
        begin
          old_value = old_entry.read if old_value.nil?
        rescue Chef::ChefFS::FileSystem::NotFoundError
          old_value = :none
        end
        begin
          new_value = new_entry.read if new_value.nil?
        rescue Chef::ChefFS::FileSystem::NotFoundError
          new_value = :none
        end

        old_path = old_entry.path_for_printing
        new_path = new_entry.path_for_printing
        result = ''
        result << "diff --knife #{old_path} #{new_path}\n"
        if old_value == :none
          result << "new file\n"
          old_path = "/dev/null"
          old_value = ''
        end
        if new_value == :none
          result << "deleted file\n"
          new_path = "/dev/null"
          new_value = ''
        end
        result << diff_text(old_path, new_path, old_value, new_value)
        yield result
      end
    end
  end
  return true
end