#!/usr/local/bin/perl -w

# Copyright 2005 Thomas A. Limoncelli
# 
#     This program is free software; you can redistribute it and/or modify
#     it under the terms of the GNU General Public License as published by
#     the Free Software Foundation; either version 2 of the License, or
#     (at your option) any later version.
#     This program is distributed in the hope that it will be useful,
#     but WITHOUT ANY WARRANTY; without even the implied warranty of
#     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#     GNU General Public License for more details.
# 
# 
#     You should have received a copy of the GNU General Public License
#     along with this program; if not, write to the Free Software
#     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA

use strict;

my ($left, $right, @sources, @dests);
my ($safe);
my (@srcitems, @remoteitems, @localitems, @diffitems, @syncupitems);
my (@reloadItemsLocal, @reloadItemsRemote, @reloadhosts);
my (@reloadifItemsLocal, @reloadifItemsRemote);
my $cmd;
my $locale;
my (%seen, %reloads, %reloadif);

# History:
#  2005-09-26: Initial release
#  2005-09-27: Added "make syncup" and "make diff"
#
# Todo:
#	o  Add some way to specify what command to run to reload the BIND server.
#

# Turn a filepath into something that is safe to use as a filename.
# (A perl guru might be able to do this in one line.)
sub safename {
	my ($name) = @_;
	$_ = $name;

	# the ones that we're really worred about
    s/_/__/g;
    s/:/_C/g;
    s[/][_L]g;
    s/\\/_B/g;
#    s/\./_P/g;

	# 0 thru 9 (shifted)
    s/!/_1/g;
    s/\@/_2/g;
    s/#/_3/g;
    s/\$/_4/g;
    s/%/_5/g;
    s/\^/_6/g;
    s/&/_7/g;
    s/\*/_8/g;
    s/\(/_9/g;
    s/\)/_0/g;

	# Others:
    s/\+/_a/g;
    s/`/_b/g;
    s/\]/_c/g;
    s/=/_e/g;
    s/>/_g/g;
    s/</_l/g;
    s/\[/_o/g;
    s/\|/_p/g;
    s/"/_Q/g;
    s/\?/_q/g;
    s/ /_s/g;
    s/;/_S/g;
    s/'/_T/g;
    s/~/_t/g;

	return $_;
}

print "\nall: push-local\n";

my $copycmd;
my $line;
my $junk;

while (defined($line = <>) ) {
	$line =~ s/#.*//;		# toss comments
	chomp $line;
	if ($line =~ s/\\\s*$//) {
		$line .= <>;
        	redo unless eof;
    	}

	$_ = $line;
	next if /^\s*$/;	# skip blank lines

	# Parse the line:
	if (/^\s*RELOAD/) {
		my ($host, $cmd) = m/^RELOAD\s+(\S+)\s+(.*)$/;
		push @reloadhosts, $host;	# record the order they appear in destinations.txt
		$reloads{ $host } = $cmd;	# record what command to run for that host
		next;
	}
	s/\s+/ /;		# unify whitespace
	($left, $right) = split( /\s+->\s*/, $_, 2 );
	#print "#LEFT=$left\n";
	#print "#RIGHT=$right\n";

	foreach my $src ( split( " ", $left) ) {

		print "\n# If $src is new, update the MS and MP version:";

		do {
			print "\n";
			print "MS/$src: $src\n";
			print "\t\@if [ ! -r MP/$src ] ; \\\n\tthen \\\n\t\techo CREATING MP/$src ; \\\n\t\tcp $src MP/$src ; \\\n\tfi\n";
			print "\t\@if [ ! -r MS/$src ] ; \\\n\tthen \\\n\t\techo CREATING MS/$src ; \\\n\t\tsed 's/:serial:/'\`cat serial\`'/g' <$src >MS/$src ; \\\n\tfi\n";
			print "\t\@if ! cmp $src MP/$src  > /dev/null ; \\\n\tthen \\\n\t\techo UPDATE MP/$src ; \\\n\t\tcp $src MP/$src ;\\\n\t\techo UPDATE MS/$src ;\\\n\t\tsed 's/:serial:/'\`cat serial\`'/g' <$src >MS/$src ; \\\n\tfi\n";
		} unless $seen{"MP/$src"}++;

		print "\n";
		print "# Compare $src against the MS version:\n";
		print "diff-$src:\n";
		print "\t-diff \$(DIFFOPT) MP/$src $src\n";
		push @diffitems, "diff-$src";
		push @syncupitems, "MS/$src";

		foreach my $dst ( split( " ", $right) ) {
			$safe = safename($dst . "--" . $src);

			print "\n# If file needs to be copied to $dst...";

			do {
				my $host;
				if ($dst =~ /:/) {
					$copycmd = "scp";
					push @remoteitems, "DS/$safe";
					($host, $junk) = split(':', $dst);
				} else {
					$copycmd = "cp";
					push @localitems, "DS/$safe";
					$host = 'local';
				}

				print "\n";
				print "DS/$safe: MS/$src\n";
				print "\t$copycmd MS/$src $dst\n";
				print "\t\@cp MS/$src DS/$safe\n";

				$reloadif{$host}{ "DS/$safe" } =  1;
			} unless $seen{"DS/$safe"}++;
		}
	}
}
print "\n";

print "\n# Sync up the MS/MP directories:\n\n";
print "syncup:\\\n\t", join("\\\n\t", @syncupitems), "\n\n";

print "\n# Do all diffs: (compare 'out' since last 'syncup'):\n\n";
print "diff:\\\n\t", join("\\\n\t", @diffitems), "\n\n";

print "\n# Recipes to push files to appropriate servers:\n\n";
print "push-all: push-local push-remote\n\n";
print "push-local:";
	if (@srcitems || @localitems) {
		print "\\\n\t";
		print join(" \\\n\t", @srcitems, @localitems);
	}
	print "\n\n";
print "push-remote:";
	if (@srcitems || @remoteitems) {
		print "\\\n\t";
		print join(" \\\n\t", @srcitems, @remoteitems);
	}
	print "\n\n";


# Output the plain reloads

print "\n# Recipes to force reloads:\n\n";
foreach my $host ( @reloadhosts ) {
	$safe = safename("reload-" . $host);
	if ($host eq "local") {
		print "reload-$host:\n";
		print "\t", $reloads{$host}, "\n";
		print "\t\@touch DS/$safe\n";
		print "\n";
		push @reloadItemsLocal, "reload-$host";
		
	} else {
		my $cmd = $reloads{$host};
		$cmd =~ s/'/\\'/g;	# protect use of '
		print "reload-$host:\n";
		print "\tssh $host '$cmd'\n";
		print "\t\@touch DS/$safe\n";
		print "\n";
		push @reloadItemsRemote, "reload-$host";
	}
}

print "reload-all: reload-local reload-remote\n\n";
print "reload-local:\n\n" unless @reloadItemsLocal;	# Already output a reload-local?
print "reload-remote:";
	if (@reloadItemsRemote) {
		print "\\\n\t";
		print join(" \\\n\t", @reloadItemsRemote);
	}
	print "\n\n";



# "reloadif" receipes:
print "\n# Recipes to reload 'named' only if it is needed:\n\n";
foreach my $host ( sort keys %reloadif ) {
#print STDERR "DEBUGreloadif: X" . $host, "X\n";
	$safe = safename($host);
		#print "reloadif-$host:";
		print "DS/reload-$safe:";
		for my $ds ( sort keys %{ $reloadif{$host} } ) {
			print "\\\n\t\t$ds";
		}
		print "\n";

	if ($host eq "local") {
		print "\t", $reloads{$host}, "\n" if defined($reloads{$host});
		print "\t\@touch DS/reload-$safe\n";
		print "\n";
		push @reloadifItemsLocal, "DS/reload-$safe";
	} else {
		my $cmd = $reloads{$host};
		$cmd =~ s/'/\\'/g;	# protect use of '
		print "\tssh $host '$cmd'\n";
		print "\t\@touch DS/reload-$safe\n";
		print "\n";
		push @reloadifItemsRemote, "DS/reload-$safe";
	}
}


print "reloadif-all: reloadif-local reloadif-remote\n\n";
print "reloadif-local:";
	if (@reloadifItemsLocal) {
		print "\\\n\t";
		print join(" \\\n\t", @reloadifItemsLocal);
	}
	print "\n\n";
print "reloadif-remote:";
	if (@reloadifItemsRemote) {
		print "\\\n\t";
		print join(" \\\n\t", @reloadifItemsRemote);
	}
	print "\n\n";

