Sfoglia il codice sorgente

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.GA17707@rivendell.home.ouaza.com
for the discussion that enterined this change.
Raphaël Hertzog 15 anni fa
parent
commit
46b688e482

+ 6 - 0
debian/changelog

@@ -87,6 +87,12 @@ dpkg (1.16.1) UNRELEASED; urgency=low
     under root. Closes: #634961
   * Change merge conflict separators created by dpkg-mergechangelogs to match
     the usual norm of being composed of 7 characters. LP: #815700
+  * 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
+    --commit operation 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

+ 29 - 3
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
 .
@@ -87,6 +87,12 @@ last). This command is idempotent and can be called multiple times. Not
 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.
@@ -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,20 @@ 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
+.B Recording changes
+.TP
+.RI "\fB\-\-commit\fP [" 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 +545,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 +730,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.

+ 7 - 1
scripts/Dpkg/Source/Package.pm

@@ -1,4 +1,4 @@
-# Copyright © 2008 Raphaël Hertzog <hertzog@debian.org>
+# Copyright © 2008-2011 Raphaël Hertzog <hertzog@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'};

+ 59 - 9
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"),
-         $self->{'fields'}{'Source'}, "@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);
@@ -368,7 +373,7 @@ sub generate_patch {
 
     # Create a patch
     my ($difffh, $tmpdiff) = tempfile($self->get_basename(1) . ".diff.XXXXXX",
-                                      DIR => $updir, UNLINK => 0);
+                                      DIR => File::Spec->tmpdir(), UNLINK => 0);
     push @Dpkg::Exit::handlers, sub { unlink($tmpdiff) };
     my $diff = Dpkg::Source::Patch->new(filename => $tmpdiff,
                                         compression => "none");
@@ -496,15 +501,19 @@ sub do_build {
     my $tmpdiff = $self->generate_patch($dir, order_from => $autopatch,
                                         handle_binary => $handle_binary,
                                         usage => 'build');
+    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);
+    }
     push @Dpkg::Exit::handlers, sub { unlink($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;

+ 16 - 6
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.