#!/usr/bin/perl

use strict;

# map is initialised with paths which can't be guessed easily
my %map = (
    "usr/src/lib/libzpool/common/taskq.c" => "src/lib/libzpool/taskq.c",
    "usr/src/uts/common/os/taskq.c" => "src/lib/libsolkerncompat/taskq.c",
    "usr/src/uts/common/sys/cred.h" => "src/lib/libsolcompat/include/sys/cred.h",
    "usr/src/uts/common/sys/proc.h" => "src/lib/libsolcompat/include/sys/proc.h",
);

my $arg = $ARGV[0];
open(F,">header");
open(G,">diff");
$arg =~ /export-(\d+)/;
my $commit = $1;
print F "hg commit $commit:";
my $author;
while (<>) {
    if (/^# User (.+)/) {
	$author = $1;
	chomp $author;
    }
    next if (/^#/);
    last if (/^diff/);
    print F;
}
close(F);
my @files = ();
while (1) {
    / a\/(.+) /;  # /
    my $f1 = $1;
    if ($f1 =~ /(\.py$|grub|mapfile-vers$|cmd\/[a-y]|lib\/libc\/|\/fs\/[a-y]|\/vdev_disk.c$|libdiskmgt\/|dumpsubr.c$|zinject|Makefile\.(com|files|lint)$|pkgdefs\/|llib-lzfs$|fsreparse\/|\/xattr\/|libreparse\/|lib(secdb|topo)|zut\/|io\/|smbsrv|common\/syscall)|(llib-lzpool|spa_boot.c)$|zoneadmd\/|tsol\/|src\/(head|Target)|uts\/common\/(disp|brand|os|sys\/class.h)|Makefile|sysdc.*h|startup.c|fth$/) {
	print "skipping diff for $f1\n";
	while (<>) {
	    last if (/^diff/); # skip this diff
	}
    } else {
	if (!$map{$f1}) {
	    my $target = "src/";
	    if ($f1 =~ /(cmd\/z.+)/) {
		$target .= "$1";
		$map{$f1} = $target if (-f $target);
	    } elsif ($f1 =~ /(lib\/.+?\/)(.+)/) {
		$target .= $1;
		my $file = $2;
		die "lib $target\n" if (! -d $target);
		$file =~ s/^common\///;
		if ($file =~ /.h$/ && ! -f "$target$file") {
		    $file = "include/$file";
		}
		die "mapping lib $f1 -> $target $file\n" if (!-f "$target$file");
		$map{$f1} = "$target$file";
	    } else {
		# a file without any obvious directory
		my $file;
		if ($f1 =~ /(sys\/.+)/) {
		    $file = $1;
		} elsif ($f1 =~ /.+\/(.+?)$/) {
		    $file = $1;
		}
		my @list = glob("src/*/$file");
		@list = glob("src/*/*/$file") if (!@list);
		@list = glob("src/*/*/include/$file") if (!@list && $file =~ /h$/);
		if ($#list == 0) {
#		    print "new map ok $f1 -> @list\n";
		    $map{$f1} = $list[0];
		} elsif ($list[0] =~ /solkerncompat/) {
		    $map{$f1} = $list[0];
		    printf("choosing kerncompat option : $f1\n");
		} elsif ($list[1] =~ /solkerncompat/) {
		    $map{$f1} = $list[1];
		    printf("choosing kerncompat option : $f1\n");
		} else {
		    my ($dir) = $f1 =~ /^(.+)\//;
		    my %dirs =
		    (
			"usr/src/uts/common/fs/zfs" => "src/lib/libzpool",
			"usr/src/uts/common/fs/zfs/sys" => "src/lib/libzpool/include/sys",
		    );
		    if ($dirs{$dir}) {
			$map{$f1} = $dirs{$dir}."/$file";
			print "mapping for new file $map{$f1}\n";
		    } else {
			die "new map problem $f1 -> @list (using $file) dir $dir\n";
		    }
		}
	    }
	} 
	die "map $f1\n" if (!$map{$f1});
	push @files,$map{$f1};
	s:$f1:$map{$f1}:g;
	print G;
	do {
	    $_ = <>;
	    die "renames must be handled manually (file $f1)\n" if (/^rename/);
	} while ($_ !~ /^--/);
	s:$f1:$map{$f1}:g;
	print G;
	$_ = <>;
	s:$f1:$map{$f1}:g;
	print G;
	while (<>) {
	    last if (/^diff/);
	    print G;
	}
    }
    next if (/^diff/);
    last;
}
close(G);
unlink "ok";
system("patch -p1 < diff && echo ok && touch ok");
if ( -f "ok" ) {
    print "commiting...\n";
    system("git commit -F header --author \"$author\" @files && rm $arg");
} else {
    print "commit with : git commit -F header --author \"$author\" @files\n";
    print "or revert with git checkout @files\n";
}
