#!/usr/bin/perl -w eval 'exec /usr/bin/perl -w -S $0 ${1+"$@"}' if 0; # not running under some shell # -*- Mode: Perl -*- # Debian-pkg.pm --- # Author : Manoj Srivastava ( srivasta@tiamat.datasync.com ) # Created On : Wed Jan 22 09:53:33 1997 # Created On Node : tiamat.datasync.com # Last Modified By : Manoj Srivastava # Last Modified On : Sat Mar 14 13:08:24 1998 # Last Machine Used: tiamat.datasync.com # Update Count : 346 # Status : Unknown, Use with caution! # HISTORY : # Description : # # use strict; use diagnostics; use Carp; require 5.001; use Debian::Package::Dependency_List; use Debian::Package::Package; use Debian::Package::List; use Getopt::Long; package main; #Handle The auto generated eval line. use vars qw($running_under_some_shell); =head1 NAME pkg-order - A Package dependency checker and install ordering tool. =cut =head1 SYNOPSIS usage: pkg-order [options] where the options are: =over 2 =item --nocheck-depends =item --check-depends Do a dependency check as well as the ordering [ON] =item --nostrict-depends =item --strict-depends Do not carry on ordering after dependency failure [ON] =item --nooutput-order =item --output-order Do a package ordering [ON] =item --nocheck-recommends =item --check-recommends Check the Recommends field as well [OFF] =item --nocheck-suggests =item --check-suggests Check the Suggests field as well [OFF] =item --nocheck-consistency =item --check-consistency Make sure that extra warning are issued if the new packages are not consistent [ON] =item --noprint-failures =item --print-failures Make a full report of dependency failures [ON] =item --noprint-dependencies =item --print-dependencies Print fulfilled dependencies as well [OFF] =item --installed-packages =back =cut =head1 DESCRIPTION This utility does dependency checks, if you wish. It knows the difference between installed, new (and available) packages, and the relationship fields (pre-depends, depends, recommends, and suggests). (For example, the current packages list need not be read in unless you want dependency checks; you may already have done that and now merely wish an ordering). It comes with a Test::Harness test suite, to protect the world against my typos. Oh, it knows about epochs as well if your dpkg does. This could be the basis of mass compiling the packages on a new architecture, or to build a release from scratch. It creates associative arrays of currently installed packages (/var/lib/dpkg/status), and new packages (given a packages file at the command line). Then, in the checking dependency phase, for each package in the new packages list, it looks at the dependencies, and ensure that each dependency is satisfied in either the new list or the installed list If the directive is satisfied from the new list, add a line to an output file with the format required by tsort, which is the entity that gives us the ordered list. The default is to assume that the list of installed packages may be derived from the file I, but the user may override this by providing a I file listing all the packages that are assumed to be already installed. =cut sub main { my $installed; my $candidates; my $ret; my $do_depends = 1; my $strict_depends = 1; my $do_conflicts = 1; my $do_order = 1; my $recommends = 0; my $suggests = 0; my $consistent = 1; my $print_failures = 1; my $print_found = 0; my $dohelp = 0; my $filename = ''; my $usage = ''; my $installed_packages = ''; my $MYNAME = ''; ($MYNAME = $0) =~ s|.*/||; $usage= < where the options are: --help This message. --nocheck-depends --check-depends Do a dependency check as well as the ordering [ON] --nostrict-depends --strict-depends Die on failing to satisfy dependency. [ON] --nocheck-conflicts --check-conflicts Do a conflicts check [ON] --nooutput-order --output-order Do a package ordering [ON] --nocheck-recommends --check-recommends Check the Recommends field as well [OFF] --nocheck-suggests --check-suggests Check the Suggests field as well [OFF] --nocheck-consistency --check-consistency Make sure that extra warning are issued if the new packages are not consistent [ON] --noprint-failures --print-failures Make a full report of dependency failures [ON] --noprint-dependencies --print-dependencies Print fulfilled dependencies as well [OFF] --installed-packages EOUSAGE $ret = GetOptions("check-depends!" => \$do_depends, "strict-depends!" => \$strict_depends, "output-order!" => \$do_order, "check-recommends!" => \$recommends, "check-suggests!" => \$suggests, "check-conflicts!" => \$do_conflicts, "check-consistency!" => \$consistent, "print-failures!" => \$print_failures, "print-dependencies!" => \$print_found, "help" => \$dohelp, "installed-packages=s" => \$installed_packages); if ($dohelp) { print "$usage"; exit (0); } die "$usage" unless $ret; $filename = shift @ARGV; die "Need a New packages file (Packages))" unless $filename; die "Could not find new Packages file $filename" unless -f $filename; ###################################################################### # Phase One: Gather data # ###################################################################### # Installed file (default value taken from status file) if ($do_depends) { if (-f $installed_packages) { $installed = Debian::Package::New->new('filename' => $installed_packages); } else { $installed = Debian::Package::Installed->new(); } } # The new candidates (taken from the packages file) $candidates = Debian::Package::New->new('filename' => $filename); ###################################################################### # Phase Two: Check dependencies # ###################################################################### # Omit phase Two and Three unless $do_depends is TRUE if ($do_depends) { # This sets Types which will show up as critical errors. Does not # change what errors are recorded. $candidates->set_fatal_failure_on_types('Type List' => "Pre-Depends Depends Conflict"); # Check Pre-Dependencies $candidates->check_relations('Consistent' => $consistent, 'Installed' => $installed, 'Field' => 'Pre-Depends'); # Check Dependencies $candidates->check_relations('Consistent' => $consistent, 'Installed' => $installed, 'Field' => 'Depends'); # Check Conflicts $candidates->check_relations('Consistent' => $consistent, 'Installed' => $installed, 'Field' => 'Conflicts') if $do_conflicts; # Check Recommendations $candidates->check_relations('Consistent' => $consistent, 'Installed' => $installed, 'Warn' => 'True', 'Field' => 'Recommendations') if $recommends; # Check Suggestions $candidates->check_relations('Consistent' => $consistent, 'Installed' => $installed, 'Warn' => 'True', 'Field' => 'Suggestions') if $suggests; ###################################################################### # Phase Three: Print Results # ###################################################################### if ($print_failures) { my $result_string = $candidates->result_as_string('Type' => 'All', 'Category' => 'Failed'); if ($result_string) { print STDERR "=" x70, "\n"; print STDERR "Failed:\n"; print "$result_string"; print STDERR "=" x70, "\n"; } my $unknowns = $candidates->result_as_string('Type' => 'All', 'Category' => 'Unknown'); if ($unknowns) { print STDERR "=" x70, "\n"; print STDERR "Unknown:\n"; print "$unknowns"; print STDERR "=" x70, "\n"; } # Different from above to see an example of print result my $numconflicts = $candidates->check_result('Type' => 'All', 'Category' => 'Conflict'); if ($numconflicts > 0) { print STDERR "=" x70, "\n"; print STDERR "Conflicted:\n"; $candidates->print_result('Type' => 'All', 'Category' => 'Conflict');; print STDERR "=" x70, "\n"; } } if ($print_found) { my $result_string = $candidates->result_as_string('Type' => 'All', 'Category' => 'Found'); if ($result_string) { print STDERR "=" x70, "\n"; print STDERR "Found:\n"; print "$result_string"; print STDERR "=" x70, "\n"; } } if ($strict_depends) { my $critical_errors = $candidates->check_result('Type' => "Critical", 'Category' => 'Failed') + $candidates->check_result('Type' => "Critical", 'Category' => 'Conflict') + $candidates->check_result('Type' => "Critical", 'Category' => 'Unknown'); if ($critical_errors > 0) { print "$critical_errors Critical errors encountered. Exiting.\n"; exit ($critical_errors); } } } ###################################################################### # Phase Four: Gather ordering data # ###################################################################### return 0 unless $do_order; # Order Pre-Dependencies $candidates->order('Field' => 'Pre-Depends'); # Order Dependencies $candidates->order('Field' => 'Depends'); # Order Conflicts $candidates->order('Field' => 'Conflicts', 'Installed' => $installed); ###################################################################### # Phase Five: Do ordering # ###################################################################### # Get ordering info and do topological sorting my $order_string = $candidates->get_ordering(); # This is the raw order string # print $order_string; print "No packages to order. Exiting.\n" unless $order_string; return 2 unless $order_string; # This is the first method used to insert Breaks my $order_one = $candidates->insert_breaks('Ordered List' => $order_string); print "$order_one\n"; # This is another way to insert breaks # print "=" x 70; # my $order_two = # $candidates->{' _Targets'}->insert_breaks('Ordered List' => $order_string); # print "$order_two\n"; my %force_options = $candidates->list_marks("Mark" => '\-\-'); my $forced_pkg; foreach $forced_pkg (keys %force_options) { my $option; my @options = split ' ', $force_options{$forced_pkg}; for $option (@options) { next unless $option =~ /\-\-/o; print "Package $forced_pkg will need $option for installation)\n"; } } exit 0; } =head2 list_diff This is an example of how to detect packages and list packages in list A that are not in list B. Takes two Package::List objects, and returns a list object. This is how one may take an installed list, a final list, and figure out the packages to be removed, and the new packages, by just taking A - B and B - A set differences. =cut sub list_diff { my %params = @_; my $ListA; my $ListB; my $ListC; croak("Need argument 'List A'") unless defined $params{'List A'}; croak("Need argument 'List B'") unless defined $params{'List B'}; $ListA = $params{'List A'}; $ListB = $params{'List B'}; $ListC = Debian::Package::New->new(); my $name; for $name (sort keys %{$ListA}) { my $pkg; next if $name =~ /^\s+_/o; $pkg = $ListA->{$name}; next if $ListB->{$name}->{'Package'}; $ListC->add('Package_desc' => $pkg->print()); } return $ListC; } =head1 CAVEATS This is very inchoate, at the moment, and needs testing. =cut =head1 BUGS None Known so far. =cut =head1 AUTHOR Manoj Srivastava =cut &main::main(); __END__