Packaging Best Practices - Dependencies

> Producing and Maintaining Packages

Overview

Dependencies specified in packages help to ensure that required software components are present on a system during installation of new packages and updates of existing packages. IPS supports dependency specifications via the depend action. For example

depend fmri=pkg:/wxpython@2.8.10.1-34 type=require

The fmri specifies the package that is depended on. It consists of the package name and a version constraint given after the @ sign. The type attribute defines the dependency type. IPS supports three dependency types:

require The dependency is satisfied if the specified package is installed and its version is greater than or equal to the version specified in the version constraint.
optional The dependency is satisfied if the specified package is not installed at all, or if it is installed and its version is greater than or equal to the version specified in the version constraint.
incorporate Like optional, except that the version constraint establishes a ceiling as well as a floor. The dependency is satisfied if the package version matches the version constraint up to the degree of significance used in the version constraint. For example foo@2 would be satisfied by foo@2.0 and foo@2.1 but not foo@3.0 or foo@1.0

If a package dependency is not satisfied, then IPS will attempt to install or update an installed package to a version that will satisfy the dependency. IPS will pick the newest version of the package that matches the version constraint from the repository.

Dependencies of type require and optional do not prevent a package from being updated to a version that exceeds a version constraint. For example an installed package with a required dependency on foo@2 would not prevent the user from updating foo to foo@3. As a consequence of this performing a pkg image-update will update all packages to the latest versions in the repository – even if those versions exceed the constraints specified in a required or optional dependency.

Dependencies of the type incorporate, on the other hand, will prevent a user from updating a package to a version that exceeds the version constraint since it establishes a ceiling as well as a floor. This means that if an incorporate dependency is in effect it will cap the version of a package installed via pkg image-update (or any other update triggerd by a pkg install). So if I had an installed package with an incorporate dependency on foo@2, then the user could update foo to foo@2.1, but not foo@3.

incorporate dependencies are typically used in special packages called incorporations. They are rarely (if ever) used as a direct dependency between packages. See Packaging Best Practices - Metapackages and Incorporations for more information.

Best Practices

How you build and release your projects's packages has an impact on how you should set up your package dependencies. This best practice differentiates between packages generated as part of your project's build and those packages you may depend on that are delivered by another project. It also assumes you are following the Package Versioning best practices.

# Title Description
1 Use require when dependencies are required for basic functionality When basic features provided by a package rely on the presence of features in other known packages installed on the same system, then the dependent package should express required dependencies on the other packages.
2 Use optional when dependencies are not required for basic functionality When dependencies are only required for optional features, use the optional dependency type. This will ensure those dependencies are of the correct version if installed, but do not require the installation of those dependencies.
3 Use incorporate to create incorporations Incorporations are packages that consist of dependencies of type incorporate. They provide a mechanism to freeze a collection of packages to specific release families.
4 Use fairly specific version constraints for dependencies between packages you deliver. When specifying dependencies between packages that your project builds and releases together use fairly specific version constraints in the package dependencies.
5 Use looser version constraints for dependencies on packages delivered by other projects. When specifying a dependency on a package delivered by another project you should try to keep the version constraint as loosely specified as possible.
6 The version constraints used in your meta-packages and incorporations
should be consistent with those used in you direct package dependencies.
This ensures consistent, predictable behavior when installing your project's packages.
7 Be aware of limitations regarding dependencies on OS native packages Currently there is no support in IPS for specifying a dependency on non-IPS packages. Therefore on most OS platforms you are not able to specify dependencies on native OS packages.

Details

1. Use require when dependencies are required for basic functionality

Install-time and run-time dependencies can be represented within packages, but only when the packages that satisfy those dependencies are fixed and known in advance of building the packages. In this case those dependencies that are required for basic functionality should be specified using a require dependency.

In cases where a run-time dependency may be satisfied by a variable set of other packages or files, one cannot accurately represent such dependencies using the package dependency specification facilities. For example, if at run- time a package relies on the presence of an installation of J2SE yet there could be different packages that provide the required J2SE functionality, it is not likely that the dependency could be reasonably expressed using the dependency specification facility of a package format. In this case, it is desirable to provide as part of the run-time configuration interface the ability to set the location of a suitable installation of J2SE and to verify the suitability of the specified installation of J2SE.

2. Use optional when dependencies are not required for basic functionality

Self explanatory.

3. Use incorporate to create incorporations.

incorporate dependencies specify very narrow version constraints, and therefore should be reserved for specific use cases. The typical use case is to define an incorporation. An incorporation is an IPS package that has no contents on its own. Instead it contains a collection of incorporate dependencies on other packages. In this way an incorporation defines a snapshot of a collection of package versions.

An example application of an incorporation is an OpenSolaris SRU. An SRU fills the role that a patch cluster had in classic Solaris. A SRU represents a collection of fixes to other packages - it contains a set of incorporate dependencies on specific versions of updated packages. By installing the SRU all installed packages are upgraded to the exact version represented by the SRU incorporation.

Also, when an image-update is performed the latest version of the incorporation is installed, which then causes all of it's dependencies to be updated to the release families defined in the incorporation.

See Packaging Best Practices - Metapackages and Incorporations for more information.

4. Use fairly specific version constraints for dependencies between packages you deliver.

When specifying dependencies between packages that your project builds and releases together use fairly specific version constraints on the package dependencies. In particular if your project produces development builds that are made available to other projects or users, then consider specifying the constraint down to the build number. For example say your project produces five packages as part of its release. Every two weeks you produce a development build that is numbered, and you publish those packages to a repository. Your packages follow the Versioning Best Practice and they include the build number in their package version. In this case your project should include the build number in the version constraints for dependencies between your project's packages. For example if the package foobar is versioned 2.2-34.2132 you would define a dependency on it like this:

depend fmri=pkg:/foobar@2.2-34 type=require

The main benefit for using specific version constraints between packages your project produces is that it helps to avoid the situation where your customer ends up mixing packages from different project builds. Plus it makes it a bit easier for a customer to install packages from your project for a specific build (instead of just the latest).

If being specific is good then why not include the "2132" package/revision number? Because that locks you in a bit too much. By leaving that off you have the option of updating a single package (maybe with a bug fix) and bumping the revision number without needing to increment the dependency specification in other packages that depend on the updated package.

5. Use looser version constraints for dependencies on packages delivered by other projects.

When specifying a dependency on a package delivered by another project you should try to keep the version constraint as loosely specified as possible.

In this case take into account the compatibility policy of the package your are depending on. For example if the other project guarantees compatibility accross minor releases then you may just want to include the major version number in your specification:

depend fmri=pkg:/java@1 type=require

By using a loser constraint you reduce the ongoing cost of maintaining dependency specifications as new versions of your dependencies release. For example, if a new bugfix update of Java is published you don't want to have to rebuild and republish your packages to update the version constraints in the package dependencies.

On the other hand when it is known that not all versions of a named package contain the required implementation of a required interface,inclusion of version numbers (and perhaps even revisions) in dependency specifications can help ensure that compatible implementations are present. But in general these version dependencies should be specified as loosely as possible.

Guidelines for Specifying Version Level Dependencies:

  1. As a starting point, specify the version of the package containing the implementation of the interface(s) required by the package in which the dependency is being specified.
  2. Next, if a fundamental feature provided in a package depends on one or more fixes present in a newer version of the package containing the required interface implementation, specify the version of the providing package that contains the fix(es) as the minimally required version. A defect in a fundamental feature, if known prior to a release, would typically stop shipment of the component product. Such defects are typically P1 or P2 defects and typically affect a wide variety of customers.
  3. Similarly, if a fix affects multiple packages and the absence of one or more of the packages would result in a failure (either the fix wouldn't work or a new, serious error would be introduced), then it is advisable to specify dependencies such that all of the packages involved in the fix are required to be present.
  4. In isolated cases, a decision may be made to support only certain versions of packages even though earlier versions may satisfy the interface requirements of a particular package. Under these exceptional circumstances, the version specified may be newer than the absolute minimum functional version required by package.
6. The version constraints used in your meta-packages and incorporations should be consistent with those used in you direct package dependencies.

If your project produces meta-packages and incorporations then those should use the same level of version constraints that are used in your direct package dependencies.

This ensures consistent, predictable behavior when installing your projects packages.

7. Be aware of limitations regarding dependencies on OS native packages

Self explanatory.

Enter labels to add to this page:
Please wait 
Looking for a label? Just start typing.

Sign up or Log in to add a comment or watch this page.


The individuals who post here are part of the extended Sun Microsystems community and they might not be employed or in any way formally affiliated with Sun Microsystems. The opinions expressed here are their own, are not necessarily reviewed in advance by anyone but the individual authors, and neither Sun nor any other party necessarily agrees with them.

© 2010, Oracle Corporation and/or its affiliates
Powered by Atlassian Confluence
Oracle Social Media Participation Policy Privacy Policy Terms of Use Trademarks Site Map Employment Investor Relations Contact