#!/usr/bin/perl -w

#  emdebuild -- Emdebian version of debuild
#
# Checks if a package is emdebianised and runs em_make if not.
# Otherwise, updates emdebian-rules.patch,
# rebuilds the package using dpkg-buildpackage -sa -rfakeroot -a$arch
# and generates a debuild-style build log.
#
#  Copyright 2006-2007 Neil Williams <codehelp@debian.org>
#  Copyright 1998-2006 Craig Small <csmall@debian.org>
#  Copyright 1999-2003 Julian Gilbey <jdg@debian.org>
#
#  This program is free software; you can redistribute it and/or modify
#  it under the terms of the GNU General Public License as published by
#  the Free Software Foundation; either version 2 of the License, or
#  (at your option) any later version.
#
#  This program is distributed in the hope that it will be useful,
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#  GNU General Public License for more details.
#
#  You should have received a copy of the GNU General Public License
#  along with this program; if not, write to the Free Software
#  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#

# note: running debian/rules alone is unsupported due to the cross-build.

# Most debuild options are not supported - in particular, lintian and linda are not
# supported.

use Carp;
use Cwd;
use Debian::Debhelper::Dh_Lib;
use Emdebian::Tools;
use File::HomeDir;
use strict;
require "dpkg-cross.pl";
use warnings;
use vars qw/@packages $username $email $date $native $emdebvers $emN $addsource $progname $arch $verbose @options $dpkg_extra $conf $home $changes $ourversion $emvers $increment $source $vers $svnci $dosign $onlysvn *BUILD *OLDOUT *OLDERR %archtable /;

$ourversion = "0.1.3";

sub usageversion {
    print(STDERR <<END)
$progname version $ourversion

Usage:
 emdebuild [-a|--arch ARCH] [-n|--next] [--svn] [--sign] [-v|--verbose] [-q|--quiet]
 emdebuild [--svn-only] [-v|--verbose] [-q|--quiet]
 emdebuild -h|--help|--version

Options:
 -a|--arch ARCH:      set architecture (default: defined by dpkg-cross)
 -n|--next:           Increment the emdebian version before building.
    --svn:            Build package and commit changes to emdebian patches 
    					to emdebian SVN if successful (requires developer access).
    --svn-only:       Commit changes to emdebian patches to emdebian SVN.
    --sign:           Use 'debsign' on the .changes file.
 -v|--verbose:        Increase verbosity (max: 3)
 -q|--quiet:          Reduce verbosity.
 -h|--help:           print this usage message and exit
 --version:           print this usage message and exit

emdebuild is the emdebian version of debuild. After a Debian
package has been 'emdebianised' with em_make, emdebuild provides
a convenient wrapper around dpkg-buildpackage.

emdebuild needs to be run in the source directory of the package.

By default, emdebuild cross-builds the package for the dpkg-cross
default architecture. Specify other architectures with -a|--arch. 
Ensure the current toolchain is installed for the chosen architecture.

Only automated builds would normally use --quiet, most users are
advised to use --verbose.

If the source is prepared using 'emsource', changes to the emdebian
patch files can be committed to emdebian svn using the --svn option.

END
        || die "$progname: failed to write usage: $!\n";
}

$verbose = 1;
$increment = 0;
my $dpkg_opts_var = 'DEBUILD_DPKG_BUILDPACKAGE_OPTS';
my $dpkg_options = " -nocheck ";
$svnci = "false";
$home = File::HomeDir->my_home;
&read_config();
$arch = &get_architecture();
$addsource = "";
$dosign = "false";
$onlysvn = "false";

while( @ARGV ) {
    $_= shift( @ARGV );
    last if m/^--$/;
    if (!/^-/) {
        unshift(@ARGV,$_);
		last;
    }
	elsif (/^(-h|--help|--version)$/) {
		&usageversion;
		exit( 0 );
	}
	elsif (/^(-v|--verbose)$/) {
		$verbose++;
	}
	elsif (/^(-q|--quiet)$/) {
		$verbose--;
	}
	elsif (/^(-a|--arch)$/) {
		$arch = shift(@ARGV);
	}
	elsif (/^(-n|--next)$/) {
		$increment = 1;
	}
	elsif (/^(--svn)$/) {
		$svnci = "true";
	}
	elsif (/^(--sign)$/) {
		$dosign = "true";
	}
	elsif (/^(--svn-only)$/) {
		$onlysvn = "true";
	}
}

if ((!$arch)||($arch eq ""))
{
	warn ("\n$progname: Cannot determine the architecture to build.\n");
	&usageversion;
	exit (1);
}

my @config_files = ('/etc/devscripts.conf', "$home/.devscripts");
$dpkg_extra = "";
foreach $conf (@config_files)
{
	my $val;
	next if (! -f $conf);
	print ("Reading devscripts configuration\n") if ($verbose >= 3);
	open (CONF, $conf) or warn "Cannot read $conf: $!\n";
	@options=<CONF>;
	close CONF;
	foreach $val (@options)
	{
		if ($val =~ /^$dpkg_opts_var="(.*)"\n$/)
		{
			$dpkg_extra .= " " . $1;
		}
	}
}

print ("Checking for debian/control\n") if ($verbose >= 2);
&check_emdebian_control;

if ($onlysvn eq "true")
{
	# exit the working directory first.
	chdir ("../") if ( -f "debian/control");
	# cannot pass $build here - determining the build log filename
	# may involve changing the patch files or emdebian version.
	# globbing may be unreliable.
	&handle_svn;
	exit;
}
&init;
@packages = getpackages();
$native = isnative($dh{MAINPACKAGE});
my $package = $dh{MAINPACKAGE};
print ("Building $package.\n") if ($verbose >= 3);

my $parse = `parsechangelog`;
$parse =~ /Source: (.*)\n/;
$source = $1;
$source = $dh{MAINPACKAGE} if (!$source);
$parse =~ /(Version: .*)\n/;

$emvers = &extract_emdebversion($1);

if ($emvers eq "")
{
	# run em_make via the emdebian-tools package.
	my $maker = ($verbose >= 2) ? "em_make -v" : "em_make";
	( -f "/usr/bin/em_make") ? system "$maker" : die ("Please run em_make before emdebuild.\n");
}
elsif (($emvers eq "em1") && ($increment == 0))
{
	print ("New emdebian release detected, using '-sa' to include .orig.tar.gz\n") if 
		($verbose >=2);
	$addsource = '-sa';
}

if ($increment)
{
	print ("Incrementing emdebian version.\n") if ($verbose >= 2);
	$vers = emdeb_versionstring("next");
	system "debchange -p -v $vers \"New emdebian release.\"";
}

# update the patches to reflect any manual changes.
&create_patches($source);

# ensure any hand-edited cache file is preserved - debian/rules will need it.
my $target_gnu_type = $archtable{$arch};
if (-f "${target_gnu_type}.cache")
{
	print "Protecting cache file ${target_gnu_type}.cache . . \n" if ($verbose >=2);
	my $file = "${target_gnu_type}.cache";
	# protect the cache file
	chmod 0444, $file;
	my $cwd = cwd;
	my $working = basename($cwd);
	chdir ("../$source.old/");
	open (CPY, ">$file") or die "Cannot write ../$source.old/$file: $!";
	close CPY;
	chdir ("../");
	system "diff -u $source.old/$file $working/$file > emdebian-$file.patch";
	chdir ("$cwd");
	print "$file backed up to ../$source.old/\n" if ($verbose >=2);
}

$emvers = &emdeb_versionstring("") if (!$vers);
$changes = "${source}_${emvers}_${arch}.changes\n";
# noepoch = version without epoch and colon
my $noepoch = "";
if ($emvers =~ /^[0-9]?:.*/)
{
	$emvers =~ /^[0-9]?:(.*)/;
	$noepoch = $1;
	$changes = "${source}_${noepoch}_${arch}.changes\n";
}
my $build="${source}_${emvers}_${arch}.build";
print "Logging build messages to ../$build\n" if ($verbose >= 2);

# Always create .build logs, emulate how debuild works
# dpkg-buildpackage doesn't log by default!
# from debuild:
# Start by duping STDOUT and STDERR
open OLDOUT, ">&STDOUT" or croak "cannot duplicate stdout: $!\n";
open OLDERR, ">&STDERR" or croak "cannot duplicate stderr: $!\n";
open BUILD, "| tee ../$build" or croak "could not open pipe to tee $build: $!";
close STDOUT;
close STDERR;
open STDOUT, ">&BUILD" or croak "cannot reopen stdout: $!";
open STDERR, ">&BUILD" or croak "cannot reopen stderr: $!";
# prepare the dpkg-buildpackage command and environment
my $cmd .= "DEB_BUILD_OPTIONS='$dpkg_options' dpkg-buildpackage ";
# arm is the master arch, others must use -B
$cmd .= "-B " if ($arch ne "arm");
$cmd .= "-a$arch $addsource -rfakeroot -D $dpkg_extra\n";
my $msg = "Building ${source} ${emvers} for ${arch} with $cmd";
print $msg if ($verbose >= 2);
# build the package here:
my $exitval = system "$cmd";
# return things to normal before aborting with any dpkg errors
close STDOUT;
close STDERR;
close BUILD;
open STDOUT, ">&OLDOUT";
open STDERR, ">&OLDERR";
exit $exitval if ($exitval);

chmod 0644, "${target_gnu_type}.cache" 
	if (-f "${target_gnu_type}.cache");
open (CHG, "../$changes") or croak ("FAILED: unable to read ../$changes: $!\n");
open (BUILD, ">>../$build") or croak ("Cannot append .changes to .build: $!\n");
print BUILD "\n";
while(<CHG>) {
	print $_;
	print BUILD $_;
}
close BUILD;
close CHG;

chdir ("../");
system "debsign $changes" if ($dosign eq "true");
&handle_svn($build) if ($svnci eq "true");
exit 0;

# handle svn
sub handle_svn
{
	my $build = $_[0];
	print "Checking in emdebian patch files . . \n" if ($verbose >= 2);
	system ("svn ci -m \"automated emdebuild checkin\" emdebian-changelog.patch emdebian-rules.patch emdebian-control.patch");
	# check if build log is already in svn for this arch and this version.
	return if (!defined $build);
	my $check = `svn list $build 2>/dev/null`;
	if (!$check)
	{
		print "Adding build log '$build' to SVN . . \n" if ($verbose >= 2);
		system ("svn -q add $build");
		# Disallow updated build logs for the same arch and version.
		# only the first successful build of this version on this arch is held in SVN.
		print "Checkin build log '$build' into SVN . . \n" if ($verbose >= 2);
		system ("svn ci -q -m \"automated build log checkin\" $build");
	}
}
