[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Bug#563546: pu: package dpkg/1.14.28



Package: release.debian.org
Severity: normal
User: release.debian.org@packages.debian.org
Usertags: pu

I'd like to update dpkg in stable another time to include more
fixes/improvements made to new source formats in sid since the last time.
I expect this update to be the last one.

The reason that I want this update in stable is that dpkg-source now
creates quilt's .pc directory. This change has been requested by the
release team and several people and having this in stable will let people
use quilt in debian/rules. Up to now they could not because old buildd
extract the source package outside of the build chroot and thus would not
get the .pc directory required by quilt.

See #557667 mainly for some discussion.

You can review the individual commits here:
http://git.debian.org/?p=users/hertzog/dpkg.git;a=shortlog;h=refs/heads/pu/stable-update

This code is working fine in sid since several weeks and I tested the
updated dpkg on lenny as well.

I also attach a full git diff between 1.14.27 and the proposed 1.14.28.
If it's ok for you, I'll upload it. Thanks!

-- System Information:
Debian Release: squeeze/sid
  APT prefers unstable
  APT policy: (500, 'unstable'), (500, 'testing'), (500, 'stable'), (150, 'experimental')
Architecture: i386 (x86_64)

Kernel: Linux 2.6.32-trunk-amd64 (SMP w/2 CPU cores)
Locale: LANG=fr_FR.UTF-8, LC_CTYPE=fr_FR.UTF-8 (charmap=UTF-8)
Shell: /bin/sh linked to /bin/dash

-- 
Raphaël Hertzog
 debian/changelog                        |   20 ++
 man/dpkg-source.1                       |   35 ++--
 scripts/Dpkg/Source/Package/V2.pm       |   50 ++++-
 scripts/Dpkg/Source/Package/V3/quilt.pm |  326 ++++++++++++++++---------------
 4 files changed, 250 insertions(+), 181 deletions(-)

diff --git a/debian/changelog b/debian/changelog
index 5b2d048..afa5980 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,23 @@
+dpkg (1.14.28) UNRELEASED; urgency=low
+
+  * Another round of updates concerning new source formats:
+    - fix dpkg-source to not complain on binary files that are ignored and are
+      not going to be included in the debian tarball of a "3.0 (quilt)" source
+      package. Closes: #524375
+    - let dpkg-source fail if several upstream orig.tar files are
+      available (using different compression scheme) since we don't know
+      which one to use.
+    - before accepting to build a 3.0 (quilt) source packages, ensure that
+      debian/patches is a directory (or non-existing) and that
+      debian/patches/series is a file (or non-existing). Closes: #557618
+    - modify implementation of "3.0 (quilt)" source format to not be
+      behave differently depending on whether quilt is installed or not.
+      The option --without-quilt is thus gone and dpkg-source creates and
+      relies on the .pc directory to know whether patches are applied or
+      not. Closes: #557667
+
+ -- Raphael Hertzog <hertzog@debian.org>  Sun, 03 Jan 2010 18:21:35 +0100
+
 dpkg (1.14.27) stable; urgency=low
 
   * Cherry-pick some fixes from squeeze concerning new source formats:
diff --git a/man/dpkg-source.1 b/man/dpkg-source.1
index 2b5bf7d..838a8fd 100644
--- a/man/dpkg-source.1
+++ b/man/dpkg-source.1
@@ -371,7 +371,7 @@ such options, and the build is likely to fail.
 .PP
 Similarly to quilt's default behaviour, the patches can remove files too.
 .PP
-The file \fBdebian/patches/.dpkg-source-applied\fP is created if some
+The file \fB.pc/applied-patches\fP is created if some
 patches have been applied during the extraction.
 .PP
 .B Building
@@ -400,18 +400,28 @@ files as well as many temporary files (see default value associated to
 automatic patch.
 
 Note: \fBdpkg\-source\fP expects the source tree to have all patches
-applied when you generate the source package. This is not the case
-when the source tree has been obtained by unpacking a source package using
-the Format: 1.0 for instance. To mitigate the problem, \fBdpkg\-source\fP
-will apply patches before building unless it finds
-\fBdebian/patches/.dpkg-source-applied\fP. The presence of a \fB.pc\fP
-subdirectory is also interpreted as a sign that some patches have been
-applied and in this case \fBquilt unapplied\fP is called to verify that
-all patches are applied. The option \fB\-\-no\-preparation\fP can be used
-to disable this behaviour.
+applied when you generate the source package.
+This is not the case when the source tree has been obtained by unpacking a
+source package using the Format: 1.0 for instance. To mitigate the
+problem, \fBdpkg\-source\fP will apply the patches by itself if it
+believes that they have not yet been applied. To detect this situation, it
+uses the following heuristic: it finds the list of supposedly unapplied
+patches (they are listed in the \fBseries\fP file but not in
+\fB.pc/applied-patches\fP), and if the first patch in that set can be
+applied without errors, it will apply them all.
+The option \fB\-\-no\-preparation\fP can be used to disable this
+behaviour.
 .PP
 .B Build options
 .TP
+.BI \-\-allow\-version\-of\-quilt\-db= version
+Allow \fBdpkg\-source\fP to build the source package if the version of
+the quilt metadata is the one specified, even if \fBdpkg\-source\fP
+doesn't know about it. Effectively this says that the given version of the
+quilt metadata is compatible with the version 2 that \fBdpkg\-source\fP
+currently supports. The version of the quilt metadata is stored in
+\fB.pc/.version\fP.
+.TP
 .B \-\-include\-removal
 Do not ignore removed files and include them in the automatically
 generated patch.
@@ -432,11 +442,6 @@ apparently unapplied.
 .TP
 .B \-\-skip\-patches
 Do not apply patches at the end of the extraction.
-.TP
-.B \-\-without\-quilt
-Don't use quilt to apply patches but dpkg-source's own code. It won't be
-possible to use quilt directly on the unpacked directory but it will be
-free of quilt's temporary files as well.
 .
 .SS Format: 3.0 (custom)
 This format is particular. It doesn't represent a real source package
diff --git a/scripts/Dpkg/Source/Package/V2.pm b/scripts/Dpkg/Source/Package/V2.pm
index a162f53..e7fb9d8 100644
--- a/scripts/Dpkg/Source/Package/V2.pm
+++ b/scripts/Dpkg/Source/Package/V2.pm
@@ -148,7 +148,8 @@ sub do_extract {
                   @exclude_symlinks ]);
 
     # Apply patches (in a separate method as it might be overriden)
-    $self->apply_patches($newdirectory) unless $self->{'options'}{'skip_patches'};
+    $self->apply_patches($newdirectory, usage => 'unpack')
+        unless $self->{'options'}{'skip_patches'};
 }
 
 sub get_autopatch_name {
@@ -156,7 +157,8 @@ sub get_autopatch_name {
 }
 
 sub get_patches {
-    my ($self, $dir, $skip_auto) = @_;
+    my ($self, $dir, %opts) = @_;
+    $opts{"skip_auto"} = 0 unless defined($opts{"skip_auto"});
     my @patches;
     my $pd = "$dir/debian/patches";
     my $auto_patch = $self->get_autopatch_name();
@@ -165,7 +167,7 @@ sub get_patches {
         foreach my $patch (sort readdir(DIR)) {
             # patches match same rules as run-parts
             next unless $patch =~ /^[\w-]+$/ and -f "$pd/$patch";
-            next if $skip_auto and $patch eq $auto_patch;
+            next if $opts{"skip_auto"} and $patch eq $auto_patch;
             push @patches, $patch;
         }
         closedir(DIR);
@@ -174,15 +176,16 @@ sub get_patches {
 }
 
 sub apply_patches {
-    my ($self, $dir, $skip_auto) = @_;
-    my @patches = $self->get_patches($dir, $skip_auto);
+    my ($self, $dir, %opts) = @_;
+    $opts{"skip_auto"} = 0 unless defined($opts{"skip_auto"});
+    my @patches = $self->get_patches($dir, %opts);
     return unless scalar(@patches);
     my $timestamp = time();
     my $applied = File::Spec->catfile($dir, "debian", "patches", ".dpkg-source-applied");
     open(APPLIED, '>', $applied) || syserr(_g("cannot write %s"), $applied);
-    foreach my $patch ($self->get_patches($dir, $skip_auto)) {
+    foreach my $patch ($self->get_patches($dir, %opts)) {
         my $path = File::Spec->catfile($dir, "debian", "patches", $patch);
-        info(_g("applying %s"), $patch) unless $skip_auto;
+        info(_g("applying %s"), $patch) unless $opts{"skip_auto"};
         my $patch_obj = Dpkg::Source::Patch->new(filename => $path);
         $patch_obj->apply($dir, force_timestamp => 1,
                           timestamp => $timestamp,
@@ -217,7 +220,7 @@ sub check_patches_applied {
     my $applied = File::Spec->catfile($dir, "debian", "patches", ".dpkg-source-applied");
     unless (-e $applied) {
         warning(_g("patches have not been applied, applying them now (use --no-preparation to override)"));
-        $self->apply_patches($dir);
+        $self->apply_patches($dir, usage => 'preparation');
     }
 }
 
@@ -245,6 +248,10 @@ sub do_build {
     my @origtarballs;
     foreach (sort $self->find_original_tarballs()) {
         if (/\.orig\.tar\.$comp_regex$/) {
+            if (defined($tarfile)) {
+                error(_g("several orig.tar files found (%s and %s) but only " .
+                         "one is allowed"), $tarfile, $_);
+            }
             $tarfile = $_;
             push @origtarballs, $_;
             $self->add_file($_);
@@ -280,7 +287,7 @@ sub do_build {
     subprocerr(_g("copy of the debian directory")) if $?;
 
     # Apply all patches except the last automatic one
-    $self->apply_patches($tmp, 1);
+    $self->apply_patches($tmp, skip_auto => 1, usage => 'build');
 
     # Prepare handling of binary files
     my %auth_bin_files;
@@ -324,7 +331,30 @@ sub do_build {
             }
         }
     };
-    find({ wanted => $check_binary, no_chdir => 1 }, File::Spec->catdir($dir, "debian"));
+    my $tar_ignore_glob = "{" . join(",",
+        map {
+            my $copy = $_;
+            $copy =~ s/,/\\,/g;
+            $copy;
+        } @{$self->{'options'}{'tar_ignore'}}) . "}";
+    my $filter_ignore = sub {
+        # Filter out files that are not going to be included in the debian
+        # tarball due to ignores.
+        my %exclude;
+        my $reldir = File::Spec->abs2rel($File::Find::dir, $dir);
+        foreach my $fn (glob($tar_ignore_glob)) {
+            $exclude{$fn} = 1;
+        }
+        my @result;
+        foreach my $fn (@_) {
+            unless (exists $exclude{$fn} or exists $exclude{"$reldir/$fn"}) {
+                push @result, $fn;
+            }
+        }
+        return @result;
+    };
+    find({ wanted => $check_binary, preprocess => $filter_ignore,
+           no_chdir => 1 }, File::Spec->catdir($dir, "debian"));
     error(_g("detected %d unwanted binary file(s) " .
         "(add them in debian/source/include-binaries to allow their " .
         "inclusion)."), $unwanted_binaries) if $unwanted_binaries;
diff --git a/scripts/Dpkg/Source/Package/V3/quilt.pm b/scripts/Dpkg/Source/Package/V3/quilt.pm
index 5b45f6c..4ec79c3 100644
--- a/scripts/Dpkg/Source/Package/V3/quilt.pm
+++ b/scripts/Dpkg/Source/Package/V3/quilt.pm
@@ -1,5 +1,5 @@
-# Copyright 2008 Raphaël Hertzog <hertzog@debian.org>
-
+# Copyright © 2008-2009 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
 # the Free Software Foundation; either version 2 of the License, or
@@ -26,6 +26,7 @@ use Dpkg;
 use Dpkg::Gettext;
 use Dpkg::ErrorHandling qw(error syserr warning usageerr subprocerr info);
 use Dpkg::Source::Patch;
+use Dpkg::Source::Functions qw(erasedir);
 use Dpkg::IPC;
 
 use POSIX;
@@ -37,22 +38,40 @@ our $CURRENT_MINOR_VERSION = "0";
 
 sub init_options {
     my ($self) = @_;
+    $self->{'options'}{'allow-version-of-quilt-db'} = []
+        unless exists $self->{'options'}{'allow-version-of-quilt-db'};
+
     $self->SUPER::init_options();
-    # By default use quilt, unless it's not available
-    $self->{'options'}{'without_quilt'} = (-x "/usr/bin/quilt") ? 0 : 1
-        unless exists $self->{'options'}{'without_quilt'};
 }
 
 sub parse_cmdline_option {
     my ($self, $opt) = @_;
     return 1 if $self->SUPER::parse_cmdline_option($opt);
-    if ($opt =~ /^--without-quilt$/) {
-        $self->{'options'}{'without_quilt'} = 1;
+    if ($opt =~ /^--allow-version-of-quilt-db=(.*)$/) {
+        push @{$self->{'options'}{'allow-version-of-quilt-db'}}, $1;
         return 1;
     }
     return 0;
 }
 
+sub can_build {
+    my ($self, $dir) = @_;
+    my ($code, $msg) = $self->SUPER::can_build($dir);
+    return ($code, $msg) if $code eq 0;
+    my $pd = File::Spec->catdir($dir, "debian", "patches");
+    if (-e $pd and not -d _) {
+        return (0, sprintf(_g("%s should be a directory or non-existing"), $pd));
+    }
+    my $series_vendor = $self->get_series_file($dir);
+    my $series_main = File::Spec->catfile($pd, "series");
+    foreach my $series ($series_vendor, $series_main) {
+        if (defined($series) and -e $series and not -f _) {
+            return (0, sprintf(_g("%s should be a file or non-existing"), $series));
+        }
+    }
+    return (1, "");
+}
+
 sub get_autopatch_name {
     my ($self) = @_;
     return "debian-changes-" . $self->{'fields'}{'Version'};
@@ -70,60 +89,80 @@ sub get_series_file {
     return undef;
 }
 
-sub get_patches {
-    my ($self, $dir, $skip_auto) = @_;
+sub read_patch_list {
+    my ($self, $file, %opts) = @_;
+    return () if not defined $file or not -f $file;
+    $opts{"warn_options"} = 0 unless defined($opts{"warn_options"});
+    $opts{"skip_auto"} = 0 unless defined($opts{"skip_auto"});
     my @patches;
     my $auto_patch = $self->get_autopatch_name();
-    my $series = $self->get_series_file($dir);
-    if (defined($series)) {
-        open(SERIES, "<" , $series) || syserr(_g("cannot read %s"), $series);
-        while(defined($_ = <SERIES>)) {
-            chomp; s/^\s+//; s/\s+$//; # Strip leading/trailing spaces
-            s/(^|\s+)#.*$//; # Strip comment
-            next unless $_;
-            if (/^(\S+)\s+(.*)$/) {
-                $_ = $1;
-                if ($2 ne '-p1') {
-                    warning(_g("the series file (%s) contains unsupported " .
-                               "options ('%s', line %s), dpkg-source might " .
-                               "fail when applying patches."),
-                            $series, $2, $.) unless $skip_auto;
-                }
+    open(SERIES, "<" , $file) || syserr(_g("cannot read %s"), $file);
+    while(defined($_ = <SERIES>)) {
+        chomp; s/^\s+//; s/\s+$//; # Strip leading/trailing spaces
+        s/(^|\s+)#.*$//; # Strip comment
+        next unless $_;
+        if (/^(\S+)\s+(.*)$/) {
+            $_ = $1;
+            if ($2 ne '-p1') {
+                warning(_g("the series file (%s) contains unsupported " .
+                           "options ('%s', line %s), dpkg-source might " .
+                           "fail when applying patches."),
+                        $file, $2, $.) if $opts{"warn_options"};
             }
-            next if $skip_auto and $_ eq $auto_patch;
-            push @patches, $_;
         }
-        close(SERIES);
+        next if $opts{"skip_auto"} and $_ eq $auto_patch;
+        push @patches, $_;
     }
+    close(SERIES);
     return @patches;
 }
 
-sub run_quilt {
-    my ($self, $dir, $params, %more_opts) = @_;
-    $params = [ $params ] unless ref($params) eq "ARRAY";
-    my $absdir = $dir;
-    unless (File::Spec->file_name_is_absolute($absdir)) {
-        $absdir = File::Spec->rel2abs($dir);
+sub create_quilt_db {
+    my ($self, $dir) = @_;
+    my $db_dir = File::Spec->catdir($dir, ".pc");
+    if (not -d $db_dir) {
+        mkdir $db_dir or syserr(_g("cannot mkdir %s"), $db_dir);
     }
-    my $series = $self->get_series_file($dir);
-    # Use default name if no series files exist yet
-    $series = "$absdir/debian/patches/series" unless defined $series;
-    unless (File::Spec->file_name_is_absolute($series)) {
-        $series = File::Spec->rel2abs($series);
+    my $version_file = File::Spec->catfile($db_dir, ".version");
+    if (not -e $version_file) {
+        open(VERSION, ">", $version_file);
+        print VERSION "2\n";
+        close(VERSION);
     }
-    my %opts = (
-        env => { QUILT_PATCHES => "$absdir/debian/patches",
-                 QUILT_SERIES => $series },
-        'chdir' => $dir,
-        'exec' => [ 'quilt', '--quiltrc', '/dev/null', @$params ],
-        %more_opts
-    );
-    my $pid = fork_and_exec(%opts);
-    return $pid;
+}
+
+sub apply_quilt_patch {
+    my ($self, $dir, $patch, %opts) = @_;
+    $opts{"verbose"} = 0 unless defined($opts{"verbose"});
+    $opts{"timestamp"} = time() unless defined($opts{"timestamp"});
+    my $path = File::Spec->catfile($dir, "debian", "patches", $patch);
+    my $obj = Dpkg::Source::Patch->new(filename => $path);
+
+    info(_g("applying %s"), $patch) if $opts{"verbose"};
+    $obj->apply($dir, timestamp => $opts{"timestamp"},
+                force_timestamp => 1, create_dirs => 1, remove_backup => 0,
+                options => [ '-s', '-t', '-F', '0', '-N', '-p1', '-u',
+                             '-V', 'never', '-g0', '-E', '-b',
+                             '-B', ".pc/$patch/" ]);
+}
+
+sub get_patches {
+    my ($self, $dir, %opts) = @_;
+    my $series = $self->get_series_file($dir);
+    return $self->read_patch_list($series, %opts);
 }
 
 sub apply_patches {
-    my ($self, $dir, $skip_auto) = @_;
+    my ($self, $dir, %opts) = @_;
+
+    if ($opts{'usage'} eq 'unpack') {
+        $opts{'verbose'} = 1;
+    } elsif ($opts{'usage'} eq 'build') {
+        $opts{'warn_options'} = 1;
+        $opts{'verbose'} = 0;
+    }
+
+    my $patches = $opts{"patches"};
 
     # Update debian/patches/series symlink if needed to allow quilt usage
     my $series = $self->get_series_file($dir);
@@ -137,46 +176,22 @@ sub apply_patches {
                 syserr(_g("can't create symlink %s"), $dest);
         }
     }
-    my @patches = $self->get_patches($dir, $skip_auto);
-    return unless scalar(@patches);
 
-    # Apply patches
-    my $applied = File::Spec->catfile($dir, "debian", "patches", ".dpkg-source-applied");
-    open(APPLIED, '>', $applied) || syserr(_g("cannot write %s"), $applied);
-    my $now = time();
-    my $pobj = {};
-    my $panalysis = {};
-    foreach my $patch (@patches) {
-        my $path = File::Spec->catfile($dir, "debian", "patches", $patch);
-        $pobj->{$patch} = Dpkg::Source::Patch->new(filename => $path);
-        if ($self->{'options'}{'without_quilt'}) {
-            info(_g("applying %s"), $patch) unless $skip_auto;
-            $pobj->{$patch}->apply($dir, timestamp => $now,
-                    force_timestamp => 1, create_dirs => 1,
-                    add_options => [ '-E' ]);
-            print APPLIED "$patch\n";
-        } else {
-            $panalysis->{$patch} = $pobj->{$patch}->analyze($dir);
-            foreach my $dir (keys %{$panalysis->{$patch}->{'dirtocreate'}}) {
-                eval { mkpath($dir); };
-                syserr(_g("cannot create directory %s"), $dir) if $@;
-            }
-        }
+    unless (defined($patches)) {
+        $patches = [ $self->get_patches($dir, %opts) ];
     }
-    if (not $self->{'options'}{'without_quilt'}) {
-        my %opts;
-        $opts{"to_file"} = "/dev/null" if $skip_auto;
-        info(_g("applying all patches with %s"), "quilt push -q " . $patches[-1]) unless $skip_auto;
-        $self->run_quilt($dir, ['push', '-q', $patches[-1]],
-                         delete_env => ['QUILT_PATCH_OPTS'],
-                         wait_child => 1, %opts);
-        foreach my $patch (@patches) {
-            foreach my $fn (keys %{$panalysis->{$patch}->{'filepatched'}}) {
-                utime($now, $now, $fn) || $! == ENOENT ||
-                    syserr(_g("cannot change timestamp for %s"), $fn);
-            }
-            print APPLIED "$patch\n";
-        }
+    return unless scalar(@$patches);
+
+    # Apply patches
+    $self->create_quilt_db($dir);
+    my $pc_applied = File::Spec->catfile($dir, ".pc", "applied-patches");
+    my @applied = $self->read_patch_list($pc_applied);
+    my @patches = $self->read_patch_list($self->get_series_file($dir));
+    open(APPLIED, '>>', $pc_applied) || syserr(_g("cannot write %s"), $pc_applied);
+    $opts{"timestamp"} = time();
+    foreach my $patch (@$patches) {
+        $self->apply_quilt_patch($dir, $patch, %opts);
+        print APPLIED "$patch\n";
     }
     close(APPLIED);
 }
@@ -189,7 +204,6 @@ sub prepare_build {
     # stamp file created by ourselves
     my $func = sub {
         return 1 if $_[0] =~ m{^debian/patches/series$} and -l $_[0];
-        return 1 if $_[0] =~ m{^debian/patches/.dpkg-source-applied$};
         return 1 if $_[0] =~ /^.pc(\/|$)/;
         return 1 if $_[0] =~ /$self->{'options'}{'diff_ignore_regexp'}/;
         return 0;
@@ -197,99 +211,99 @@ sub prepare_build {
     $self->{'diff_options'}{'diff_ignore_func'} = $func;
 }
 
+sub do_build {
+    my ($self, $dir) = @_;
+    my $pc_ver = File::Spec->catfile($dir, ".pc", ".version");
+    if (-f $pc_ver) {
+        open(VER, "<", $pc_ver) || syserr(_g("cannot read %s"), $pc_ver);
+        my $version = <VER>;
+        chomp $version;
+        close(VER);
+        if ($version != 2) {
+            if (scalar grep { $version eq $_ }
+                @{$self->{'options'}{'allow-version-of-quilt-db'}})
+            {
+                warning(_g("unsupported version of the quilt metadata: %s"),
+                        $version);
+            } else {
+                error(_g("unsupported version of the quilt metadata: %s"),
+                      $version);
+            }
+        }
+    }
+    $self->SUPER::do_build($dir);
+}
+
 sub check_patches_applied {
     my ($self, $dir) = @_;
-    my $applied = File::Spec->catfile($dir, "debian", "patches", ".dpkg-source-applied");
-    my $auto_patch = $self->get_autopatch_name();
-    my @patches ;
-    # First we try to get a list of patches that are probably not napplied
-    if (not $self->{'options'}{'without_quilt'}) {
-        my $pipe;
-        my $pid = $self->run_quilt($dir, ['unapplied'], error_to_file => '/dev/null',
-                                   to_pipe => \$pipe);
-        @patches = map { chomp; $_ } (<$pipe>);
-        close ($pipe) || syserr("close on 'quilt unapplied' pipe");
-        wait_child($pid, cmdline => "quilt unapplied", nocheck => 1);
-        subprocerr("quilt unapplied") unless WIFEXITED($?);
-    } else {
-        @patches = $self->get_patches($dir);
+    my $pc_applied = File::Spec->catfile($dir, ".pc", "applied-patches");
+    my @applied = $self->read_patch_list($pc_applied);
+    my @patches = $self->read_patch_list($self->get_series_file($dir));
+    my @to_apply;
+    foreach my $patch (@patches) {
+        next if scalar grep { $_ eq $patch } @applied;
+        push @to_apply, $patch;
     }
-    # Then we check if it's applicable, and if yes, we make the
-    # assumption that patches are not applied and need to be applied
-    if (scalar(@patches)) {
-        my $first_patch = File::Spec->catfile($dir, "debian", "patches", $patches[0]);
+    if (scalar(@to_apply)) {
+        my $first_patch = File::Spec->catfile($dir, "debian", "patches",
+                                              $to_apply[0]);
         my $patch_obj = Dpkg::Source::Patch->new(filename => $first_patch);
         if ($patch_obj->check_apply($dir)) {
-            warning(_g("patches have not been applied, applying them now (use --no-preparation to override)"));
-            $self->apply_patches($dir);
+            warning(_g("patches have not been applied, applying them now " .
+                       "(use --no-preparation to override)"));
+            $self->apply_patches($dir, usage => 'preparation', verbose => 1,
+                                 patches => \@to_apply);
         }
     }
 }
 
 sub register_autopatch {
     my ($self, $dir) = @_;
+
+    sub add_line {
+        my ($file, $line) = @_;
+        open(FILE, ">>", $file) || syserr(_g("cannot write %s"), $file);
+        print FILE "$line\n";
+        close(FILE);
+    }
+
+    sub drop_line {
+        my ($file, $re) = @_;
+        open(FILE, "<", $file) || syserr(_g("cannot read %s"), $file);
+        my @lines = <FILE>;
+        close(FILE);
+        open(FILE, ">", $file) || syserr(_g("cannot write %s"), $file);
+        print(FILE $_) foreach grep { not /^\Q$re\E\s*$/ } @lines;
+        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 $series = $self->get_series_file($dir);
     $series ||= File::Spec->catfile($dir, "debian", "patches", "series");
-    my $applied = File::Spec->catfile($dir, "debian", "patches", ".dpkg-source-applied");
+    my $applied = File::Spec->catfile($dir, ".pc", "applied-patches");
     my $patch = File::Spec->catfile($dir, "debian", "patches", $auto_patch);
-    my $absdir = $dir;
-    unless (File::Spec->file_name_is_absolute($absdir)) {
-        $absdir = File::Spec->rel2abs($dir);
-    }
+
     if (-e $patch) {
         # Add auto_patch to series file
         if (not $has_patch) {
-            # Use quilt to register only if it's wanted/available AND :
-            # - either we have patches and quilt has been used (.pc dir exists)
-            # - or we don't have patches, hence quilt couldn't be used
-            if ((-d "$dir/.pc" or not scalar(@patches)) and
-                not $self->{'options'}{'without_quilt'})
-            {
-                # Registering the new patch with quilt requires some
-                # trickery: reverse-apply the patch, create a new quilt patch,
-                # fold the patch into the quilt-managed one
-                my $patch_obj = Dpkg::Source::Patch->new(filename => $patch);
-                $patch_obj->apply($dir, add_options => ['-R', '-E']);
-                $self->run_quilt($dir, ['new', "$auto_patch"],
-                                 wait_child => 1, to_file => '/dev/null');
-                $self->run_quilt($dir, ['fold'],
-                                 from_file => "$absdir/debian/patches/$auto_patch",
-                                 wait_child => 1, to_file => '/dev/null');
-            } else {
-                open(SERIES, ">>", $series) || syserr(_g("cannot write %s"), $series);
-                print SERIES "$auto_patch\n";
-                close(SERIES);
-            }
-        } else {
-            # If quilt was used, ensure its meta-information are
-            # synchronized with the updated patch
-            if (-d "$dir/.pc" and not $self->{'options'}{'without_quilt'}) {
-                # Some trickery needed: reverse-apply the patch, fold the
-                # new patch into the quilt-managed one
-                my $patch_obj = Dpkg::Source::Patch->new(filename => $patch);
-                $patch_obj->apply($dir, add_options => ['-R', '-E']);
-                $self->run_quilt($dir, ['fold'],
-                                 from_file => "$absdir/debian/patches/$auto_patch",
-                                 wait_child => 1, to_file => '/dev/null');
-            }
+            add_line($series, $auto_patch);
+            add_line($applied, $auto_patch);
         }
+        # 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']);
+        erasedir(File::Spec->catdir($dir, ".pc", $auto_patch));
+        $self->apply_quilt_patch($dir, $auto_patch);
     } else {
         # Remove auto_patch from series
         if ($has_patch) {
-            if ($self->{'options'}{'without_quilt'}) {
-                open(SERIES, "<", $series) || syserr(_g("cannot read %s"), $series);
-                my @lines = <SERIES>;
-                close(SERIES);
-                open(SERIES, ">", $series) || syserr(_g("cannot write %s"), $series);
-                print(SERIES $_) foreach grep { not /^\Q$auto_patch\E\s*$/ } @lines;
-                close(SERIES);
-            } else {
-                $self->run_quilt($dir, ['delete', $auto_patch],
-                                 wait_child => 1, to_file => '/dev/null');
-            }
+            drop_line($series, $auto_patch);
+            drop_line($applied, $auto_patch);
+            erasedir(File::Spec->catdir($dir, ".pc", $auto_patch));
         }
         # Clean up empty series
         unlink($series) if not -s $series;

Reply to: