]> err.no Git - dpkg/commitdiff
Dpkg::Deps: add some integrated POD documentation of the API
authorRaphael Hertzog <hertzog@debian.org>
Wed, 17 Oct 2007 20:49:46 +0000 (22:49 +0200)
committerRaphael Hertzog <hertzog@debian.org>
Thu, 18 Oct 2007 12:30:16 +0000 (14:30 +0200)
scripts/Dpkg/Deps.pm

index cebbe9c810ac9771f5ec00aa6c786c0dbfe41ccf..11ab8c0d036542d250cde9e5723b682a1ac3fed6 100644 (file)
 
 package Dpkg::Deps;
 
+=head1 NAME
+
+Dpkg::Deps - parse and manipulate dependencies of Debian packages
+
+=head1 DESCRIPTION
+
+The Dpkg::Deps module provides one generic Dpkg::Deps::parse() function
+to turn a dependency line in a set of Dpkg::Deps::{Simple,AND,OR,Union}
+objects depending on the case.
+
+It also provides some constants:
+
+=over 4
+
+=item @pkg_dep_fields
+
+List of fields that contains dependency-like information in a binary
+Debian package. The fields that express real dependencies are sorted from
+the stronger to the weaker.
+
+=item @src_dep_fields
+
+List of fields that contains dependencies-like information in a binary
+Debian package.
+
+=item %dep_field_type
+
+Associate to each field a type, either "normal" for a real dependency field
+(Pre-Depends, Depends, ...) or "union" for other relation fields sharing
+the same syntax (Conflicts, Breaks, etc.).
+
+=back
+
+=head1 FUNCTIONS
+
+=over 4
+
+=cut
+
 use strict;
 use warnings;
 
@@ -60,13 +99,19 @@ our %dep_field_type = (
 
 # Some factorized function
 
-# Returns true if the arch list $p is a superset of arch list $q
+=item Dpkg::Deps::arch_is_superset(\@p, \@q)
+
+Returns true if the arch list @p is a superset of arch list @q.
+The arguments can also be undef in case there's no explicit architecture
+restriction.
+
+=cut
 sub arch_is_superset {
     my ($p, $q) = @_;
     my $p_arch_neg = defined($p) && $p->[0] =~ /^!/;
     my $q_arch_neg = defined($q) && $q->[0] =~ /^!/;
 
-    # If "a" has no arches, it is a superset of q and we should fall through
+    # If "p" has no arches, it is a superset of q and we should fall through
     # to the version check.
     if (not defined $p) {
        return 1;
@@ -120,6 +165,17 @@ sub arch_is_superset {
     return 1;
 }
 
+=item Dpkg::Deps::version_implies($rel_p, $v_p, $rel_q, $v_q)
+
+($rel_p, $v_p) and ($rel_q, $v_q) express two dependencies as (relation,
+version). The relation variable can have the following values: '=', '<<',
+'<=', '>=', '>>'.
+
+This functions returns 1 if the "p" dependency implies the "q"
+dependency. It returns 0 if the "p" dependency implies that "q" is
+not satisfied. It returns undef when there's no implication.
+
+=cut
 sub version_implies {
     my ($rel_p, $v_p, $rel_q, $v_q) = @_;
 
@@ -195,6 +251,41 @@ sub version_implies {
     return undef;
 }
 
+=item Dpkg::Deps::parse($line, %options)
+
+This function parse the dependency line and returns an object, either a
+Dpkg::Deps::AND or a Dpkg::Deps::Union. Various options can alter the
+behaviour of that function.
+
+=over 4
+
+=item use_arch (defaults to 1)
+
+Take into account the architecture restriction part of the dependencies.
+Set to 0 to completely ignore that information.
+
+=item host_arch (defaults to the current architecture)
+
+Define the host architecture. Needed only if the reduce_arch option is
+set to 1. By default it uses Dpkg::Arch::get_host_arch() to identify
+the proper architecture.
+
+=item reduce_arch (defaults to 0)
+
+If set to 1, ignore dependencies that do not concern the current host
+architecture. This implicitely strips off the architecture restriction
+list so that the resulting dependencies are directly applicable to the
+current architecture.
+
+=item union (defaults to 0)
+
+If set to 1, returns a Dpkg::Deps::Union instead of a Dpkg::Deps::AND. Use
+this when parsing non-dependency fields like Conflicts (see
+%dep_field_type).
+
+=back
+
+=cut
 sub parse {
     my $dep_line = shift;
     my %options = (@_);
@@ -241,6 +332,137 @@ sub parse {
 
 package Dpkg::Deps::Simple;
 
+=head1 OBJECTS - Dpkg::Deps::*
+
+There are several kind of dependencies. A Dpkg::Deps::Simple dependency
+represents a single dependency statement (it relates to one package only).
+Dpkg::Deps::Multiple dependencies are built on top of this object
+and combine several dependencies in a different manners. Dpkg::Deps::AND
+represents the logical "AND" between dependencies while Dpkg::Deps::OR
+represents the logical "OR". Dpkg::Deps::Multiple objects can contain
+Dpkg::Deps::Simple object as well as other Dpkg::Deps::Multiple objects.
+
+In practice, the code is only meant to handle the realistic cases which,
+given Debian's dependencies structure, imply those restrictions: AND can
+contain Simple or OR objects, OR can only contain Simple objects.
+
+Dpkg::Deps::KnowFacts is a special object that is used while evaluating
+dependencies and while trying to simplify them. It represents a set of
+installed packages along with the virtual packages that they might
+provide.
+
+=head2 Common functions
+
+=over 4
+
+=item $dep->is_empty()
+
+Returns true if the dependency is empty and doesn't contain any useful
+information. This is true when a Dpkg::Deps::Simple object has not yet
+been initialized or when a (descendant of) Dpkg::Deps::Multiple contains
+an empty list of dependencies.
+
+=item $dep->get_deps()
+
+Return a list of sub-dependencies. For Dpkg::Deps::Simple it returns
+itself.
+
+=item $dep->dump()
+
+Return a string representing the dependency.
+
+=item $dep->implies($other_dep)
+
+Returns 1 when $dep implies $other_dep. Returns 0 when $dep implies
+NOT($other_dep). Returns undef when there's no implication. $dep and
+$other_dep do not need to be of the same type.
+
+=item $dep->sort()
+
+Sort alphabetically the internal list of dependencies. It's a no-op for
+Dpkg::Deps::Simple objects.
+
+=item $dep->arch_is_concerned($arch)
+
+Returns true if the dependency applies to the indicated architecture. For
+multiple dependencies, it returns true if at least one of the
+sub-dependencies apply to this architecture.
+
+=item $dep->reduce_arch($arch)
+
+Simplify the dependency to contain only information relevant to the given
+architecture. A Dpkg::Deps::Simple object can be left empty after this
+operation. For Dpkg::Deps::Multiple objects, the non-relevant
+sub-dependencies are simply removed.
+
+This trims off the architecture restriction list of Dpkg::Deps::Simple
+objects.
+
+=item $dep->get_evaluation($facts)
+
+Evaluates the dependency given a list of installed packages and a list of
+virtual packages provided. Those lists are part of the
+Dpkg::Deps::KnownFacts object given as parameters.
+
+Returns 1 when it's true, 0 when it's false, undef when some information
+is lacking to conclude.
+
+=item $dep->simplify_deps($facts, @assumed_deps)
+
+Simplify the dependency as much as possible given the list of facts (see
+object Dpkg::Deps::KnownFacts) and a list of other dependencies that we
+know to be true.
+
+=back
+
+=head2 Dpkg::Deps::Simple
+
+Such an object has four interesting properties:
+
+=over 4
+
+=item package
+
+The package name (can be undef if the dependency has not been initialized
+or if the simplification of the dependency lead to its removal).
+
+=item relation
+
+The relational operator: "=", "<<", "<=", ">=" or ">>". It can be
+undefined if the dependency had no version restriction. In that case the
+following field is also undefined.
+
+=item version
+
+The version.
+
+=item arches
+
+The list of architectures where this dependency is applicable. It's
+undefined when there's no restriction, otherwise it's an
+array ref. It can contain an exclusion list, in that case each
+architecture is prefixed with an exclamation mark.
+
+=back
+
+=head3 Methods
+
+=over 4
+
+=item $simple_dep->parse("dpkg-dev (>= 1.14.8) [!hurd-i386]")
+
+Parse the dependency and modify internal properties to match the parsed
+dependency.
+
+=item $simple_dep->merge_union($other_dep)
+
+Returns true if $simple_dep could be modified to represent the union of
+both dependencies. Otherwise returns false.
+
+=back
+
+=cut
+
 use strict;
 use warnings;
 
@@ -443,7 +665,7 @@ sub get_evaluation {
            return 1;
        }
     }
-    return undef;
+    return 0;
 }
 
 sub simplify_deps {
@@ -500,6 +722,19 @@ sub merge_union {
 
 package Dpkg::Deps::Multiple;
 
+=head2 Dpkg::Deps::Multiple
+
+This the base class for Dpkg::Deps::{AND,OR,Union}. It contains the
+
+=over 4
+
+=item $mul->add($dep)
+
+Add a new dependency object at the end of the list.
+
+=back
+
+=cut
 use strict;
 use warnings;
 
@@ -520,7 +755,7 @@ sub add {
 
 sub get_deps {
     my $self = shift;
-    return @{$self->{list}};
+    return grep { not $_->is_empty() } @{$self->{list}};
 }
 
 sub sort {
@@ -560,6 +795,21 @@ sub merge_union {
 
 package Dpkg::Deps::AND;
 
+=head2 Dpkg::Deps::AND
+
+This object represents a list of dependencies who must be met at the same
+time.
+
+=over 4
+
+=item $and->dump()
+
+The dump method uses ", " to join the list of sub-dependencies.
+
+=back
+
+=cut
+
 use strict;
 use warnings;
 
@@ -596,12 +846,14 @@ sub implies {
 
 sub get_evaluation {
     my ($self, $facts) = @_;
+    # Return 1 only if all members evaluates to true
+    # Return 0 if at least one member evaluates to false
+    # Return undef otherwise
     my $result = 1;
     foreach my $dep ($self->get_deps()) {
        my $eval = $dep->get_evaluation($facts);
        if (not defined $eval) {
            $result = undef;
-           last;
        } elsif ($eval == 0) {
            $result = 0;
            last;
@@ -632,6 +884,21 @@ WHILELOOP:
 
 package Dpkg::Deps::OR;
 
+=head2 Dpkg::Deps::OR
+
+This object represents a list of dependencies of which only one must be met
+for the dependency to be true.
+
+=over 4
+
+=item $or->dump()
+
+The dump method uses " | " to join the list of sub-dependencies.
+
+=back
+
+=cut
+
 use strict;
 use warnings;
 
@@ -671,12 +938,14 @@ sub implies {
 
 sub get_evaluation {
     my ($self, $facts) = @_;
+    # Returns false if all members evaluates to 0
+    # Returns true if at least one member evaluates to true
+    # Returns undef otherwise
     my $result = 0;
     foreach my $dep ($self->get_deps()) {
        my $eval = $dep->get_evaluation($facts);
        if (not defined $eval) {
            $result = undef;
-           last;
        } elsif ($eval == 1) {
            $result = 1;
            last;
@@ -709,6 +978,30 @@ WHILELOOP:
 
 package Dpkg::Deps::Union;
 
+=head2 Dpkg::Deps::Union
+
+This object represents a list of relationships.
+
+=over 4
+
+=item $union->dump()
+
+The dump method uses ", " to join the list of relationships.
+
+=item $union->implies($other_dep)
+=item $union->get_evaluation($other_dep)
+
+Those methods are not meaningful for this object and always return undef.
+
+=item $union->simplify_deps($facts)
+
+The simplication is done to generate an union of all the relationships.
+It uses $simple_dep->merge_union($other_dep) to get the its job done.
+
+=back
+
+=cut
+
 use strict;
 use warnings;
 
@@ -746,6 +1039,18 @@ WHILELOOP:
 
 package Dpkg::Deps::KnownFacts;
 
+=head2 Dpkg::Deps::KnowFacts
+
+This object represents a list of installed packages and a list of virtual
+packages provided (by the set of installed packages).
+
+=over 4
+
+=item my $facts = Dpkg::Deps::KnownFacts->new();
+
+Create a new object.
+
+=cut
 use strict;
 use warnings;
 
@@ -757,11 +1062,25 @@ sub new {
     return $self;
 }
 
+=item $facts->add_installed_package($package, $version)
+
+Record that the given version of the package is installed. If $version is
+undefined we know that the package is installed but we don't know which
+version it is.
+
+=cut
 sub add_installed_package {
     my ($self, $pkg, $ver) = @_;
     $self->{pkg}{$pkg} = $ver;
 }
 
+=item $facts->add_provided_package($virtual, $relation, $version, $by)
+
+Record that the "$by" package provides the $virtual package. $relation
+and $version correspond to the associated relation given in the Provides
+field. This might be used in the future for versioned provides.
+
+=cut
 sub add_provided_package {
     my ($self, $pkg, $rel, $ver, $by) = @_;
     if (not exists $self->{virtualpkg}{$pkg}) {
@@ -770,6 +1089,16 @@ sub add_provided_package {
     push @{$self->{virtualpkg}{$pkg}}, [ $by, $rel, $ver ];
 }
 
+=item my ($check, $param) = $facts->check_package($package)
+
+$check is one when the package is found. For a real package, $param
+contains the version. For a virtual package, $param contains an array
+reference containing the list of packages that provide it (each package is
+listed as [ $provider, $relation, $version ]).
+
+=back
+
+=cut
 sub check_package {
     my ($self, $pkg) = @_;
     if (exists $self->{pkg}{$pkg}) {