From 1f7cf2a3a6a657436f700b00a3f0101adb258df8 Mon Sep 17 00:00:00 2001 From: Raphael Hertzog Date: Wed, 4 Jun 2008 21:26:47 +0200 Subject: [PATCH] dpkg-source: improve the patch parser * scripts/Dpkg/Source/Patch.pm (analyze): Enhance function to parse correctly many more patches that are accepted by the patch utility itself: - ignore/strip carriage return of patches with Windows end of lines - accept empty lines as contextual lines (instead of the expected " ") - accept spaces as separator between filename and timestamp if there's no tab - accept a name that differs on the +++ line if the name in --- is correct, and use the name in +++ if this one exists while the one on --- doesn't. --- ChangeLog | 13 +++++++++ debian/changelog | 2 ++ scripts/Dpkg/Source/Patch.pm | 55 +++++++++++++++++++++++------------- 3 files changed, 50 insertions(+), 20 deletions(-) diff --git a/ChangeLog b/ChangeLog index cb2d2898..4286dfc7 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,16 @@ +2008-06-04 Raphael Hertzog + + * scripts/Dpkg/Source/Patch.pm (analyze): Enhance function to + parse correctly many more patches that are accepted by the patch + utility itself: + - ignore/strip carriage return of patches with Windows end of lines + - accept empty lines as contextual lines (instead of the expected " ") + - accept spaces as separator between filename and timestamp if + there's no tab + - accept a name that differs on the +++ line if the name in --- is + correct, and use the name in +++ if this one exists while the one + on --- doesn't. + 2008-05-28 Raphael Hertzog * scripts/Dpkg/Source/Package.pm (extract): If we extract a diff --git a/debian/changelog b/debian/changelog index 9111662e..84e5a82d 100644 --- a/debian/changelog +++ b/debian/changelog @@ -11,6 +11,8 @@ dpkg (1.14.20) UNRELEASED; urgency=low as default name for the automatic patch created by the format "3.0 (quilt)". This ensures a saner cohabitation with patch systems that apply all of debian/patches/*.{diff,patch}. + * Improve patch parser to accept more patches that are accepted by patch + itself. [ Helge Kreutzmann ] * Fix a typo in dselect.1 diff --git a/scripts/Dpkg/Source/Patch.pm b/scripts/Dpkg/Source/Patch.pm index 26cbe2a6..52c35e01 100644 --- a/scripts/Dpkg/Source/Patch.pm +++ b/scripts/Dpkg/Source/Patch.pm @@ -279,21 +279,38 @@ sub analyze { my %dirtocreate; my $diff_count = 0; - $_ = <$diff_handle>; + sub getline { + my $handle = shift; + my $line = <$handle>; + if (defined $line) { + # Strip end-of-line chars + chomp($line); + $line =~ s/\r$//; + } + return $line; + } + sub strip_ts { # Strip timestamp + my $header = shift; + # Tab is the official separator, it's always used when + # filename contain spaces. Try it first, otherwise strip on space + # if there's no tab + $header =~ s/\s.*// unless ($header =~ s/\t.*//); + return $header; + } + $_ = getline($diff_handle); HUNK: while (defined($_) || not eof($diff_handle)) { # skip comments leading up to patch (if any) until (/^--- /) { - last HUNK if not defined($_ = <$diff_handle>); + last HUNK if not defined($_ = getline($diff_handle)); } - chomp; $diff_count++; # read file header (---/+++ pair) unless(s/^--- //) { error(_g("expected ^--- in line %d of diff `%s'"), $., $diff); } - s/\t.*//; # Strip any timestamp at the end + $_ = strip_ts($_); unless ($_ eq '/dev/null' or s{^(\./)?[^/]+/}{$destdir/}) { error(_g("diff `%s' patches file with no subdirectory"), $diff); } @@ -302,23 +319,25 @@ sub analyze { } my $fn = $_; - unless (defined($_= <$diff_handle>) and chomp) { + unless (defined($_ = getline($diff_handle))) { error(_g("diff `%s' finishes in middle of ---/+++ (line %d)"), $diff, $.); } - s/\t.*//; # Strip any timestamp at the end - unless (s/^\+\+\+ // and ($_ eq '/dev/null' or s!^(\./)?[^/]+/!!)) { - error(_g("line after --- isn't as expected in diff `%s' (line %d)"), - $diff, $.); + unless (s/^\+\+\+ //) { + error(_g("line after --- isn't as expected in diff `%s' (line %d)"), $diff, $.); + } + $_ = strip_ts($_); + unless (($_ eq '/dev/null') or s!^(\./)?[^/]+/!!) { + error(_g("line after --- isn't as expected in diff `%s' (line %d)"), $diff, $.); } if ($fn eq '/dev/null') { error(_g("original and modified files are /dev/null in diff `%s' (line %d)"), $diff, $.) if $_ eq '/dev/null'; $fn = "$destdir/$_"; - } else { - unless ($_ eq '/dev/null' or $_ eq substr($fn, length($destdir) + 1)) { - error(_g("line after --- isn't as expected in diff `%s' (line %d)"), - $diff, $.); + } elsif ($_ ne '/dev/null') { + $fn = "$destdir/$_" if ((not -e $fn) and -e "$destdir/$_"); + unless ($_ eq substr($fn, length($destdir) + 1)) { + error(_g("line after --- isn't as expected in diff `%s' (line %d)"), $diff, $.); } } @@ -337,23 +356,19 @@ sub analyze { # read hunks my $hunk = 0; - while (defined($_ = <$diff_handle>)) { + while (defined($_ = getline($diff_handle))) { # read hunk header (@@) - chomp; next if /^\\ No newline/; last unless (/^@@ -\d+(,(\d+))? \+\d+(,(\d+))? @\@( .*)?$/); my ($olines, $nlines) = ($1 ? $2 : 1, $3 ? $4 : 1); # read hunk while ($olines || $nlines) { - unless (defined($_ = <$diff_handle>)) { + unless (defined($_ = getline($diff_handle))) { error(_g("unexpected end of diff `%s'"), $diff); } - unless (chomp) { - error(_g("diff `%s' is missing trailing newline"), $diff); - } next if /^\\ No newline/; # Check stats - if (/^ /) { --$olines; --$nlines; } + if (/^ / || /^$/) { --$olines; --$nlines; } elsif (/^-/) { --$olines; } elsif (/^\+/) { --$nlines; } else { -- 2.39.5