[Pulp-dev] Representing Debian dependencies in pulp

Mihai Ibanescu mihai.ibanescu at gmail.com
Tue Mar 14 16:01:13 UTC 2017


I need some recommendations on how to represent Debian dependencies.

Pulp currently represents Requires and Provides for rpm packages as lists
of dictionaries:

    :ivar provides: List of packages/libraries this package provides. Each
entry is a
                    dictionary with the "release", "epoch", "version",
"flags", and "name"
    :type provides: list of dict

    :ivar requires: List of packages/libraries this package requires. Each
entry is a dictionary
                    with the "release", "epoch", "version", "flags", and
"name" field.
    :type requires: list of dict

flags is one of None, EQ, LT, LE, GT, GE.

Debian package dependencies are "different". They support version
comparisons, just like rpm packages. In addition to that, they support
architecture matching (positive or negative), build profile matching
(positive or negative). They also support disjunction (I want python2 or

The python-debian library has a deb822 module that will parse these
dependencies and return some format that I don't want to store directly in
pulp, because it's far too distant from what we have in rpm.

Here is the documentation from deb822:

    def relations(self):
        """Return a dictionary of inter-package relationships among the
        and other packages.

        Dictionary keys depend on the package kind. Binary packages have
        like 'depends', 'recommends', ... while source packages have keys
        'build-depends', 'build-depends-indep' and so on. See the Debian
        for the comprehensive field list.

        Dictionary values are package relationships returned as lists of
        of dictionaries (see below for some examples).
        The encoding of package relationships is as follows:
        - the top-level lists corresponds to the comma-separated list of
          Deb822, their components form a conjunction, i.e. they have to be
          AND-ed together
        - the inner lists corresponds to the pipe-separated list of Deb822,
          their components form a disjunction, i.e. they have to be OR-ed
        - member of the inner lists are dictionaries with the following
          - name:       package (or virtual package) name
          - version:    A pair <operator, version> if the relationship is
                        versioned, None otherwise. operator is one of "<<",
                        "<=", "=", ">=", ">>"; version is the given version
                        a string.
          - arch:       A list of pairs <enabled, arch> if the
                        relationship is architecture specific, None
                        Enabled is a boolean (false if the architecture is
                        negated with "!", true otherwise), arch the
                        Debian architecture name as a string.
          - restrictions: A list of lists of tuples <enabled, profile>
                        if there is a restriction formula defined, None
                        otherwise. Each list of tuples represents a
                        list while each tuple represents an individual term
                        within the restriction list. Enabled is a boolean
                        (false if the restriction is negated with "!", true
                        otherwise). The profile is the name of the build

          The arch and restrictions tuples are available as named tuples so
          elements are available as term[0] or alternatively as
          term.enabled (and so forth).


          "emacs | emacsen, make, debianutils (>= 1.7)"     becomes
          [ [ {'name': 'emacs'}, {'name': 'emacsen'} ],
            [ {'name': 'make'} ],
            [ {'name': 'debianutils', 'version': ('>=', '1.7')} ] ]

          "tcl8.4-dev, procps [!hurd-i386]"                 becomes
          [ [ {'name': 'tcl8.4-dev'} ],
            [ {'name': 'procps', 'arch': (false, 'hurd-i386')} ] ]

          "texlive <!cross>"                                becomes
          [ [ {'name': 'texlive',
                    'restriction': [[(false, 'cross')]]} ] ]

I personally don't like the list of (disjunction of lists) representation,
given that it's a relatively uncommon case. Also, I don't like breaking out
the arch and profile as tuples just to represent positive or negative

My proposal is to reuse as much as possible from Yum's syntax. Like so:

* single package is a dictionary, conjunction is a list of packages (i.e.
* flag represents the operator of the relationship if one exists, and use
the same string values as rpm: GT, GE, LT, LE, EQ. arch
* arch is a list of one or more strings. Negation is represented with a
leading exclamation mark
* restriction, if present, is a list of one or more strings, with the same
meaning as arch.

So, for the examples in the deb822 package:

"emacs | emacsen, make, debianutils (>= 1.7)"
deb822: [ [ {'name': 'emacs'}, {'name': 'emacsen'} ], [ {'name': 'make'} ],
[ {'name': 'debianutils', 'version': ('>=', '1.7')} ] ]
pulp: [ [{'name': 'emacs'}, {'name': 'emacsen'} ], {'name': 'make'},
{'name': 'debianutils', 'version': '1.7', 'flag': 'GE'} ]

"tcl8.4-dev, procps [!hurd-i386]"
deb822: [ [ {'name': 'tcl8.4-dev'} ], [ {'name': 'procps', 'arch': (false,
'hurd-i386')} ] ]
pulp: [ {'name': 'tcl8.4-dev'}, {'name': 'procps', 'arch': ['!hurd-i383']} ]

"texlive <!cross>"
deb822: [ [ {'name': 'texlive', 'restriction': [[(false, 'cross')]]} ] ]
pulp: [ {'name': 'texlive', 'restriction': ['!cross']} ]

Do you like how the lines prefixed with pulp: look like? I know it's not my
goal to write a dep solver in pulp for debian packages, and I don't know
how well I can map Mongo queries on this data structure for disjunctions (I
think everything else should be fine). Does anyone have a concern with the
proposed data structures?

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://listman.redhat.com/archives/pulp-dev/attachments/20170314/b2874bc7/attachment.htm>

More information about the Pulp-dev mailing list