class Bosh::Director::Changeset
Constants
- KEY_NAME
- REDACT_KEY_NAMES
Public Class Methods
new(before, after, redacted_before = nil, redacted_after = nil)
click to toggle source
# File lib/bosh/director/manifest/changeset.rb, line 10 def initialize(before, after, redacted_before = nil, redacted_after = nil) @redacted_before = redacted_before.nil? ? Changeset.redact_properties!(Bosh::Common::DeepCopy.copy(before)) : redacted_before @redacted_after = redacted_after.nil? ? Changeset.redact_properties!(Bosh::Common::DeepCopy.copy(after)) : redacted_after @before = before @after = after if @before && @after @merged = deep_merge(@before, @after) elsif @before @merged = @before else @merged = @after end end
redact_properties!(obj, redact_key_is_ancestor = false)
click to toggle source
redacts properties from ruby object to avoid having to use a regex to redact properties from diff output please do not use regexes for diffing/redacting
# File lib/bosh/director/manifest/changeset.rb, line 28 def self.redact_properties!(obj, redact_key_is_ancestor = false) if redact_key_is_ancestor if obj.respond_to?(:key?) obj.keys.each{ |key| if obj[key].respond_to?(:each) redact_properties!(obj[key], true) else obj[key] = '<redacted>' end } elsif obj.respond_to?(:each_index) obj.each_index { |i| if obj[i].respond_to?(:each) redact_properties!(obj[i], true) else obj[i] = '<redacted>' end } end else if obj.respond_to?(:each) obj.each{ |a| if obj.respond_to?(:key?) && REDACT_KEY_NAMES.any? { |key| key == a.first } && a.last.respond_to?(:key?) redact_properties!(a.last, true) else redact_properties!(a.respond_to?(:last) ? a.last : a) end } end end obj end
Public Instance Methods
diff(redact=true, indent = 0)
click to toggle source
# File lib/bosh/director/manifest/changeset.rb, line 63 def diff(redact=true, indent = 0) lines = DiffLines.new if redact output_values_before = @redacted_before output_values_after = @redacted_after else output_values_before = @before output_values_after = @after end @merged.each_pair do |key, value| if @before[key] != @after[key] if @before.nil? || @before[key].nil? lines.concat(yaml_lines({key => output_values_after[key]}, indent, 'added')) elsif @after.nil? || @after[key].nil? lines.concat(yaml_lines({key => output_values_before[key]}, indent, 'removed')) elsif @before[key].is_a?(Array) && @after[key].is_a?(Array) lines.concat(compare_arrays(@before[key], @after[key], output_values_before[key], output_values_after[key], key, redact, indent)) elsif @before[key].is_a?(Hash) && @after[key].is_a?(Hash) changeset = Changeset.new(@before[key], @after[key], output_values_before[key], output_values_after[key]) diff_lines = changeset.diff(redact, indent+1) unless diff_lines.empty? lines << Line.new(indent, "#{key}:", nil) lines.concat(diff_lines) end else lines.concat(yaml_lines({key => output_values_before[key]}, indent, 'removed')) lines.concat(yaml_lines({key => output_values_after[key]}, indent, 'added')) end end end lines end
Private Instance Methods
compare_arrays(old_value, new_value, output_old_value, output_new_value, parent_name, redact, indent)
click to toggle source
# File lib/bosh/director/manifest/changeset.rb, line 117 def compare_arrays(old_value, new_value, output_old_value, output_new_value, parent_name, redact, indent) # combine arrays of redacted and unredacted values. unredacted arrays for diff logic, and redacted arrays for output combined_old_value = old_value.zip output_old_value combined_new_value = new_value.zip output_new_value added = combined_new_value - combined_old_value removed = combined_old_value - combined_new_value lines = DiffLines.new added.each do |pair| elem = pair.first redacted_elem = pair.last if elem.is_a?(Hash) using_names = (added+removed).all? { |e| e.first['name'] } using_ranges = (added+removed).all? { |e| e.first['range'] } if using_names || using_ranges if using_names removed_same_name_element = removed.find { |e| e.first['name'] == elem['name'] } elsif using_ranges removed_same_name_element = removed.find { |e| e.first['range'] == elem['range'] } end removed.delete(removed_same_name_element) if removed_same_name_element changeset = Changeset.new(removed_same_name_element.first, elem, removed_same_name_element.last, redacted_elem) diff_lines = changeset.diff(redact, indent+1) unless diff_lines.empty? # write name if elem has been changed if using_names lines.concat(yaml_lines([{'name' => redacted_elem['name']}], indent, nil)) elsif using_ranges lines.concat(yaml_lines([{'range' => redacted_elem['range']}], indent, nil)) end lines.concat(diff_lines) end else lines.concat(yaml_lines([redacted_elem], indent, 'added')) end else lines.concat(yaml_lines([redacted_elem], indent, 'added')) end else lines.concat(yaml_lines([redacted_elem], indent, 'added')) end end unless removed.empty? redacted_removed = [] removed.each do |pair| redacted_removed.push(pair.last) end lines.concat(yaml_lines(redacted_removed, indent, 'removed')) end unless lines.empty? lines.unshift(Line.new(indent, "#{parent_name}:", nil)) end lines end
deep_merge(first, second)
click to toggle source
# File lib/bosh/director/manifest/changeset.rb, line 104 def deep_merge(first, second) merger = proc { |key, v1, v2| Hash === v1 && Hash === v2 ? v1.merge(v2, &merger) : v2 } first.merge(second, &merger) end
yaml_lines(value, indent, state)
click to toggle source
# File lib/bosh/director/manifest/changeset.rb, line 109 def yaml_lines(value, indent, state) lines = DiffLines.new value.to_yaml(indent: Line::INDENT).gsub(/^---\n/, '').split("\n").each do |line| lines << Line.new(indent, line, state) end lines end