#!/usr/bin/perl
# (c) Eduard Bloch <blade@debian.org>, 2003
# License: GPL
# Version: $Id: svn-buildpackage 418 2003-10-05 12:02:00Z inet $

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

$startdir=getcwd;

sub help {
print "
Usage: svn-buildpackage [ OPTIONS... ] [ OPTIONS for dpkg-buildpackage ]
Builds Debian package within the SVN repository. The source code
repository must be in the format created by svn-inject, and this script
must be executed from the work directory (trunk/package).

  -h, --help         Show the help message
  --svn-dont-clean   Don't run debian/rules clean (default: clean first)
  --svn-dont-purge   Don't wipe the build directory (default: clean after build)
  --svn-no-links     Don't use file links (default: use where possible)
  --svn-ignore-new   Don't stop on svn conflicts or new/changed files
  --svn-verbose      More verbose program output
  --svn-tag          Final build: Tag, export, build cleanly & make
                     new changelog entry
  --svn-lintian      Run lintian in the build area when done
  --svn-pkg PACKAGE  Specifies the package name if executed from TOPDIR

If the debian directory has the mergeWithUpstream property, svn-buildpackage
will extract .orig.tar.gz file first and add the Debian files to it.

"; exit 1;
}
$quiet="-q";
my $opt_help;
my $opt_verbose;
my $opt_dontclean;
my $opt_ignnew;
my $opt_tag;
my $opt_lintian;
my $opt_nolinks;
my $opt_pretag;
my $opt_prebuild;
my $opt_posttag;
my $opt_postbuild;
my $package;

if(-f $ENV{"HOME"}."/.svn-buildpackage.conf") {
   open($rc, "<".$ENV{"HOME"}."/.svn-buildpackage.conf");
   SKIP: while(<rc>) {
      next SKIP if /^#/;
      $opt_pretag = $1 if /pre-tag-action\s*=\s*(.*)\n?/;
      $opt_posttag = $1 if /post-tag-action\s*=\s*(.*)\n?/;
      $opt_prebuild = $1 if /pre-build-action\s*=\s*(.*)\n?/;
      $opt_postbuild = $1 if /post-build-action\s*=\s*(.*)\n?/;
   }
   close($rc);
}

%options = (
   "h|help"                => \$opt_help,
   "svn-verbose"           => \$opt_verbose,
   "svn-ignore-new"        => \$opt_ignnew,
   "svn-dont-clean"        => \$opt_dontclean,
   "svn-tag"               => \$opt_tag,
   "svn-lintian"           => \$opt_lintian,
   "svn-no-links"          => \$opt_nolinks,
   "svn-prebuild=s"             => \$opt_prebuild,
   "svn-postbuild=s"             => \$opt_postbuild,
   "svn-pretag=s"             => \$opt_pretag,
   "svn-posttag=s"             => \$opt_posttag,
   "svn-pkg=s"             => \$package
);
&help unless ( GetOptions(%options));
&help if ($opt_help);
$quiet="" if ($opt_verbose);

#$sd_dir = ( -e "/usr/share/svn-devscripts" ) ? 
#              "/usr/share/svn-devscripts" :
#              (defined($ENV{"SDDIR"}) ? $ENV{"SDDIR"} : ".");
#
#require "$sd_dir/common.pm";

use SD;
$SD::opt_verbose=$opt_verbose;
withecho "fakeroot debian/rules clean || debian/rules clean" if(!$opt_dontclean);
SD::check_uncommited if(!$opt_ignnew);

if(`dpkg-parsechangelog` =~ /NOT\ RELEASED\ YET/) {
   print STDERR "NOT RELEASED YET tag found - you don't want to release it with it, do you?\n";
   die "Aborting now, set \$FORCETAG to ignore it.\n" if($opt_tag && !$ENV{"FORCETAG"});
}

SD::configure;
needs_tagsUrl if($opt_tag);
$c=\%SD::c;
$tagVersion=$SD::tagVersion;

$ENV{"TAG_VERSION"} = $tagVersion;
$ENV{"PACKAGE"}=$SD::package;
$package = $SD::package if(!$package);

system "$opt_prebuild" if($opt_prebuild);

$$c{"buildArea"}=abs_path($startdir."/..")."/build-area" if(!$$c{"buildArea"});

mkdir $$c{"buildArea"} if (! -d $$c{"buildArea"});

$orig = $package."_".$SD::upVersion.".orig.tar.gz";
$origfile = $$c{"origDir"}."/$orig" if ($$c{"origDir"});

$ba=$$c{"buildArea"};

if(-e "$ba/$package-$tagVersion") {
   $backupNr=rand;
   print STDERR "$ba/$package-$tagVersion exists, renaming to $package-$tagVersion.$backupNr\n";
   rename("$ba/$package-$tagVersion","$ba/$package-$tagVersion.obsolete.$backupNr");
}

mkdir "$ba" if(! -d "$ba");

if($tagVersion =~ /-/ && $origfile) {
      if(-e $origfile && ! -e "$ba/".$orig) {
         ( (!$opt_nolinks) && 
         ( link($origfile,"$ba/".$orig) || 
            symlink($origfile,"$ba/".$orig)
         )
         ) ||
         withecho "cp $origfile $ba/".$orig || 
         print STDERR "Failed to copy or link/symlink the orig file, ignoring.";
      }
}

# let's make svn play "cp -l"
open($stat, "svn status -v |");
while(<$stat>) {
   chomp;
   undef $_ if /^\S/ ;
   s/\ +/ /g; 
   $_= (split(/\ /, $_))[4];
   if ($_ ne ".") {
      if(-d $_) { push(@dirs,$_); } else { push(@files,$_); }
   }
}

if(`svn proplist debian` =~ /mergeWithUpstream/i) {
   # debian is the only directory or during-build-merging is wanted
   print STDERR "I: mergeWithUpstream property set, looking for upstream source tarball...\n";
   die "E: Could not find the origDir directory, please check the settings!\n" if(! -e $$c{"origDir"});
   die "E: Could not find the upstream source file $origfile!" if(! ($origfile && -e $origfile));
   $mod=rand;
   mkdir "$ba/tmp-$mod";
   withecho "tar zxf $origfile -C $ba/tmp-$mod";
   withecho "mv $ba/tmp-$mod/* $ba/$package-$tagVersion";
   withecho "rm -rf $ba/tmp-$mod";
   if($opt_nolinks || $opt_ignnew) {
      withecho ("svn", "export", $$c{"trunkDir"},"$ba/tmp-$mod");
      withecho "cp -af $ba/tmp-$mod/. $ba/$package-$tagVersion/";
   }
   else {
      if( (system "cd $ba/$package-$tagVersion && mkdir -p ".join(' ',@dirs)) +
         system "cp --parents -laf ".join(' ',@files)." $ba/$package-$tagVersion/") {
         # 0=good; but if pure copy failed...
         withecho ("svn", "export", $$c{"trunkDir"},"$ba/tmp-$mod");
         withecho "cp -af $ba/tmp-$mod/. $ba/$package-$tagVersion/";
      }
   }
   withecho "rm -rf $ba/tmp-$mod";
}
else {
   if($opt_nolinks || $opt_ignnew) {
      withecho "svn","export",$$c{"trunkDir"},"$ba/$package-$tagVersion";
   }
   else {
      if(system("mkdir", "$ba/$package-$tagVersion") +
         system("cp","--parents","-laf",@files,"$ba/$package-$tagVersion") )
      {
         # 0=good; but if pure copy failed...
         withecho "svn","export",$$c{"trunkDir"},"$ba/$package-$tagVersion";
      }
   }
}

chdir "$ba/$package-$tagVersion" || die "Mh, something is going wrong...";

if (0 != system("dpkg-buildpackage",@ARGV)) {
   system "$opt_postbuild" if($opt_postbuild);
   print STDERR "dpkg-buildpackage failed in $ba/$package-$tagVersion\nAborting.\n";
   print STDERR "W: build directory not purged!\n";
   print STDERR "W: no lintian checks done!\n" if($opt_lintian);
   print STDERR "W: package not tagged!\n" if($opt_tag);
   exit 1;
}
else {
   system "$opt_postbuild" if($opt_postbuild);
   $arch=`dpkg --print-architecture`; chomp($arch);
   print STDERR `tput smso`, 
"dpkg-buildpackage was successful; binaries are in 
$ba/. The changes file is 
$ba/$package"."_$tagVersion"."_$arch.changes\n", `tput rmso`;
   chdir "..";
   withecho "rm -rf $package-$tagVersion" if(length($tagVersion));
   if($opt_lintian) {
      withecho "lintian $package"."_$tagVersion"."_$arch.changes";
   }
   if($opt_tag) {
      system "$opt_pretag" if($opt_pretag);
      withecho ("svn", "-m", "Tagging version $tagVersion", "cp", $$c{"trunkUrl"}, $$c{"tagsUrl"}."/$tagVersion");
      system "$opt_posttag" if($opt_posttag);
      chdir $$c{"trunkDir"};
      withecho "dch -i \"NOT RELEASED YET\"";
      print "\nI: Done! Last commit pending, please execute manually.\n";
   }
}
SD::writeCfg;
