.. 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 or http://www.opensolaris.org/os/licensing. 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.``, 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.