[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

[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: