Hi, On Wed, 20 Jul 2011, Guillem Jover wrote: > > It required some important restructuring of the source package build > > procedure so I would be glad to have some more people running with this. > > Also you might have some input on the new interface. > > It would be preferable in general to split refactoring from new > additional features so that reviewing is actually easier.
I made the effort to split the changes in several commits, the new series is attached (and in my pu/master branch). Reviews and tests are welcome. > Yes, there are some pending changes I want to merge first, some > requirements for the other multiarch changes, but I don't want to > upload it as long as at least the the Build-Features stuff is on > master. Still waiting on your feedback to my other reply on this. Unfortunately the tech-ctte has still not yet decided on this but it will likely happen in the upcoming days. Cheers, -- Raphaël Hertzog ◈ Debian Developer Follow my Debian News ▶ http://RaphaelHertzog.com (English) ▶ http://RaphaelHertzog.fr (Français)
>From c6cfc41b5963da180c993de61c830be2a28465f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Hertzog?= <hert...@debian.org> Date: Thu, 14 Jul 2011 18:56:30 +0200 Subject: [PATCH 1/6] dpkg-source: accept "." as the directory parameter dpkg-source should never be called from within the unpacked source tree, the result is usually not what one would expect. Fix this by automatically converting the directory name and by changing the current directory to the parent one. This is particularly interesting for the upcoming --record-changes option. --- scripts/dpkg-source.pl | 9 ++++++++- 1 files changed, 8 insertions(+), 1 deletions(-) diff --git a/scripts/dpkg-source.pl b/scripts/dpkg-source.pl index 209368f..6279fc1 100755 --- a/scripts/dpkg-source.pl +++ b/scripts/dpkg-source.pl @@ -11,7 +11,7 @@ # Copyright © 2005 Brendan O'Dea <b...@debian.org> # Copyright © 2006-2008 Frank Lichtenheld <dj...@debian.org> # Copyright © 2006-2009 Guillem Jover <guil...@debian.org> -# Copyright © 2008-2010 Raphaël Hertzog <hert...@debian.org> +# Copyright © 2008-2011 Raphaël Hertzog <hert...@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 @@ -45,6 +45,8 @@ use Dpkg::Changelog::Parse; use Dpkg::Source::Package; use Dpkg::Vendor qw(run_vendor_hook); +use Cwd; +use File::Basename; use File::Spec; textdomain("dpkg-dev"); @@ -104,6 +106,11 @@ if (defined($options{'opmode'}) && if (not -d $dir) { error(_g("directory argument %s is not a directory"), $dir); } + if ($dir eq ".") { + # . is never correct, adjust automatically + $dir = basename(cwd()); + chdir("..") || syserr(_g("unable to chdir to `%s'"), ".."); + } # --format options are not allowed, they would take precedence # over real command line options, debian/source/format should be used # instead -- 1.7.5.4
>From 547989307084abaf89c450f44a3bd404fd140158 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Hertzog?= <hert...@debian.org> Date: Thu, 14 Jul 2011 19:02:49 +0200 Subject: [PATCH 2/6] dpkg-source: uniform handling of the patch header Formats "2.0" and "3.0 (quilt)" now generate the patch header with the same code. Drop some useless duplication. --- scripts/Dpkg/Source/Package/V2.pm | 39 +++++++++++++++++++--- scripts/Dpkg/Source/Package/V3/quilt.pm | 52 +----------------------------- 2 files changed, 35 insertions(+), 56 deletions(-) diff --git a/scripts/Dpkg/Source/Package/V2.pm b/scripts/Dpkg/Source/Package/V2.pm index 7a1880a..8be3312 100644 --- a/scripts/Dpkg/Source/Package/V2.pm +++ b/scripts/Dpkg/Source/Package/V2.pm @@ -1,4 +1,4 @@ -# Copyright © 2008 Raphaël Hertzog <hert...@debian.org> +# Copyright © 2008-2011 Raphaël Hertzog <hert...@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 @@ -30,6 +30,9 @@ use Dpkg::Source::Archive; use Dpkg::Source::Patch; use Dpkg::Exit; use Dpkg::Source::Functions qw(erasedir is_binary fs_time); +use Dpkg::Vendor qw(run_vendor_hook); +use Dpkg::Control; +use Dpkg::Changelog::Parse; use POSIX; use File::Basename; @@ -526,7 +529,7 @@ sub do_build { } sub get_patch_header { - my ($self, $dir, $previous) = @_; + my ($self, $dir) = @_; my $ph = File::Spec->catfile($dir, "debian", "source", "local-patch-header"); unless (-f $ph) { $ph = File::Spec->catfile($dir, "debian", "source", "patch-header"); @@ -538,10 +541,34 @@ sub get_patch_header { close(PH); return $text; } - return "Description: Undocumented upstream changes - This patch has been created by dpkg-source during the package build - but it might have accumulated changes from several uploads. Please - check the changelog to (hopefully) learn more on those changes.\n\n"; + my $ch_info = changelog_parse(offset => 0, count => 1, + file => File::Spec->catfile($dir, "debian", "changelog")); + return '' if not defined $ch_info; + my $header = Dpkg::Control->new(type => CTRL_UNKNOWN); + $header->{'Description'} = "<short summary of the patch>\n"; + $header->{'Description'} .= +"TODO: Put a short summary on the line above and replace this paragraph +with a longer explanation of this change. Complete the meta-information +with other relevant fields (see below for details). To make it easier, the +information below has been extracted from the changelog. Adjust it or drop +it.\n"; + $header->{'Description'} .= $ch_info->{'Changes'} . "\n"; + $header->{'Author'} = $ch_info->{'Maintainer'}; + $text = "$header"; + run_vendor_hook("extend-patch-header", \$text, $ch_info); + $text .= "\n--- +The information above should follow the Patch Tagging Guidelines, please +checkout http://dep.debian.net/deps/dep3/ to learn about the format. Here +are templates for supplementary fields that you might want to add: + +Origin: <vendor|upstream|other>, <url of original patch> +Bug: <url in upstream bugtracker> +Bug-Debian: http://bugs.debian.org/<bugnumber> +Bug-Ubuntu: https://launchpad.net/bugs/<bugnumber> +Forwarded: <no|not-needed|url proving that it has been forwarded> +Reviewed-By: <name and email of someone who approved the patch> +Last-Update: <YYYY-MM-DD>\n\n"; + return $text; } sub register_autopatch { diff --git a/scripts/Dpkg/Source/Package/V3/quilt.pm b/scripts/Dpkg/Source/Package/V3/quilt.pm index eb201c1..42064e2 100644 --- a/scripts/Dpkg/Source/Package/V3/quilt.pm +++ b/scripts/Dpkg/Source/Package/V3/quilt.pm @@ -1,4 +1,4 @@ -# Copyright © 2008-2009 Raphaël Hertzog <hert...@debian.org> +# Copyright © 2008-2011 Raphaël Hertzog <hert...@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 @@ -29,9 +29,7 @@ use Dpkg::ErrorHandling; use Dpkg::Source::Patch; use Dpkg::Source::Functions qw(erasedir fs_time); use Dpkg::IPC; -use Dpkg::Vendor qw(get_current_vendor run_vendor_hook); -use Dpkg::Control; -use Dpkg::Changelog::Parse; +use Dpkg::Vendor qw(get_current_vendor); use POSIX; use File::Basename; @@ -386,51 +384,5 @@ sub register_autopatch { } } -sub get_patch_header { - my ($self, $dir, $previous) = @_; - my $ph = File::Spec->catfile($dir, "debian", "source", "local-patch-header"); - unless (-f $ph) { - $ph = File::Spec->catfile($dir, "debian", "source", "patch-header"); - } - my $text; - if (-f $ph) { - open(PH, "<", $ph) || syserr(_g("cannot read %s"), $ph); - $text = join("", <PH>); - close(PH); - return $text; - } - my $ch_info = changelog_parse(offset => 0, count => 1, - file => File::Spec->catfile($dir, "debian", "changelog")); - return '' if not defined $ch_info; - return $self->SUPER::get_patch_header($dir, $previous) - if $self->{'options'}{'single-debian-patch'}; - my $header = Dpkg::Control->new(type => CTRL_UNKNOWN); - $header->{'Description'} = "Upstream changes introduced in version " . - $ch_info->{'Version'} . "\n"; - $header->{'Description'} .= -"This patch has been created by dpkg-source during the package build. -Here's the last changelog entry, hopefully it gives details on why -those changes were made:\n"; - $header->{'Description'} .= $ch_info->{'Changes'} . "\n"; - $header->{'Description'} .= -"\nThe person named in the Author field signed this changelog entry.\n"; - $header->{'Author'} = $ch_info->{'Maintainer'}; - $text = "$header"; - run_vendor_hook("extend-patch-header", \$text, $ch_info); - $text .= "\n--- -The information above should follow the Patch Tagging Guidelines, please -checkout http://dep.debian.net/deps/dep3/ to learn about the format. Here -are templates for supplementary fields that you might want to add: - -Origin: <vendor|upstream|other>, <url of original patch> -Bug: <url in upstream bugtracker> -Bug-Debian: http://bugs.debian.org/<bugnumber> -Bug-Ubuntu: https://launchpad.net/bugs/<bugnumber> -Forwarded: <no|not-needed|url proving that it has been forwarded> -Reviewed-By: <name and email of someone who approved the patch> -Last-Update: <YYYY-MM-DD>\n\n"; - return $text; -} - # vim:et:sw=4:ts=8 1; -- 1.7.5.4
>From 06fdcc4d20a58e78dc1024480df4e931cd2249b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Hertzog?= <hert...@debian.org> Date: Thu, 28 Jul 2011 15:10:43 +0200 Subject: [PATCH 3/6] Dpkg::Source::Package: replace register_autopatch() with register_patch() While register_autopatch() is only able to register a patch as the automatic patch, register_patch() can register a patch under any desired patch name. Also it doesn't not drop the input patch file, leaving that responsibility to whoever called it. However if the input patch file is empty, it will remove the target patch from the debian source package. --- scripts/Dpkg/Source/Package/V2.pm | 40 ++++++++++++++---------------- scripts/Dpkg/Source/Package/V3/quilt.pm | 36 +++++++++++++++++---------- 2 files changed, 42 insertions(+), 34 deletions(-) diff --git a/scripts/Dpkg/Source/Package/V2.pm b/scripts/Dpkg/Source/Package/V2.pm index 8be3312..4049781 100644 --- a/scripts/Dpkg/Source/Package/V2.pm +++ b/scripts/Dpkg/Source/Package/V2.pm @@ -40,6 +40,7 @@ use File::Temp qw(tempfile tempdir); use File::Path; use File::Spec; use File::Find; +use File::Copy; our $CURRENT_MINOR_VERSION = "0"; @@ -471,31 +472,22 @@ sub do_build { %{$self->{'diff_options'}}, handle_binary_func => $handle_binary, order_from => $autopatch); error(_g("unrepresentable changes to source")) if not $diff->finish(); - # The previous auto-patch must be removed, it has not been used and it - # will be recreated if it's still needed - if (-e $autopatch) { - unlink($autopatch) || syserr(_g("cannot remove %s"), $autopatch); - } # Install the diff as the new autopatch - if (not -s $tmpdiff) { - unlink($tmpdiff) || syserr(_g("cannot remove %s"), $tmpdiff); - } else { - mkpath(File::Spec->catdir($dir, "debian", "patches")); + mkpath(File::Spec->catdir($dir, "debian", "patches")); + $autopatch = $self->register_patch($dir, $tmpdiff, + $self->get_autopatch_name()); + if (-s $autopatch) { info(_g("local changes stored in %s, the modified files are:"), $autopatch); my $analysis = $diff->analyze($dir, verbose => 0); foreach my $fn (sort keys %{$analysis->{'filepatched'}}) { print " $fn\n"; } - rename($tmpdiff, $autopatch) || - syserr(_g("cannot rename %s to %s"), $tmpdiff, $autopatch); - chmod(0666 & ~ umask(), $autopatch) || - syserr(_g("unable to change permission of `%s'"), $autopatch); } - $self->register_autopatch($dir); if (-e $autopatch and $self->{'options'}{'abort_on_upstream_changes'}) { error(_g("aborting due to --abort-on-upstream-changes")); } rmdir(File::Spec->catdir($dir, "debian", "patches")); # No check on purpose + unlink($tmpdiff) || syserr(_g("cannot remove %s"), $tmpdiff); pop @Dpkg::Exit::handlers; # Remove the temporary directory @@ -571,16 +563,22 @@ Last-Update: <YYYY-MM-DD>\n\n"; return $text; } -sub register_autopatch { - my ($self, $dir) = @_; - my $autopatch = File::Spec->catfile($dir, "debian", "patches", - $self->get_autopatch_name()); - if (-e $autopatch) { +sub register_patch { + my ($self, $dir, $patch_file, $patch_name) = @_; + my $patch = File::Spec->catfile($dir, "debian", "patches", $patch_name); + if (-s $patch_file) { + copy($patch_file, $patch) || + syserr(_g("failed to copy %s to %s"), $patch_file, $patch); + chmod(0666 & ~ umask(), $patch) || + syserr(_g("unable to change permission of `%s'"), $patch); my $applied = File::Spec->catfile($dir, "debian", "patches", ".dpkg-source-applied"); open(APPLIED, '>>', $applied) || syserr(_g("cannot write %s"), $applied); - print APPLIED ($self->get_autopatch_name() . "\n"); - close(APPLIED); + print APPLIED "$patch\n"; + close(APPLIED) || syserr(_g("cannot close %s"), $applied); + } elsif (-e $patch) { + unlink($patch) || syserr(_g("cannot remove %s"), $patch); } + return $patch; } # vim:et:sw=4:ts=8 diff --git a/scripts/Dpkg/Source/Package/V3/quilt.pm b/scripts/Dpkg/Source/Package/V3/quilt.pm index 42064e2..4db776b 100644 --- a/scripts/Dpkg/Source/Package/V3/quilt.pm +++ b/scripts/Dpkg/Source/Package/V3/quilt.pm @@ -35,6 +35,7 @@ use POSIX; use File::Basename; use File::Spec; use File::Path; +use File::Copy; our $CURRENT_MINOR_VERSION = "0"; @@ -330,8 +331,8 @@ sub check_patches_applied { } } -sub register_autopatch { - my ($self, $dir) = @_; +sub register_patch { + my ($self, $dir, $tmpdiff, $patch_name) = @_; sub add_line { my ($file, $line) = @_; @@ -350,38 +351,47 @@ sub register_autopatch { close(FILE); } - my $auto_patch = $self->get_autopatch_name(); my @patches = $self->get_patches($dir); - my $has_patch = (grep { $_ eq $auto_patch } @patches) ? 1 : 0; + my $has_patch = (grep { $_ eq $patch_name } @patches) ? 1 : 0; my $series = $self->get_series_file($dir); $series ||= File::Spec->catfile($dir, "debian", "patches", "series"); my $applied = File::Spec->catfile($dir, ".pc", "applied-patches"); - my $patch = File::Spec->catfile($dir, "debian", "patches", $auto_patch); + my $patch = File::Spec->catfile($dir, "debian", "patches", $patch_name); + + if (-s $tmpdiff) { + copy($tmpdiff, $patch) || + syserr(_g("failed to copy %s to %s"), $tmpdiff, $patch); + chmod(0666 & ~ umask(), $patch) || + syserr(_g("unable to change permission of `%s'"), $patch); + } elsif (-e $patch) { + unlink($patch) || syserr(_g("cannot remove %s"), $patch); + } if (-e $patch) { $self->create_quilt_db($dir); - # Add auto_patch to series file + # Add patch to series file if (not $has_patch) { - add_line($series, $auto_patch); - add_line($applied, $auto_patch); + add_line($series, $patch_name); + add_line($applied, $patch_name); } # Ensure quilt meta-data are created and in sync with some trickery: # reverse-apply the patch, drop .pc/$patch, re-apply it # with the correct options to recreate the backup files my $patch_obj = Dpkg::Source::Patch->new(filename => $patch); $patch_obj->apply($dir, add_options => ['-R', '-E'], verbose => 0); - erasedir(File::Spec->catdir($dir, ".pc", $auto_patch)); - $self->apply_quilt_patch($dir, $auto_patch); + erasedir(File::Spec->catdir($dir, ".pc", $patch_name)); + $self->apply_quilt_patch($dir, $patch_name); } else { # Remove auto_patch from series if ($has_patch) { - drop_line($series, $auto_patch); - drop_line($applied, $auto_patch); - erasedir(File::Spec->catdir($dir, ".pc", $auto_patch)); + drop_line($series, $patch_name); + drop_line($applied, $patch_name); + erasedir(File::Spec->catdir($dir, ".pc", $patch_name)); } # Clean up empty series unlink($series) if not -s $series; } + return $patch; } # vim:et:sw=4:ts=8 -- 1.7.5.4
>From af32d4fd4fca74daf44260f901bbfe603f31d03a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Hertzog?= <hert...@debian.org> Date: Thu, 28 Jul 2011 16:26:51 +0200 Subject: [PATCH 4/6] Dpkg::Source::Package::V2: move logic to create patches in a separate function This commit extracts the logic to create automatic patches in a new generate_patch() method. It's expected that this function will be reused to implement dpkg-source --commit. The code is mainly moved around as-is to simplify reviews. All desired changes have been left for further commits. --- scripts/Dpkg/Source/Package/V2.pm | 91 ++++++++++++++++++++++--------------- 1 files changed, 55 insertions(+), 36 deletions(-) diff --git a/scripts/Dpkg/Source/Package/V2.pm b/scripts/Dpkg/Source/Package/V2.pm index 4049781..f846bc8 100644 --- a/scripts/Dpkg/Source/Package/V2.pm +++ b/scripts/Dpkg/Source/Package/V2.pm @@ -312,23 +312,12 @@ sub check_patches_applied { } } -sub do_build { - my ($self, $dir) = @_; +sub generate_patch { + my ($self, $dir, %opts) = @_; my ($dirname, $updir) = fileparse($dir); - my @argv = @{$self->{'options'}{'ARGV'}}; - if (scalar(@argv)) { - usageerr(_g("-b takes only one parameter with format `%s'"), - $self->{'fields'}{'Format'}); - } - $self->prepare_build($dir); - - my $include_binaries = $self->{'options'}{'include_binaries'}; - my @tar_ignore = map { "--exclude=$_" } @{$self->{'options'}{'tar_ignore'}}; - my $sourcepackage = $self->{'fields'}{'Source'}; my $basenamerev = $self->get_basename(1); - my $basename = $self->get_basename(); - my $basedirname = $basename; + my $basedirname = $self->get_basename(); $basedirname =~ s/_/-/; # Identify original tarballs @@ -379,6 +368,53 @@ sub do_build { # Apply all patches except the last automatic one $self->apply_patches($tmp, skip_auto => 1, usage => 'build'); + # Create a patch + my $autopatch = File::Spec->catfile($dir, "debian", "patches", + $self->get_autopatch_name()); + my ($difffh, $tmpdiff) = tempfile("$basenamerev.diff.XXXXXX", + DIR => $updir, UNLINK => 0); + push @Dpkg::Exit::handlers, sub { unlink($tmpdiff) }; + my $diff = Dpkg::Source::Patch->new(filename => $tmpdiff, + compression => "none"); + $diff->create(); + $diff->set_header($self->get_patch_header($dir, $autopatch)); + $diff->add_diff_directory($tmp, $dir, basedirname => $basedirname, + %{$self->{'diff_options'}}, + handle_binary_func => $opts{'handle_binary'}, + order_from => $opts{'order_from'}); + error(_g("unrepresentable changes to source")) if not $diff->finish(); + + if (-s $autopatch) { + info(_g("local changes stored in %s, the modified files are:"), $autopatch); + my $analysis = $diff->analyze($dir, verbose => 0); + foreach my $fn (sort keys %{$analysis->{'filepatched'}}) { + print " $fn\n"; + } + } + + # Remove the temporary directory + erasedir($tmp); + pop @Dpkg::Exit::handlers; + pop @Dpkg::Exit::handlers; + + return $tmpdiff; +} + +sub do_build { + my ($self, $dir) = @_; + my @argv = @{$self->{'options'}{'ARGV'}}; + if (scalar(@argv)) { + usageerr(_g("-b takes only one parameter with format `%s'"), + $self->{'fields'}{'Format'}); + } + $self->prepare_build($dir); + + my $include_binaries = $self->{'options'}{'include_binaries'}; + my @tar_ignore = map { "--exclude=$_" } @{$self->{'options'}{'tar_ignore'}}; + + my $sourcepackage = $self->{'fields'}{'Source'}; + my $basenamerev = $self->get_basename(1); + # Prepare handling of binary files my %auth_bin_files; my $incbin_file = File::Spec->catfile($dir, "debian", "source", "include-binaries"); @@ -461,28 +497,15 @@ sub do_build { # Create a patch my $autopatch = File::Spec->catfile($dir, "debian", "patches", $self->get_autopatch_name()); - my ($difffh, $tmpdiff) = tempfile("$basenamerev.diff.XXXXXX", - DIR => $updir, UNLINK => 0); + my $tmpdiff = $self->generate_patch($dir, order_from => $autopatch, + handle_binary => $handle_binary, + usage => 'build'); push @Dpkg::Exit::handlers, sub { unlink($tmpdiff) }; - my $diff = Dpkg::Source::Patch->new(filename => $tmpdiff, - compression => "none"); - $diff->create(); - $diff->set_header($self->get_patch_header($dir, $autopatch)); - $diff->add_diff_directory($tmp, $dir, basedirname => $basedirname, - %{$self->{'diff_options'}}, handle_binary_func => $handle_binary, - order_from => $autopatch); - error(_g("unrepresentable changes to source")) if not $diff->finish(); + # Install the diff as the new autopatch mkpath(File::Spec->catdir($dir, "debian", "patches")); $autopatch = $self->register_patch($dir, $tmpdiff, $self->get_autopatch_name()); - if (-s $autopatch) { - info(_g("local changes stored in %s, the modified files are:"), $autopatch); - my $analysis = $diff->analyze($dir, verbose => 0); - foreach my $fn (sort keys %{$analysis->{'filepatched'}}) { - print " $fn\n"; - } - } if (-e $autopatch and $self->{'options'}{'abort_on_upstream_changes'}) { error(_g("aborting due to --abort-on-upstream-changes")); } @@ -490,10 +513,6 @@ sub do_build { unlink($tmpdiff) || syserr(_g("cannot remove %s"), $tmpdiff); pop @Dpkg::Exit::handlers; - # Remove the temporary directory - erasedir($tmp); - pop @Dpkg::Exit::handlers; - # Update debian/source/include-binaries if needed if (scalar(@binary_files) and $include_binaries) { mkpath(File::Spec->catdir($dir, "debian", "source")); @@ -509,7 +528,7 @@ sub do_build { # Create the debian.tar my $debianfile = "$basenamerev.debian.tar." . $self->{'options'}{'comp_ext'}; info(_g("building %s in %s"), $sourcepackage, $debianfile); - $tar = Dpkg::Source::Archive->new(filename => $debianfile); + my $tar = Dpkg::Source::Archive->new(filename => $debianfile); $tar->create(options => \@tar_ignore, 'chdir' => $dir); $tar->add_directory("debian"); foreach my $binary (@binary_files) { -- 1.7.5.4
>From e601fb8fe9277c6236d8ecde22b689572fa4ec6f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Hertzog?= <hert...@debian.org> Date: Thu, 28 Jul 2011 17:14:55 +0200 Subject: [PATCH 5/6] Dpkg::Source::Package::V2: cleanup generate_patch() Drop all references to $autopatch which has nothing to do with generating a patch. Move the message explaining where the changes have been recorded outside of the function. Drop unused parameter to get_patch_header(). Drop intermediary variables which are only used once. --- scripts/Dpkg/Source/Package/V2.pm | 11 ++++------- 1 files changed, 4 insertions(+), 7 deletions(-) diff --git a/scripts/Dpkg/Source/Package/V2.pm b/scripts/Dpkg/Source/Package/V2.pm index f846bc8..9a16cc6 100644 --- a/scripts/Dpkg/Source/Package/V2.pm +++ b/scripts/Dpkg/Source/Package/V2.pm @@ -315,8 +315,6 @@ sub check_patches_applied { sub generate_patch { my ($self, $dir, %opts) = @_; my ($dirname, $updir) = fileparse($dir); - my $sourcepackage = $self->{'fields'}{'Source'}; - my $basenamerev = $self->get_basename(1); my $basedirname = $self->get_basename(); $basedirname =~ s/_/-/; @@ -369,23 +367,21 @@ sub generate_patch { $self->apply_patches($tmp, skip_auto => 1, usage => 'build'); # Create a patch - my $autopatch = File::Spec->catfile($dir, "debian", "patches", - $self->get_autopatch_name()); my ($difffh, $tmpdiff) = tempfile("$basenamerev.diff.XXXXXX", DIR => $updir, UNLINK => 0); push @Dpkg::Exit::handlers, sub { unlink($tmpdiff) }; my $diff = Dpkg::Source::Patch->new(filename => $tmpdiff, compression => "none"); $diff->create(); - $diff->set_header($self->get_patch_header($dir, $autopatch)); + $diff->set_header($self->get_patch_header($dir)); $diff->add_diff_directory($tmp, $dir, basedirname => $basedirname, %{$self->{'diff_options'}}, handle_binary_func => $opts{'handle_binary'}, order_from => $opts{'order_from'}); error(_g("unrepresentable changes to source")) if not $diff->finish(); - if (-s $autopatch) { - info(_g("local changes stored in %s, the modified files are:"), $autopatch); + if (-s $tmpdiff) { + info(_g("local changes detected, the modified files are:")); my $analysis = $diff->analyze($dir, verbose => 0); foreach my $fn (sort keys %{$analysis->{'filepatched'}}) { print " $fn\n"; @@ -509,6 +505,7 @@ sub do_build { if (-e $autopatch and $self->{'options'}{'abort_on_upstream_changes'}) { error(_g("aborting due to --abort-on-upstream-changes")); } + info(_g("local changes have been recorded in a new patch: %s"), $autopatch); rmdir(File::Spec->catdir($dir, "debian", "patches")); # No check on purpose unlink($tmpdiff) || syserr(_g("cannot remove %s"), $tmpdiff); pop @Dpkg::Exit::handlers; -- 1.7.5.4
>From 47f2b6f03cead378b8657cdfe14af093b026707c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Hertzog?= <hert...@debian.org> Date: Thu, 14 Jul 2011 20:31:33 +0200 Subject: [PATCH 6/6] dpkg-source: implement --commit and fail with unrecorded changes Formats "2.0" and "3.0 (quilt)" now fail by default in presence of changes to upstream files that are not managed by their respective patch system. The user is invited to run dpkg-source --commit if he wants to keep the changes. This will avoid that maintainers upload packages with unexpected changes. The old behaviour can be kept with the option --auto-commit. The option --abort-on-upstream-changes is now useless with formats "2.0" and "3.0 (quilt)" except to cancel the effect of a former --auto-commit. See http://lists.debian.org/20110529085303.ga17...@rivendell.home.ouaza.com for the discussion that enterined this change. --- debian/changelog | 6 +++ man/dpkg-source.1 | 29 ++++++++++++++-- scripts/Dpkg/Source/Package.pm | 8 ++++- scripts/Dpkg/Source/Package/V2.pm | 70 +++++++++++++++++++++++++++++++----- scripts/dpkg-source.pl | 22 ++++++++--- 5 files changed, 115 insertions(+), 20 deletions(-) diff --git a/debian/changelog b/debian/changelog index 293e0f5..6b4f4d5 100644 --- a/debian/changelog +++ b/debian/changelog @@ -85,6 +85,12 @@ dpkg (1.16.1) UNRELEASED; urgency=low Closes: #606839 * Fix the dpkg-divert test-suite to also skip test that would fail if run under root. Closes: #634961 + * With source format 2.0 and 3.0 (quilt), dpkg-source now fails by default + when upstream changes have not been recorded in a quilt patch. The new + option --commit can be used to properly record the changes before-hand. + LP: #797839 + And it fails before installing the automatic patch in debian/patches/ + Closes: #615899 [ Guillem Jover ] * Install deb-src-control(5) man pages in dpkg-dev. Closes: #620520 diff --git a/man/dpkg-source.1 b/man/dpkg-source.1 index 025f7db..1e45974 100644 --- a/man/dpkg-source.1 +++ b/man/dpkg-source.1 @@ -1,5 +1,5 @@ .\" Authors: Ian Jackson, Raphaël Hertzog -.TH dpkg\-source 1 "2011-07-04" "Debian Project" "dpkg utilities" +.TH dpkg\-source 1 "2011-07-12" "Debian Project" "dpkg utilities" .SH NAME dpkg\-source \- Debian source package (.dsc) manipulation tool . @@ -88,6 +88,12 @@ all source formats implement something in this hook, and those that do usually use it to undo what \fB\-\-before\-build\fP has done. .TP +.RI "\fB\-\-commit\fP [" directory "] ..." +Record changes in the source tree unpacked in \fIdirectory\fP. This +command can take supplementary parameters depending on the source format. +It will error out for formats where this operation doesn't mean anything. + +.TP .BR \-h ", " \-\-help Show the usage message and exit. .TP @@ -437,7 +443,9 @@ debian directory is copied over in the temporary directory, and all patches except the automatic patch (\fBdebian-changes-\fP\fIversion\fP or \fBdebian-changes\fP, depending on \fB\-\-single\-debian\-patch\fP) are applied. The temporary directory is compared to the source package -directory and the diff (if non-empty) is stored in the automatic patch. +directory. When the diff is non-empty, the build fails unless +\fB\-\-single\-debian\-patch\fP or \fB\-\-auto\-commit\fP +has been used. In the latter case, the diff is stored in the automatic patch. If the automatic patch is created/deleted, it's added/removed from the series file and from the quilt metadata. @@ -466,6 +474,17 @@ unapplied patches (they are listed in the \fBseries\fP file but not in applied without errors, it will apply them all. The option \fB\-\-no\-preparation\fP can be used to disable this behavior. +.PP Recording changes +.RI "\fB\-\-commit " [ directory "] [" patch-name "] [" patch-file ] +Generates a patch corresponding to the local changes that are not managed +by the quilt patch system and integrates it in the patch system under +the name \fIpatch-name\fP. If the name is missing, it will be asked +interactively. If \fIpatch-file\fP is given, it is used as the patch +corresponding to the local changes to integrate. This is mainly useful +after a build failure that pre-generated this file. Once integrated, an +editor is launched so that you can edit the meta-information in the patch +header. + .PP .B Build options .TP @@ -523,6 +542,10 @@ can be used to ensure that all changes were properly recorded in separate quilt patches prior to the source package build. This option is not allowed in \fBdebian/source/options\fP but can be used in \fBdebian/source/local\-options\fP. +.TP +.B \-\-auto\-commit +The process doesn't fail if an automatic patch has been generated, instead +it's immediately recorded in the quilt series. .PP .B Extract options @@ -704,7 +727,7 @@ Copyright \(co 1995-1996 Ian Jackson .br Copyright \(co 2000 Wichert Akkerman .br -Copyright \(co 2008-2010 Rapha\[:e]l Hertzog +Copyright \(co 2008-2011 Rapha\[:e]l Hertzog .sp This is free software; see the GNU General Public Licence version 2 or later for copying conditions. There is NO WARRANTY. diff --git a/scripts/Dpkg/Source/Package.pm b/scripts/Dpkg/Source/Package.pm index 21089a2..94e6b8f 100644 --- a/scripts/Dpkg/Source/Package.pm +++ b/scripts/Dpkg/Source/Package.pm @@ -1,4 +1,4 @@ -# Copyright © 2008 Raphaël Hertzog <hert...@debian.org> +# Copyright © 2008-2011 Raphaël Hertzog <hert...@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 @@ -512,6 +512,12 @@ sub add_file { use_files_for_md5 => 1); } +sub commit { + my ($self, $dir) = @_; + info(_g("'%s' is not supported by the source format '%s'"), + "dpkg-source --commit", $self->{'fields'}{'Format'}); +} + sub write_dsc { my ($self, %opts) = @_; my $fields = $self->{'fields'}; diff --git a/scripts/Dpkg/Source/Package/V2.pm b/scripts/Dpkg/Source/Package/V2.pm index 9a16cc6..1ea18bd 100644 --- a/scripts/Dpkg/Source/Package/V2.pm +++ b/scripts/Dpkg/Source/Package/V2.pm @@ -63,8 +63,8 @@ sub init_options { unless exists $self->{'options'}{'skip_debianization'}; $self->{'options'}{'create_empty_orig'} = 0 unless exists $self->{'options'}{'create_empty_orig'}; - $self->{'options'}{'abort_on_upstream_changes'} = 0 - unless exists $self->{'options'}{'abort_on_upstream_changes'}; + $self->{'options'}{'auto_commit'} = 0 + unless exists $self->{'options'}{'auto_commit'}; } sub parse_cmdline_option { @@ -94,7 +94,10 @@ sub parse_cmdline_option { $self->{'options'}{'create_empty_orig'} = 1; return 1; } elsif ($opt =~ /^--abort-on-upstream-changes$/) { - $self->{'options'}{'abort_on_upstream_changes'} = 1; + $self->{'options'}{'auto_commit'} = 0; + return 1; + } elsif ($opt =~ /^--auto-commit$/) { + $self->{'options'}{'auto_commit'} = 1; return 1; } return 0; @@ -340,8 +343,10 @@ sub generate_patch { error(_g("no upstream tarball found at %s"), $self->upstream_tarball_template()) unless $tarfile; - info(_g("building %s using existing %s"), - $sourcepackage, "@origtarballs"); + if ($opts{'usage'} eq "build") { + info(_g("building %s using existing %s"), + $self->{'fields'}{'Source'}, "@origtarballs"); + } # Unpack a second copy for comparison my $tmp = tempdir("$dirname.orig.XXXXXX", DIR => $updir); @@ -367,8 +372,8 @@ sub generate_patch { $self->apply_patches($tmp, skip_auto => 1, usage => 'build'); # Create a patch - my ($difffh, $tmpdiff) = tempfile("$basenamerev.diff.XXXXXX", - DIR => $updir, UNLINK => 0); + my ($difffh, $tmpdiff) = tempfile($self->get_basename(1) . ".diff.XXXXXX", + DIR => File::Spec->tmpdir(), UNLINK => 0); push @Dpkg::Exit::handlers, sub { unlink($tmpdiff) }; my $diff = Dpkg::Source::Patch->new(filename => $tmpdiff, compression => "none"); @@ -497,14 +502,18 @@ sub do_build { handle_binary => $handle_binary, usage => 'build'); push @Dpkg::Exit::handlers, sub { unlink($tmpdiff) }; + unless (not -s $tmpdiff or $self->{'options'}{'single_debian_patch'} + or $self->{'options'}{'auto_commit'}) { + info(_g("you can integrate the local changes with %s"), + "dpkg-source --commit . '' $tmpdiff"); + error(_g("aborting due to unexpected upstream changes, see %s"), + $tmpdiff); + } # Install the diff as the new autopatch mkpath(File::Spec->catdir($dir, "debian", "patches")); $autopatch = $self->register_patch($dir, $tmpdiff, $self->get_autopatch_name()); - if (-e $autopatch and $self->{'options'}{'abort_on_upstream_changes'}) { - error(_g("aborting due to --abort-on-upstream-changes")); - } info(_g("local changes have been recorded in a new patch: %s"), $autopatch); rmdir(File::Spec->catdir($dir, "debian", "patches")); # No check on purpose unlink($tmpdiff) || syserr(_g("cannot remove %s"), $tmpdiff); @@ -597,5 +606,46 @@ sub register_patch { return $patch; } +sub commit { + my ($self, $dir) = @_; + my ($patch_name, $tmpdiff) = @{$self->{'options'}{'ARGV'}}; + + sub bad_patch_name { + my ($dir, $patch_name) = @_; + return 1 if not defined($patch_name); + return 1 if not length($patch_name); + my $patch = File::Spec->catfile($dir, "debian", "patches", $patch_name); + if (-e $patch) { + warning(_g("cannot register changes in %s, this patch already exists"), $patch); + return 1; + } + return 0; + } + + $self->prepare_build($dir); + + unless ($tmpdiff && -e $tmpdiff) { + $tmpdiff = $self->generate_patch($dir, usage => "commit"); + } + push @Dpkg::Exit::handlers, sub { unlink($tmpdiff) }; + unless (-s $tmpdiff) { + unlink($tmpdiff) || syserr(_g("cannot remove %s"), $tmpdiff); + info(_g("there are no local changes to record")); + return; + } + while (bad_patch_name($dir, $patch_name)) { + # Ask the patch name interactively + print STDOUT _g("Enter the desired patch name: "); + chomp($patch_name = <STDIN>); + $patch_name =~ s/\s+/-/g; + $patch_name =~ s/\///g; + } + my $patch = $self->register_patch($dir, $tmpdiff, $patch_name); + system("sensible-editor", $patch); + unlink($tmpdiff) || syserr(_g("cannot remove %s"), $tmpdiff); + pop @Dpkg::Exit::handlers; + info(_g("local changes have been recorded in a new patch: %s"), $patch); +} + # vim:et:sw=4:ts=8 1; diff --git a/scripts/dpkg-source.pl b/scripts/dpkg-source.pl index 6279fc1..1b90491 100755 --- a/scripts/dpkg-source.pl +++ b/scripts/dpkg-source.pl @@ -87,6 +87,8 @@ while (@ARGV && $ARGV[0] =~ m/^-/) { setopmode('-x'); } elsif (m/^--(before|after)-build$/) { setopmode($_); + } elsif (m/^--commit$/) { + setopmode($_); } elsif (m/^--print-format$/) { setopmode('--print-format'); report_options(info_fh => \*STDERR); # Avoid clutter on STDOUT @@ -97,11 +99,14 @@ while (@ARGV && $ARGV[0] =~ m/^-/) { my $dir; if (defined($options{'opmode'}) && - $options{'opmode'} =~ /^(-b|--print-format|--before-build|--after-build)$/) { + $options{'opmode'} =~ /^(-b|--print-format|--(before|after)-build|--commit)$/) { if (not scalar(@ARGV)) { - usageerr(_g("%s needs a directory"), $options{'opmode'}); + usageerr(_g("%s needs a directory"), $options{'opmode'}) + unless $1 eq "--commit"; + $dir = "."; + } else { + $dir = File::Spec->catdir(shift(@ARGV)); } - $dir = File::Spec->catdir(shift(@ARGV)); stat($dir) || syserr(_g("cannot stat directory %s"), $dir); if (not -d $dir) { error(_g("directory argument %s is not a directory"), $dir); @@ -206,10 +211,10 @@ while (@options) { } unless (defined($options{'opmode'})) { - usageerr(_g("need a command (-x, -b, --before-build, --after-build, --print-format)")); + usageerr(_g("need a command (-x, -b, --before-build, --after-build, --print-format, --commit)")); } -if ($options{'opmode'} =~ /^(-b|--print-format|--(before|after)-build)$/) { +if ($options{'opmode'} =~ /^(-b|--print-format|--(before|after)-build|--commit)$/) { $options{'ARGV'} = \@ARGV; @@ -363,6 +368,9 @@ if ($options{'opmode'} =~ /^(-b|--print-format|--(before|after)-build)$/) { } elsif ($options{'opmode'} eq "--after-build") { $srcpkg->after_build($dir); exit(0); + } elsif ($options{'opmode'} eq "--commit") { + $srcpkg->commit($dir); + exit(0); } # Verify pre-requisites are met @@ -466,7 +474,9 @@ Commands: extract source package. -b <dir> build source package. --print-format <dir> print the source format that would be - used to build the source package.") + used to build the source package. + --commit [<dir> [<patch-name>]] + store upstream changes in a new patch.") . "\n\n" . _g( "Build options: -c<controlfile> get control info from this file. -- 1.7.5.4