#!/usr/bin/perl
# (c) Eduard Bloch <blade@debian.org>, 2003
# License: GPL
# Version: $Id: svn-upgrade 1141 2004-07-27 05:55:17Z inet $

use Getopt::Long qw(:config no_ignore_case bundling);
use File::Basename;
use Cwd;
#use diagnostics;

$startdir=getcwd;
$scriptname="[svn-upgrade]";

sub help {
print "
Usage: svn-upgrade newsource [ OPTIONS... ]
Upgrade a source code package from an upstream revision. The source code
repository must be in the format created by svn-inject.

  -V, --upstreamversion  STRING    Forces a different upstream version string
  -c, --clean                      generic cleanup of upstream source - remove
                                   debian directory and object files
  -f, --force                      Force execution of certain operations
  -v, --verbose                    More verbose program output
  -r, --replay-conflicting         Special cleanup action: replaces all
                                   conflicting files with upstream versions

The new source may be a tarball compressed with gzip or bzip2 or a
directory with extraced source.
"; exit 1;
}

my $opt_help;
my $opt_replay;
my $opt_force;
my $opt_clean;
my $version;
my $verbose;
my $keep_removed;
my $quiet="-q";

%options = (
   "h|help"                => \$opt_help,
   "V|upstreamversion=s"   => \$version,
   "upstream-version=s"   => \$version,
   "c|clean"             => \$opt_clean,
   "f|force"             => \$opt_force,
   "v|verbose"             => \$verbose,
   "r|replay-conflicting"  => \$opt_replay
);

&help unless ( GetOptions(%options));
&help if ($opt_help);

$mergemode = (`svn proplist debian` =~ /mergeWithUpstream/i);

if(!$opt_replay) {
   &help if $#ARGV < 0;
   $newsource=$ARGV[0];
   &help if(!-r $newsource);
   shift(@ARGV);

   # don't use abs_path yet, it resolves the symlinks
   #$newsource=$startdir."/".$newsource if(! $newsource=~/^\//);

   if(-d $newsource) { 
      basename($newsource) =~ /(.*)-(\d.*)/i;

      # provisoric package definition, to be overriden by the config module later
      $package = $1;
      $version = $2 if(!defined($version));
   }
   else {
      basename($newsource) =~/(.*)-(\d.*)\.(tar|tgz|tbz)/i;

      # provisoric package definition, to be overriden by the config module later
      $package = $1;
      $version = $2 if(!defined($version));

      # workaround for debianized tarballs
      if(! length($1.$2)) {
         basename($newsource) =~/(.*)_(.*)\.orig.tar.gz/i;
         # provisoric package definition, to be overriden by the config module later
         $package = $1;
         $version = $2 if(!defined($version));
      }
      
   }

   # no resolve it, we don't need the user-specified filename any longer
   $newsource = long_path($newsource);

   die "Unrecognized upstream version, use -V\n" if(!length($version));
}

undef($quiet) if ($verbose);

use lib "/usr/share/svn-buildpackage";
use SDCommon;
$SDCommon::opt_verbose=$verbose;
SDCommon::configure;
#$tagVersion=$SDCommon::tagVersion;
$upVersion=$SDCommon::upVersion;
$package  =$SDCommon::package;
needs_tagsUrl;
needs_upsTagUrl if !$mergemode;
needs_upsCurrentUrl if !$mergemode;
$c=\%SDCommon::c;

if($opt_replay) {
   for(split(/\n/,`svn status`)) {
      if(/^C\s+(.*)/) {
         withecho("svn cat ".$$c{"upsCurrentUrl"}."/$1 > $1 && svn resolved $1");
      }
   }
   SDCommon::sd_exit 0;
}

# my private copy of the setting
if($$c{"origDir"}){$origdir=$$c{"origDir"}}else{chomp($origdir=`mktemp -d`)};

chomp($tmpdir=`mktemp -d`);
#print "D: ".$$c{"upsTagUrl"}.join(",", values(%c));
$upsOldVersUrl=$$c{"upsTagUrl"}."/$upVersion";
#print $upsOldVersUrl ; exit 1;
mkdir $tmpdir;

$filestr = `file \"$newsource\"`;
if ($filestr =~ /gzip/){
   $cat = "zcat \"$newsource\"";
   $justcopy=1;# Always copy. Maintainer should recompress manually, if needed. if ($filestr =~ /max compression/);
}
elsif ($filestr =~ /bzip/){
   $cat = "bzcat \"$newsource\"";
}
elsif ($filestr =~ /tar archive/){
   $cat = "cat $newsource";
}
elsif ($filestr =~ /directory/){
   $cat = " ( cd \"".dirname($newsource)."\" ; tar c \"".basename($newsource)."\" ) ";
}
else {
   die "Unknown compression method!\n";
}

$neworig="$origdir/".$package."_".$version.".orig.tar.gz";

die "$neworig exists, aborting...\n" if (-e $neworig);

# repack the new source file to tarballs/...orig.tar.gz
if(! -f $neworig) {
   # only if correct gzip format, not a directory, see above
   if($justcopy) {
      link($newsource,$neworig) || withecho("cp",$newsource,$neworig);
   }
   else {
      withecho("$cat | gzip -9 > \"$neworig\"");
   };
}

# FIXME: dircheck hier irgendwo rein
withecho("svn",$quiet,"add",$neworig) if(defined $SDCommon::c{"origUrl"});

if($mergemode) {
   print "I: Upstream source not maintained in the repository.\n";
   print "I: Assuming that it will be merged at build time.\n";
}
else
{
   if(! insvn($upsOldVersUrl)) {
         die "
         Could not find the unmodified upstream version in
         $upsOldVersUrl!
         If you think that $$c{\"upsCurrentUrl\"} is the upstream source
         which $$c{\"trunkUrl\"} is based on, run:

         svn copy $$c{\"upsCurrentUrl\"} $upsOldVersUrl

         Otherwise, please fix the headline of debian/changelog.\n";
   }
}

if($filestr =~ /directory/) {
   withecho("cp","-a", $newsource, "$tmpdir/");
}
else {
   withecho("tar", "zxf", $neworig, "-C", "$tmpdir");
}

$srcdir="$package-$version";

# fix the FSCKING upstream source that comes without top subdirectory

chdir $tmpdir;
@filesInside=(<*>);
if($#filesInside > 0) {
   mkdir $srcdir;
   withecho("mv",@filesInside, $srcdir);
}

# create the list of modified files if needed
if($mergemode) {
   chdir $startdir;
   open($dl, "find -type f | grep -v \"\\.svn\" |");
   while(<$dl>) {
      push(@difflist, $1) if(/^[^\/]+\/(.+)\n/);
   }
   close($dl);
}

chdir $tmpdir;
system "rm -f *.gz";

# if needed, remove uninteressting files from the upstream directory,
# or move the directory to some with the proper name
if(@difflist) {
   withecho "mv * $srcdir-tmp; mkdir $srcdir";
   withecho "cd $srcdir-tmp; tar c ".join(" ", @difflist)." 2>/dev/null | tar x -C ../$srcdir";
}
else {
   # work around identical dir names
   withecho "mv * $srcdir-tmp";
   withecho "mv $srcdir-tmp $srcdir";
}

if(-d "$tmpdir/$srcdir/debian" && !$opt_force) {
   print "
Warning: it is generaly a bad idea to keep the debian directory in the
upstream source tarball. Please specify -f to ignore this warning or
-c to wipe debian/ and other suspicious files. Aborting now.
";
   SDCommon::sd_exit 1;
}

if($opt_clean) {
   my $dir=Cwd::getcwd;
   chdir "$tmpdir/$srcdir";
   system "make clean";
   system "rm -rf debian";
   chdir $dir;
}

# now we have the new upstream source we need in $tmpdir/$version
# allow the import to be skipped in mergeWithUpstream mode if the
# upsCurrentUrl is not known
if(defined($$c{"upsCurrentUrl"}) || !$mergemode) {
   # first look for conflicting .svn dirs
   oldSvnDirsCheck"$tmpdir/$srcdir";
   withecho("svn_load_dirs", $$c{"upsCurrentUrl"}, ".", "$tmpdir/$srcdir");
   withecho("svn", "copy", "-m", "$scriptname Tagging new upstream version, $package ($version)", $$c{"upsCurrentUrl"},  $$c{"upsTagUrl"}."/$version");
   chdir $$c{"trunkDir"};
   if($mergemode) {
      # allow to fail, eg. if upstream dir is there but empty
      withechoNoPrompt("svn","merge", $upsOldVersUrl, $$c{"upsCurrentUrl"}, ".");
   }
   else {
      withecho("svn","merge", $upsOldVersUrl, $$c{"upsCurrentUrl"}, ".");
   }
   withechoNoPrompt "svn up";
}
else {
   chdir $$c{"trunkDir"};
}

open($svn, "svn status|");
@conflicts = grep(/^C/, <$svn>);
map {s/^..//} @conflicts;
if ($#conflicts != -1) {
   print "Files in conflict state:\n\n @conflicts\n";
   print "Resolve them manually and run \"svn resolve\" on each file\n.",
      "Or use \"svn-upgrade -r\" to overwrite them with new upstream verions\n";
}
withecho("rm", "-rf", $tmpdir) if(length($tmpdir));

withecho "debchange -D UNRELEASED -v \"$version-1\" \"(NOT RELEASED YET) New upstream release\"";
print "Done! Last commit pending, please execute manually.\n";
