Quellcode durchsuchen

Dpkg::Source::Package::V3::quilt: create and use .pc directory

Instead of calling quilt to apply patches, we always apply them
by hand and we create the .pc directory used by quilt (version 2 in
.pc/.version). That way we are fully compatible with quilt and we can't
have differing behaviour whether quilt is installed or not.

Update the documentation accordingly. The option --without-quilt is gone
as is debian/patches/.dpkg-source-applied (replaced by
.pc/applied-patches).
Raphaël Hertzog vor 16 Jahren
Ursprung
Commit
d881cdca55
4 geänderte Dateien mit 145 neuen und 180 gelöschten Zeilen
  1. 5 0
      debian/changelog
  2. 5 12
      man/dpkg-source.1
  3. 12 9
      scripts/Dpkg/Source/Package/V2.pm
  4. 123 159
      scripts/Dpkg/Source/Package/V3/quilt.pm

+ 5 - 0
debian/changelog

@@ -2,6 +2,11 @@ dpkg (1.15.5.4) UNRELEASED; urgency=low
 
 
   * Fix Dpkg::Index::get() and remove(). Thanks to Roderich Schupp
   * Fix Dpkg::Index::get() and remove(). Thanks to Roderich Schupp
     <roderich.schupp@googlemail.com> for the patch. Closes: #558595
     <roderich.schupp@googlemail.com> for the patch. Closes: #558595
+  * 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, 29 Nov 2009 18:15:16 +0100
  -- Raphael Hertzog <hertzog@debian.org>  Sun, 29 Nov 2009 18:15:16 +0100
 
 

+ 5 - 12
man/dpkg-source.1

@@ -394,7 +394,7 @@ such options, and the build is likely to fail.
 .PP
 .PP
 Similarly to quilt's default behaviour, the patches can remove files too.
 Similarly to quilt's default behaviour, the patches can remove files too.
 .PP
 .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.
 patches have been applied during the extraction.
 .PP
 .PP
 .B Building
 .B Building
@@ -428,12 +428,10 @@ 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
 source package using the Format: 1.0 for instance. To mitigate the
 problem, \fBdpkg\-source\fP will apply the patches by itself if it
 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
 believes that they have not yet been applied. To detect this situation, it
-uses the following heuristic: if a \fB.pc\fP subdirectory is detected, it
-will call \fBquilt unapplied\fP to find out if some patches are not
-applied. After that, it will take the first patch of the series (or the
-first unapplied patch returned by \fBquilt unapplied\fP, if any) and
-verify if it can be applied without errors. If the verification succeeds,
-it concludes that patches have not been applied and will apply them all.
+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
 The option \fB\-\-no\-preparation\fP can be used to disable this
 behaviour.
 behaviour.
 .PP
 .PP
@@ -462,11 +460,6 @@ Skips extraction of the debian tarball on top of the upstream sources.
 .TP
 .TP
 .B \-\-skip\-patches
 .B \-\-skip\-patches
 Do not apply patches at the end of the extraction.
 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)
 .SS Format: 3.0 (custom)
 This format is particular. It doesn't represent a real source package
 This format is particular. It doesn't represent a real source package

+ 12 - 9
scripts/Dpkg/Source/Package/V2.pm

@@ -151,7 +151,8 @@ sub do_extract {
                   @exclude_symlinks ]);
                   @exclude_symlinks ]);
 
 
     # Apply patches (in a separate method as it might be overriden)
     # 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 {
 sub get_autopatch_name {
@@ -159,7 +160,8 @@ sub get_autopatch_name {
 }
 }
 
 
 sub get_patches {
 sub get_patches {
-    my ($self, $dir, $skip_auto) = @_;
+    my ($self, $dir, %opts) = @_;
+    $opts{"skip_auto"} = 0 unless defined($opts{"skip_auto"});
     my @patches;
     my @patches;
     my $pd = "$dir/debian/patches";
     my $pd = "$dir/debian/patches";
     my $auto_patch = $self->get_autopatch_name();
     my $auto_patch = $self->get_autopatch_name();
@@ -168,7 +170,7 @@ sub get_patches {
         foreach my $patch (sort readdir(DIR)) {
         foreach my $patch (sort readdir(DIR)) {
             # patches match same rules as run-parts
             # patches match same rules as run-parts
             next unless $patch =~ /^[\w-]+$/ and -f "$pd/$patch";
             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;
             push @patches, $patch;
         }
         }
         closedir(DIR);
         closedir(DIR);
@@ -177,15 +179,16 @@ sub get_patches {
 }
 }
 
 
 sub apply_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);
     return unless scalar(@patches);
     my $timestamp = time();
     my $timestamp = time();
     my $applied = File::Spec->catfile($dir, "debian", "patches", ".dpkg-source-applied");
     my $applied = File::Spec->catfile($dir, "debian", "patches", ".dpkg-source-applied");
     open(APPLIED, '>', $applied) || syserr(_g("cannot write %s"), $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);
         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);
         my $patch_obj = Dpkg::Source::Patch->new(filename => $path);
         $patch_obj->apply($dir, force_timestamp => 1,
         $patch_obj->apply($dir, force_timestamp => 1,
                           timestamp => $timestamp,
                           timestamp => $timestamp,
@@ -220,7 +223,7 @@ sub check_patches_applied {
     my $applied = File::Spec->catfile($dir, "debian", "patches", ".dpkg-source-applied");
     my $applied = File::Spec->catfile($dir, "debian", "patches", ".dpkg-source-applied");
     unless (-e $applied) {
     unless (-e $applied) {
         warning(_g("patches have not been applied, applying them now (use --no-preparation to override)"));
         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');
     }
     }
 }
 }
 
 
@@ -287,7 +290,7 @@ sub do_build {
     subprocerr(_g("copy of the debian directory")) if $?;
     subprocerr(_g("copy of the debian directory")) if $?;
 
 
     # Apply all patches except the last automatic one
     # 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
     # Prepare handling of binary files
     my %auth_bin_files;
     my %auth_bin_files;

+ 123 - 159
scripts/Dpkg/Source/Package/V3/quilt.pm

@@ -1,4 +1,4 @@
-# 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
 # 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
 # it under the terms of the GNU General Public License as published by
@@ -25,6 +25,7 @@ use Dpkg;
 use Dpkg::Gettext;
 use Dpkg::Gettext;
 use Dpkg::ErrorHandling;
 use Dpkg::ErrorHandling;
 use Dpkg::Source::Patch;
 use Dpkg::Source::Patch;
+use Dpkg::Source::Functions qw(erasedir);
 use Dpkg::IPC;
 use Dpkg::IPC;
 use Dpkg::Vendor qw(get_current_vendor run_vendor_hook);
 use Dpkg::Vendor qw(get_current_vendor run_vendor_hook);
 use Dpkg::Control;
 use Dpkg::Control;
@@ -40,18 +41,11 @@ our $CURRENT_MINOR_VERSION = "0";
 sub init_options {
 sub init_options {
     my ($self) = @_;
     my ($self) = @_;
     $self->SUPER::init_options();
     $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 {
 sub parse_cmdline_option {
     my ($self, $opt) = @_;
     my ($self, $opt) = @_;
     return 1 if $self->SUPER::parse_cmdline_option($opt);
     return 1 if $self->SUPER::parse_cmdline_option($opt);
-    if ($opt =~ /^--without-quilt$/) {
-        $self->{'options'}{'without_quilt'} = 1;
-        return 1;
-    }
     return 0;
     return 0;
 }
 }
 
 
@@ -89,63 +83,80 @@ sub get_series_file {
     return undef;
     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 @patches;
     my $auto_patch = $self->get_autopatch_name();
     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;
     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,
-                 # Kept as close as possible to default patch options in
-                 # Dpkg::Source::Patch (used in without_quilt mode)
-                 QUILT_PATCH_OPTS => "-t -F 0 -N -u -V never -g0" },
-        '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 {
 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
     # Update debian/patches/series symlink if needed to allow quilt usage
     my $series = $self->get_series_file($dir);
     my $series = $self->get_series_file($dir);
@@ -159,45 +170,22 @@ sub apply_patches {
                 syserr(_g("can't create symlink %s"), $dest);
                 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]],
-                         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);
     close(APPLIED);
 }
 }
@@ -210,7 +198,6 @@ sub prepare_build {
     # stamp file created by ourselves
     # stamp file created by ourselves
     my $func = sub {
     my $func = sub {
         return 1 if $_[0] =~ m{^debian/patches/series$} and -l $_[0];
         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] =~ /^.pc(\/|$)/;
         return 1 if $_[0] =~ /$self->{'options'}{'diff_ignore_regexp'}/;
         return 1 if $_[0] =~ /$self->{'options'}{'diff_ignore_regexp'}/;
         return 0;
         return 0;
@@ -220,97 +207,74 @@ sub prepare_build {
 
 
 sub check_patches_applied {
 sub check_patches_applied {
     my ($self, $dir) = @_;
     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);
         my $patch_obj = Dpkg::Source::Patch->new(filename => $first_patch);
         if ($patch_obj->check_apply($dir)) {
         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 {
 sub register_autopatch {
     my ($self, $dir) = @_;
     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 $auto_patch = $self->get_autopatch_name();
     my @patches = $self->get_patches($dir);
     my @patches = $self->get_patches($dir);
     my $has_patch = (grep { $_ eq $auto_patch } @patches) ? 1 : 0;
     my $has_patch = (grep { $_ eq $auto_patch } @patches) ? 1 : 0;
     my $series = $self->get_series_file($dir);
     my $series = $self->get_series_file($dir);
     $series ||= File::Spec->catfile($dir, "debian", "patches", "series");
     $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 $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) {
     if (-e $patch) {
         # Add auto_patch to series file
         # Add auto_patch to series file
         if (not $has_patch) {
         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 {
     } else {
         # Remove auto_patch from series
         # Remove auto_patch from series
         if ($has_patch) {
         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
         # Clean up empty series
         unlink($series) if not -s $series;
         unlink($series) if not -s $series;