-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Hi

I have recreated the patches to add pdebdiff against the head of devscripts's GIT repository. I have also made some changes to pdebdiff and the fixed a typo in d/copyright.

Patch 0001 only adds pdebdiff and patch 0002 updates the packaging to include the newly added pdebdiff. I have created them separately since it makes it easier to review the packaging changes.
  I will gladly maintain the script even after it enters devscripts.

Thank you in advance,
~Niels
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.10 (GNU/Linux)
Comment: Topal (http://freshmeat.net/projects/topal)

iEYEARECAAYFAkwon+gACgkQVCqoiq1YlqyRyQCbBcaqNsW0sg5phqOFaMzHpaxd
0wkAoOEUcr76iumdqbEMoyDIc6I605tk
=86m0
-----END PGP SIGNATURE-----
From 91799593e16ada1dab4266d1f614d6be4998863a Mon Sep 17 00:00:00 2001
From: Niels Thykier <ni...@thykier.net>
Date: Mon, 28 Jun 2010 14:56:51 +0200
Subject: [PATCH 2/2] Added all the packaging related changes to include pdebdiff.

---
 debian/changelog |    6 ++++++
 debian/control   |    8 +++++---
 debian/copyright |    4 ++--
 scripts/Makefile |    2 +-
 4 files changed, 14 insertions(+), 6 deletions(-)

diff --git a/debian/changelog b/debian/changelog
index 0fc3282..c286602 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -36,6 +36,12 @@ devscripts (2.10.65) UNRELEASED; urgency=low
     + Fix handling of indented heredoc delimiters.
     + Fix some parsing of quoted strings.
 
+  [ Niels Thykier ]
+  * Added pdebdiff, which diffs the debian folder of two packages.
+    (Closes: #575395)
+  * Replaced a "copyright" that should have been "licensed" in d/copyright.
+
+
  -- Martin Zobel-Helas <zo...@debian.org>  Tue, 11 May 2010 20:48:16 +0200
 
 devscripts (2.10.64) unstable; urgency=low
diff --git a/debian/control b/debian/control
index cc603ed..9c6b2f0 100644
--- a/debian/control
+++ b/debian/control
@@ -21,9 +21,9 @@ Recommends: at, curl | wget, dctrl-tools, debian-keyring, debian-maintainers,
  man-db, patch, patchutils, ssh-client, strace, unzip, wdiff, www-browser,
  subversion | cvs | darcs | tla | bzr | git-core | mercurial, lzma,
  xz-utils, sensible-utils, libjson-perl
-Suggests: build-essential, cvs-buildpackage, devscripts-el, gnuplot,
- libfile-desktopentry-perl, libnet-smtp-ssl-perl (>= 1.01-2), mutt,
- svn-buildpackage, w3m
+Suggests: build-essential, colordiff, cvs-buildpackage, devscripts-el,
+ gnuplot, less, libfile-desktopentry-perl, libdpkg-perl,
+ libnet-smtp-ssl-perl (>= 1.01-2), mutt, svn-buildpackage, w3m
 Description: scripts to make the life of a Debian Package maintainer easier
  Contains the following scripts, dependencies/recommendations shown in
  brackets afterwards:
@@ -105,6 +105,8 @@ Description: scripts to make the life of a Debian Package maintainer easier
   - namecheck: Check project names are not already taken.
   - nmudiff: mail a diff of the current package against the previous version
     to the BTS to assist in tracking NMUs [patchutils, mutt]
+  - pdebdiff: diffs only the debian/ folder of two packages
+    [libdpkg-perl, patchutils, git-core, less, colordiff]
   - plotchangelog: view a nice plot of the data in a changelog file
     [libtimedate-perl, gnuplot]
   - pts-subscribe: subscribe to the PTS for a limited period of time
diff --git a/debian/copyright b/debian/copyright
index 822b50b..b7368d6 100644
--- a/debian/copyright
+++ b/debian/copyright
@@ -25,8 +25,8 @@ the GPL, version 2 or later.
 
 - deb-reversion is under the Artistic License version 2.0.
 
-- namecheck and the Perl module DB_File::Lock used by bts are copyright
-  under the same terms as Perl, that is:
+- qdebdiff, namecheck and the Perl module DB_File::Lock used by bts are
+  licensed under the same terms as Perl, that is:
 
     This program is free software; you can redistribute it and/or modify
     it under the terms of either:
diff --git a/scripts/Makefile b/scripts/Makefile
index b1dbea9..60dde26 100644
--- a/scripts/Makefile
+++ b/scripts/Makefile
@@ -16,7 +16,7 @@ COMPLETION = $(patsubst %.bash_completion,devscripts.%,$(COMPL_FILES))
 GEN_MAN1S = bts.1 build-rdeps.1 chdist.1 dcontrol.1 debcheckout.1 debcommit.1 \
 	    deb-reversion.1 desktop2menu.1 dget.1 licensecheck.1 mass-bug.1 \
 	    mk-build-deps.1 namecheck.1 rmadison.1 svnpath.1 tagpending.1 \
-	    transition-check.1 devscripts.1
+	    transition-check.1 devscripts.1 pdebdiff.1
 
 BINDIR = /usr/bin
 LIBDIR = /usr/lib/devscripts
-- 
1.7.1

From 7e14b5dc8b85b77f799d3856f0aa89cb32de4145 Mon Sep 17 00:00:00 2001
From: Niels Thykier <ni...@thykier.net>
Date: Mon, 28 Jun 2010 14:56:33 +0200
Subject: [PATCH 1/2] Added pdebdiff.pl (only the script).

---
 scripts/pdebdiff.pl |  718 +++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 718 insertions(+), 0 deletions(-)
 create mode 100755 scripts/pdebdiff.pl

diff --git a/scripts/pdebdiff.pl b/scripts/pdebdiff.pl
new file mode 100755
index 0000000..38a9493
--- /dev/null
+++ b/scripts/pdebdiff.pl
@@ -0,0 +1,718 @@
+#!/usr/bin/perl
+#
+# Copyright: 2010, Niels Thykier <ni...@thykier.net>
+# It comes with ABSOLUTELY NO WARRANTY and may distributed
+# and modified under the same terms as Perl itself.
+#
+# Mini-changelog:
+#  28/06-2010 - Made pdediff strip the tmpdir from the resulting
+#               diff.
+#             - Added support for git based packaging.
+#             - Use File::Temp to create the tempdir.
+#
+
+=head1 NAME
+
+pdebdiff - Diffs the debian folder of two debian sources.
+
+=head1 SYNOPSIS
+
+B<pdebdiff> [I<options>] [I<src1>[ I<src2>]]
+
+B<pdebdiff> B<--help>
+
+=head1 DESCRIPTION
+
+B<pdebdiff> compares the debian/ folder of two debian packages and
+optionally pipes it to B<colordiff> or/and a pager. A source package
+is either a dsc file or the folder containing an unpacked debian
+source package.
+
+If passed two sources, it will compare the debian parts of
+these. Otherwise B<pdebdiff> will check if it has been run from an
+unpacked source package and (if so) compare this with either a source
+passed per command line or a previous released version (extracting the
+version from the changelog)
+
+If B<pdebdiff> is run from an unpacked source package and notices a
+VCS it supports (currently only B<git>), it will generate the diff
+based on the tags of that VCS. In case the VCS diff generator supports
+it, B<pdebdiff> will use its coloring instead of B<colordiff>. If the
+newest version does not appear to be tagged, it will be assumed to be
+the HEAD of the current VCS branch.
+
+When comparing a non-native 1.0 package with any other type of
+package, B<pdebdiff> will convert debian/ folder of the other package
+to a diff.gz and use interdiff to compare the changes.  Due to how
+these diff.gz files are created, B<pdebdiff> may lie about the version
+of the converted package, if it believes this will produce better
+output.
+
+=head1 OPTIONS
+
+=over 4
+
+=item B<-h> B<--help>
+
+Prints usage info and exits.
+
+=item B<--version>
+
+Prints version and license info and exits.
+
+=item B<--color>, B<--colour>
+
+Pipe the resulting diff through colordiff or use the colouring of the
+VCS diff generator (if any).
+
+With this option, pdebdiff will pass -R to the pager if it thinks it
+is less.
+
+Note: This is silently ignored if colordiff is not in PATH and the VCS
+diff being used (if any) does not have a colouring option.
+
+=item B<--pager>
+
+Pipe the resulting diff to a pager. If environment variable PAGER is
+set, this will be used; otherwise pdebdiff will look for a pager.
+
+=item B<--less>
+
+Assume the pager is less; this option implies B<--pager>. If PAGER is
+set, it is assumed to be less. If PAGER is not set pdebdiff will fail
+with an error, if it cannot find less.
+
+By default, pdebdiff will guess whether the pager is less based on the
+name of the command.
+
+=item B<--vcs> B<--no-vcs>
+
+Determines whether pdebdiff should check for a Version Control System
+(VCS) and use that to generate the diff.
+
+This defaults to using VCS and is only used if pdebdiff is run from
+an unpacked source package and given no source package per command
+line.
+
+=item B<--dch-limit=>I<N>
+
+Check at most I<N> releases for the released version. By default this
+is 10.
+
+Only used if not passed any sources.
+
+Note: The first entry is never considered a match and is not included
+in I<N>.
+
+=item B<--dist=>I<distribution>
+
+When parsing a changelog, find the first entry that was released into
+I<distribution>. If not passed, pdebdiff will find the first entry in
+the changelog that does not have "UNRELEASED" as dist.
+
+Only used if not passed any sources.
+
+Note: The first entry is never considered a match.
+
+=item B<--include=>I<dir>
+
+Adds I<dir> to the list of folders of where to find a dsc.
+
+Only used if not passed any sources.
+
+By default pdebdiff will check the following dirs:
+
+ .., ../build-area and /var/cache/pbuilder/result
+
+=item B<-d> B<--debug>
+
+Enable debug printing to stderr.
+
+=item B<--keep-temp> B<--no-keep-temp> 
+
+Whether to keep the temp files and dirs.
+
+Defaults to removing them.
+
+=back
+
+=cut
+
+use strict;
+use warnings;
+use Dpkg::Control;
+use Dpkg::Changelog::Debian;
+use Cwd 'abs_path';
+use Getopt::Long;
+use File::Temp;
+
+my $progname = $0;
+my $debug = 0;
+my $diff = 'diff';
+my $idiff = 'interdiff';
+my $pager = 0;
+my $isless = 0;
+my $color = 0;
+my $dist = undef;
+my $dchlimit = 10;
+my @dscinc = ();
+my $usevcs = '';
+my $keeptmp = '';
+# Needed tools.
+my @needed = ("diff", "tar");
+
+$progname =~ s...@[^/]*/@@g;
+
+GetOptions( 'd|debug' => sub { $debug = 1; },
+	    'h|help' => sub { usage(); exit(0); },
+	    'version' => sub { version(); exit(0); },
+	    'pager' => \$pager,
+	    'less' => sub { $pager = 1; $isless = 1; },
+	    'color|colour' => \$color, # I like British.
+	    'dist=s' => \$dist,
+	    'dch-limit=i' => \$dchlimit,
+	    'include=s' => \...@dscinc,
+	    'vcs!' => \$usevcs,
+	    'keep-temp!' => \$keeptmp,
+    ) or choke("Usage: $progname [options] [<dsc1>[ <dsc2>]]\nUse: $progname --help for more details.");
+
+if(!(scalar(@ARGV) == 2 or -f 'debian/changelog' && scalar(@ARGV) < 2)){
+    usage();
+    exit(1);
+}
+
+push(@dscinc, "..", "../build-area", "/var/cache/pbuilder/result");
+
+if( ! -t STDOUT && $pager){
+    print STDERR "Ignoring request for pager - stdout is not a tty!\n";
+    $pager = 0;
+}
+
+$usevcs = 1 if($usevcs eq '');
+
+my $api = undef;
+eval { $api = $Dpkg::Control::VERSION; };
+$api = -1 if(!defined($api) or $api =~ m/^-1,/);
+my $nsrcpkg;
+my $osrcpkg;
+my $tmpdir = undef;
+my $basedir = undef;
+if(scalar(@ARGV) == 2){
+    my ($opkg, $npkg) = @ARGV;
+    debug("$opkg - $npkg");
+    if( -d $opkg ){
+	$osrcpkg = parseChangelog($opkg);
+    } else {
+	$osrcpkg = parseDSC($opkg);
+	choke("Cannot find " . $osrcpkg->debian_packaging()) unless( -e $osrcpkg->debian_packaging());
+    }
+    if( -d $npkg ){
+	$nsrcpkg = parseChangelog($npkg);
+    } else {
+	$nsrcpkg = parseDSC($npkg);
+	choke("Cannot find " . $nsrcpkg->debian_packaging()) unless( -e $nsrcpkg->debian_packaging());
+    }
+} else {
+    if(scalar(@ARGV) > 0){
+	my $opkg = shift(@ARGV);
+	$nsrcpkg = parseChangelog('.');
+	if( -d $opkg ){
+	    $osrcpkg = parseChangelog($opkg);
+	} else {
+	    $osrcpkg = parseDSC($opkg);
+	    choke("Cannot find " . $osrcpkg->debian_packaging()) unless( -e $osrcpkg->debian_packaging());
+	}
+    } else {
+	($nsrcpkg, $osrcpkg) = parseChangelog('.', $dchlimit, $dist);
+	if( $usevcs && -d ".git" ) {
+	    # Hello GIT.
+	    my $gcmd = "git tag | grep -q ^debian/" . $nsrcpkg->{'version'}. "'\$'";
+	    my $isTagged;
+	    @needed = ("git");
+	    checkRequirements();
+	    debug("$gcmd");
+	    `$gcmd`;
+	    $isTagged = $?;
+	    $gcmd = "git diff";
+	    if($color){
+		$gcmd .= " --color";
+		$color = 2;
+	    }
+	    output("$gcmd debian/" .  $osrcpkg->{'version'} . ".." . ($isTagged?"debian/" . $nsrcpkg->{'version'}:"HEAD") . " -- debian/");
+	    exit(0);
+	}
+    }
+}
+
+checkRequirements();
+
+$tmpdir = File::Temp::tempdir( CLEANUP => $keeptmp?0:1 );
+
+if(($osrcpkg->{'native'} || $osrcpkg->{'format'} ne '1.0') && ($nsrcpkg->{'native'} || $nsrcpkg->{'format'} ne '1.0')){
+    # Both are 3.0 or both are native 1.0
+    # ensure the name + version are not equal
+    my ($ounpack, $nunpack);
+    my $oversion = $osrcpkg->{'version'};
+    $oversion .= "~" if($nsrcpkg->{'version'} eq $oversion && $osrcpkg->{'source'} eq $nsrcpkg->{'source'});
+    $ounpack = $osrcpkg->move($tmpdir, $oversion);
+    $nunpack = $nsrcpkg->move($tmpdir);
+    output("$diff -Nur \"$ounpack\" \"$nunpack\"");
+} else {
+    my $odgz;
+    my $ndgz;
+    my $oup = $osrcpkg->{'version'};
+    my $nup = $nsrcpkg->{'version'};
+    $oup =~ s/-[^-]*$//;
+    $nup =~ s/-[^-]*$//;
+    if(($nsrcpkg->{'native'} || $nsrcpkg->{'format'} ne '1.0') &&
+       ($osrcpkg->{'source'} eq $nsrcpkg->{'source'})){
+	# lie - it gives a better result.
+	debug("Lying about the current version to obtain better results... $nup -> $oup");
+	$nup = $oup;
+    }
+    print "$0: Since the upstream versions differ, this will probably not produce anything useful.\n" unless($oup eq $nup);
+    print "$0: Since the source names differ, this will probably not produce anything useful.\n"
+	unless($osrcpkg->{'source'} eq $nsrcpkg->{'source'});
+    $odgz = $osrcpkg->diffgz($tmpdir, $oup, ".old");
+    $ndgz = $nsrcpkg->diffgz($tmpdir, $nup);
+    output("$idiff -z \"$odgz\" \"$ndgz\"");
+}
+
+exit(0);
+
+### END OF SCRIPT ###
+
+sub output{
+    my $command = shift;
+    my $pcmd;
+    my $res;
+    my $outcmd = '';
+    my $out;
+    my $diff;
+    my $err;
+    # Check if color has already been handled.
+    if($color != 2){
+	# We only use color if colordiff is available
+	$color = 0 unless($color && hasCommand('colordiff'));
+	if($color){
+	    $outcmd .= " | colordiff ";
+	}
+    }
+    if($pager){
+	my $pagercmd = $ENV{PAGER};
+	if(!defined($pagercmd)){
+	    foreach my $cmd ('less', 'more'){
+		if(hasCommand($cmd)){
+		    $pagercmd = $cmd;
+		    last;
+		}
+	    }
+	    choke("less does not appear in path.") if($isless && $pagercmd ne 'less');
+	    $isless = $isless || $pagercmd =~ m/less/;
+	}
+	$pagercmd .= " -R" if($pagercmd !~ m/-R/ && $isless && $color);
+	$outcmd .= " | $pagercmd";
+    }
+    if($outcmd){
+	debug("Running: $command $outcmd");
+	open($out, $outcmd) or choke("$outcmd: $!");
+    } else {
+	debug("Running: $command");
+	$out = \*STDOUT;
+    }
+    open($diff, "-|", $command) or choke("$command: $!");
+    while(my $line = <$diff>){
+	$line =~ s...@^(\+\+\+|---) $tmpdir/*...@$1 @o if(defined($tmpdir));
+	print $out $line;
+    }
+    close($out) if($outcmd);    
+    close($diff);
+    $err = ($? >> 8);
+    choke("$command failed with $err!") if($err != 1 && $err != 0);
+}
+
+
+sub doParseDSC {
+    my $filename = shift;
+    my $dsc = Dpkg::Control->new("type" => CTRL_PKG_SRC);
+    debug("api: $api " . ($api>0?'libdpkg-perl':'dpkg-dev [unstable api]'));
+    if($api > 0){
+	# dpkg >= 1.15.6 - using libdpkg-perl
+	open(my $fd, "<", $filename) or choke("$filename: $!");
+	$dsc->parse($fd, $filename);
+	close($fd);
+    } else {
+	# dpkg < 1.15.6 - using dpkg-dev
+	$dsc->parse($filename);
+    }
+    return $dsc;
+}
+
+sub parseDSC {
+    my $filename = shift;
+    my ($src, $version, $format, $debchanges);
+    my $dsc;
+    my $dscdir = $filename;
+    my $orig = undef;
+    my $native = 0;
+    my $diffgz;
+    my $mover;
+    $dscdir = "." unless($dscdir =~ m@/@o);
+    $dscdir =~ s@/[^/]*$@@o;
+    choke("Could not find: $filename") unless( -e $filename );
+    $dsc = doParseDSC($filename);
+    ($src, $version, $format) = ($dsc->{'Source'}, $dsc->{'Version'}, $dsc->{'Format'});
+    choke("Source field was not present in $filename (or it was not a dsc file)") unless(defined($src));
+    debug("$filename - $dscdir - " . join(" - ", ($src, $version)));
+    {
+	my @filesField = split(/\s+/, $dsc->{'Files'});
+	my $len = scalar(@filesField);
+	my $i = 3;
+	for( ; $i < $len ; $i+=3 ){
+	    if($format eq '3.0 (quilt)'){
+		$debchanges = $filesField[$i] if($filesField[$i] =~ m/^${src}_${version}\.debian\.tar\./);
+	    } elsif($format eq '3.0 (native)'){
+		$debchanges = $filesField[$i] if($filesField[$i] =~ m/^${src}_${version}\.tar\./);
+	    } else {
+		$debchanges = $filesField[$i] if($filesField[$i] =~ m/^${src}_${version}\.diff\.gz/);
+		$orig = $filesField[$i] if($filesField[$i] =~ m/^${src}_${version}\.tar/);
+	    }
+	}
+    }
+    if(!defined($debchanges) and $format eq '1.0'){
+	$debchanges = $orig;
+	$native = 1;
+    } else {
+	$native = $format eq '3.0 (native)';
+    }
+    if($format eq '1.0' && !$native){
+	$diffgz = \&diffgzFetch;
+	$mover = sub { choke("Assertion Failed: Mover not defined for non-native 1.0 sources"); };
+    } else {
+	$diffgz = \&diffgzTar;
+	$mover = \&unpackTar;
+    }
+
+    choke("Could not find debian changes.") unless(defined($debchanges));
+    return Debian::Devscripts::PDebDiff->new({ 'source' => $src,
+					       'version' => $version,
+					       'format' => $format,
+					       'native' => $native,
+					       'basedir' => $dscdir,
+					       'debian-changes' => $debchanges,
+					       'unpacked' => 0,
+					       '!mover' => $mover,
+					       '!diffgz' => $diffgz
+					     });
+}
+
+sub parseChangelog {
+    my $basedir = shift;
+    my $limit = shift;
+    my $dist = shift;
+    my $dch = Dpkg::Changelog::Debian->new();
+    my $dchf = "${basedir}/debian/changelog";
+    my @range;
+    my $entry;
+    my $unr;
+    my $dsc;
+    my $srcpkg;
+    my $oldsrcpkg;
+    choke("limit must be >= 1 (value $limit)") if(defined($limit) && $limit < 1);
+    choke("Cannot find $dchf") unless( -e $dchf );
+    open(DCH, "<", $dchf) or choke("$dchf: $!");
+    $dch->parse(\*DCH, $dchf);
+    close(DCH);
+    $limit = 0 unless(defined($limit));
+    @range = $dch->get_range( { count => $limit +1} );
+    $unr = shift(@range);
+    $srcpkg = Debian::Devscripts::PDebDiff->new({ 'source' => $unr->get_source(),
+						  'version' => $unr->get_version(),
+						  'format' => '0.0 (unpacked-source)',
+						  'native' => '', # is neither
+						  'basedir' => $basedir,
+						  'debian-changes' => 'debian',
+						  'unpacked' => 1,
+						  '!mover' => \&moveDebDir,
+						  '!diffgz' => \&diffgzMovedDebDir
+						});
+    return $srcpkg unless($limit > 0);
+    range:
+    foreach my $r (@range){
+	# find the first entry that is in unstable.
+	my @dists = $r->get_distributions();
+	foreach my $d (@dists){
+	    if((!defined($dist) && $d ne 'UNRELEASED') or
+		(defined($dist) && $d eq $dist)) {
+		$entry = $r;
+		last range;
+	    }
+	}
+    }
+    choke("Could not find a release " . (defined($dist)? "to $dist": "") .
+	  " within $limit entries (use --dch-limit to increase this limit)") unless(defined($entry) && $limit > 0);
+    $dsc = $entry->get_source() . "_" . $entry->get_version() . ".dsc";
+    foreach my $dir (@dscinc){
+	if( -e "$dir/$dsc"){
+	    debug("$dsc is in $dir");
+	    return ($srcpkg, parseDSC("$dir/$dsc"));
+	}
+	debug("Tried: $dir/$dsc");
+    }
+    choke("Could not find $dsc");
+}
+
+sub moveDebDir{
+    my $this = shift;
+    my $tmp = shift;
+    my $dir = $this->debian_packaging();
+    my $src = $this->{'source'};
+    my $version = $this->{'version'};
+    my $findcmd = " && find \"$tmp/$src-$version\" -depth \\( -name '.svn' -o -name 'CVS' \\) -exec rm -fr {} \\;";
+    debug("mkdir -p \"$tmp/$src-$version\" && cp -a \"$dir\"  \"$tmp/$src-$version\" $findcmd");
+    system("mkdir -p \"$tmp/$src-$version\" && cp -a \"$dir\"  \"$tmp/$src-$version\" $findcmd") == 0
+	or choke("Failed to link $dir/debian to $tmp/$src-$version");
+    return "$tmp/$src-$version";
+}
+
+sub unpackTar {
+    my $this = shift;
+    my $tmp = shift;
+    my $tar = abs_path($this->debian_packaging());
+    my $src = $this->{'source'};
+    my $version = $this->{'version'};
+    my $native = $this->{'native'};
+    my $vch = shift//$version;
+    my $comp = " --auto-compress ";
+    my $args = $native ? "$src-$version/debian/" : "";
+    $tmp = "$tmp/$src-$vch" unless($native);
+    debug("mkdir -p \"$tmp\" && cd \"$tmp\" && tar -x $comp -f \"$tar\" $args");
+    system("mkdir -p \"$tmp\" && cd \"$tmp\" && tar -x $comp -f \"$tar\" $args") == 0
+	or choke("Failed to untar $tar.");
+    if($native){
+	system("mv -f \"$tmp/$src-$version\" \"$tmp/$src-$vch\"") == 0
+	    or choke("Failed to rename unpacked source") unless($version eq $vch);
+	$tmp = "$tmp/$src-$vch";
+    }
+    return $tmp;
+}
+
+sub diffgzTar {
+    my $this = shift;
+    my $tmp = shift;
+    my $vch = shift;
+    my $version = $this->{'version'};
+    my $unpacked;
+    $unpacked = unpackTar($this, $tmp);
+    debug("diffgzTar:" . $this->{'source'} . " $version, $vch");
+    if(defined($vch) && $vch ne $version){
+	my $src = $this->{'source'};
+	debug("mv -f \"$unpacked\" \"$tmp/$src-$vch\"");
+	system("mv -f \"$unpacked\" \"$tmp/$src-$vch\"") == 0
+	    or choke("Failed to rename \"$unpacked\" -> \"$tmp/$src-$vch\"");
+	$unpacked = "$src-$vch";
+    } else {
+	$unpacked =~ s...@^$tmp/@@;
+    }
+    return diffgzDir($this, $tmp, $unpacked, @_);
+}
+
+sub diffgzMovedDebDir{
+    my $this = shift;
+    my $tmp = shift;
+    my $moved = moveDebDir($this, $tmp);
+    my $vch = shift;
+    my $version = $this->{'version'};
+    if(defined($vch) && $vch ne $version){
+	my $src = $this->{'source'};
+	debug("mv -f \"$moved\" \"$tmp/$src-$vch\"");
+	system("mv -f \"$moved\" \"$tmp/$src-$vch\"") == 0
+	    or choke("Failed to rename \"$moved\" -> \"$tmp/$src-$vch\"");
+	$moved = "$src-$vch";
+    } else {
+	$moved =~ s...@^$tmp/@@;
+    }
+    return diffgzDir($tmp, $tmp, $moved, @_);
+}
+
+sub diffgzDir {
+    my $this = shift;
+    my $tmp = shift;
+    my $name = shift;
+    my $extra = shift//'';
+    # trailing slashses gives problems.
+    $name =~ s@/*$@@;
+    debug("mkdir -p \"$tmp/$name.orig\" && cd \"$tmp\" && $diff -Nur $name.orig $name  | gzip -9c > $name$extra.diff.gz");
+    system("mkdir -p \"$tmp/$name.orig\" && cd \"$tmp\" && $diff -Nur $name.orig $name  | gzip -9c > $name$extra.diff.gz") == 0 or
+	choke("Failed to create $name$extra.diff.gz");
+    debug("mv -f \"$tmp/$name\" \"$tmp/$name\"`date +%s`");
+    system("mv -f \"$tmp/$name\" \"$tmp/$name\"`date +%s`") == 0 or choke("Renaming \"$tmp/$name\" failed");
+    return "$tmp/$name$extra.diff.gz";
+}
+
+sub diffgzFetch{
+    my $this = shift;
+    return $this->debian_packaging();
+}
+
+sub debug{
+    my $msg = shift;
+    print STDERR "D: $msg\n" if($debug);
+}
+
+sub choke{
+    my $msg = shift;
+    print STDERR "$msg\n";
+    system("rm -fr \"$tmpdir\"") if(defined($tmpdir));
+    exit(1);
+}
+
+sub hasCommand{
+    my $cmd = shift;
+    return system("which $cmd 2>/dev/null >/dev/null") == 0;
+}
+
+sub checkRequirements{
+    push(@needed, "interdiff") if((!$osrcpkg->{'native'} && $osrcpkg->{'format'} eq '1.0') ||
+				  (!$nsrcpkg->{'native'} && $nsrcpkg->{'format'} eq '1.0'));
+    foreach my $cmd (@needed){
+	debug("Checking for $cmd");
+	hasCommand($cmd) or choke("Cannot find $cmd, which is needed for this operation.");
+    }
+    # We are good.
+    1;
+}
+
+sub version {
+    print <<EOF
+$progname: ###VERSION###
+Copyright (C): 2010, Niels Thykier <nie...@thykier.net>.
+
+This script comes with ABSOLUTELY NO WARRANTY and may be modified
+and distributed under the same terms as Perl.
+EOF
+;
+}
+
+sub usage{
+    my $slash = '/';
+    print <<EOF
+Usage: $progname [OPTION]... [src1 [src2]]
+
+$progname compares the debian folder of two debian packages and
+optionally pipes it to colordiff or${slash}and a pager. A source package
+is either a dsc file or the folder containing an unpacked debian
+source package.
+
+If run from an unpacked source package being passed one or zero
+source packages, it will compare the unpacked source package to
+either the source package passed or to an earlier version of
+the same source.
+
+ -d, --debug      Prints debug information to stderr.
+ -h, --help       Prints this usage and exits.
+ --version        Prints version and license info and exits.
+ --pager          Pipe the output to a pager.
+ --less           Assume the pager is less (implies --pager).
+ --color,--colour Pipe the output through colordiff.
+                  NB: May not work, if your pager is not less.
+ --[no-]vcs       Do (not) look for/use known VCS repositories to
+                  generate the diff.
+                  Ignored if not run from an unpacked source.
+ --dist <dist>    Look for <dist> in the changelog.
+                  Defaults to any dist, which is not UNRELEASED.
+                  Ignored if passed one or more sources.
+ --dch-limit <N>  Look at most <N> version back in the changelog (def: 10)
+                  Ignored if passed one or more sources.
+ --include <dir>  Look for dsc files in <dir>.
+                  Ignored if passed one or more sources.
+ --[no-]keep-temp Do (not) leave temp dirs/files behind (for debugging).
+                  Defaults to removing them.
+
+If at least one of the source packages are 1.0, then the final difference
+will be generated using interdiff. diff will still be used to convert any
+3.0 sources into a diff.gz.
+
+If name of the pager suggests it is less (or --less is passed), $progname
+will pass the correct options to make it display the colors.
+
+Note: --color is silently ignored if colordiff is not available and the
+VCS used does not have its own colouring option.
+
+VCSs supported: git
+
+EOF
+;
+
+}
+
+package Debian::Devscripts::PDebDiff;
+
+# Pseudo module for encapsulating src-packages.
+
+sub new{
+    my ($ref, $opt) = @_;
+    return bless($opt, $ref);
+}
+
+sub debian_packaging {
+    my $this = shift;
+    return $this->{'basedir'} . "/" . $this->{'debian-changes'};
+}
+
+sub move {
+    my $this = shift;
+    my $handler = $this->{'!mover'};
+    return $handler->($this, @_);
+}
+
+sub diffgz{
+    my $this = shift;
+    my $handler = $this->{'!diffgz'};
+    return $handler->($this, @_);
+}
+
+=head1 EXAMPLES
+
+When run from an unpacked source package, B<pdebdiff> will
+diff the unpacked source package against the latest
+released version.
+
+ u...@host:/my/package-1.0$ ls debian/changelog
+ debian/changelog
+ u...@host:/my/package-1.0$ pdebdiff
+
+The case above, it will first look for a known VCS repository
+and use the tag of the previous version to generate the diff.
+If it cannot find a known VCS, it will attempt to look for a
+packed source of the previous version.
+
+In case your builder places dsc files in a non-standard place,
+you may have to pass B<--include> to pdebdiff.
+
+ u...@host:/my/package-1.0$ pdebdiff --include $HOME/myresults
+
+You can also specify that the unpacked source package should
+be diffed against a specific dsc file.
+
+ u...@host:/my/package-1.0$ ../build-area/package_0.9-1.dsc
+
+Or even another unpacked source:
+
+ u...@host:/my/package-1.0$ ls ../package-0.9/debian/changelog
+ ../package-0.9/debian/changelog
+ u...@host:/my/package-1.0$ pdebdiff ../package-0.9
+
+Alternatively you can compare two sources by passing them both
+by command line. These can also be unpacked sources.
+
+ u...@host:~$ pdebdiff package_1.0-1.dsc package_1.0-2.dsc
+ u...@host:~$ pdebdiff package-0.9/ package-1.0/
+ u...@host:~$ pdebdiff package_1.0-1.dsc package-1.0/
+ u...@host:~$ pdebdiff package-1.0/ package_1.0-3.dsc
+
+=head1 AUTHOR
+
+Niels Thykier <ni...@thykier.net>
+
+=cut
-- 
1.7.1

Reply via email to