#!/usr/bin/env perl use strict; use warnings; use YAML::Syck qw(LoadFile); use Test::Differences; use Pod::Usage (); use Getopt::Long (); =head1 NAME locale-diff - Compare two YAML files and print how their datastructures differ =head1 SYNOPSIS locale-diff en.yml is.yml locale-diff en.yml is.yml | grep '*' =head1 DESCRIPTION This utility prints the differences between two YAML files using L. The purpose of it is to diff the files is F to find out what keys need to be added to the translated files when F changes. =head1 OPTIONS =over =item -h, --help Print this help message. =item --diff-keys Show the hash keys that differ between the two files, useful merging new entries from F to a local file. =item --untranslated-values Show keys whose values are either exactly the same between the two files, or don't exist in the target file (the latter file specified). This helps to find untranslated values. =back =head1 AUTHOR Evar ArnfjErE Bjarmason =cut # Get the command-line options Getopt::Long::Parser->new( config => [ qw< bundling no_ignore_case no_require_order pass_through > ], )->getoptions( 'h|help' => \my $help, 'diff-keys' => \my $diff_keys, 'undiff-values' => \my $undiff_values, ) or help(); # On --help help() if $help; # If we're not given two .yml files help() if @ARGV != 2 or (!-f $ARGV[0] or !-f $ARGV[1]); my ($from, $to) = @ARGV; my $from_data = LoadFile($from); my $to_data = LoadFile($to); my $from_parsed = { iterate($from_data->{basename($from)}) }; my $to_parsed = { iterate($to_data->{basename($to)}) }; # Since this used to be the default, support that... if ((not $undiff_values and not $diff_keys) or $diff_keys) { print_key_differences(); } elsif ($undiff_values) { my @untranslated = untranslated_keys($from_parsed, $to_parsed); print $_, "\n" for @untranslated; } exit 0; sub print_key_differences { # Hack around Test::Differences wanting a Test::* module loaded $INC{"Test.pm"} = 1; sub Test::ok { print shift } # Diff the tree eq_or_diff([ sort keys %$from_parsed ], [ sort keys %$to_parsed ]); } sub untranslated_keys { my ($from_parsed, $to_parsed) = @_; sort grep { not exists $to_parsed->{$_} or $from_parsed->{$_} eq $to_parsed->{$_} } keys %$from_parsed; } sub iterate { my ($hash, @path) = @_; my @ret; while (my ($k, $v) = each %$hash) { if (ref $v eq 'HASH') { push @ret => iterate($v, @path, $k); } else { push @ret => join(".",@path, $k), $v; } } return @ret; } sub basename { my $name = shift; $name =~ s[\..*?$][]; $name; } sub help { my %arg = @_; Pod::Usage::pod2usage( -verbose => $arg{ verbose }, -exitval => $arg{ exitval } || 0, ); }