#! /usr/bin/perl -w
#
# $Yahoo: //depot/yahoo/misc/p4tocvs/repl_RELENG_4.pl#7 $
#
# XXX security note.. has embedded passwords to a non privilged perforce
# user, and uses a hard coded tmpfile name.  caveat emptor!

use strict;

# Super security at work here...
$ENV{"P4USER"} = "review";
$ENV{"P4PASSWD"} = "XXXX";
$ENV{"P4PORT"} = "localhost:1666";
$ENV{"P4CONFIG"} = "/c/p4repl/foo";
my $p4  = "/usr/local/bin/p4";
my $commitlog = `mktemp /tmp/commitlog.XXXXXX`;
chomp $commitlog;

my $once = 0;		# set to 1 to make it run once and exit
my $sleeptime = 120;	# loop sleep time in loop mode

my @commitdirs;
my $badness = 0;
my $done;
my $changes;

select(STDOUT); $| = 1;     # make unbuffered

do {
	$done = `$p4 counter merged_kse`;
	chomp($done);

	$changes = `$p4 counter change`;
	chomp($changes);

	while ($done < $changes) {
		@commitdirs = ();
		&replchange($done + 1);
	}
} while (!$once && !$badness && sleep(120));
exit 0;

sub replchange {
	my $dochange = shift;

	my $seenstart = 0;
	my $lastline = "";
	my $realcommit = 0;
	my $line;

	print "doing change $dochange\n";
	unlink "$commitlog";
	open(LOG, ">$commitlog") || die "cannot open $commitlog: $!";
	open(CHANGE, "$p4 describe -s $dochange 2>/dev/null |") || die "cannot run p4: $!";
	while($line = <CHANGE>) {
		chomp($line);
		if ($seenstart == 0) {
			if ($line =~ /^Change /) {
				printf LOG ">>>Replicated %s<<<\n", $line;
				$lastline = "\n";
				$seenstart = 1;
				$line = <CHANGE>;	# absorb a blank line
				next;
			}
			next;
		}
		if ($seenstart == 1) {
			if ($line =~ /^Affected files \.\.\./) {
				$seenstart = 2;
				$line = <CHANGE>;	# absorb a blank line
				next;
			}
			if ($line eq "") {
				$lastline = "\n";
			} else {
				if ($lastline eq "\n") {
					print LOG "\n";
				}
				printf LOG "%s\n", $line;
				$lastline = "";
			}
			next;
		}
		if ($seenstart == 2) {
			if ($line eq '') {
				next;
			}
			if ($line =~ /^\.\.\. /) {
				my $filespec;
				my $action;
				my $file;
				my $rev;

				$realcommit++;
				$line =~ s/^\.\.\. //;

				($filespec, $action) = split(' ', $line);
				($file, $rev) = split('#', $filespec);
				if ($line =~ /^\/\/depot\/projects\/kse\//) {
					&repl_kse($action, $file, $rev);
				}
			} else {
				printf "bad line '%s'\n", $line;
			}
			next;
		}
	}
	close CHANGE;
	close LOG;
	die "replication failed in prep stage: $badness" if $badness > 0;
	&commitit();
	unlink "$commitlog";
	die "replication failed after commit: $badness" if $badness > 0;
	$done++;
	if ($realcommit > 0) {
		`$p4 counter merged_kse $done`;
	}
}

sub commitit {
	my $key;
	my $repo;
	my $root;
	my $dir;

	foreach $key (@commitdirs) {
		($repo, $root, $dir) = split('\|', $key);
		printf "COMMIT LOG:\n";
		open(LOG, "<$commitlog") || die "cannot open $commitlog: $!";
		while(<LOG>) {
			chomp;
			printf "%s\n", $_;
		}
		close LOG;
		cmd("cd $root && cvs -d $repo commit -l -F $commitlog $dir");
	}
}

sub repl_kse {
	my $action = shift;
	my $file = shift;
	my $rev = shift;

	my $repo = "/c/p4repl/ncvs";
	my $root = "projects/kse";
	my $path = $file;

	$path =~ s/^\/\/depot\/projects\/kse\///;

	&repl($action, $path, $rev, $repo, $root, $file);
}

sub repl {
	my $action = shift;
	my $file = shift;
	my $rev = shift;
	my $repo = shift;
	my $root = shift;
	my $path = shift;

	my $addit = 0;
	my $key;
	my $dir = "";
	my $elm = "";

	my @components = split('/', $file);
	while(@components > 1) {
		$elm = shift @components;
		if ($dir ne "") {
			$dir .= '/';
		}
		$dir .= $elm;
		if (! -d $root . '/' . $dir) {
			cmd("cd $root && mkdir $dir");
			cmd("cd $root && cvs -d $repo add $dir");
		}
	}
	$dir = $repo . '|' . $root . '|' . $dir;
	foreach $key (@commitdirs) {
		if ($dir eq $key) {
			$dir = "";
			last;
		}
	}
	if ($dir ne "") {
		push(@commitdirs, $dir);
	}

	if ($action eq "add" || $action eq "branch") {
		cmd("cd $root && p4 print -o $file $path#$rev");
		cmd("cd $root && cvs -d $repo add $file");
		return;
	}
	if ($action eq "edit" || $action eq "integrate") {
		if (! -f $root . '/' . $file) {
			$addit++;
		}
		cmd("cd $root && p4 print -o $file $path#$rev");
		if ($addit) {
			cmd("cd $root && cvs -d $repo add $file");
		}
		return;
	}
	if ($action eq "delete") {
		cmd("cd $root && cvs -d $repo rm -f $file");
		return;
	}
	die "WTF? Do '%s' on '%s' rev %d\n", $action, $file, $rev;
}

sub cmd {
	my $cmd = shift;

	print "CMD: $cmd\n";
	system "$cmd";
	if ($?) {
		printf "SYSTEM FAILED: $?\n";
		$badness++;
	}
}
