Last active
July 22, 2019 13:05
-
-
Save jordanorelli/0fd0e92f6ae530fefbe84c272c39651c to your computer and use it in GitHub Desktop.
diff yaml trees semantically
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env ruby | |
# diffs the contents of yaml files semantically. that is, ydiff will parse each | |
# yaml file and then diff their resulting trees, instead of attempting to diff | |
# the text. it's specifically for comparing directories of translations from | |
# Crowdin, so it's effectively only concerned with strings. | |
require 'pathname' | |
require 'rubygems' | |
require 'yaml' | |
require 'pp' | |
def diff_dir(left_path, right_path) | |
left_path.each_child do |left_child| | |
if left_child.directory? | |
right_candidate = right_path.join(left_child) | |
next unless right_candidate.exist? | |
diff_dir(left_child, right_candidate) | |
else | |
right_candidate = right_path.join(left_child) | |
next unless right_candidate.exist? | |
diff_file(left_child, right_candidate) | |
end | |
end | |
end | |
def diff_file(left_path, right_path) | |
left_tree = YAML.load_file(left_path) | |
right_tree = YAML.load_file(right_path) | |
puts "# ================================================================================" | |
puts "# < #{left_path}" | |
puts "# > #{right_path}" | |
puts "# ================================================================================" | |
puts "" | |
diff_tree(left_tree, right_tree) | |
end | |
def diff_tree(left, right, path = '') | |
case left | |
when Hash | |
diff_hash(left, right, path) | |
when String | |
diff_string(left, right, path) | |
when Array | |
diff_array(left, right, path) | |
when Symbol | |
diff_symbol(left, right, path) | |
else | |
STDERR.puts "SKIP #{path}: left type of #{left.class} is unhandled" | |
end | |
end | |
def added(item, path) | |
case item | |
when Hash | |
item.each_key do |key| | |
added(item[key], "#{path}/#{key}") | |
end | |
when String | |
puts "+ #{path}: #{item}" | |
when Array | |
item.each_with_index do |v, i| | |
added(v, "#{path}[#{i}]") | |
end | |
when Symbol | |
puts "+ #{path}: #{item}" | |
else | |
STDERR.puts "SKIP ADDED #{path}: dunno how to report #{item.class}: #{item}" | |
end | |
end | |
def diff_symbol(left, right, path = '') | |
if left != right | |
puts "- #{path} #{left}" | |
puts "+ #{path} #{right}" | |
end | |
end | |
def diff_array(left, right, path = '') | |
left.each_with_index do |v, i| | |
diff_tree(v, right[i], "#{path}[#{i}]") | |
end | |
end | |
def diff_string(left, right, path = '') | |
if left != right | |
puts "- #{path} #{left}" | |
puts "+ #{path} #{right}" | |
end | |
end | |
def diff_hash(left, right, path = '') | |
left.each_key do |key| | |
if right[key] | |
diff_tree(left[key], right[key], "#{path}/#{key}") | |
else | |
puts "- #{path}/#{key}" | |
end | |
end | |
right.each_key do |key| | |
unless left[key] | |
added(right[key], "#{path}/#{key}") | |
end | |
end | |
end | |
left_path = ARGV[0] | |
right_path = ARGV[1] | |
if File.directory? left_path | |
diff_dir(Pathname.new(left_path), Pathname.new(right_path)) | |
else | |
diff_file(left_path, right_path) | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment