1 # Copyright © 2008-2012 Raphaël Hertzog <hertzog@debian.org>
3 # This program is free software; you can redistribute it and/or modify
4 # it under the terms of the GNU General Public License as published by
5 # the Free Software Foundation; either version 2 of the License, or
6 # (at your option) any later version.
8 # This program is distributed in the hope that it will be useful,
9 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # GNU General Public License for more details.
13 # You should have received a copy of the GNU General Public License
14 # along with this program. If not, see <https://www.gnu.org/licenses/>.
20 Dpkg::Source::Package::V3::Quilt - class for source format 3.0 (quilt)
24 This module provides a class to handle the source package format 3.0 (quilt).
26 B<Note>: This is a private module, its API can change at any time.
30 package Dpkg
::Source
::Package
::V3
::Quilt
0.01;
35 use List
::Util
qw(any);
40 use Dpkg
::ErrorHandling
;
43 use Dpkg
::Source
::Patch
;
44 use Dpkg
::Source
::Functions
qw(erasedir chmod_if_needed fs_time);
45 use Dpkg
::Source
::Quilt
;
48 # Based on wig&pen implementation
49 use parent
qw(Dpkg::Source::Package::V2);
51 our $CURRENT_MINOR_VERSION = '0';
55 $self->{options
}{single_debian_patch
} //= 0;
56 $self->{options
}{allow_version_of_quilt_db
} //= [];
58 $self->SUPER::init_options
();
61 my @module_cmdline = (
63 name
=> '--single-debian-patch',
64 help
=> N_
('use a single debianization patch'),
67 name
=> '--allow-version-of-quilt-db=<version>',
68 help
=> N_
('accept quilt metadata <version> even if unknown'),
73 sub describe_cmdline_options
{
76 my @cmdline = ( $self->SUPER::describe_cmdline_options
(), @module_cmdline );
81 sub parse_cmdline_option
{
82 my ($self, $opt) = @_;
83 return 1 if $self->SUPER::parse_cmdline_option
($opt);
84 if ($opt eq '--single-debian-patch') {
85 $self->{options
}{single_debian_patch
} = 1;
86 # For backwards compatibility.
87 $self->{options
}{auto_commit
} = 1;
89 } elsif ($opt =~ /^--allow-version-of-quilt-db=(.*)$/) {
90 push @
{$self->{options
}{allow_version_of_quilt_db
}}, $1;
96 sub _build_quilt_object
{
97 my ($self, $dir) = @_;
98 return $self->{quilt
}{$dir} if exists $self->{quilt
}{$dir};
99 $self->{quilt
}{$dir} = Dpkg
::Source
::Quilt
->new($dir);
100 return $self->{quilt
}{$dir};
104 my ($self, $dir) = @_;
105 my ($code, $msg) = $self->SUPER::can_build
($dir);
106 return ($code, $msg) if $code == 0;
108 my $v = Dpkg
::Version
->new($self->{fields
}->{'Version'});
109 return (0, g_
('non-native package version does not contain a revision'))
112 my $quilt = $self->_build_quilt_object($dir);
113 $msg = $quilt->find_problems();
114 return (0, $msg) if $msg;
118 sub get_autopatch_name
{
120 if ($self->{options
}{single_debian_patch
}) {
121 return 'debian-changes';
123 return 'debian-changes-' . $self->{fields
}{'Version'};
128 my ($self, $dir, %opts) = @_;
130 if ($opts{usage
} eq 'unpack') {
132 } elsif ($opts{usage
} eq 'build') {
133 $opts{warn_options
} = 1;
137 my $quilt = $self->_build_quilt_object($dir);
138 $quilt->load_series(%opts) if $opts{warn_options
}; # Trigger warnings
140 # Always create the quilt db so that if the maintainer calls quilt to
141 # create a patch, it's stored in the right directory
144 # Update debian/patches/series symlink if needed to allow quilt usage
145 my $series = $quilt->get_series_file();
146 my $basename = (File
::Spec
->splitpath($series))[2];
147 if ($basename ne 'series') {
148 my $dest = $quilt->get_patch_file('series');
149 unlink($dest) if -l
$dest;
150 unless (-f _
) { # Don't overwrite real files
151 symlink($basename, $dest)
152 or syserr
(g_
("can't create symlink %s"), $dest);
156 return unless scalar($quilt->series());
158 info
(g_
('using patch list from %s'), "debian/patches/$basename");
160 if ($opts{usage
} eq 'preparation' and
161 $self->{options
}{unapply_patches
} eq 'auto') {
162 # We're applying the patches in --before-build, remember to unapply
163 # them afterwards in --after-build
164 my $pc_unapply = $quilt->get_db_file('.dpkg-source-unapply');
165 file_touch
($pc_unapply);
169 my $pc_applied = $quilt->get_db_file('applied-patches');
170 $opts{timestamp
} = fs_time
($pc_applied);
171 if ($opts{skip_auto
}) {
172 my $auto_patch = $self->get_autopatch_name();
173 $quilt->push(%opts) while ($quilt->next() and $quilt->next() ne $auto_patch);
175 $quilt->push(%opts) while $quilt->next();
179 sub unapply_patches
{
180 my ($self, $dir, %opts) = @_;
182 my $quilt = $self->_build_quilt_object($dir);
184 $opts{verbose
} //= 1;
186 my $pc_applied = $quilt->get_db_file('applied-patches');
187 my @applied = $quilt->applied();
188 $opts{timestamp
} = fs_time
($pc_applied) if @applied;
190 $quilt->pop(%opts) while $quilt->top();
192 erasedir
($quilt->get_db_dir());
196 my ($self, $dir) = @_;
197 $self->SUPER::prepare_build
($dir);
198 # Skip .pc directories of quilt by default and ignore difference
199 # on debian/patches/series symlinks and d/p/.dpkg-source-applied
200 # stamp file created by ourselves
202 my $pathname = shift;
204 return 1 if $pathname eq 'debian/patches/series' and -l
$pathname;
205 return 1 if $pathname =~ /^\.pc(\/|$)/;
206 return 1 if $pathname =~ /$self->{options}{diff_ignore_regex}/;
209 $self->{diff_options
}{diff_ignore_func
} = $func;
213 my ($self, $dir) = @_;
215 my $quilt = $self->_build_quilt_object($dir);
216 my $version = $quilt->get_db_version();
218 if (defined($version) and $version != 2) {
219 if (any
{ $version eq $_ }
220 @
{$self->{options
}{allow_version_of_quilt_db
}})
222 warning
(g_
('unsupported version of the quilt metadata: %s'), $version);
224 error
(g_
('unsupported version of the quilt metadata: %s'), $version);
228 $self->SUPER::do_build
($dir);
232 my ($self, $dir) = @_;
233 my $quilt = $self->_build_quilt_object($dir);
234 my $pc_unapply = $quilt->get_db_file('.dpkg-source-unapply');
235 my $opt_unapply = $self->{options
}{unapply_patches
};
236 if (($opt_unapply eq 'auto' and -e
$pc_unapply) or $opt_unapply eq 'yes') {
238 $self->unapply_patches($dir);
242 sub check_patches_applied
{
243 my ($self, $dir) = @_;
245 my $quilt = $self->_build_quilt_object($dir);
246 my $next = $quilt->next();
247 return if not defined $next;
249 my $first_patch = File
::Spec
->catfile($dir, 'debian', 'patches', $next);
250 my $patch_obj = Dpkg
::Source
::Patch
->new(filename
=> $first_patch);
251 return unless $patch_obj->check_apply($dir, fatal_dupes
=> 1);
253 $self->apply_patches($dir, usage
=> 'preparation', verbose
=> 1);
257 my ($self, $dir, $tmpdiff, $patch_name) = @_;
259 my $quilt = $self->_build_quilt_object($dir);
260 my $patch = $quilt->get_patch_file($patch_name);
263 copy
($tmpdiff, $patch)
264 or syserr
(g_
('failed to copy %s to %s'), $tmpdiff, $patch);
265 chmod_if_needed
(0666 & ~ umask(), $patch)
266 or syserr
(g_
("unable to change permission of '%s'"), $patch);
267 } elsif (-e
$patch) {
268 unlink($patch) or syserr
(g_
('cannot remove %s'), $patch);
272 # Add patch to series file
273 $quilt->register($patch_name);
275 # Remove auto_patch from series
276 $quilt->unregister($patch_name);
285 This is a private module.