Sfoglia il codice sorgente

dpkg-source: new --unapply-patches option

This option is used by source formats 2.0 and 3.0 (quilt) to unapply
patches after a successful build. It's useful for people who manage their
packages in a VCS repository and prefer to have patches unapplied, even
after a package build.

Given that this option is a matter of personal taste, do not allow it
in debian/source/options so that the resulting source package cannot
have this behaviour by default and so that all source packages behave
in a consistent way: patches applied by default is a major feature
of the new formats.
Raphaël Hertzog 16 anni fa
parent
commit
2b204533b8

+ 4 - 0
debian/changelog

@@ -31,6 +31,10 @@ dpkg (1.15.8) UNRELEASED; urgency=low
   * update-alternatives has been rewritten in C, the only feature change
     should be that it uses its own logfile /var/log/alternatives.log (rotated
     like dpkg.log).
+  * Implement new --unapply-patches option for dpkg-source with source formats
+    2.0 and 3.0 (quilt) that unapplies the patches after a successful build.
+    This option can be put in debian/source/local-options in the package VCS
+    repository for instance.
 
   [ Guillem Jover ]
   * Require gettext 0.18:

+ 9 - 0
man/dpkg-source.1

@@ -506,6 +506,15 @@ Automatically create the main original tarball as empty if it's missing
 and if there are supplementary original tarballs. This option is meant to
 be used when the source package is just a bundle of multiple upstream
 software and where there's no "main" software.
+.TP
+.B \-\-unapply\-patches
+Unapply the patches in the \fB\-\-after\-build\fP hook. This is mainly
+useful when you build your package directly in a VCS that contains
+unpatched upstream source and where you want to keep the tree unpatched
+even after a package build. This option is usually put in
+\fBdebian/source/local\-options\fP (it's not allowed in
+\fBdebian/source/options\fP so that all generated source packages have the
+same behaviour by default).
 
 .PP
 .B Extract options

+ 27 - 0
scripts/Dpkg/Source/Package/V2.pm

@@ -53,6 +53,8 @@ sub init_options {
         unless exists $self->{'options'}{'preparation'};
     $self->{'options'}{'skip_patches'} = 0
         unless exists $self->{'options'}{'skip_patches'};
+    $self->{'options'}{'unapply_patches'} = 0
+        unless exists $self->{'options'}{'unapply_patches'};
     $self->{'options'}{'skip_debianization'} = 0
         unless exists $self->{'options'}{'skip_debianization'};
     $self->{'options'}{'create_empty_orig'} = 0
@@ -76,6 +78,9 @@ sub parse_cmdline_option {
     } elsif ($opt =~ /^--skip-patches$/) {
         $self->{'options'}{'skip_patches'} = 1;
         return 1;
+    } elsif ($opt =~ /^--unapply-patches$/) {
+        $self->{'options'}{'unapply_patches'} = 1;
+        return 1;
     } elsif ($opt =~ /^--skip-debianization$/) {
         $self->{'options'}{'skip_debianization'} = 1;
         return 1;
@@ -206,6 +211,23 @@ sub apply_patches {
     close(APPLIED);
 }
 
+sub unapply_patches {
+    my ($self, $dir, %opts) = @_;
+    my @patches = reverse($self->get_patches($dir, %opts));
+    return unless scalar(@patches);
+    my $timestamp = time();
+    my $applied = File::Spec->catfile($dir, "debian", "patches", ".dpkg-source-applied");
+    foreach my $patch (@patches) {
+        my $path = File::Spec->catfile($dir, "debian", "patches", $patch);
+        info(_g("unapplying %s"), $patch) unless $opts{"quiet"};
+        my $patch_obj = Dpkg::Source::Patch->new(filename => $path);
+        $patch_obj->apply($dir, force_timestamp => 1,
+                          timestamp => $timestamp,
+                          add_options => [ '-E', '-R' ]);
+    }
+    unlink($applied);
+}
+
 sub can_build {
     my ($self, $dir) = @_;
     return 1 if $self->find_original_tarballs(include_supplementary => 0);
@@ -219,6 +241,11 @@ sub before_build {
     $self->check_patches_applied($dir) if $self->{'options'}{'preparation'};
 }
 
+sub after_build {
+    my ($self, $dir) = @_;
+    $self->unapply_patches($dir) if $self->{'options'}{'unapply_patches'};
+}
+
 sub prepare_build {
     my ($self, $dir) = @_;
     $self->{'diff_options'} = {

+ 23 - 0
scripts/Dpkg/Source/Package/V3/quilt.pm

@@ -227,6 +227,29 @@ sub apply_patches {
     close(APPLIED);
 }
 
+sub unapply_patches {
+    my ($self, $dir, %opts) = @_;
+
+    $opts{'verbose'} = 1 unless defined $opts{'verbose'};
+
+    my $pc_applied = File::Spec->catfile($dir, ".pc", "applied-patches");
+    my @applied = $self->read_patch_list($pc_applied);
+    $opts{"timestamp"} = time();
+    foreach my $patch (reverse @applied) {
+        my $path = File::Spec->catfile($dir, "debian", "patches", $patch);
+        my $obj = Dpkg::Source::Patch->new(filename => $path);
+
+        info(_g("unapplying %s"), $patch) if $opts{"verbose"};
+        $obj->apply($dir, timestamp => $opts{"timestamp"},
+                    force_timestamp => 1, remove_backup => 0,
+                    options => [ '-R', '-s', '-t', '-N', '-p1',
+                                 '-u', '-V', 'never', '-g0', '-E',
+                                 '--no-backup-if-mismatch' ]);
+        erasedir(File::Spec->catdir($dir, ".pc", $patch));
+    }
+    unlink($pc_applied);
+}
+
 sub prepare_build {
     my ($self, $dir) = @_;
     $self->SUPER::prepare_build($dir);

+ 10 - 4
scripts/dpkg-source.pl

@@ -104,15 +104,21 @@ if (defined($options{'opmode'}) &&
     if (not -d $dir) {
 	error(_g("directory argument %s is not a directory"), $dir);
     }
+    # --format options are not allowed, they would take precedence
+    # over real command line options, debian/source/format should be used
+    # instead
+    # --unapply-patches is only allowed in local-options as it's a matter
+    # of personal taste and the default should be to keep patches applied
+    my $forbidden_opts_re = {
+	"options" => qr/^--(?:format=|unapply-patches$)/,
+	"local-options" => qr/^--format=/,
+    };
     foreach my $filename ("local-options", "options") {
 	my $conf = Dpkg::Conf->new();
 	my $optfile = File::Spec->catfile($dir, "debian", "source", $filename);
 	next unless -f $optfile;
 	$conf->load($optfile);
-	# --format options are not allowed, they would take precedence
-	# over real command line options, debian/source/format should be used
-	# instead
-	@$conf = grep { ! /^--format=/ } @$conf;
+	$conf->filter(remove => sub { $_[0] =~ $forbidden_opts_re->{$filename} });
 	if (@$conf) {
 	    info(_g("using options from %s: %s"), $optfile, join(" ", @$conf))
 		unless $options{'opmode'} eq "--print-format";