[SCM] Debian package checker branch, master, updated. 2.5.0-rc2-122-g12888e8
The following commit has been merged in the master branch:
commit 9dee20cd35ba5b09a841735db93f29d038e9076b
Merge: d774378912b91430dd8f6c41a0659f9fcd1c8219 e739298c2923a526202eb1d9380a1f770f2b6f3c
Author: Niels Thykier <niels@thykier.net>
Date: Sun Feb 6 22:27:00 2011 +0100
Merge branch 'master' into infra-513663
Conflicts:
frontend/lintian
lib/Lab.pm
man/lintian.pod.in
unpack/unpack-binpkg-l1
unpack/unpack-changes-l1
diff --combined checks/files.desc
index 87ba830,9dd1a0c..fc62411
--- a/checks/files.desc
+++ b/checks/files.desc
@@@ -2,7 -2,7 +2,7 @@@ Check-Script: file
Author: Christian Schwarz <schwarz@debian.org>
Abbrev: fil
Type: binary, udeb
-Needs-Info: unpacked, objdump-info, scripts, file-info
+Needs-Info: unpacked, objdump-info, scripts, file-info, fields
Info: This script checks if a binary package conforms to policy
WRT to files and directories.
@@@ -770,12 -770,42 +770,42 @@@ Info: The package installs a file with
This can happen if ${python:Depends} was omitted from the Depends field
in debian/control.
- Tag: package-installs-python-pyc
+ Tag: missing-dependency-on-python-support
+ Severity: important
+ Certainty: possible
+ Info: The package installs a file in usr/share/python-support/ but does
+ not declare the necessary dependency on python-support.
+ .
+ This can happen if ${python:Depends} was omitted from the Depends field
+ in debian/control.
+
+ Tag: package-installs-python-bytecode
Severity: serious
Certainty: certain
+ Ref: python-policy 2.6
Info: Compiled python source files must not be included in the package.
These files should be removed from the package and created at package
- installation time in the postinst.
+ installation time in the postinst.
+
+ Tag: package-installs-python-egg
+ Severity: serious
+ Certainty: possible
+ Ref: python-policy 2.6
+ Info: Python eggs should not be installed, since the Debian package is
+ supposed to do the required steps for installing the Python code.
+ .
+ The egg may contain pre-compiled python bytecode or shared libraries.
+
+ Tag: package-installs-python-pycache-dir
+ Severity: serious
+ Certainty: certain
+ Ref: python-policy 2.6
+ Info: The package installs a __pycache__ directory, which is normally
+ only used to store compiled python source files. Compiled python
+ source files must not be included in the package, instead they
+ should be generated at installation time in the postinst.
+ .
+ Note this tag is issues even if the directory is empty.
Tag: bad-permissions-for-ali-file
Severity: normal
diff --combined frontend/lintian
index 387685b,c6a70f5..485c519
--- a/frontend/lintian
+++ b/frontend/lintian
@@@ -25,7 -25,6 +25,7 @@@
use strict;
use Getopt::Long;
+use Cwd;
# }}}
# {{{ Global Variables
@@@ -49,6 -48,7 +49,6 @@@ my $lintian_info = 0; #flag for -i|--i
our $display_experimentaltags = 0; #flag for -E|--display-experimental switch
our $display_pedantictags = 0; #flag for --pedantic switch
our $ftpmaster_tags = 0; #flag for -F|--ftp-master-rejects switch
-my $unpack_level = undef; #flag for -l|--unpack-level switch
our $no_override = 0; #flag for -o|--no-override switch
our $show_overrides = 0; #flag for --show-overrides switch
my $color = 'never'; #flag for --color switch
@@@ -65,6 -65,7 +65,6 @@@ our $OPT_LINTIAN_AREA = ''; #string fo
# These options can also be used via default or environment variables
our $LINTIAN_CFG = ''; #config file to use
our $LINTIAN_ROOT; #location of the lintian modules
-our $OPT_LINTIAN_SECTION = ''; #old name for OPT_LINTIAN_ARCH
my $experimental_output_opts = undef;
@@@ -87,7 -88,7 +87,7 @@@ my $exit_code = 0
my $LAB;
my %collection_info;
-my %checks;
+my %enabled_checks;
my %check_abbrev;
my %unpack_infos;
my %check_info;
@@@ -96,6 -97,7 +96,6 @@@
our $LINTIAN_LAB = undef;
our $LINTIAN_ARCHIVEDIR = undef;
our $LINTIAN_DIST = undef;
-our $LINTIAN_UNPACK_LEVEL = undef;
our $LINTIAN_ARCH = undef;
our $LINTIAN_SECTION = undef;
our $LINTIAN_AREA = undef;
@@@ -137,54 -139,54 +137,54 @@@ sub syntax
print <<"EOT-EOT-EOT";
Syntax: lintian [action] [options] [--] [packages] ...
Actions:
- -S, --setup-lab set up static lab
- -R, --remove-lab remove static lab
-c, --check check packages (default action)
-C X, --check-part X check only certain aspects
- -X X, --dont-check-part X don\'t check certain aspects
+ -F, --ftp-master-rejects only check for automatic reject tags
+ -r, --remove remove package from the lab
+ -R, --remove-lab remove static lab
+ -S, --setup-lab set up static lab
-T X, --tags X only run checks needed for requested tags
--tags-from-file X like --tags, but read list from file
- -F, --ftp-master-rejects only check for automatic reject tags
-u, --unpack only unpack packages in the lab
- -r, --remove remove package from the lab
+ -X X, --dont-check-part X don\'t check certain aspects
General options:
+ -d, --debug turn Lintian\'s debug messages ON
-h, --help display short help text
- -v, --verbose verbose messages
- -V, --version display Lintian version and exit
--print-version print unadorned version number and exit
- -d, --debug turn Lintian\'s debug messages ON
-q, --quiet suppress all informational messages
+ -v, --verbose verbose messages
+ -V, --version display Lintian version and exit
Behaviour options:
+ --allow-root suppress lintian\'s warning when run as root
+ --color never/always/auto disable, enable, or enable color for TTY
+ --display-source X restrict displayed tags by source
+ -E, --display-experimental display "X:" tags (normally suppressed)
+ --fail-on-warnings return a non-zero exit status if warnings found
-i, --info give detailed info about tags
-I, --display-info display "I:" tags (normally suppressed)
- -E, --display-experimental display "X:" tags (normally suppressed)
- --pedantic display "P:" tags (normally suppressed)
+ --keep-lab keep lab after run, even if temporary
-L, --display-level display tags with the specified level
- --display-source X restrict displayed tags by source
- --suppress-tags T,... don\'t show the specified tags
- --suppress-tags-from-file X don\'t show the tags listed in file X
+ -m, --md5sums, --checksums check checksums when processing a .changes file
-o, --no-override ignore overrides
+ --pedantic display "P:" tags (normally suppressed)
--show-overrides output tags that have been overriden
- --color never/always/auto disable, enable, or enable color for TTY
+ --suppress-tags T,... don\'t show the specified tags
+ --suppress-tags-from-file X don\'t show the tags listed in file X
-U X, --unpack-info X specify which info should be collected
- -m, --md5sums, --checksums check checksums when processing a .changes file
- --allow-root suppress lintian\'s warning when run as root
- --fail-on-warnings return a non-zero exit status if warnings found
- --keep-lab keep lab after run, even if temporary
Configuration options:
- --cfg CONFIGFILE read CONFIGFILE for configuration
- --lab LABDIR use LABDIR as permanent laboratory
+ --arch ARCH scan packages with architecture ARCH
+ --area AREA scan packages in this archive area (e.g. main)
--archivedir ARCHIVEDIR location of Debian archive to scan for packages
+ --cfg CONFIGFILE read CONFIGFILE for configuration
--dist DIST scan packages in this distribution (e.g. sid)
- --area AREA scan packages in this archive area (e.g. main)
- --arch ARCH scan packages with architecture ARCH
+ --lab LABDIR use LABDIR as permanent laboratory
--root ROOTDIR use ROOTDIR instead of /usr/share/lintian
Package selection options:
-a, --all process all packages in distribution
-b, --binary process only binary packages
+ -p X, --packages-file X process all files in file (special syntax!)
-s, --source process only source packages
--udeb process only udeb packages
- -p X, --packages-file X process all files in file (special syntax!)
EOT-EOT-EOT
exit 0;
@@@ -384,6 -386,7 +384,6 @@@ my %opthash = ( # ------------------
'display-source=s' => \&record_display_source,
'suppress-tags=s' => \&record_suppress_tags,
'suppress-tags-from-file=s' => \&record_suppress_tags_from_file,
- 'unpack-level|l=i' => \$unpack_level,
'no-override|o' => \$no_override,
'show-overrides' => \$show_overrides,
'color=s' => \$color,
@@@ -392,7 -395,6 +392,7 @@@
'allow-root' => \$allow_root,
'fail-on-warnings' => \$fail_on_warnings,
'keep-lab' => \$keep_lab,
+
# Note: Ubuntu has (and other derivatives might gain) a
# -D/--debian option to make lintian behave like in Debian, that
# is, to revert distribution-specific changes
@@@ -426,10 -428,10 +426,10 @@@ GetOptions(%opthash
or die("error parsing options\n");
# determine current working directory--we'll need this later
-chop($cwd = `pwd`);
+$cwd = Cwd::getcwd();
# determine LINTIAN_ROOT if it was not set with --root.
-$LINTIAN_ROOT = $LINTIAN_ROOT || $ENV{'LINTIAN_ROOT'};
+$LINTIAN_ROOT = $ENV{'LINTIAN_ROOT'} unless (defined($LINTIAN_ROOT));
if (defined $LINTIAN_ROOT) {
unless ($LINTIAN_ROOT =~ m,^/,) {
$LINTIAN_ROOT = "$cwd/$LINTIAN_ROOT";
@@@ -482,7 -484,7 +482,7 @@@ if ($LINTIAN_CFG)
undef $LINTIAN_CFG;
}
-use constant VARS => qw(LAB ARCHIVEDIR DIST UNPACK_LEVEL SECTION AREA ARCH);
+use constant VARS => qw(LAB ARCHIVEDIR DIST AREA ARCH);
# read configuration file
if ($LINTIAN_CFG) {
open(CFG, '<', $LINTIAN_CFG)
@@@ -532,6 -534,40 +532,6 @@@ unless (defined $LINTIAN_ARCH)
}
}
-# LINTIAN_SECTION is deprecated in favour of LINTIAN_AREA
-if (defined $LINTIAN_SECTION) {
- print STDERR "warning: LINTIAN_SECTION has been deprecated in favour of LINTIAN_AREA.\n";
- if (defined $LINTIAN_AREA) {
- print STDERR "Using LINTIAN_AREA as both were defined.\n";
- } else {
- print STDERR "Both are currently accepted, but LINTIAN_SECTION may be removed\n";
- print STDERR "in a future Lintian release.\n";
- $LINTIAN_AREA = $LINTIAN_SECTION;
- }
-}
-
-# determine requested unpack level
-if (defined($unpack_level)) {
- print STDERR "warning: --unpack-level is deprecated, ignoring.\n";
- # specified through command line
-} elsif (defined($LINTIAN_UNPACK_LEVEL)) {
- # specified via configuration file or env variable
- print STDERR "warning: LINTIAN_UNPACK_LEVEL is deprecated, ignoring.\n";
-}
-
-# determine by action
-if (($action eq 'unpack') or ($action eq 'check')) {
- $unpack_level = 1;
-} else {
- $unpack_level = 0;
-}
-
-unless (($unpack_level == 0) or ($unpack_level == 1)) {
- die("bad unpack level $unpack_level specified");
-}
-
-$LINTIAN_UNPACK_LEVEL = $unpack_level;
-
# export current settings for our helper scripts
foreach (('ROOT', 'CFG', VARS)) {
no strict 'refs';
@@@ -569,9 -605,6 +569,9 @@@ require Read_pkglists
import Util;
+require Checker;
+require Lintian::Collect;
+require Lintian::DepMap::Properties;
require Lintian::Data;
require Lintian::Schedule;
require Lintian::Output;
@@@ -626,6 -659,7 +626,6 @@@ debug_msg(1
"Laboratory: $LINTIAN_LAB",
"Archive directory: $LINTIAN_ARCHIVEDIR",
"Distribution: $LINTIAN_DIST",
- "Default unpack level: $LINTIAN_UNPACK_LEVEL",
"Architecture: $LINTIAN_ARCH",
delimiter(),
);
@@@ -830,71 -864,182 +830,71 @@@ while (my $arg = shift)
}
}
-if (not $check_everything and not $packages_file and not $schedule->count) {
- v_msg('No packages selected.');
- exit $exit_code;
-}
-# }}}
-
-# {{{ A lone subroutine
-#----------------------------------------------------------------------------
-# Check to make sure there are packages to check.
-sub set_value {
- my ($f,$target,$field,$source,$required) = @_;
- if ($required and not defined($source->{$field})) {
- fail("description file $f does not define required tag $field");
- }
- $target->{$field} = $source->{$field};
- delete $source->{$field};
-}
-# }}}
-
-# {{{ Load information about collector scripts
-opendir(COLLDIR, "$LINTIAN_ROOT/collection")
- or fail("cannot read directory $LINTIAN_ROOT/collection");
-
-for my $f (readdir COLLDIR) {
- next if $f =~ /^\./;
- next unless $f =~ /\.desc$/;
-
- debug_msg(2, "Reading collector description file $f ...");
- my @secs = read_dpkg_control("$LINTIAN_ROOT/collection/$f");
- my $script;
- ($#secs+1 == 1)
- or fail("syntax error in description file $f: too many sections");
-
- ($script = $secs[0]->{'collector-script'})
- or fail("error in description file $f: `Collector-Script:' not defined");
-
- delete $secs[0]->{'collector-script'};
- $collection_info{$script}->{'script'} = $script;
- my $p = $collection_info{$script};
-
- set_value($f, $p,'type',$secs[0],1);
- # convert Type:
- my %type;
- for (split(/\s*,\s*/o,$p->{'type'})) {
- if ($_ eq 'binary') {
- $type{'b'} = 1;
- } elsif ($_ eq 'source') {
- $type{'s'} = 1;
- } elsif ($_ eq 'udeb') {
- $type{'u'} = 1;
- } elsif ($_ eq 'changes') {
- $type{'c'} = 1;
- } else {
- fail("unknown type $_ specified in description file $f");
- }
- }
- $p->{'type'} = \%type;
+if ($check_everything) {
+ # make sure package info is available
+ read_src_list("$LINTIAN_LAB/info/source-packages", 0);
+ read_bin_list("$LINTIAN_LAB/info/binary-packages", 0);
+ read_udeb_list("$LINTIAN_LAB/info/udeb-packages", 0);
- set_value($f,$p,'version',$secs[0],1);
- set_value($f,$p,'auto-remove',$secs[0],0);
+ debug_msg(2, "pkg_mode = $pkg_mode");
- if (exists $secs[0]->{'needs-info'} && defined $secs[0]->{'needs-info'}) {
- for (split(/\s*,\s*/o,$secs[0]->{'needs-info'})) {
- push @{$p->{'needs-info'}}, $_;
+ if (($pkg_mode eq 'a') or ($pkg_mode eq 's')) {
+ for my $arg (sort keys %source_info) {
+ debug_msg(1, "doing stuff with $LINTIAN_ARCHIVEDIR/$source_info{$arg}->{'file'}");
+ $schedule->add_file('s', "$LINTIAN_ARCHIVEDIR/$source_info{$arg}->{'file'}",
+ %{$source_info{$arg}});
}
- delete $secs[0]->{'needs-info'};
}
-
- # ignore Info: and other fields for now
- delete $secs[0]->{'info'};
- delete $secs[0]->{'author'};
-
- for (keys %{$secs[0]}) {
- warning("unused tag $_ in description file $f");
- }
-
- debug_msg(2, map( { "$_: $p->{$_}" if defined($p->{$_}) } sort keys %$p ));
-}
-
-closedir(COLLDIR);
-# }}}
-
-# {{{ Now we're ready to load info about checks & tags
-
-# load information about checker scripts
-opendir(CHECKDIR, "$LINTIAN_ROOT/checks")
- or fail("cannot read directory $LINTIAN_ROOT/checks");
-
-for my $f (readdir CHECKDIR) {
- next if $f =~ /^\./;
- next unless $f =~ /\.desc$/;
- debug_msg(2, "Reading checker description file $f ...");
-
- my @secs = read_dpkg_control("$LINTIAN_ROOT/checks/$f");
- my $script;
- ($script = $secs[0]->{'check-script'})
- or fail("error in description file $f: `Check-Script:' not defined");
-
- # ignore check `lintian' (this check is a special case and contains the
- # tag info for the lintian frontend--this script here)
- next if $script eq 'lintian';
-
- delete $secs[0]->{'check-script'};
- $check_info{$script}->{'script'} = $script;
- my $p = $check_info{$script};
-
- set_value($f,$p,'type',$secs[0],1);
- my %type;
- # convert Type:
- for (split(/\s*,\s*/o,$p->{'type'})) {
- if ($_ eq 'binary') {
- $type{'b'} = 1;
- } elsif ($_ eq 'source') {
- $type{'s'} = 1;
- } elsif ($_ eq 'udeb') {
- $type{'u'} = 1;
- } elsif ($_ eq 'changes') {
- $type{'c'} = 1;
- } else {
- fail("unknown type $_ specified in description file $f");
+ if (($pkg_mode eq 'a') or ($pkg_mode eq 'b')) {
+ for my $arg (sort keys %binary_info) {
+ debug_msg(1, "doing stuff with $LINTIAN_ARCHIVEDIR/$binary_info{$arg}->{'file'}");
+ $schedule->add_file('b', "$LINTIAN_ARCHIVEDIR/$binary_info{$arg}->{'file'}",
+ %{$binary_info{$arg}});
}
}
- $p->{'type'} = \%type;
-
- set_value($f,$p,'abbrev',$secs[0],1);
-
- if (exists $secs[0]->{'needs-info'} && defined $secs[0]->{'needs-info'}) {
- for (split(/\s*,\s*/o,$secs[0]->{'needs-info'})) {
- push @{$p->{'needs-info'}}, $_;
- $p->{$_} = 1;
+ if (($pkg_mode eq 'a') or ($pkg_mode eq 'u')) {
+ for my $arg (sort keys %udeb_info) {
+ debug_msg(1, "doing stuff with $LINTIAN_ARCHIVEDIR/$udeb_info{$arg}->{'file'}");
+ $schedule->add_file('u', "$LINTIAN_ARCHIVEDIR/$udeb_info{$arg}->{'file'}",
+ %{$udeb_info{$arg}});
}
- delete $secs[0]->{'needs-info'};
- }
-
- # ignore Info: and other fields for now...
- delete $secs[0]->{'info'};
- delete $secs[0]->{'standards-version'};
- delete $secs[0]->{'author'};
-
- for (keys %{$secs[0]}) {
- warning("unused tag $_ in description file $f");
}
- debug_msg(2, map( { "$_: $p->{$_}" } sort keys %$p ));
-
- shift(@secs);
- $p->{'requested-tags'} = 0;
- foreach my $tag (@secs) {
- $p->{'requested-tags'}++ if $TAGS->displayed($tag->{'tag'});
+ # package list still empty?
+ unless ($schedule->count) {
+ warning('no packages found in distribution directory');
}
+} elsif ($packages_file) { # process all packages listed in packages file?
+ $schedule->add_pkg_list($packages_file);
}
+# }}}
-closedir(CHECKDIR);
+# {{{ Some silent exit
+my $count = $schedule->count;
+unless ($count) {
+ v_msg('No packages selected.');
+ exit $exit_code;
+}
+# }}}
+# {{{ Load information about collector scripts
+load_collections(\%collection_info, "$LINTIAN_ROOT/collection");
# }}}
-# {{{ Again some lone code the author just dumped where his cursor just happened to be
-if ($unpack_info) {
- # determine which info has been requested
- for my $i (split(/,/,$unpack_info)) {
- unless ($collection_info{$i}) {
- fail("unknown info specified: $i");
- }
- $unpack_infos{$i} = 1;
- }
-}
+# {{{ Now we're ready to load info about checks & tags
-# create check_abbrev hash
-for my $c (keys %check_info) {
- $check_abbrev{$check_info{$c}->{'abbrev'}} = $c;
-}
+# load information about checker scripts
+load_checks(\%check_info, $TAGS, "$LINTIAN_ROOT/checks");
# }}}
# {{{ determine which checks have been requested
if ($action eq 'check') {
+ # create check_abbrev hash
+ for my $c (keys %check_info) {
+ $check_abbrev{$check_info{$c}->{'abbrev'}} = $c;
+ }
+
if ($check_tags) {
foreach my $t (split(/,/, $check_tags)) {
my $info = Lintian::Tag::Info->new($t);
@@@ -903,7 -1048,7 +903,7 @@@
my $script = $info->script;
next if $script eq 'lintian';
if ($check_info{$script}) {
- $checks{$script} = 1;
+ $enabled_checks{$script} = 1;
} else {
# should never happen
fail("no info for script $script");
@@@ -921,11 -1066,11 +921,11 @@@
} elsif ($check_info{$c}->{'requested-tags'} == 0) {
#no need to run this check, no tags will be issued
} else {
- $checks{$c} = 1;
+ $enabled_checks{$c} = 1;
}
} elsif (exists $check_abbrev{$c}) {
#abbrevs only used when -C is given, so we don't need %dont_check
- $checks{$check_abbrev{$c}} = 1;
+ $enabled_checks{$check_abbrev{$c}} = 1;
} else {
fail("unknown check specified: $c");
}
@@@ -933,7 -1078,7 +933,7 @@@
}
# determine which info is needed by the checks
- for my $c (keys %checks) {
+ for my $c (keys %enabled_checks) {
for my $i (keys %collection_info) {
# required by $c ?
if ($check_info{$c}->{$i}) {
@@@ -945,57 -1090,29 +945,57 @@@
# }}}
-require Lintian::DepMap::Properties;
+# {{{ determine which info is needed by the collection scripts
+if ($action eq 'unpack') {
+ # With --unpack we want all of it
+ for my $c (keys %collection_info) {
+ $unpack_infos{$c} = 1;
+ }
+} else {
+ for my $c (keys %unpack_infos) {
+ if (exists $collection_info{$c}{'needs-info'}) {
+ map { $unpack_infos{$_} = 1; } @{$collection_info{$c}{'needs-info'}};
+ }
+ }
+ if ($unpack_info) {
+ # Add collections specifically requested by the user (--unpack-info)
+ for my $i (split(/,/,$unpack_info)) {
+ unless ($collection_info{$i}) {
+ fail("unknown info specified: $i");
+ }
+ $unpack_infos{$i} = 1;
+ }
+ }
+}
+# }}}
+
+# {{{ Create the dependency tree and populate it with checks and collections
+
+# All required checks and collections have been calculated at this point.
+# We are just adding this information to a map now that will generate the
+# execution order.
my $map = Lintian::DepMap::Properties->new();
-# {{{ determine which info is needed by the collection scripts
-for my $c (keys %unpack_infos) {
- if (exists $collection_info{$c}{'needs-info'}) {
- map { $unpack_infos{$_} = 1; } @{$collection_info{$c}{'needs-info'}};
+unless ($no_override) {
+ # add the override-file collection
+ $map->add('coll-override-file', {'type' => 'collection', 'name' => 'override-file'});
+ if (exists $collection_info{'override-file'}{'needs-info'}) {
+ $map->addp('coll-override-file', 'coll-',
+ @{$collection_info{'override-file'}{'needs-info'}});
}
}
-# }}}
-# {{{ add the collection scripts to the dependencies tree
for my $c (keys %unpack_infos) {
+ # Add the collections with their dependency information
$map->add('coll-' . $c, {'type' => 'collection', 'name' => $c});
if (exists $collection_info{$c}{'needs-info'}) {
$map->addp('coll-' . $c, 'coll-', @{$collection_info{$c}{'needs-info'}});
}
}
-# }}}
-# {{{ add the checks to the dependencies tree
-for my $c (keys %checks) {
+for my $c (keys %enabled_checks) {
+ # Add the checks with their dependency information
$map->add('check-' . $c, {'type' => 'check', 'name' => $c});
if (exists $check_info{$c}{'needs-info'}) {
$map->addp('check-' . $c, 'coll-', @{$check_info{$c}{'needs-info'}});
@@@ -1003,12 -1120,76 +1003,12 @@@
}
# }}}
-# {{{ make --unpack collect all info
-if ($action eq 'unpack') {
- for my $c (keys %collection_info) {
- $unpack_infos{$c} = 1;
- }
-}
-# }}}
-
-# {{{ process all packages in the archive?
-if ($check_everything) {
- # make sure package info is available
- read_src_list("$LINTIAN_LAB/info/source-packages", 0);
- read_bin_list("$LINTIAN_LAB/info/binary-packages", 0);
- read_udeb_list("$LINTIAN_LAB/info/udeb-packages", 0);
-
- debug_msg(2, "pkg_mode = $pkg_mode");
-
- if (($pkg_mode eq 'a') or ($pkg_mode eq 's')) {
- for my $arg (sort keys %source_info) {
- debug_msg(1, "doing stuff with $LINTIAN_ARCHIVEDIR/$source_info{$arg}->{'file'}");
- $schedule->add_file('s', "$LINTIAN_ARCHIVEDIR/$source_info{$arg}->{'file'}",
- %{$source_info{$arg}});
- }
- }
- if (($pkg_mode eq 'a') or ($pkg_mode eq 'b')) {
- for my $arg (sort keys %binary_info) {
- debug_msg(1, "doing stuff with $LINTIAN_ARCHIVEDIR/$binary_info{$arg}->{'file'}");
- $schedule->add_file('b', "$LINTIAN_ARCHIVEDIR/$binary_info{$arg}->{'file'}",
- %{$binary_info{$arg}});
- }
- }
- if (($pkg_mode eq 'a') or ($pkg_mode eq 'u')) {
- for my $arg (sort keys %udeb_info) {
- debug_msg(1, "doing stuff with $LINTIAN_ARCHIVEDIR/$udeb_info{$arg}->{'file'}");
- $schedule->add_file('u', "$LINTIAN_ARCHIVEDIR/$udeb_info{$arg}->{'file'}",
- %{$udeb_info{$arg}});
- }
- }
-
- # package list still empty?
- unless ($schedule->count) {
- warning('no packages found in distribution directory');
- }
-} elsif ($packages_file) { # process all packages listed in packages file?
- $schedule->add_pkg_list($packages_file);
-}
-# }}}
-
-# {{{ Some silent exit
-my $count = $schedule->count;
-unless ($count) {
- v_msg('No packages selected.');
- exit 0;
-}
-# }}}
-
# {{{ Okay, now really processing the packages in one huge loop
v_msg(sprintf('Processing %d packages...', $count));
debug_msg(1,
"Selected action: $action",
- "Requested unpack level: $unpack_level",
sprintf('Requested data to collect: %s', join(',',sort keys %unpack_infos)),
- sprintf('Selected checks: %s', join(',',sort keys %checks)),
+ sprintf('Selected checks: %s', join(',',sort keys %enabled_checks)),
);
@@@ -1016,34 -1197,8 +1016,34 @@@
scalar($map->missing()) == 0
or fail('There are missing nodes on the resolver: '.join(', ', $map->missing()));
-require Checker;
-require Lintian::Collect;
+## REFACTORING NOTES:
+## If we are here $action is one of "check", "unpack" or "remove"
+##
+
+if($action eq 'remove'){
+ # Handle remove here - makes the unpack/check loop simpler.
+ foreach my $pkg_info ($schedule->get_all) {
+ my ($type, $pkg, $ver, $arch, $file) =
+ @$pkg_info{qw(type package version architecture file)};
+ my $lpkg;
+ eval{ $lpkg = $LAB->get_lab_package($pkg, $ver, $type, $file); };
+ if(!defined($lpkg)){
+ my $err = '.';
+ $err = ": $@" if(defined($@));
+ warning("skipping $action of $type package $pkg$err");
+ $exit_code = 2;
+ next;
+ }
+ $TAGS->file_start($file, $pkg, $ver, $arch, $lpkg->pkg_type());
+ unless($lpkg->delete_lab_entry()){
+ $exit_code = 2;
+ }
+ }
+ $TAGS->file_end();
+ exit $exit_code;
+}
+
+# Now action is always either "check" or "unpack"
my %overrides;
my %running_jobs;
@@@ -1051,22 -1206,9 +1051,22 @@@ PACKAGE
foreach my $pkg_info ($schedule->get_all) {
my ($type, $pkg, $ver, $arch, $file) =
@$pkg_info{qw(type package version architecture file)};
- my $long_type = ($type eq 'b' ? 'binary' :
- ($type eq 'c' ? 'changes' :
- ($type eq 's' ? 'source' : 'udeb' )));
+ my $lpkg;
+ my $long_type;
+ my $base;
+ my $info;
+ my $loaded_overrides = 0;
+ eval{ $lpkg = $LAB->get_lab_package($pkg, $ver, $type, $file); };
+ if(!defined($lpkg)){
+ my $err = '.';
+ $err = ": $@" if(defined($@));
+ warning("skipping $action of $type package $pkg$err");
+ $exit_code = 2;
+ next PACKAGE;
+ }
+
+ # The Lab will normalize it.
+ $long_type = $lpkg->pkg_type();
$TAGS->file_start($file, $pkg, $ver, $arch, $long_type);
$map->initialise();
@@@ -1076,172 -1218,246 +1076,172 @@@
%running_jobs = ();
# determine base directory
- my $base = "$LINTIAN_LAB/$long_type/$pkg";
- unless ($base =~ m,^/,) {
- $base = "$cwd/$base";
- }
+ $base = $lpkg->base_dir();
debug_msg(1, "Base directory in lab: $base");
- my $act_unpack_level = 0;
-
- # unpacked package up-to-date?
- if (-d $base) {
- my $remove_basedir = 0;
-
- # there's a base dir, so we assume that at least
- # one level of unpacking has been done
- $act_unpack_level = 1;
-
- # lintian status file exists?
- unless (-f "$base/.lintian-status") {
- v_msg('No lintian status file found (removing old directory in lab)');
- $remove_basedir = 1;
- goto REMOVE_BASEDIR;
- }
-
- # read unpack status -- catch any possible errors
- my $data;
- eval { ($data) = read_dpkg_control("$base/.lintian-status"); };
- if ($@) { # error!
- v_msg($@);
- $remove_basedir = 1;
- goto REMOVE_BASEDIR;
- }
-
- # compatible lintian version?
- if (not exists $data->{'lab-format'} or ($data->{'lab-format'} < $LAB_FORMAT)) {
- v_msg('Lab directory was created by incompatible lintian version');
- $remove_basedir = 1;
- goto REMOVE_BASEDIR;
- }
-
- # version up to date?
- if (not exists $data->{'version'} or ($data->{'version'} ne $ver)) {
- debug_msg(1, 'Removing package in lab (newer version exists) ...');
- $remove_basedir = 1;
- goto REMOVE_BASEDIR;
- }
-
- # file modified?
- my $timestamp;
- my @stat;
- unless (@stat = stat $file) {
- warning("cannot stat file $file: $!");
- } else {
- $timestamp = $stat[9];
- }
- if ((not defined $timestamp) or (not exists $data->{'timestamp'}) or ($data->{'timestamp'} != $timestamp)) {
- debug_msg(1, 'Removing package in lab (package has been changed) ...');
- $remove_basedir = 1;
- goto REMOVE_BASEDIR;
- }
-
- REMOVE_BASEDIR:
- if ($remove_basedir) {
- v_msg("Removing $pkg");
- unless (remove_pkg($base)) {
- warning("skipping $action of $long_type package $pkg");
- $exit_code = 2;
- next PACKAGE;
- }
- $act_unpack_level = 0;
- }
+ # Ensure it has been unpacked
+ unless ($lpkg->create_entry()){
+ warning('could not create the package entry in the lab',
+ "skipping $action of $long_type package $pkg");
+ $exit_code = 2;
+ next PACKAGE;
}
+ $info = Lintian::Collect->new($pkg, $long_type);
- # unpack to requested unpack level
- $act_unpack_level = unpack_pkg($type,$base,$file,$act_unpack_level,
- $unpack_level);
- if ($act_unpack_level == -1) {
- warning('could not unpack package to desired level',
+ # chdir to base directory
+ unless (chdir($base)) {
+ warning("could not chdir into directory $base: $!",
"skipping $action of $long_type package $pkg");
$exit_code = 2;
next PACKAGE;
}
- if (($action eq 'unpack') or ($action eq 'check')) {
- my $info = Lintian::Collect->new($pkg, $long_type);
- my $loaded_overrides = 0;
-
- # chdir to base directory
- unless (chdir($base)) {
- warning("could not chdir into directory $base: $!",
- "skipping $action of $long_type package $pkg");
- $exit_code = 2;
- next PACKAGE;
- }
+ while ($map->pending) {
+ foreach my $req (sort sort_coll $map->selectable) {
+ my $ri = $map->getProp($req);
+ if ($ri->{'type'} eq 'collection') {
+ my $coll = $ri->{'name'};
+ my $ci = $collection_info{$coll};
- while ($map->pending) {
- foreach my $req (sort sort_coll $map->selectable) {
- my $ri = $map->getProp($req);
- if ($ri->{'type'} eq 'collection') {
- my $coll = $ri->{'name'};
- my $ci = $collection_info{$coll};
-
- # current type?
- unless (exists $ci->{'type'}{$type}) {
- $map->satisfy($req);
- next;
- }
+ # current type?
+ unless (exists $ci->{'type'}{$type}) {
+ $map->satisfy($req);
+ next;
+ }
- # If a file named .SCRIPT-VERSION already exists, we've already
- # collected this information and we can skip it. Otherwise,
- # remove any .SCRIPT-* files (which are old version information).
- if (-f "$base/.${coll}-$ci->{'version'}") {
- $map->satisfy($req);
- next;
- }
- opendir(BASE, $base)
- or fail("cannot read directory $base: $!");
- for my $file (readdir BASE) {
- if ($file =~ /^\.\Q$coll-/) {
- unlink("$base/$file");
- }
- }
- closedir(BASE);
-
- # collect info
- $map->select($req);
- remove_status_file($base);
- debug_msg(1, "Collecting info: $coll ...");
- my $script = "$LINTIAN_ROOT/collection/$ci->{'script'}";
- my $cmd = Lintian::Command::Simple->new();
- unless ($cmd->background($script, $pkg, $long_type) > 0) {
- warning("collect info $coll about package $pkg failed",
- "skipping $action of $long_type package $pkg");
- $exit_code = 2;
- next PACKAGE;
- }
- $running_jobs{$coll} = $cmd;
- } elsif ($ri->{'type'} eq 'check') {
- # skip check if overrides were not yet loaded
- last unless $loaded_overrides or $no_override;
- my $check = $ri->{'name'};
- my $ci = $check_info{$check};
-
- # current type?
- unless (exists $ci->{'type'}{$type}) {
- $map->satisfy($req);
- next;
+ # If a file named .SCRIPT-VERSION already exists, we've already
+ # collected this information and we can skip it. Otherwise,
+ # remove any .SCRIPT-* files (which are old version information).
+ if (-f "$base/.${coll}-$ci->{'version'}") {
+ $map->satisfy($req);
+ next;
+ }
+ opendir(BASE, $base)
+ or fail("cannot read directory $base: $!");
+ for my $file (readdir BASE) {
+ if ($file =~ /^\.\Q$coll-/) {
+ unlink("$base/$file");
}
+ }
+ closedir(BASE);
- debug_msg(1, "Running check: $check ...");
- my $returnvalue = Checker::runcheck($pkg, $long_type, $info, $check);
- # Set exit_code correctly if there was not yet an exit code
- $exit_code = $returnvalue unless $exit_code;
-
- if ($returnvalue == 2) {
- warning("skipping $action of $long_type package $pkg");
- next PACKAGE;
- }
+ # collect info
+ $map->select($req);
+ $lpkg->remove_status_file();
+ debug_msg(1, "Collecting info: $coll ...");
+ my $script = "$LINTIAN_ROOT/collection/$ci->{'script'}";
+ my $cmd = Lintian::Command::Simple->new();
+ unless ($cmd->background($script, $pkg, $long_type) > 0) {
+ warning("collect info $coll about package $pkg failed",
+ "skipping $action of $long_type package $pkg");
+ $exit_code = 2;
+ next PACKAGE;
+ }
+ $running_jobs{$coll} = $cmd;
+ } elsif ($ri->{'type'} eq 'check') {
+ # skip check if overrides were not yet loaded
+ last unless $loaded_overrides or $no_override;
+ my $check = $ri->{'name'};
+ my $ci = $check_info{$check};
+
+ # current type?
+ unless (exists $ci->{'type'}{$type}) {
$map->satisfy($req);
+ next;
}
- }
- # wait until a job finishes to run its branches, if any, or skip
- # this package if any of the jobs failed.
- debug_msg(1, 'Reaping done jobs ...');
-
- while (my ($coll, $cmd) = Lintian::Command::Simple::wait(\%running_jobs)) {
- delete $running_jobs{$coll};
- if ($cmd->status() == 0) {
- my $ci = $collection_info{$coll};
- open(VERSION, '>', "$base/.${coll}-$ci->{'version'}")
- or fail("cannot create $base/.${coll}-$ci->{'version'}: $!");
- print VERSION "Lintian-Version: $LINTIAN_VERSION\n"
- . 'Timestamp: ' . time . "\n";
- close(VERSION);
- debug_msg(1, "Collection script $coll done");
- } else {
- warning("collect info $coll about package $pkg failed");
+
+ debug_msg(1, "Running check: $check ...");
+ my $returnvalue = Checker::runcheck($pkg, $long_type, $info, $check);
+ # Set exit_code correctly if there was not yet an exit code
+ $exit_code = $returnvalue unless $exit_code;
+
+ if ($returnvalue == 2) {
warning("skipping $action of $long_type package $pkg");
$exit_code = 2;
next PACKAGE;
}
+ $map->satisfy($req);
+ }
+ }
+ # wait until a job finishes to run its branches, if any, or skip
+ # this package if any of the jobs failed.
+ debug_msg(1, 'Reaping done jobs ...');
+
+ while (my ($coll, $cmd) = Lintian::Command::Simple::wait(\%running_jobs)) {
+ delete $running_jobs{$coll};
+ if ($cmd->status() == 0) {
+ my $ci = $collection_info{$coll};
+ open(VERSION, '>', "$base/.${coll}-$ci->{'version'}")
+ or fail("cannot create $base/.${coll}-$ci->{'version'}: $!");
+ print VERSION "Lintian-Version: $LINTIAN_VERSION\n"
+ . 'Timestamp: ' . time . "\n";
+ close(VERSION);
+ debug_msg(1, "Collection script $coll done");
+ } else {
+ warning("collect info $coll about package $pkg failed");
+ warning("skipping $action of $long_type package $pkg");
+ $exit_code = 2;
+ next PACKAGE;
+ }
- $map->satisfy('coll-' . $coll);
+ $map->satisfy('coll-' . $coll);
- # give a chance to other jobs to finish while we
- # process other stuff:
- last;
- }
+ # give a chance to other jobs to finish while we
+ # process other stuff:
+ last;
+ }
- unless ($no_override or $loaded_overrides) {
- if ($map->done('coll-override-file')) {
- debug_msg(1, 'Override file collected, loading it ...');
- $loaded_overrides = 1;
- $TAGS->file_overrides("$base/override")
- if (-f "$base/override");
- }
+ unless ($no_override or $loaded_overrides) {
+ if ($map->done('coll-override-file')) {
+ debug_msg(1, 'Override file collected, loading it ...');
+ $loaded_overrides = 1;
+ $TAGS->file_overrides("$base/override")
+ if (-f "$base/override");
}
}
- %running_jobs = ();
-
- if ($action eq 'check') {
- unless ($exit_code) {
- my $stats = $TAGS->statistics($file);
- if ($stats->{types}{E}) {
- $exit_code = 1;
- } elsif ($fail_on_warnings && $stats->{types}{W}) {
- $exit_code = 1;
- }
+ }
+ %running_jobs = ();
+
+ if ($action eq 'check') {
+ unless ($exit_code) {
+ my $stats = $TAGS->statistics($file);
+ if ($stats->{types}{E}) {
+ $exit_code = 1;
+ } elsif ($fail_on_warnings && $stats->{types}{W}) {
+ $exit_code = 1;
}
+ }
- # report unused overrides
- if (not $no_override) {
- my $overrides = $TAGS->overrides($file);
+ # report unused overrides
+ if (not $no_override) {
+ my $overrides = $TAGS->overrides($file);
- for my $tag (sort keys %$overrides) {
- next if $TAGS->suppressed($tag);
+ for my $tag (sort keys %$overrides) {
+ next if $TAGS->suppressed($tag);
- # Did we run the check script containing the tag?
- my $taginfo = Lintian::Tag::Info->new($tag);
- if (defined $taginfo) {
- next unless $checks{$taginfo->script};
- }
+ # Did we run the check script containing the tag?
+ my $taginfo = Lintian::Tag::Info->new($tag);
+ if (defined $taginfo) {
+ next unless $enabled_checks{$taginfo->script};
+ }
- for my $extra (sort keys %{$overrides->{$tag}}) {
- next if $overrides->{$tag}{$extra};
+ for my $extra (sort keys %{$overrides->{$tag}}) {
+ next if $overrides->{$tag}{$extra};
- tag( 'unused-override', $tag, $extra );
- }
+ tag( 'unused-override', $tag, $extra );
}
}
+ }
- # Report override statistics.
- if (not $no_override and not $show_overrides) {
- my $stats = $TAGS->statistics($file);
- my $errors = $stats->{overrides}{types}{E} || 0;
- my $warnings = $stats->{overrides}{types}{W} || 0;
- my $info = $stats->{overrides}{types}{I} || 0;
- $overrides{errors} += $errors;
- $overrides{warnings} += $warnings;
- $overrides{info} += $info;
- }
+ # Report override statistics.
+ if (not $no_override and not $show_overrides) {
+ my $stats = $TAGS->statistics($file);
+ my $errors = $stats->{overrides}{types}{E} || 0;
+ my $warnings = $stats->{overrides}{types}{W} || 0;
+ my $info = $stats->{overrides}{types}{I} || 0;
+ $overrides{errors} += $errors;
+ $overrides{warnings} += $warnings;
+ $overrides{info} += $info;
}
}
@@@ -1253,13 -1469,24 +1253,13 @@@
next PACKAGE;
}
- # clean up
- if ($act_unpack_level > $unpack_level) {
- $act_unpack_level = clean_pkg($type,$base,$file,$act_unpack_level,$unpack_level);
- if ($act_unpack_level == -1) {
- warning("could not clean up laboratory for package $pkg: $!",
- 'skipping clean up');
- $exit_code = 2;
- next PACKAGE;
- }
- }
# if the package's basedir was not removed then run the
# auto-remove: yes collection scripts
- if (-d $base) {
+ if (!$keep_lab) {
chdir($base);
for my $coll (keys %collection_info) {
my $ci = $collection_info{$coll};
if (defined($ci->{'auto-remove'}) && $ci->{'auto-remove'} eq 'yes') {
- next if $keep_lab;
next unless (-f "$base/.${coll}-$ci->{'version'}");
my $script = "$LINTIAN_ROOT/collection/$ci->{'script'}";
debug_msg(1, "Auto removing: $ci->{'script'} ...");
@@@ -1276,9 -1503,31 +1276,9 @@@
chdir($LINTIAN_ROOT);
}
- # create Lintian status file
- if (($act_unpack_level > 0) and (not -f "$base/.lintian-status")) {
- my @stat;
- unless (@stat = stat $file) {
- warning("cannot stat file $file: $!",
- 'skipping creation of status file');
- $exit_code = 2;
- next PACKAGE;
- }
- my $timestamp = $stat[9];
-
- unless (open(STATUS, '>', "$base/.lintian-status")) {
- warning("could not create status file $base/.lintian-status for package $pkg: $!");
- $exit_code = 2;
- next PACKAGE;
- }
-
- print STATUS "Lintian-Version: $LINTIAN_VERSION\n";
- print STATUS "Lab-Format: $LAB_FORMAT\n";
- print STATUS "Package: $pkg\n";
- print STATUS "Version: $ver\n";
- print STATUS "Type: $type\n";
- print STATUS "Timestamp: $timestamp\n";
- close(STATUS);
- }
+ # All successful, make sure to record it so we do not recheck the same package
+ # in a later run (mostly for archive-wide checks).
+ $lpkg->update_status_file($LINTIAN_VERSION);
}
$TAGS->file_end();
@@@ -1321,169 -1570,119 +1321,169 @@@ exit $exit_code
# {{{ Some subroutines
-sub unpack_pkg {
- my ($type,$base,$file,$cur_level,$new_level) = @_;
+# Check to make sure there are packages to check.
+sub set_value {
+ my ($f,$target,$field,$source,$required) = @_;
+ if ($required and not defined($source->{$field})) {
+ fail("description file $f does not define required tag $field");
+ }
+ $target->{$field} = $source->{$field};
+ delete $source->{$field};
+}
- debug_msg(1, sprintf('Current unpack level is %d',$cur_level));
+# Given a ref to %collection_info and the path to the collection
+# directory, this will load all the collection information into
+# %collection_info.
+sub load_collections{
+ my ($cinfo, $dirname) = @_;
+ opendir(my $dir, $dirname)
+ or fail("cannot read directory $dirname");
+
+ for my $f (readdir($dir)) {
+ next if $f =~ /^\./;
+ next unless $f =~ /\.desc$/;
+
+ debug_msg(2, "Reading collector description file $f ...");
+ my @secs = read_dpkg_control("$dirname/$f");
+ my $script;
+ ($#secs+1 == 1)
+ or fail("syntax error in description file $f: too many sections");
+
+ ($script = $secs[0]->{'collector-script'})
+ or fail("error in description file $f: `Collector-Script:' not defined");
+
+ delete $secs[0]->{'collector-script'};
+ $cinfo->{$script}->{'script'} = $script;
+ my $p = $cinfo->{$script};
+
+ set_value($f, $p,'type',$secs[0],1);
+ # convert Type:
+ my %type;
+ for (split(/\s*,\s*/o,$p->{'type'})) {
+ if ($_ eq 'binary') {
+ $type{'b'} = 1;
+ } elsif ($_ eq 'source') {
+ $type{'s'} = 1;
+ } elsif ($_ eq 'udeb') {
+ $type{'u'} = 1;
+ } elsif ($_ eq 'changes') {
+ $type{'c'} = 1;
+ } else {
+ fail("unknown type $_ specified in description file $f");
+ }
+ }
+ $p->{'type'} = \%type;
- return $cur_level if $cur_level == $new_level;
+ set_value($f,$p,'version',$secs[0],1);
+ set_value($f,$p,'auto-remove',$secs[0],0);
- # remove .lintian-status file
- remove_status_file($base);
+ if (exists $secs[0]->{'needs-info'} && defined $secs[0]->{'needs-info'}) {
+ for (split(/\s*,\s*/o,$secs[0]->{'needs-info'})) {
+ push @{$p->{'needs-info'}}, $_;
+ }
+ delete $secs[0]->{'needs-info'};
+ }
- if ( ($cur_level == 0) and (-d $base) ) {
- # We were lied to, there's something already there - clean it up first
- remove_pkg($base) or return -1;
- }
+ # ignore Info: and other fields for now
+ delete $secs[0]->{'info'};
+ delete $secs[0]->{'author'};
- if ( ($new_level >= 1) and
- (not defined ($cur_level) or ($cur_level < 1)) ) {
- # create new directory
- debug_msg(1, 'Unpacking package to level 1 ...');
- if (($type eq 'b') || ($type eq 'u')) {
- Lintian::Command::Simple::run("$LINTIAN_ROOT/unpack/unpack-binpkg-l1", $base, $file) == 0
- or return -1;
- } elsif ($type eq 'c') {
- spawn({}, ["$LINTIAN_ROOT/unpack/unpack-changes-l1", $base, $file])
- or return -1;
- } else {
- Lintian::Command::Simple::run("$LINTIAN_ROOT/unpack/unpack-srcpkg-l1", $base, $file) == 0
- or return -1;
+ for (keys %{$secs[0]}) {
+ warning("unused tag $_ in description file $f");
}
- $cur_level = 1;
- }
- if ($new_level >= 2) {
- warning('Requested no longer existent unpack-level 2, expect errors');
- return $cur_level;
+ debug_msg(2, map( { "$_: $p->{$_}" if defined($p->{$_}) } sort keys %$p ));
}
- return $cur_level;
+ closedir($dir);
}
-sub sort_coll {
- my ($ap, $bp);
- $ap = $map->getProp($a);
- $bp = $map->getProp($b);
- # override-file should be the first script to be run
- return -1 if ($ap->{'name'} eq 'override-file');
- return 1 if ($bp->{'name'} eq 'override-file');
- # sort collection scripts first
- return -1 if ($ap->{'type'} eq 'collection' && $bp->{'type'} ne 'collection');
- return 1 if ($bp->{'type'} eq 'collection' && $ap->{'type'} ne 'collection');
- return ($ap->{'name'} cmp $bp->{'name'});
-}
-
-# TODO: is this the best way to clean dirs in perl?
-# no, look at File::Path module
-sub clean_pkg {
- my ($type,$base,$file,$cur_level,$new_level) = @_;
-
- return $cur_level if $cur_level == $new_level;
-
- if ($new_level < 1) {
- # remove base directory
- remove_pkg($base) or return -1;
- return 0;
+# Given a ref to %check_info, $TAGS and the path to the checks
+# directory, this will load all the information about checks into
+# %check_info.
+sub load_checks{
+ my ($cinfo, $tags, $dirname) = @_;
+ opendir(my $dir, $dirname)
+ or fail("cannot read directory $dirname");
+
+ for my $f (readdir($dir)) {
+ next if $f =~ /^\./;
+ next unless $f =~ /\.desc$/;
+ debug_msg(2, "Reading checker description file $f ...");
+
+ my @secs = read_dpkg_control("$dirname/$f");
+ my $script;
+ ($script = $secs[0]->{'check-script'})
+ or fail("error in description file $f: `Check-Script:' not defined");
+
+ # ignore check `lintian' (this check is a special case and contains the
+ # tag info for the lintian frontend--this script here)
+ next if $script eq 'lintian';
+
+ delete $secs[0]->{'check-script'};
+ $cinfo->{$script}->{'script'} = $script;
+ my $p = $cinfo->{$script};
+
+ set_value($f,$p,'type',$secs[0],1);
+ my %type;
+ # convert Type:
+ for (split(/\s*,\s*/o,$p->{'type'})) {
+ if ($_ eq 'binary') {
+ $type{'b'} = 1;
+ } elsif ($_ eq 'source') {
+ $type{'s'} = 1;
+ } elsif ($_ eq 'udeb') {
+ $type{'u'} = 1;
+ } elsif ($_ eq 'changes') {
+ $type{'c'} = 1;
+ } else {
+ fail("unknown type $_ specified in description file $f");
+ }
}
+ $p->{'type'} = \%type;
- if ( ($new_level < 2) and defined ($cur_level) and ($cur_level >= 2) ) {
- # remove .lintian-status file
- remove_status_file($base);
+ set_value($f,$p,'abbrev',$secs[0],1);
- # remove unpacked/ directory
- debug_msg(1, 'Decreasing unpack level to 1 (removing files) ...');
- if ( -l "$base/unpacked" ) {
- delete_dir("$base/".readlink("$base/unpacked"))
- or return -1;
- delete_dir("$base/unpacked") or return -1;
- } else {
- delete_dir("$base/unpacked") or return -1;
+ if (exists $secs[0]->{'needs-info'} && defined $secs[0]->{'needs-info'}) {
+ for (split(/\s*,\s*/o,$secs[0]->{'needs-info'})) {
+ push @{$p->{'needs-info'}}, $_;
+ $p->{$_} = 1;
+ }
+ delete $secs[0]->{'needs-info'};
}
- $cur_level = 1;
- }
+ # ignore Info: and other fields for now...
+ delete $secs[0]->{'info'};
+ delete $secs[0]->{'standards-version'};
+ delete $secs[0]->{'author'};
- return $cur_level;
-}
+ for (keys %{$secs[0]}) {
+ warning("unused tag $_ in description file $f");
+ }
-# this function removes a package's base directory in the lab completely
-sub remove_pkg {
- my ($base) = @_;
+ debug_msg(2, map( { "$_: $p->{$_}" } sort keys %$p ));
- debug_msg(1, 'Removing package in lab ...');
- unless (delete_dir($base)) {
- warning("cannot remove directory $base: $!");
- return 0;
+ shift(@secs);
+ $p->{'requested-tags'} = 0;
+ foreach my $tag (@secs) {
+ $p->{'requested-tags'}++ if $tags->displayed($tag->{'tag'});
+ }
}
-
- return 1;
+ closedir($dir);
}
-sub remove_status_file {
- my ($base) = @_;
- # status file exists?
- if (not -e "$base/.lintian-status") {
- return 1;
- }
-
- if (not unlink("$base/.lintian-status")) {
- warning("cannot remove status file $base/.lintian-status: $!");
- return 0;
- }
-
- return 1;
+sub sort_coll {
+ my ($ap, $bp);
+ $ap = $map->getProp($a);
+ $bp = $map->getProp($b);
+ # override-file should be the first script to be run
+ return -1 if ($ap->{'name'} eq 'override-file');
+ return 1 if ($bp->{'name'} eq 'override-file');
+ # sort collection scripts first
+ return -1 if ($ap->{'type'} eq 'collection' && $bp->{'type'} ne 'collection');
+ return 1 if ($bp->{'type'} eq 'collection' && $ap->{'type'} ne 'collection');
+ return ($ap->{'name'} cmp $bp->{'name'});
}
# -------------------------------
diff --combined lib/Lab.pm
index 4c316f3,d7142b2..253440d
--- a/lib/Lab.pm
+++ b/lib/Lab.pm
@@@ -19,36 -19,15 +19,36 @@@
# MA 02110-1301, USA.
package Lab;
+
use strict;
use warnings;
+use base qw(Exporter);
+
+use constant LAB_FORMAT => 10;
+
+# Export now due to cicular depends between Lab and Lab::Package.
+our (@EXPORT, @EXPORT_OK, %EXPORT_TAGS);
+
+BEGIN {
+ @EXPORT = ();
+ %EXPORT_TAGS = (
+ constants => [qw(LAB_FORMAT)],
+ );
+ @EXPORT_OK = (
+ @{$EXPORT_TAGS{constants}}
+ );
+};
use Util;
use Lintian::Output qw(:messages);
use Lintian::Command qw(spawn);
+use Lab::Package;
+use Cwd;
use File::Temp;
+
+
# Quiet "Name "main::LINTIAN_ROOT" used only once"
() = ($main::LINTIAN_ROOT);
@@@ -79,23 -58,20 +79,23 @@@ sub setup
my ( $self, $dir, $dist ) = @_;
if ( $dir ) {
+ # Make sure we can always find it, even if we chdir around a lot.
+ my $absdir = Cwd::realpath($dir);
+ fail("Cannot determine the absolute path of $dir: $!") unless($absdir);
$self->{mode} = 'static';
- $self->{dir} = $dir;
+ $self->{dir} = $absdir;
$self->{dist} = $dist;
- if (-d $dir && ! -d "$dir/changes") {
- mkdir("$dir/changes", 0777)
- or fail("cannot create lab directory $dir/changes");
+ if (-d "$absdir" && ! -d "$absdir/changes") {
+ mkdir("$absdir/changes", 0777)
- or fail("cannot create lab directory $dir/changes");
++ or fail("cannot create lab directory $absdir/changes");
}
} else {
$self->{mode} = 'temporary';
my $created = 0;
for (1..10) {
- $dir = tmpnam();
+ $dir = tmpnam(); # [NT] Double check this - would tempdir be better? Is it always absolute?
if ($self->setup_force( $dir, $dist )) {
$created = 1;
@@@ -211,6 -187,12 +211,6 @@@ sub delete_force
v_msg("Removing $self->{dir} ...");
- # since we will chdir in a moment, make the path of the lab absolute
- unless ( $self->{dir} =~ m,^/, ) {
- require Cwd;
- $self->{dir} = Cwd::getcwd() . "/$self->{dir}";
- }
-
# chdir to root (otherwise, the shell will complain if we happen
# to sit in the directory we want to delete :)
chdir('/');
@@@ -257,35 -239,6 +257,35 @@@
return 1;
}
+
+{
+
+ # private helper variable.
+ my %pkg_types = (
+ 'b' => 'binary',
+ 'binary' => 'binary',
+ 'c' => 'changes',
+ 'changes' => 'changes',
+ 's' => 'source',
+ 'sources' => 'source',
+ 'u' => 'udeb',
+ 'udeb' => 'udeb',
+ );
+
+ sub get_lab_package {
+ my ($self, $pkg_name, $pkg_version, $pkg_type, $pkg_path) = @_;
+ my $vpkg_type = $pkg_types{$pkg_type};
+ my $realpath = Cwd::realpath($pkg_path);
+ my $dir;
+ fail("Unknown package type $pkg_type") unless($vpkg_type);
+ fail("Could not resolve the path of $pkg_path") unless($realpath);
+ $dir = $self->{dir} . '/' . $vpkg_type . '/' . $pkg_name;
+ return new Lab::Package($self, $pkg_name, $pkg_version, $vpkg_type,
+ $realpath, $dir);
+
+ }
+}
+
1;
# vim: ts=4 sw=4 noet
diff --combined man/lintian.pod.in
index c747ab5,b42b24a..c5cd16a
--- a/man/lintian.pod.in
+++ b/man/lintian.pod.in
@@@ -57,14 -57,6 +57,6 @@@ Actions of the lintian command: (Only o
=over 4
- =item B<-S>, B<--setup-lab>
-
- Set up or update the laboratory.
-
- =item B<-R>, B<--remove-lab>
-
- Remove the laboratory directory.
-
=item B<-c>, B<--check>
Run all checks over the specified packages. This is the default action.
@@@ -75,6 -67,27 +67,27 @@@ Run only the specified checks. You ca
check script or the abbreviation. For details, see the L</CHECKS> section
below.
+ =item B<-F>, B<--ftp-master-rejects>
+
+ Run only the checks that issue tags that result in automatic rejects
+ from the Debian upload queue. The list of such tags is refreshed with
+ each Lintian release, so may be slightly out of date if it has changed
+ recently. This option does not, as yet, ignore overrides for fatal
+ tags for which overrides aren't allowed.
+
+ =item B<-r>, B<--remove>
+
+ Clean up the lintian directory of the specified packages up to the
+ current unpack level. The default unpack level is 0 for this option.
+
+ =item B<-R>, B<--remove-lab>
+
+ Remove the laboratory directory.
+
+ =item B<-S>, B<--setup-lab>
+
+ Set up or update the laboratory.
+
=item B<-T> tag1,tag2,..., B<--tags> tag1,tag2,...
Run only the checks that issue the requested tags. The tests for
@@@ -88,13 -101,14 +101,13 @@@ file. Blank lines and lines beginning
lines are taken to be tag names or comma-separated lists of tag names
to (potentially) issue.
- =item B<-F>, B<--ftp-master-rejects>
+ =item B<-u>, B<--unpack>
- Run only the checks that issue tags that result in automatic rejects
- from the Debian upload queue. The list of such tags is refreshed with
- each Lintian release, so may be slightly out of date if it has changed
- recently. This option does not, as yet, ignore overrides for fatal
- tags for which overrides aren't allowed.
-Unpack the specified packages up to the current unpack level. The
-default and only unpack level is 1 for this option. See the L</UNPACK
-LEVELS> section below.
++Unpacks the package will all collections. See the L</COLLECTION>
++section below.
+
+ Note in this option will also run all collections. See the
+ L</COLLECTION> section below.
=item B<-X> chk1,chk2,..., B<--dont-check-part> chk1,chk2,...
@@@ -102,46 -116,37 +115,37 @@@ Run all but the the specified checks.
of the check script or the abbreviation. For details, see the
L</CHECKS> section below.
- =item B<-u>, B<--unpack>
-
- Unpacks the package will all collections. See the L</COLLECTION>
- section below.
-
- =item B<-r>, B<--remove>
-
- Clean up the lintian directory of the specified packages.
-
=back
General options:
=over 4
- =item B<-h>, B<--help>
+ =item B<-d>, B<--debug>
- Display usage information and exit.
+ Display debugging messages. (Implies B<-v>).
- =item B<-V>, B<--version>
+ =item B<-h>, B<--help>
- Display lintian version number and exit.
+ Display usage information and exit.
- =item B<--print-version>
+ =item B<-q>, B<--quiet>
- Print unadorned version number and exit.
+ Suppress all informational messages. Currently, the only message this
+ suppresses is the message at the end of the run giving the total count
+ of overrides.
=item B<-v>, B<--verbose>
Display verbose messages.
- =item B<-d>, B<--debug>
+ =item B<-V>, B<--version>
- Display debugging messages. (Implies B<-v>).
+ Display lintian version number and exit.
- =item B<-q>, B<--quiet>
+ =item B<--print-version>
- Suppress all informational messages. Currently, the only message this
- suppresses is the message at the end of the run giving the total count
- of overrides.
+ Print unadorned version number and exit.
=back
@@@ -149,16 -154,27 +153,27 @@@ Behaviour options for B<lintian>
=over 4
- =item B<-i>, B<--info>
+ =item B<--allow-root>
- Print explanatory information about each problem discovered in
- addition to the lintian error tags. To print a long tag description
- without running lintian, see L<lintian-info(1)>..
+ Override lintian's warning when it is run with superuser privileges.
- =item B<-I>, B<--display-info>
+ =item B<--color> (never|always|auto|html)
- Display informational ("I:") tags as well. They are normally
- suppressed. (This is equivalent to B<-L> ">=wishlist").
+ Whether to colorize tags in lintian output based on their severity.
+ The default is "never", which never uses color. "always" will always
+ use color, "auto" will use color only if the output is going to a
+ terminal, and "html" will use HTML E<lt>spanE<gt> tags with a color style
+ attribute (instead of ANSI color escape sequences).
+
+ =item B<--display-source> X
+
+ Only display tags from the source X (e.g. the Policy Manual or the
+ Developer Reference). This option can be used multiple times to
+ add additional sources. Example sources are "policy" or "devref"
+ being the Policy Manual and the Developer Reference (respectively).
+
+ The entire list of sources can be found in
+ I<$LINTIAN_ROOT/data/output/manual-references>
=item B<-E>, B<--display-experimental>
@@@ -171,15 -187,39 +186,39 @@@ and might still give surprising results
Experimental messages that do not seem to make sense, though of course
bug reports are always welcomed (particularly if they include fixes).
- =item B<--pedantic>
+ =item B<--fail-on-warnings>
- Display pedantic ("P:") tags as well. They are normally suppressed.
+ By default, B<lintian> exits with 0 status if only warnings were
+ found. If this flag is given, exit with a status of 1 if either
+ warnings or errors are found.
- Pedantic tags are Lintian at its most pickiest and include checks for
- particular Debian packaging styles and checks that many people
- disagree with. Expect false positives and Lintian tags that you don't
- consider useful if you use this option. Adding overrides for pedantic
- tags is probably not worth the effort.
+ =item B<-i>, B<--info>
+
+ Print explanatory information about each problem discovered in
+ addition to the lintian error tags. To print a long tag description
+ without running lintian, see L<lintian-info(1)>.
+
+ =item B<-I>, B<--display-info>
+
+ Display informational ("I:") tags as well. They are normally
+ suppressed. (This is equivalent to B<-L> ">=wishlist").
+
+ =item B<--keep-lab>
+
+ By default, temporary labs will be removed after lintian is finished.
+ Specifying this options will leave the lab behind, which might be
+ useful for debugging purposes. You can find out where the temporary
+ lab is located by running lintian with the B<--verbose> option.
+
+ For static (non-temporary) labs this option causes Lintian to skip
+ the automatical clean up of some collections.
+
+ =item B<-l> n, B<--unpack-level> n
+
+ Set unpack level to I<n>. See the L</UNPACK LEVELS> section, below.
+
+ Note that the UNPACK LEVEL system is deprecated in favour of the
+ L</COLLECTION> system.
=item B<-L> [+|-|=][>=|>|<|<=][S|C|S/C], B<--display-level> [+|-|=][>=|>|<|<=][S|C|S/C]
@@@ -190,6 -230,30 +229,30 @@@ possible, wild-guess), or both (S/C).
equivalent to B<-L> ">=important" B<-L> "+>=normal/possible" B<-L>
+minor/certain).
+ =item B<-m>, B<--md5sums>, B<--checksums>
+
+ Check checksums when processing a .changes file. Normally, Lintian
+ only checks the checksums for .dsc files when processing a .changes
+ file.
+
+ =item B<-o>, B<--no-override>
+
+ Don't use the overrides file.
+
+ =item B<--pedantic>
+
+ Display pedantic ("P:") tags as well. They are normally suppressed.
+
+ Pedantic tags are Lintian at its most pickiest and include checks for
+ particular Debian packaging styles and checks that many people
+ disagree with. Expect false positives and Lintian tags that you don't
+ consider useful if you use this option. Adding overrides for pedantic
+ tags is probably not worth the effort.
+
+ =item B<--show-overrides>
+
+ Output tags that have been overridden.
+
=item B<--suppress-tags> tag1,tag2,...
Suppress the listed tags. They will not be reported if they occur and
@@@ -203,68 -267,30 +266,30 @@@ names or comma-separated lists of tag n
suppressed tags will not be reported if they occur and will not affect
the exit status of Lintian.
- =item B<-o>, B<--no-override>
-
- Don't use the overrides file.
-
- =item B<--show-overrides>
-
- Output tags that have been overridden.
-
- =item B<--color> (never|always|auto|html)
-
- Whether to colorize tags in lintian output based on their severity.
- The default is "never", which never uses color. "always" will always
- use color, "auto" will use color only if the output is going to a
- terminal, and "html" will use HTML E<lt>spanE<gt> tags with a color style
- attribute (instead of ANSI color escape sequences).
-
=item B<-U> info1,info2,..., B<--unpack-info> info1,info2,...
Collect information info1, info2, etc. even if these are not required
by the checks.
- =item B<-m>, B<--md5sums>, B<--checksums>
-
- Check checksums when processing a .changes file. Normally, Lintian
- only checks the checksums for .dsc files when processing a .changes
- file.
-
- =item B<--allow-root>
-
- Override lintian's warning when it is run with superuser privileges.
-
- =item B<--fail-on-warnings>
-
- By default, B<lintian> exits with 0 status if only warnings were
- found. If this flag is given, exit with a status of 1 if either
- warnings or errors are found.
-
- =item B<--keep-lab>
-
- By default, temporary labs will be removed after lintian is finished.
- Specifying this options will leave the lab behind, which might be
- useful for debugging purposes. You can find out where the temporary
- lab is located by running lintian with the B<--verbose> option.
-
=back
Configuration options:
=over 4
- =item B<--cfg> configfile
+ =item B<--arch> arch
- Read the configuration from configfile rather than the default
- locations. This option overrides the B<LINTIAN_CFG> environment
- variable.
+ When scanning for packages in the distdir, select only packages for
+ architecture I<arch>. This option overrides the B<LINTIAN_ARCH>
+ environment variable and the configuration file entry of the same
+ name.
- =item B<--lab> labdir
+ =item B<--area> area
- Use labdir as the permanent laboratory. This is where Lintian keeps
- information about the packages it checks. This option overrides the
- B<LINTIAN_LAB> environment variable and the configuration file entry
- of the same name.
+ When scanning for packages in the distdir, select only packages from
+ the comma-separated list of archive I<areas> (e.g. main, contrib).
+ This option overrides the B<LINTIAN_AREA> environment variable and the
+ configuration file entry of the same name.
=item B<--archivedir> archivedir
@@@ -275,6 -301,12 +300,12 @@@ just single packages. This option overr
environment variable and the configuration file entry of the same
name.
+ =item B<--cfg> configfile
+
+ Read the configuration from configfile rather than the default
+ locations. This option overrides the B<LINTIAN_CFG> environment
+ variable.
+
=item B<--dist> distdir
Scan for packages in the I<distdir> directory. (See the L</FILES>
@@@ -284,24 -316,17 +315,17 @@@ just single packages. This option over
environment variable and the configuration file entry of the same
name.
- =item B<--area> area
-
- When scanning for packages in the distdir, select only packages from
- the comma-separated list of archive I<areas> (e.g. main, contrib).
- This option overrides the B<LINTIAN_AREA> environment variable and the
- configuration file entry of the same name.
-
=item B<--section> area
This is an old name for the B<--area> option and accepted as a synonym
for that option.
- =item B<--arch> arch
+ =item B<--lab> labdir
- When scanning for packages in the distdir, select only packages for
- architecture I<arch>. This option overrides the B<LINTIAN_ARCH>
- environment variable and the configuration file entry of the same
- name.
+ Use labdir as the permanent laboratory. This is where Lintian keeps
+ information about the packages it checks. This option overrides the
+ B<LINTIAN_LAB> environment variable and the configuration file entry
+ of the same name.
=item B<--root> rootdir
@@@ -324,14 -349,6 +348,6 @@@ LINTIAN_DIST variable is defined in th
The following packages listed on the command line are binary packages.
- =item B<-s>, B<--source>
-
- The following packages listed on the command line are source packages.
-
- =item B<--udeb>
-
- The following packages listed on the command line are udeb packages.
-
=item B<-p> X, B<--packages-file> X
Process all packages which are listed in file X. Each package has to
@@@ -344,8 -361,53 +360,53 @@@ package), B<package> is the package nam
version, and B<file> is the package file name (absolute path
specification).
+ =item B<-s>, B<--source>
+
+ The following packages listed on the command line are source packages.
+
+ =item B<--udeb>
+
+ The following packages listed on the command line are udeb packages.
+
=back
+ =head1 UNPACK LEVELS
+
+ Note that the UNPACK LEVEL system is deprecated in favour of the
+ L</COLLECTION> system.
+
+ =over 4
+
+ =item B<0 (none)>
+
+ The package does not exist in the I<laboratory> at all.
+
+ =item B<1 (basic)>
+
+ A directory for this package exists in the I<laboratory> and basic
+ information is extracted. This does not take much space.
+
+ For binary and udeb packages, the I<control> and I<fields> directories
+ and the index file are unpacked, and symbolic links are made to the
+ B<.deb> file and to the lintian directory for the source package.
+
+ For source packages, the binary and fields directories are unpacked,
+ and symbolic links are made to the source package files.
+
+ =item B<2 (contents)>
+
+ This unpack level is deprecated and no longer functional. The
+ I<unpacked> collection script replaced it.
+
+ =back
+
+ Lintian will unpack packages as far as is necessary to do its checks,
+ but it will leave the package in whatever unpack level was specified
+ when it is done.
+
+ The default unpack level can be overwritten by setting the
+ B<LINTIAN_UNPACK_LEVEL> variable in the configuration file.
+
=head1 CHECKS
@CHECKS@
@@@ -469,7 -531,7 +530,7 @@@ Search for package foo in the Debian ar
on what is found, this command will check either the source or binary
package foo, or both.)
-=item B<$ lintian --archivedir /var/packages --dist custom --section main>
+=item B<$ lintian --archivedir /var/packages --dist custom --area main>
Check all packages found in the Debian archive at
I</var/packages/dists/custom/main>.
diff --combined unpack/unpack-binpkg-l1
index 3eedb00,589c0c4..2311c78
--- a/unpack/unpack-binpkg-l1
+++ b/unpack/unpack-binpkg-l1
@@@ -43,9 -43,42 +43,9 @@@ my (@jobs, $job)
# create directory in lab
print "N: Creating directory $base_dir ...\n" if $verbose;
- mkdir("$base_dir", 0777) or fail("mkdir $base_dir: $!");
- mkdir("$base_dir/fields", 0777) or fail("mkdir $base_dir/fields: $!");
+ mkdir($base_dir, 0777) or fail("mkdir $base_dir: $!");
-mkdir("$base_dir/control", 0777) or fail("mkdir $base_dir/control: $!");
-mkdir("$base_dir/fields", 0777) or fail("mkdir $base_dir/fields: $!");
-symlink($file,"$base_dir/deb") or fail("symlink: $!");
-
-# The following calls use knowledge of the .deb format for speed
-
-# (replaces dpkg-deb -e)
-# extract control files' tarball
-spawn({ fail => 'error', out => "$base_dir/control.tar" },
- ['ar', 'p', $file, 'control.tar.gz'],
- '|', ['gzip', '-dc']);
-
-$job = { fail => 'error', err => "$base_dir/control-errors" };
-push @jobs, $job;
-# extract the tarball's contents
-spawn($job,
- ['tar', 'xf', "$base_dir/control.tar", '-C', "$base_dir/control", '&']);
-
-$job = { fail => 'error',
- out => "$base_dir/control-index",
- err => "$base_dir/control-index-errors" };
-push @jobs, $job;
-# create index of control.tar.gz
-spawn($job,
- ['tar', 'tvf', "$base_dir/control.tar"],
- '|', ['sort', '-k', '6'], '&');
-
-reap(@jobs);
-undef @jobs;
-# clean up control.tar
-unlink("$base_dir/control.tar") or fail();
+
-# fix permissions
-spawn({ fail => 'error' },
- ['chmod', '-R', 'u+rX,o-w', "$base_dir/control"]);
+symlink($file,"$base_dir/deb") or fail("symlink: $!");
$job = { fail => 'error',
out => "$base_dir/index",
@@@ -71,7 -104,28 +71,7 @@@ spawn($job
'|', ['sed', '-e', 's/^h/-/'],
'|', ['sort', '-k', '6'], '&');
-# get package control information
-my $data = (read_dpkg_control("$base_dir/control/control"))[0];
-$data->{'source'} or ($data->{'source'} = $data->{'package'});
-
-# create control field files
-for my $field (keys %$data) {
- my $value = $data->{$field};
- # checks/fields will convert colons into slashes
- $field =~ s,/,:,g;
- my $field_file = "$base_dir/fields/$field";
- open(F, '>', $field_file) or fail("cannot open file $field_file for writing: $!");
- print F $value,"\n";
- close(F);
-}
-# create symlink to source package
-$data->{'source'} =~ s/\s*\(.*\)\s*$//;
-# but only create it if it doesn't traverse directories
-if ($data->{'source'} !~ m,/,) {
- symlink("../../source/$data->{'source'}","$base_dir/source")
- or fail("symlink: $!");
-}
reap(@jobs);
undef @jobs;
--
Debian package checker
Reply to: