From 53fa0ea2e520cd26857ff577ffe7e49558af440c Mon Sep 17 00:00:00 2001 From: Raphael Hertzog Date: Wed, 28 May 2008 18:05:50 +0200 Subject: [PATCH] dpkg-source/3.0 (quilt): improve reliability of check_patches_applied * scripts/Dpkg/Source/Patch.pm (check_apply): New function to verify if a patch will successfully apply on top of a given directory. * scripts/Dpkg/Source/Package/V3/quilt.pm (check_patches_applied): Don't trust debian/patches/.dpkg-source-applied blindly. Get a list of (supposedly unapplied) patches and verify if the first patch applies or not. If yes, then apply the patch series, otherwise do not (and assume that the patch series is already applied). --- ChangeLog | 12 +++++++ scripts/Dpkg/Source/Package/V3/quilt.pm | 29 +++++++-------- scripts/Dpkg/Source/Patch.pm | 48 +++++++++++++++++++++---- 3 files changed, 66 insertions(+), 23 deletions(-) diff --git a/ChangeLog b/ChangeLog index d469819f..c816cca2 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,15 @@ +2008-05-28 Raphael Hertzog + + * scripts/Dpkg/Source/Patch.pm (check_apply): New function to + verify if a patch will successfully apply on top of a given + directory. + * scripts/Dpkg/Source/Package/V3/quilt.pm (check_patches_applied): + Don't trust debian/patches/.dpkg-source-applied blindly. Get a + list of (supposedly unapplied) patches and verify if the first + patch applies or not. If yes, then apply the patch series, + otherwise do not (and assume that the patch series is already + applied). + 2008-05-23 Raphael Hertzog * scripts/Dpkg/Source/Package/V2.pm (do_build): Display a diff --git a/scripts/Dpkg/Source/Package/V3/quilt.pm b/scripts/Dpkg/Source/Package/V3/quilt.pm index 979d2074..c02d0730 100644 --- a/scripts/Dpkg/Source/Package/V3/quilt.pm +++ b/scripts/Dpkg/Source/Package/V3/quilt.pm @@ -173,8 +173,9 @@ sub prepare_build { sub check_patches_applied { my ($self, $dir) = @_; my $applied = File::Spec->catfile($dir, "debian", "patches", ".dpkg-source-applied"); - my $quiltdir = File::Spec->catdir($dir, ".pc"); - if (-d $quiltdir) { + my @patches ; + # First we try to get a list of patches that could be unapplied + if (-x "/usr/bin/quilt") { my $auto_patch = $self->get_autopatch_name(); my $pipe; my %opts = (env => { QUILT_PATCHES => 'debian/patches' }, @@ -188,24 +189,18 @@ sub check_patches_applied { # quilt... but by the user who made changes live in the tree # and whose changes lead to this patch addition by a previous # dpkg-source run. - my @patches = grep { chomp; $_ ne $auto_patch } (<$pipe>); + @patches = grep { chomp; $_ ne $auto_patch } (<$pipe>); close ($pipe) || syserr("close on 'quilt unapplied' pipe"); wait_child($pid, cmdline => "quilt unapplied", nocheck => 1); - if (@patches) { - warning(_g("patches have not been applied, applying them now (use --no-preparation to override)")); - $opts{'wait_child'} = 1; - $opts{'to_file'} = "/dev/null"; - delete $opts{'to_pipe'}; - foreach my $patch (@patches) { - info(_g("applying %s with quilt"), $patch); - $opts{'exec'} = [ 'quilt', '--quiltrc', '/dev/null', 'push', $patch ]; - fork_and_exec(%opts); - } - } - return; + } else { + @patches = $self->get_patches($dir); } - unless (-e $applied) { - if (scalar($self->get_patches($dir))) { + # 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]); + 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); } diff --git a/scripts/Dpkg/Source/Patch.pm b/scripts/Dpkg/Source/Patch.pm index 0ad407d0..26cbe2a6 100644 --- a/scripts/Dpkg/Source/Patch.pm +++ b/scripts/Dpkg/Source/Patch.pm @@ -377,6 +377,16 @@ sub analyze { return $self->{'analysis'}{$destdir}; } +sub prepare_apply { + my ($self, $analysis, %opts) = @_; + if ($opts{"create_dirs"}) { + foreach my $dir (keys %{$analysis->{'dirtocreate'}}) { + eval { mkpath($dir, 0, 0777); }; + syserr(_g("cannot create directory %s"), $dir) if $@; + } + } +} + sub apply { my ($self, $destdir, %opts) = @_; # Set default values to options @@ -389,12 +399,7 @@ sub apply { push @{$opts{"options"}}, @{$opts{"add_options"}}; # Check the diff and create missing directories my $analysis = $self->analyze($destdir, %opts); - if ($opts{"create_dirs"}) { - foreach my $dir (keys %{$analysis->{'dirtocreate'}}) { - eval { mkpath($dir, 0, 0777); }; - syserr(_g("cannot create directory %s"), $dir) if $@; - } - } + $self->prepare_apply($analysis, %opts); # Apply the patch my $diff_handle = $self->open_for_read(); fork_and_exec( @@ -421,6 +426,37 @@ sub apply { } } +# Verify if check will work... +sub check_apply { + my ($self, $destdir, %opts) = @_; + # Set default values to options + $opts{"create_dirs"} = 1 unless exists $opts{"create_dirs"}; + $opts{"options"} ||= [ '--dry-run', '-s', '-t', '-F', '0', '-N', '-p1', '-u', + '-V', 'never', '-g0', '-b', '-z', '.dpkg-orig']; + $opts{"add_options"} ||= []; + push @{$opts{"options"}}, @{$opts{"add_options"}}; + # Check the diff and create missing directories + my $analysis = $self->analyze($destdir, %opts); + $self->prepare_apply($analysis, %opts); + # Apply the patch + my $diff_handle = $self->open_for_read(); + my $error; + my $patch_pid = fork_and_exec( + 'exec' => [ 'patch', @{$opts{"options"}} ], + 'chdir' => $destdir, + 'env' => { LC_ALL => 'C', LANG => 'C' }, + 'delete_env' => [ 'POSIXLY_CORRECT' ], # ensure expected patch behaviour + 'from_handle' => $diff_handle, + 'to_file' => '/dev/null', + 'error_to_file' => '/dev/null', + ); + wait_child($patch_pid, nocheck => 1); + my $exit = WEXITSTATUS($?); + subprocerr("patch --dry-run") unless WIFEXITED($?); + $self->cleanup_after_open(); + return ($exit == 0); +} + # Helper functions sub get_type { my $file = shift; -- 2.39.5