.. CDDL HEADER START
.. The contents of this file are subject to the terms of the
Common Development and Distribution License (the "License").
You may not use this file except in compliance with the License.
.. You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
See the License for the specific language governing permissions
and limitations under the License.
.. When distributing Covered Code, include this CDDL HEADER in each
file and include the License file at usr/src/OPENSOLARIS.LICENSE.
If applicable, add the following below this CDDL HEADER, with the
fields enclosed by brackets "[]" replaced with your own identifying
information: Portions Copyright [yyyy] [name of copyright owner]
.. CDDL HEADER END
.. Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
Chapter 6
---------
Specifying Dependencies
.......................
Dependencies define how packages are related.
IPS provide a variety of different dependency types as discussed in
*Chapter 3*. In this chapter we go into more detail about how each
dependency type can be used to control the software that is installed.
In IPS, a package cannot be installed unless all package dependencies are
satisfied. IPS allows packages to be mutually dependent (to have circular
dependencies). IPS also allows packages to have different kinds of
dependencies on the same package at the same time.
Dependency Types
~~~~~~~~~~~~~~~~
Each section below contains an example ``depend`` action, as it would appear in
a manifest during package creation.
``require``
```````````
The most basic type of dependency is the ``require`` dependency.
If a package A@1.0 contains a ``require`` dependency on package B@2,
it means that if A@1.0 is installed, a version of B at 2 or higher
must be installed as well.
This acceptance of higher versioned packages reflects the implicit
expectation of binary compatibility in newer versions of existing
packages.
These dependencies are typically used to express functional dependencies
such as libraries or interpreters such as Python, Perl, etc. The version
portion of the specified FMRI can be omitted; it indicates that any
version will suffice. The latter might not be actually true, but
if other dependencies constrain the version adequately, this might
save some effort.
An example ``require`` dependency is::
depend fmri=pkg:/system/library type=require
``require-any``
```````````````
The ``require-any`` dependency is used if more than one package will
satisfy a functional requirement. IPS will pick one of the packages to
install if the dependency is not already satisfied.
A typical use might be to ensure that at least one version of Perl
was installed on the system, for example. The versioning is handled
in the same manner as for the ``require`` dependency.
An example ``require-any`` dependency is::
depend type=require-any fmri=pkg:/editor/gnu-emacs/gnu-emacs-gtk \
fmri=pkg:/editor/gnu-emacs/gnu-emacs-no-x11 \
fmri=pkg:/editor/gnu-emacs/gnu-emacs-x11
``optional``
````````````
The ``optional`` dependency is similar to the ``require`` dependency, but
the specified package need not be installed. However, if it is present,
it must be at the specified version or greater.
This type of dependency is typically used to handle cases where packages
transfer content.
In this case, each version of the package post-transfer
would contain an optional dependency on the other package's
post-transfer version, so it would be impossible to install
incompatible versions of the two packages.
Omitting the version on an optional dependency makes the dependency a no-op,
but is permitted.
An example ``optional`` dependency is::
depend fmri=pkg:/x11/server/xorg@1.9.99 type=optional
``conditional``
```````````````
The ``conditional`` dependency is similar to the ``require`` dependency as
well, except that a predicate attribute is present. If the package specified
in the value of the predicate attribute is present on the system at the
specified or greater version, the conditional dependency is treated as a
``require`` dependency, otherwise it is ignored.
This type of dependency is most often used to install optional extensions
to a package if the requisite base packages are present on the system.
For example, an editor package that has both X11 and terminal versions might
place the X11 version in a separate package, and include a conditional
dependency on the X11 version from the text version with the existence
of the requisite X client library package as the predicate.
An example conditional dependency is::
depend type=conditional fmri=library/python-2/pycurl-26 \
predicate=runtime/python-26
``group``
`````````
The ``group`` dependency is used to construct groups of packages.
The group dependency will ignore the version specified; any version of the
named package satisfies this dependency. The named package
is required unless the package has been placed on the avoid list (see |pkg|),
the package is rejected with ``pkg install --reject``, or the package is
uninstalled with ``pkg uninstall``.
These three options enable administrators to 'deselect' packages that are the
subject of a group dependency. IPS will remember this and not re-install the
package during an update unless it becomes required by another dependency.
If the new dependency is removed by another subsequent operation, then the
package is uninstalled again.
A good example of how to use these dependencies is to construct packages
containing group dependencies on packages that are needed for typical uses
of a system. Some examples might be ``solaris-small-server``,
``solaris-desktop`` or ``developer-gnu``. A set of Oracle Solaris packages
delivering group dependencies is shown in *Chapter 13*.
The administrator could install all that apply and know that over subsequent
updates to newer versions of the OS, the appropriate packages would be added
to his system.
An example ``group`` dependency is::
depend fmri=package/pkg type=group
``origin``
``````````
The ``origin`` dependency exists to resolve upgrade issues that require
intermediate transitions. The default behavior is to specify the minimum
version of a package (if installed) that must be present on the system being
updated.
For example, a typical use might be a database package version 5 that supports
upgrade from version 3 or greater, but not earlier versions.
In this case, version 5 would have an origin dependency on itself at version 3.
Thus, if version 5 was being fresh installed, installation would proceed; but
if version 1 of the package was installed, one could not upgrade directly to this
version.
Thus, ``pkg update database-package`` would not select version 5
in this case but would pick version 3 instead as the latest possible
version it could upgrade to.
The behavior of this dependency can be modified by the ``root-image`` attribute
being set to ``true``; in this case the named package must be at the specified
version or greater if it is present in the running system, rather than the image
being updated.
This is generally used for operating system issues such as dependencies on boot
block installers.
An example ``origin`` dependency is::
depend fmri=pkg:/database/mydb@3.0 type=origin
``parent``
``````````
The ``parent`` dependency is used for zones or other child images. In
this case, the dependency is only checked in the child image, and specifies a
package and version that must be present in the parent image or global
zone. The version specified must match to the level of precision
specified.
For example, if the ``parent`` dependency is on A@2.1, then any version of A
beginning with 2.1. will match. This dependency is often used to require that
packages are kept in sync between non-global zones and the global zone, and as
a short cut a special package name ``feature/package/dependency/self`` is used
as a synonym for the exact version of the package that contains this dependency.
This is used to keep key operating system components, such as ``libc.so.1``
installed in the zone synchronized with the kernel installed in the global zone.
The ``parent`` dependency is also discussed in *Chapter 12*.
An example ``parent`` dependency is::
depend type=parent fmri=feature/package/dependency/self \
variant.opensolaris.zone=nonglobal
``incorporate``
```````````````
The ``incorporate`` dependency is heavily used in Oracle Solaris to ensure that
compatible versions of software are installed together.
The basic mechanism is like that of an ``optional`` dependency, except
that the version matching is that of the ``parent`` dependency: if this package
is present, it must be at the specified version to the level
specified.
How these dependencies are typically used is that many of
them are placed in the same package to define a surface in the package
version space that is compatible. Packages that contain such sets of
incorporate dependencies are often called *incorporations*; it is
typical to define such for sets of software packages that are built
together and are not separately versioned, like much of the kernel.
An example ``incorporate`` dependency is::
depend type=incorporate \
fmri=pkg:/driver/network/ethernet/e1000g@0.5.11,5.11-0.175.0.0.0.2.1
``exclude``
```````````
The ``exclude`` dependency is seldom used. It allows the containing
package to preclude installation with the specified package at the
specified version or higher.
Note that if the version is omitted, no version of the specified package
can be installed with the containing package. These constraints can be
frustrating to administrators, and should be avoided where possible.
An example exclude dependency is::
depend fmri=pkg:/x11/server/xorg@1.10.99 type=exclude
Constraints and Freezing
~~~~~~~~~~~~~~~~~~~~~~~~
Constraints
```````````
Through the careful use of the various types of ``depend`` actions described
above, packages can define the ways in which they are allowed to be upgraded.
In general, we often desire that a group of packages installed on a system
be supported and upgraded as a group: Either all packages in the group are
updated, or none of the packages in the group are updated. As mentioned earlier,
this is the reason for using the ``incorporate`` dependency in Oracle Solaris.
The following three partial package manifests show the relationship
between the ``foo`` and ``bar`` packages and the ``myincorp`` incorporation
package:
::
set name=pkg.fmri value=foo@1.0
dir path=foo owner=root group=bin mode=0755
depend fmri=myincorp type=require
::
set name=pkg.fmri value=bar@1.0
dir path=bar owner=root group=bin mode=0755
depend fmri=myincorp type=require
::
set name=pkg.fmri value=myincorp@1.0
depend fmri=foo@1.0 type=incorporate
depend fmri=bar@1.0 type=incorporate
The ``foo`` and ``bar`` packages both have a ``require`` dependency on the
``myincorp`` incorporation. The ``myincorp`` package has ``incorporate``
dependencies such that ``foo`` and ``bar`` can be upgraded to
**at most** version 1.0, to the level of granularity defined by the version
number and, if installed, must be **at least** at version 1.0 or greater.
That is, an ``incorporate`` dependency on version 1.0 allows for
1.0.1, 1.0.2.1, etc. but doesn't allow version 1.1, version 2.0, version 0.9,
etc. When we deliver a new incorporation package, one that has ``incorporate``
dependencies at a higher version, we will allow ``foo`` and ``bar`` to upgrade
to those versions instead (assuming that the incorporation package is also being
upgraded).
Note here that because ``foo`` and ``bar`` both have ``require`` dependencies on
the ``myincorp`` package, the incorporation package must always be installed.
However, conflicting with the requirement we stated at the beginning of this
section, there are some situations where we might want to relax the
incorporation constraint.
Perhaps ``bar`` can function independently of ``foo``, but we'd like ``foo``
to remain within the series of versions our incorporation constrains it to.
We can relax the incorporation constraints using *facets*, allowing the
administrator to effectively *disable* certain ``incorporate`` dependencies.
Facets are discussed in more detail in *Chapter 7*. Briefly, facets
are special attributes that can be applied to actions within a package to enable
authors to mark those actions as optional.
When actions are marked with facet attributes in this manner, the actions
containing those facets can be enabled or disabled using the
``pkg change-facet`` command.
By convention, facets that optionally install ``incorporate`` dependencies are
named ``facet.version-lock.<name>``, where *name* is the package name containing
that ``depend`` action.
So, for example, using the example above, we could have the following
incorporation::
set name=pkg.fmri value=myincorp@1.0
depend fmri=foo@1.0 type=incorporate
depend fmri=bar@1.0 type=incorporate facet.version-lock.bar=true
This incorporation includes our ``depend`` action by default, constraining
``bar`` to version 1.0. The following command relaxes this constraint::
pkg change-facet version-lock.bar=false
The ``bar`` package is free from the incorporation constraints, and can be
upgraded to version 2.0 if necessary.
Freezing
````````
So far, all of the discussion has been around constraints that have been applied
during the package authoring process, by modifying the package manifests
themselves.
|pkg| also has a means for the administrator to apply constraints to the system
at runtime.
Using the ``pkg freeze`` command, the administrator can prevent a given
package from being updated past either its current version, or a version
specified on the command line. This capability is effectively the same as an
``incorporate`` dependency.
See the |pkg| man page for more information on the ``freeze`` command.
In order to apply more complex dependencies to an image, it is necessary to
create and install a package that includes those dependencies.