#!/usr/local/bin/perl

use warnings;
use strict;
use Digest::SHA;

# after r403800, a discussion about doing proper repo-copies came up, see
# https://lists.freebsd.org/pipermail/svn-ports-all/2015-December/112201.html
# etc.
#
# why is the proper repo-copy important ?
#
# https://docs.freebsd.org/doc/3.5.1-RELEASE/usr/share/doc/faq/misc.html#AEN4345# says:
# Without a repo-copy, if a file needed to be copied or moved to
# another place in the repository, the committer would run cvs add
# to put the file in its new location, and then cvs rm on the old
# file if the old copy was being removed.

# The disadvantage of this method is that the history (i.e. the
# entries in the CVS logs) of the file would not be copied to the new
# location. As the FreeBSD Project considers this history very useful,
# a repository copy is often used instead. This is a process where
# one of the repository meisters will copy the files directly within
# the repository, rather than using the cvs program.

# how is a proper repo-copy done ?

# if we have a complicated port and it needs to be repo-copied
# in a proper manner, how would that work ?

# the big picture:
#
# cd <your repo-directory>
# tar cf - <port> | ( cd ~/bck; tar xf -)
# svn rm <port>
# svn commit <port>
# svn cp <former-port> <port>
# repo-copy <port> > /tmp/tmpf
# bash /tmp/tmpf
# svn commit <port>
#

# usage:
# repo-copy <port>

# wo liegt source, wo liegt dest ?
# source is bck/<port>
# dest is os/<port>
# testdest is tst/<port>
# output is script for cp, svn add, svn rm for all files 

my($i);
my($fn);
my($chksum);
my(@slst);
my(%sfn);
my(%sfn2sha);
my(@dlst);
my(%dfn);
my(%dfn2sha);
my($sha);

# how does it work ?
#
# two lists, source files and dest files
# - find <src> -type f -print
#   slst
# - find <dst> -type f -print
#   dlst

# for each file in source not in dest:
#    cp src/fn dst/fn, svn add fn
# for each file in dest, not in source:
#    svn rm dst/fn
# for each file changed (sha256) between src and dest
#    cp src/fn dst/fn
#
# TODO: catch case if the changes add/remove directories

die "Usage: $0 category/port\n" unless (@ARGV == 1);

chdir($ENV{HOME});

my($port) = $ARGV[0];

@slst = `cd bck; find $port -type f -print`;
chomp(@slst);
chdir($ENV{HOME});

foreach $i (0..$#slst) {
    $sfn{$slst[$i]} = 1;
    $sha = Digest::SHA->new("sha256");
    $sha->addfile("bck/$slst[$i]");
    $sfn2sha{$slst[$i]} = $sha->hexdigest;
#    print "$i: $slst[$i]\n";
}

@dlst = `cd os; find $port -type f -print`;
chomp(@dlst);
chdir($ENV{HOME});

foreach $i (0..$#dlst) {
    $dfn{$dlst[$i]} = 1;
    $sha = Digest::SHA->new("sha256");
    $sha->addfile("os/$dlst[$i]");
    $dfn2sha{$dlst[$i]} = $sha->hexdigest;
#    print "$i: $dlst[$i]\n";
}

print "#!/usr/local/bin/bash\n\n";
print "cd $ENV{HOME}\n\n";

# for each file in source not in dest:
#    cp src/fn dst/fn, svn add fn

foreach $i (0..$#slst) {
    $fn = $slst[$i];
    if (!defined($dfn{$fn})) {
	print "# add $fn\n";
	print "cp bck/$fn os/$fn\n";
	print "svn add os/$fn\n";
	print "\n";
    }
}

# for each file in dest, not in source:
#    svn rm dst/fn

foreach $i (0..$#dlst) {
    $fn = $dlst[$i];
    if (!defined($sfn{$fn})) {
	print "# rm $fn\n";
	print "svn rm os/$fn\n";
	print "\n";
    }
}

# for each file changed (sha256) between src and dest
#    cp src/fn dst/fn

foreach $i (0..$#slst) {
    $fn = $slst[$i];
    if (
	defined($sfn{$fn}) &&
	defined($dfn{$fn}) &&
	$sfn2sha{$fn} ne $dfn2sha{$fn}
    ) {
	print "# cp $fn\n";
	print "cp bck/$fn os/$fn\n";
	print "\n";
    }
}

