File Coverage

blib/lib/Dpkg/Source/Package.pm
Criterion Covered Total %
statement 57 257 22.1
branch 0 82 0.0
condition 0 66 0.0
subroutine 19 49 38.7
pod 12 30 40.0
total 88 484 18.1


line stmt bran cond sub pod time code
1             # Copyright © 2008-2011 Raphaël Hertzog
2             # Copyright © 2008-2019 Guillem Jover
3             #
4             # This program is free software; you can redistribute it and/or modify
5             # it under the terms of the GNU General Public License as published by
6             # the Free Software Foundation; either version 2 of the License, or
7             # (at your option) any later version.
8             #
9             # This program is distributed in the hope that it will be useful,
10             # but WITHOUT ANY WARRANTY; without even the implied warranty of
11             # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12             # GNU General Public License for more details.
13             #
14             # You should have received a copy of the GNU General Public License
15             # along with this program. If not, see .
16              
17             package Dpkg::Source::Package;
18              
19             =encoding utf8
20              
21             =head1 NAME
22              
23             Dpkg::Source::Package - manipulate Debian source packages
24              
25             =head1 DESCRIPTION
26              
27             This module provides a class that can manipulate Debian source
28             packages. While it supports both the extraction and the creation
29             of source packages, the only API that is officially supported
30             is the one that supports the extraction of the source package.
31              
32             =cut
33              
34 1     1   72403 use strict;
  1         12  
  1         30  
35 1     1   6 use warnings;
  1         2  
  1         90  
36              
37             our $VERSION = '2.01';
38             our @EXPORT_OK = qw(
39             get_default_diff_ignore_regex
40             set_default_diff_ignore_regex
41             get_default_tar_ignore_pattern
42             );
43              
44 1     1   7 use Exporter qw(import);
  1         2  
  1         49  
45 1     1   591 use POSIX qw(:errno_h :sys_wait_h);
  1         7489  
  1         5  
46 1     1   1812 use Carp;
  1         2  
  1         82  
47 1     1   828 use File::Temp;
  1         22189  
  1         91  
48 1     1   523 use File::Copy qw(cp);
  1         2376  
  1         59  
49 1     1   8 use File::Basename;
  1         2  
  1         102  
50              
51 1     1   429 use Dpkg::Gettext;
  1         3  
  1         63  
52 1     1   419 use Dpkg::ErrorHandling;
  1         3  
  1         94  
53 1     1   415 use Dpkg::Control;
  1         3  
  1         83  
54 1     1   454 use Dpkg::Checksums;
  1         2  
  1         63  
55 1     1   455 use Dpkg::Version;
  1         3  
  1         80  
56 1     1   472 use Dpkg::Compression;
  1         2  
  1         80  
57 1     1   427 use Dpkg::Path qw(check_files_are_the_same check_directory_traversal);
  1         3  
  1         85  
58 1     1   7 use Dpkg::Vendor qw(run_vendor_hook);
  1         3  
  1         41  
59 1     1   434 use Dpkg::Source::Format;
  1         3  
  1         30  
60 1     1   406 use Dpkg::OpenPGP;
  1         2  
  1         101  
61              
62             my $diff_ignore_default_regex = '
63             # Ignore general backup files
64             (?:^|/).*~$|
65             # Ignore emacs recovery files
66             (?:^|/)\.#.*$|
67             # Ignore vi swap files
68             (?:^|/)\..*\.sw.$|
69             # Ignore baz-style junk files or directories
70             (?:^|/),,.*(?:$|/.*$)|
71             # File-names that should be ignored (never directories)
72             (?:^|/)(?:DEADJOE|\.arch-inventory|\.(?:bzr|cvs|hg|git|mtn-)ignore)$|
73             # File or directory names that should be ignored
74             (?:^|/)(?:CVS|RCS|\.deps|\{arch\}|\.arch-ids|\.svn|
75             \.hg(?:tags|sigs)?|_darcs|\.git(?:attributes|modules|review)?|
76             \.mailmap|\.shelf|_MTN|\.be|\.bzr(?:\.backup|tags)?)(?:$|/.*$)
77             ';
78             # Take out comments and newlines
79             $diff_ignore_default_regex =~ s/^#.*$//mg;
80             $diff_ignore_default_regex =~ s/\n//sg;
81              
82 1     1   7 no warnings 'qw'; ## no critic (TestingAndDebugging::ProhibitNoWarnings)
  1         2  
  1         3130  
83             my @tar_ignore_default_pattern = qw(
84             *.a
85             *.la
86             *.o
87             *.so
88             .*.sw?
89             */*~
90             ,,*
91             .[#~]*
92             .arch-ids
93             .arch-inventory
94             .be
95             .bzr
96             .bzr.backup
97             .bzr.tags
98             .bzrignore
99             .cvsignore
100             .deps
101             .git
102             .gitattributes
103             .gitignore
104             .gitmodules
105             .gitreview
106             .hg
107             .hgignore
108             .hgsigs
109             .hgtags
110             .mailmap
111             .mtn-ignore
112             .shelf
113             .svn
114             CVS
115             DEADJOE
116             RCS
117             _MTN
118             _darcs
119             {arch}
120             );
121             ## use critic
122              
123             =head1 FUNCTIONS
124              
125             =over 4
126              
127             =item $string = get_default_diff_ignore_regex()
128              
129             Returns the default diff ignore regex.
130              
131             =cut
132              
133             sub get_default_diff_ignore_regex {
134 0     0 1   return $diff_ignore_default_regex;
135             }
136              
137             =item set_default_diff_ignore_regex($string)
138              
139             Set a regex as the new default diff ignore regex.
140              
141             =cut
142              
143             sub set_default_diff_ignore_regex {
144 0     0 1   my $regex = shift;
145              
146 0           $diff_ignore_default_regex = $regex;
147             }
148              
149             =item @array = get_default_tar_ignore_pattern()
150              
151             Returns the default tar ignore pattern, as an array.
152              
153             =cut
154              
155             sub get_default_tar_ignore_pattern {
156 0     0 1   return @tar_ignore_default_pattern;
157             }
158              
159             =back
160              
161             =head1 METHODS
162              
163             =over 4
164              
165             =item $p = Dpkg::Source::Package->new(%opts, options => {})
166              
167             Creates a new object corresponding to a source package. When the key
168             B is set to a F<.dsc> file, it will be used to initialize the
169             source package with its description. Otherwise if the B key is
170             set to a valid value, the object will be initialized for that format
171             (since dpkg 1.19.3).
172              
173             The B key is a hash ref which supports the following options:
174              
175             =over 8
176              
177             =item skip_debianization
178              
179             If set to 1, do not apply Debian changes on the extracted source package.
180              
181             =item skip_patches
182              
183             If set to 1, do not apply Debian-specific patches. This options is
184             specific for source packages using format "2.0" and "3.0 (quilt)".
185              
186             =item require_valid_signature
187              
188             If set to 1, the check_signature() method will be stricter and will error
189             out if the signature can't be verified.
190              
191             =item require_strong_checksums
192              
193             If set to 1, the check_checksums() method will be stricter and will error
194             out if there is no strong checksum.
195              
196             =item copy_orig_tarballs
197              
198             If set to 1, the extraction will copy the upstream tarballs next the
199             target directory. This is useful if you want to be able to rebuild the
200             source package after its extraction.
201              
202             =back
203              
204             =cut
205              
206             # Class methods
207             sub new {
208 0     0 1   my ($this, %args) = @_;
209 0   0       my $class = ref($this) || $this;
210 0           my $self = {
211             fields => Dpkg::Control->new(type => CTRL_PKG_SRC),
212             format => Dpkg::Source::Format->new(),
213             options => {},
214             checksums => Dpkg::Checksums->new(),
215             };
216 0           bless $self, $class;
217 0 0         if (exists $args{options}) {
218 0           $self->{options} = $args{options};
219             }
220 0 0         if (exists $args{filename}) {
    0          
221 0           $self->initialize($args{filename});
222 0           $self->init_options();
223             } elsif ($args{format}) {
224 0           $self->{fields}{Format} = $args{format};
225 0           $self->upgrade_object_type(0);
226 0           $self->init_options();
227             }
228 0           return $self;
229             }
230              
231             sub init_options {
232 0     0 0   my $self = shift;
233             # Use full ignore list by default
234             # note: this function is not called by V1 packages
235 0   0       $self->{options}{diff_ignore_regex} ||= $diff_ignore_default_regex;
236 0           $self->{options}{diff_ignore_regex} .= '|(?:^|/)debian/source/local-.*$';
237 0           $self->{options}{diff_ignore_regex} .= '|(?:^|/)debian/files(?:\.new)?$';
238 0 0         if (defined $self->{options}{tar_ignore}) {
239             $self->{options}{tar_ignore} = [ @tar_ignore_default_pattern ]
240 0 0         unless @{$self->{options}{tar_ignore}};
  0            
241             } else {
242 0           $self->{options}{tar_ignore} = [ @tar_ignore_default_pattern ];
243             }
244 0           push @{$self->{options}{tar_ignore}},
  0            
245             'debian/source/local-options',
246             'debian/source/local-patch-header',
247             'debian/files',
248             'debian/files.new';
249 0   0       $self->{options}{copy_orig_tarballs} //= 0;
250              
251             # Skip debianization while specific to some formats has an impact
252             # on code common to all formats
253 0   0       $self->{options}{skip_debianization} //= 0;
254 0   0       $self->{options}{skip_patches} //= 0;
255              
256             # Set default validation checks.
257 0   0       $self->{options}{require_valid_signature} //= 0;
258 0   0       $self->{options}{require_strong_checksums} //= 0;
259              
260             # Set default compressor for new formats.
261 0   0       $self->{options}{compression} //= 'xz';
262             $self->{options}{comp_level} //= compression_get_property($self->{options}{compression},
263 0   0       'default_level');
264             $self->{options}{comp_ext} //= compression_get_property($self->{options}{compression},
265 0   0       'file_ext');
266             }
267              
268             sub initialize {
269 0     0 0   my ($self, $filename) = @_;
270 0           my ($fn, $dir) = fileparse($filename);
271 0 0         error(g_('%s is not the name of a file'), $filename) unless $fn;
272 0   0       $self->{basedir} = $dir || './';
273 0           $self->{filename} = $fn;
274              
275             # Read the fields
276 0           my $fields = $self->{fields};
277 0           $fields->load($filename);
278 0           $self->{is_signed} = $fields->get_option('is_pgp_signed');
279              
280 0           foreach my $f (qw(Source Version Files)) {
281 0 0         unless (defined($fields->{$f})) {
282 0           error(g_('missing critical source control field %s'), $f);
283             }
284             }
285              
286 0           $self->{checksums}->add_from_control($fields, use_files_for_md5 => 1);
287              
288 0           $self->upgrade_object_type(0);
289             }
290              
291             sub upgrade_object_type {
292 0     0 0   my ($self, $update_format) = @_;
293 0   0       $update_format //= 1;
294              
295 0   0       my $format = $self->{fields}{'Format'} // '1.0';
296 0           my ($major, $minor, $variant) = $self->{format}->set($format);
297              
298 0           my $module = "Dpkg::Source::Package::V$major";
299 0 0         $module .= '::' . ucfirst $variant if defined $variant;
300 0           eval qq{
301             pop \@INC if \$INC[-1] eq '.';
302             require $module;
303             \$minor = \$${module}::CURRENT_MINOR_VERSION;
304             };
305 0 0         if ($@) {
306 0           error(g_("source package format '%s' is not supported: %s"),
307             $format, $@);
308             }
309 0 0         if ($update_format) {
310 0           $self->{format}->set_from_parts($major, $minor, $variant);
311 0           $self->{fields}{'Format'} = $self->{format}->get();
312             }
313              
314 0 0         $module->prerequisites() if $module->can('prerequisites');
315 0           bless $self, $module;
316             }
317              
318             =item $p->get_filename()
319              
320             Returns the filename of the DSC file.
321              
322             =cut
323              
324             sub get_filename {
325 0     0 1   my $self = shift;
326 0           return $self->{basedir} . $self->{filename};
327             }
328              
329             =item $p->get_files()
330              
331             Returns the list of files referenced by the source package. The filenames
332             usually do not have any path information.
333              
334             =cut
335              
336             sub get_files {
337 0     0 1   my $self = shift;
338 0           return $self->{checksums}->get_files();
339             }
340              
341             =item $p->check_checksums()
342              
343             Verify the checksums embedded in the DSC file. It requires the presence of
344             the other files constituting the source package. If any inconsistency is
345             discovered, it immediately errors out. It will make sure at least one strong
346             checksum is present.
347              
348             If the object has been created with the "require_strong_checksums" option,
349             then any problem will result in a fatal error.
350              
351             =cut
352              
353             sub check_checksums {
354 0     0 1   my $self = shift;
355 0           my $checksums = $self->{checksums};
356 0           my $warn_on_weak = 0;
357              
358             # add_from_file verify the checksums if they are already existing
359 0           foreach my $file ($checksums->get_files()) {
360 0 0         if (not $checksums->has_strong_checksums($file)) {
361 0 0         if ($self->{options}{require_strong_checksums}) {
362 0           error(g_('source package uses only weak checksums'));
363             } else {
364 0           $warn_on_weak = 1;
365             }
366             }
367 0           $checksums->add_from_file($self->{basedir} . $file, key => $file);
368             }
369              
370 0 0         warning(g_('source package uses only weak checksums')) if $warn_on_weak;
371             }
372              
373             sub get_basename {
374 0     0 0   my ($self, $with_revision) = @_;
375 0           my $f = $self->{fields};
376 0 0 0       unless (exists $f->{'Source'} and exists $f->{'Version'}) {
377 0           error(g_('%s and %s fields are required to compute the source basename'),
378             'Source', 'Version');
379             }
380 0           my $v = Dpkg::Version->new($f->{'Version'});
381 0           my $vs = $v->as_string(omit_epoch => 1, omit_revision => !$with_revision);
382 0           return $f->{'Source'} . '_' . $vs;
383             }
384              
385             sub find_original_tarballs {
386 0     0 0   my ($self, %opts) = @_;
387 0   0       $opts{extension} //= compression_get_file_extension_regex();
388 0   0       $opts{include_main} //= 1;
389 0   0       $opts{include_supplementary} //= 1;
390 0           my $basename = $self->get_basename();
391 0           my @tar;
392 0           foreach my $dir ('.', $self->{basedir}, $self->{options}{origtardir}) {
393 0 0 0       next unless defined($dir) and -d $dir;
394 0 0         opendir(my $dir_dh, $dir) or syserr(g_('cannot opendir %s'), $dir);
395 0           push @tar, map { "$dir/$_" } grep {
396 0           ($opts{include_main} and
397             /^\Q$basename\E\.orig\.tar\.$opts{extension}$/) or
398             ($opts{include_supplementary} and
399 0 0 0       /^\Q$basename\E\.orig-[[:alnum:]-]+\.tar\.$opts{extension}$/)
      0        
400             } readdir($dir_dh);
401 0           closedir($dir_dh);
402             }
403 0           return @tar;
404             }
405              
406             =item $p->get_upstream_signing_key($dir)
407              
408             Get the filename for the upstream key.
409              
410             =cut
411              
412             sub get_upstream_signing_key {
413 0     0 1   my ($self, $dir) = @_;
414              
415 0           return "$dir/debian/upstream/signing-key.asc";
416             }
417              
418             =item $p->check_original_tarball_signature($dir, @asc)
419              
420             Verify the original upstream tarball signatures @asc using the upstream
421             public keys. It requires the origin upstream tarballs, their signatures
422             and the upstream signing key, as found in an unpacked source tree $dir.
423             If any inconsistency is discovered, it immediately errors out.
424              
425             =cut
426              
427             sub check_original_tarball_signature {
428 0     0 1   my ($self, $dir, @asc) = @_;
429              
430 0           my $upstream_key = $self->get_upstream_signing_key($dir);
431 0 0         if (not -e $upstream_key) {
432 0           warning(g_('upstream tarball signatures but no upstream signing key'));
433 0           return;
434             }
435              
436 0           my $keyring = File::Temp->new(UNLINK => 1, SUFFIX => '.gpg');
437             my %opts = (
438             require_valid_signature => $self->{options}{require_valid_signature},
439 0           );
440 0           Dpkg::OpenPGP::import_key($upstream_key,
441             %opts,
442             keyring => $keyring,
443             );
444              
445 0           foreach my $asc (@asc) {
446 0           Dpkg::OpenPGP::verify_signature($asc,
447             %opts,
448             keyrings => [ $keyring ],
449             datafile => $asc =~ s/\.asc$//r,
450             );
451             }
452             }
453              
454             =item $bool = $p->is_signed()
455              
456             Returns 1 if the DSC files contains an embedded OpenPGP signature.
457             Otherwise returns 0.
458              
459             =cut
460              
461             sub is_signed {
462 0     0 1   my $self = shift;
463 0           return $self->{is_signed};
464             }
465              
466             =item $p->check_signature()
467              
468             Implement the same OpenPGP signature check that dpkg-source does.
469             In case of problems, it prints a warning or errors out.
470              
471             If the object has been created with the "require_valid_signature" option,
472             then any problem will result in a fatal error.
473              
474             =cut
475              
476             sub check_signature {
477 0     0 1   my $self = shift;
478 0           my $dsc = $self->get_filename();
479 0           my @keyrings;
480              
481 0 0 0       if (length $ENV{HOME} and -r "$ENV{HOME}/.gnupg/trustedkeys.gpg") {
482 0           push @keyrings, "$ENV{HOME}/.gnupg/trustedkeys.gpg";
483             }
484 0           foreach my $vendor_keyring (run_vendor_hook('package-keyrings')) {
485 0 0         if (-r $vendor_keyring) {
486 0           push @keyrings, $vendor_keyring;
487             }
488             }
489              
490             my %opts = (
491             keyrings => \@keyrings,
492             require_valid_signature => $self->{options}{require_valid_signature},
493 0           );
494 0           Dpkg::OpenPGP::verify_signature($dsc, %opts);
495             }
496              
497             sub describe_cmdline_options {
498 0     0 0   return;
499             }
500              
501             sub parse_cmdline_options {
502 0     0 0   my ($self, @opts) = @_;
503 0           foreach my $option (@opts) {
504 0 0         if (not $self->parse_cmdline_option($option)) {
505 0           warning(g_('%s is not a valid option for %s'), $option, ref $self);
506             }
507             }
508             }
509              
510             sub parse_cmdline_option {
511 0     0 0   return 0;
512             }
513              
514             =item $p->extract($targetdir)
515              
516             Extracts the source package in the target directory $targetdir. Beware
517             that if $targetdir already exists, it will be erased (as long as the
518             no_overwrite_dir option is set).
519              
520             =cut
521              
522             sub extract {
523 0     0 1   my ($self, $newdirectory) = @_;
524              
525 0           my ($ok, $error) = version_check($self->{fields}{'Version'});
526 0 0         if (not $ok) {
527 0 0         if ($self->{options}{ignore_bad_version}) {
528 0           warning($error);
529             } else {
530 0           error($error);
531             }
532             }
533              
534             # Copy orig tarballs
535 0 0         if ($self->{options}{copy_orig_tarballs}) {
536 0           my $basename = $self->get_basename();
537 0           my ($dirname, $destdir) = fileparse($newdirectory);
538 0   0       $destdir ||= './';
539 0           my $ext = compression_get_file_extension_regex();
540 0           foreach my $orig (grep { /^\Q$basename\E\.orig(-[[:alnum:]-]+)?\.tar\.$ext$/ }
  0            
541             $self->get_files())
542             {
543 0           my $src = File::Spec->catfile($self->{basedir}, $orig);
544 0           my $dst = File::Spec->catfile($destdir, $orig);
545 0 0         if (not check_files_are_the_same($src, $dst, 1)) {
546 0 0         cp($src, $dst)
547             or syserr(g_('cannot copy %s to %s'), $src, $dst);
548             }
549             }
550             }
551              
552             # Try extract
553 0           $self->do_extract($newdirectory);
554              
555             # Check for directory traversals.
556 0 0 0       if (not $self->{options}{skip_debianization} and not $self->{no_check}) {
557             # We need to add a trailing slash to handle the debian directory
558             # possibly being a symlink.
559 0           check_directory_traversal($newdirectory, "$newdirectory/debian/");
560             }
561              
562             # Store format if non-standard so that next build keeps the same format
563 0 0 0       if ($self->{fields}{'Format'} and
      0        
564             $self->{fields}{'Format'} ne '1.0' and
565             not $self->{options}{skip_debianization})
566             {
567 0           my $srcdir = File::Spec->catdir($newdirectory, 'debian', 'source');
568 0           my $format_file = File::Spec->catfile($srcdir, 'format');
569 0 0         unless (-e $format_file) {
570 0 0         mkdir($srcdir) unless -e $srcdir;
571 0           $self->{format}->save($format_file);
572             }
573             }
574              
575             # Make sure debian/rules is executable
576 0           my $rules = File::Spec->catfile($newdirectory, 'debian', 'rules');
577 0           my @s = lstat($rules);
578 0 0         if (not scalar(@s)) {
    0          
579 0 0         unless ($! == ENOENT) {
580 0           syserr(g_('cannot stat %s'), $rules);
581             }
582             warning(g_('%s does not exist'), $rules)
583 0 0         unless $self->{options}{skip_debianization};
584             } elsif (-f _) {
585 0 0         chmod($s[2] | 0111, $rules)
586             or syserr(g_('cannot make %s executable'), $rules);
587             } else {
588 0           warning(g_('%s is not a plain file'), $rules);
589             }
590             }
591              
592             sub do_extract {
593 0     0 0   croak 'Dpkg::Source::Package does not know how to unpack a ' .
594             'source package; use one of the subclasses';
595             }
596              
597             # Function used specifically during creation of a source package
598              
599             sub before_build {
600 0     0 0   my ($self, $dir) = @_;
601             }
602              
603             sub build {
604 0     0 0   my $self = shift;
605              
606 0           $self->do_build(@_);
607             }
608              
609             sub after_build {
610 0     0 0   my ($self, $dir) = @_;
611             }
612              
613             sub do_build {
614 0     0 0   croak 'Dpkg::Source::Package does not know how to build a ' .
615             'source package; use one of the subclasses';
616             }
617              
618             sub can_build {
619 0     0 0   my ($self, $dir) = @_;
620 0           return (0, 'can_build() has not been overridden');
621             }
622              
623             sub add_file {
624 0     0 0   my ($self, $filename) = @_;
625 0           my ($fn, $dir) = fileparse($filename);
626 0 0         if ($self->{checksums}->has_file($fn)) {
627 0           croak "tried to add file '$fn' twice";
628             }
629 0           $self->{checksums}->add_from_file($filename, key => $fn);
630             $self->{checksums}->export_to_control($self->{fields},
631 0           use_files_for_md5 => 1);
632             }
633              
634             sub commit {
635 0     0 0   my $self = shift;
636              
637 0           $self->do_commit(@_);
638             }
639              
640             sub do_commit {
641 0     0 0   my ($self, $dir) = @_;
642             info(g_("'%s' is not supported by the source format '%s'"),
643 0           'dpkg-source --commit', $self->{fields}{'Format'});
644             }
645              
646             sub write_dsc {
647 0     0 0   my ($self, %opts) = @_;
648 0           my $fields = $self->{fields};
649              
650 0           foreach my $f (keys %{$opts{override}}) {
  0            
651 0           $fields->{$f} = $opts{override}{$f};
652             }
653              
654 0 0         unless ($opts{nocheck}) {
655 0           foreach my $f (qw(Source Version Architecture)) {
656 0 0         unless (defined($fields->{$f})) {
657 0           error(g_('missing information for critical output field %s'), $f);
658             }
659             }
660 0           foreach my $f (qw(Maintainer Standards-Version)) {
661 0 0         unless (defined($fields->{$f})) {
662 0           warning(g_('missing information for output field %s'), $f);
663             }
664             }
665             }
666              
667 0           foreach my $f (keys %{$opts{remove}}) {
  0            
668 0           delete $fields->{$f};
669             }
670              
671 0           my $filename = $opts{filename};
672 0   0       $filename //= $self->get_basename(1) . '.dsc';
673 0 0         open(my $dsc_fh, '>', $filename)
674             or syserr(g_('cannot write %s'), $filename);
675 0           $fields->apply_substvars($opts{substvars});
676 0           $fields->output($dsc_fh);
677 0           close($dsc_fh);
678             }
679              
680             =back
681              
682             =head1 CHANGES
683              
684             =head2 Version 2.01 (dpkg 1.20.1)
685              
686             New method: get_upstream_signing_key().
687              
688             =head2 Version 2.00 (dpkg 1.20.0)
689              
690             New method: check_original_tarball_signature().
691              
692             Remove variable: $diff_ignore_default_regexp.
693              
694             Hide variable: @tar_ignore_default_pattern.
695              
696             =head2 Version 1.03 (dpkg 1.19.3)
697              
698             New option: format in new().
699              
700             =head2 Version 1.02 (dpkg 1.18.7)
701              
702             New option: require_strong_checksums in check_checksums().
703              
704             =head2 Version 1.01 (dpkg 1.17.2)
705              
706             New functions: get_default_diff_ignore_regex(), set_default_diff_ignore_regex(),
707             get_default_tar_ignore_pattern()
708              
709             Deprecated variables: $diff_ignore_default_regexp, @tar_ignore_default_pattern
710              
711             =head2 Version 1.00 (dpkg 1.16.1)
712              
713             Mark the module as public.
714              
715             =cut
716              
717             1;