#!/usr/bin/perl -w
#
#  emsource -- get Debian source, create and apply emdebian patches
#  Copyright (C) 2007  Neil Williams <codehelp@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.
#

# Adds libconfig-auto-perl to the dependencies of emdebian-tools

# Uses config::auto for the user's preferred working directory.
# use apt-get source to get the package, calls dpkg-source -x for us.
# checkout the emdebian changes, if any, from:
# http://buildd.emdebian.org/repos/source/target/trunk/$package/trunk/
# check for $package/ from the output of:
# svn list http://buildd.emdebian.org/repos/source/target/trunk/
# if exists, checkout the patches - use debconf setting for username to commit.
# ready for emdebuild which can modify the patches for the next release.

use Cwd;
use Config::Auto;
use File::HomeDir;
use Emdebian::Tools;
use strict;
use warnings;
require "dpkg-cross.pl";
use vars qw/$username $verbose $our_version $home $dpkg_cross_dir $cfile $workdir $package $retval $svnadd $svnlogin $progname $suite $indexchar $clog/;

$our_version = "0.1.3";
$verbose = 1;
$username = "";
$suite = &get_suite;
# svnadd == 0 if package exists in svn, 1 if files need to be added.
$svnadd = 1;
&read_config();
my $arch = &get_architecture();
$home = File::HomeDir->my_home;
$dpkg_cross_dir = "$home/.dpkg-cross";

sub usageversion {
    print(STDERR <<END)
emsource version $our_version

Usage:
 emsource [-u|--username USERNAME] [-a|--arch ARCH] [-v|--verbose] [-q|--quiet] PACKAGE
 emsource -h|--help|--version
 
Options:
 -a|--arch ARCH:      set architecture (default: defined by dpkg-cross)
 -u|--username:       your username to commit to Emdebian SVN, if any.
 -v|--verbose:        be verbose (repeat for more verbosity)
 -q|--quiet:          be quiet [default]
 -h|--help:           print this usage message and exit
 --version:           print this usage message and exit

emsource combines the functionality of 'apt-get source' and
'svn checkout' to maintain a record of Emdebian changes to
Debian packages. Changes can be committed back to Emdebian
SVN after a successful build using 'emdebuild --svn'.

User-specific configuration values in ~/.dpkg-cross/emsource,
override any debconf default in /etc/emsource.conf. If no 
preferred working directory is set, emsource unpacks the requested
package to a new subdirectory in the current working directory.

If a username is neither set in the configuration file nor supplied 
using -u | --username, emsource will use anonymous svn and 
modifications to the emdebian patches (by emdebuild) should be 
contributed back to Emdebian via other means.

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

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 (/^(-u|--username)$/) {
		$username = shift(@ARGV);
	}
	elsif (/^(-a|--arch)$/) {
		$arch = shift(@ARGV);
	}
}

&usageversion if (! $ARGV[0]);
my $quiet = "";
$quiet = "-q" if ($verbose < 1);
$package = $ARGV[0];
$package = &check_package($package);
die "\n" if ($package eq "");
($indexchar)=split(//, $package);

my $msg = "$progname: no default architecture found.\n";
$msg .= "Please use '$progname --arch ARCH $package'.\n";
die $msg if ((!$arch)||($arch eq ""));

$msg = "$progname: please install 'subversion' before using emsource.\n";
die $msg if (! -x "/usr/bin/svn");

# read emsource config file.
$workdir = &get_workdir;
$workdir = "." if ($workdir eq "");
$msg = &check_workdir($workdir);
die $msg if ($msg ne "");
chdir ("$workdir") if ($workdir ne ".");
print "Working directory: '" . cwd . "'\n" if ($verbose >= 2);
$username = &get_username if ($username eq "");

$svnlogin = "svn+ssh://" . $username . 
	"\@buildd.emdebian.org/var/emdebian/svn/current/target/trunk/"   if ($username ne "");
$svnlogin = "http://buildd.emdebian.org/repos/current/target/trunk/" if ($username eq "");

print "Checking for existing emdebian patches\n" if ($verbose >= 2);
my $svncheck = `svn list $svnlogin/$indexchar/`;
$svnadd = 0 if ($svncheck =~ /$package\//);
if (($verbose >= 2) && ($svnadd == 1) && ($username ne ""))
{
	print "Adding new package '$package' to emdebian SVN.\n";
}

# now check out the svn, if any
if ($svnadd == 0)
{
	print "Checking out working copies of existing emdebian patches\n"
		if ($verbose >= 2);
	# existing co ignores ./trunk which is created when adding a new package
	# so keep all packages together.
	mkdir ("trunk") if (! -d "trunk");
	mkdir ("trunk/$indexchar") if (! -d "trunk/$indexchar");
	chdir ("trunk/$indexchar");
	system ("svn co ${svnlogin}${indexchar}/${package}");
	# now change to the package trunk
	chdir ("$package/trunk");
}
else
{
	system ("svn co $quiet -N ${svnlogin}");
	chdir ("trunk");
	system ("svn co $quiet -N ${svnlogin}/$indexchar");
	mkdir ("$indexchar/$package");
	mkdir ("$indexchar/$package/trunk");
	mkdir ("$indexchar/$package/branches");
	mkdir ("$indexchar/$package/tags");
	system ("svn add $quiet $indexchar/$package") if ($username ne "");
	# this doesn't ignore all built files, just the main ones
	# unfortunately, svn doesn't have an 'ignore-except'
	# whilst retaining an ability to add new files (like a new cache file).
	# Using propset also *replaces* existing settings, so it has to be used
	# here and not later. (svn isn't easy to automate sometimes.) :-(
	system ("svn propset svn:ignore \"${indexchar}*\" $indexchar/$package/trunk/")
		if (($username ne "") && ($indexchar ne "e"));
	system ("svn ci $quiet -m \"automated emsource checkin of empty tree\" $indexchar/$package")
		if ($username ne "");
	chdir ("$indexchar/$package/trunk");
}

#obtain the latest version string in Debian.
my $v = my $src = "";
# avoid usual arch and conf configuration, we need the Debian data
$clog = `apt-cache $quiet showsrc $package`;
$clog =~ /Package: (.*)\n/;
$src = $1;
$clog =~ /Version: (.*)/;
exit(1) if (!&cleanup_vers($1));
$v = &cleanup_vers($1);
my $dir = $src . "-" . $v;
my $top = cwd;

print ("Checking for existing build tree in $dir.\n") if ($verbose >= 2);
# check first in case there is already an emdebianised build tree here.
if ( -d "$dir")
{
	chdir ("$dir");
	$clog = `parsechangelog --format dpkg`;
	$clog =~ /Version: (.*)\n/;
	$retval = &extract_emdebversion($clog);
	print "emdebian version = $retval\n" if (($retval ne "") && ($verbose >=2));
}
else
{
# no build tree, check for svn patches, get source then apply.
	chdir ("$top");
	print "No unpacked source directory, updating Debian source\n" if ($verbose >= 2);
	$retval = system ("apt-get $quiet source $package");
	exit($retval) if ($retval != 0);
	chdir ("$dir");
}
# this check may fail with an updated upstream. FIXME.
if (! -f "../emdebian-changelog.patch" )
{
	print "Emdebianising source tree\n" if ($verbose >= 2);
	system ("em_make $quiet --arch $arch");
}
if (( -f "../emdebian-changelog.patch") && ($svnadd == 0))
{
	# avoid patching the files twice.
	if (! -d "../${package}.old/")
	{
		&prepare_patches($package);
		print "Applying patches from SVN.\n" if ($verbose >= 2);
		# c-log patch may fail if patch is from unstable and suite == testing
		# so let em_make create it instead. (shouldn't be uploading from testing anyway).
		system ("patch -p1 < ../emdebian-changelog.patch") if ($suite eq "unstable");
		system ("patch -p1 < ../emdebian-rules.patch");
		system ("patch -p1 < ../emdebian-control.patch");
	}
	print "\nEmdebianised source tree for '$package' exists at '$top/$dir'\n";
	print "Change to this directory before running 'emdebuild'\n" if ($verbose >= 2);
	print "\n";
}
if ($svnadd == 1)
{
	chdir("../");
	if (($verbose >= 2) && ($username ne ""))
	{
		print ("Placing initial emdebian patch files under SVN version control.\n");
		print ("Completed patch files can be checked into Emdebian SVN\n");
		print (" using 'emdebuild --svn' or individually using 'svn ci <file>'.\n");
	}
	system ("svn add $quiet emdebian-changelog.patch emdebian-rules.patch emdebian-control.patch") if ($username ne "");
	chdir("$dir");
	print "\nEmdebianised source tree for '$package' exists at '$top/$dir'\n";
	print "Change to this directory before running 'emdebuild'\n" if ($verbose >= 2);
	print "\n";
}

exit (0);

sub cleanup_vers
{
	my $t = $_[0];
	$t =~ s/^[0-9]*\://;
	$t =~ s/\-.*$//;
	return $t;
}

sub check_package
{
	my $apt = `apt-cache showsrc $_[0]`;
	$apt =~ /Package: (.*)\n/;
	my $package = $1;
	if ($apt =~ /Version: (.*)\n/)
	{
		print "Using $package $1\n" if ($verbose >= 2);
		return $package;
	}
	print "Unable to locate source for package '$_[0]' - please check the spelling of the package name.\n";
	print "Consider using 'dpkg -S $_[0]' to identify the source package if the spelling is correct.\n"
		if ($verbose >= 2);
	return "";
}

sub prepare_patches
{
        my @patchfiles = qw/rules control control.in changelog /;
        my $package = $_[0];
        my @control;
        my $cwd = cwd;
        print ("Preparing patches for debian files.\n") if ($verbose >= 2);
        mkdir "../$package.old", 0755;
        mkdir "../$package.old/debian", 0755;
        foreach my $file (@patchfiles)
        {
                if (! -f "debian/$file") { next; }
                open (CPY, "debian/$file") or die "Cannot open $file: $!";
                @control=<CPY>;
                close CPY;
                chdir ("../$package.old/");
                open (CPY, ">debian/$file") or die "Cannot write $file: $!";
                print CPY @control;
                close CPY;
                chdir ("$cwd");
                print "$file backed up to ../$package.old/debian/\n" if ($verbose >=2);
        }
}

