Go to main content

Packaging and Delivering Software With the Image Packaging System in Oracle® Solaris 11.4

Exit Print View

Updated: November 2020
 
 

Creating and Publishing a Package

Packaging software with IPS is usually straightforward due to the amount of automation that is provided. Automation avoids repetitive tedium, which seems to be the principal cause of most packaging bugs.

Publication in IPS consists of the following steps:

  1. Generate a package manifest.

  2. Add necessary metadata to the generated manifest.

  3. Evaluate dependencies.

  4. Add any facets or actuators that are needed.

  5. Verify the package.

  6. Publish the package.

  7. Test the package.

Generate a Package Manifest

The easiest way to get started is to organize the component files into the same directory structure that you want on the installed system.

Two ways to do this are:

  • If the software you want to package is already in a tarball, unpack the tarball into a subdirectory. For many open source software packages that use the autoconf utility, setting the DESTDIR environment variable to point to the desired prototype area accomplishes this. The autoconf utility is available in the pkg:/developer/build/autoconf package.

  • Use the install target in a Makefile.

Suppose your software consists of a binary, a library, and a man page, and you want to install this software in a directory under /opt named mysoftware. Create a directory in your build area under which your software appears in this layout. In the following example, this directory is named proto:

proto/opt/mysoftware/lib/mylib.so.1
proto/opt/mysoftware/bin/mycmd
proto/opt/mysoftware/man/man1/mycmd.1

Use the pkgsend generate command to generate a manifest for this proto area. By default, the owner of each file and directory will be set to root in the output package manifest, and the group for each file and directory will be set to bin. To use the owner and group that are set on the files and directories in the proto directory, use the -u option with the pkgsend generate command.

Pipe the output package manifest through pkgfmt to make the manifest more readable. See the pkgsend(1) and pkgfmt(1) man pages for more information.

In the following example, the proto directory is in the current working directory:

$ pkgsend generate proto | pkgfmt > mypkg.p5m.1

The output mypkg.p5m.1 file contains the following lines:

dir  path=opt owner=root group=bin mode=0755
dir  path=opt/mysoftware owner=root group=bin mode=0755
dir  path=opt/mysoftware/bin owner=root group=bin mode=0755
file opt/mysoftware/bin/mycmd path=opt/mysoftware/bin/mycmd owner=root \
    group=bin mode=0644
dir  path=opt/mysoftware/lib owner=root group=bin mode=0755
file opt/mysoftware/lib/mylib.so.1 path=opt/mysoftware/lib/mylib.so.1 \
    owner=root group=bin mode=0644
dir  path=opt/mysoftware/man owner=root group=bin mode=0755
dir  path=opt/mysoftware/man/man1 owner=root group=bin mode=0755
file opt/mysoftware/man/man1/mycmd.1 path=opt/mysoftware/man/man1/mycmd.1 \
    owner=root group=bin mode=0644

The path of the files to be packaged appears twice in the file action:

  • The first word after the word file describes the location of the file in the proto area.

  • The path in the path= attribute specifies the location where the file is to be installed.

This double entry enables you to modify the installation location without modifying the proto area. This capability can save significant time, for example if you repackage software that was designed for installation on a different operating system.

Notice that pkgsend generate has applied default values for directory owners and groups. In the case of /opt, the defaults are not correct. Delete that directory because it is delivered by other packages already on the system, and pkg will not install the package if the attributes of /opt conflict with those already on the system. Add Necessary Metadata to the Generated Manifest below shows a programmatic way to delete the unwanted directory.

If a file name contains an equal symbol (=), double quotation mark ("), or space character, pkgsend generates a hash attribute in the manifest, as shown in the following example:

$ mkdir -p proto/opt
$ touch proto/opt/my\ file1
$ touch proto/opt/"my file2"
$ touch proto/opt/my=file3
$ touch proto/opt/'my"file4'
$ pkgsend generate proto
dir group=bin mode=0755 owner=root path=opt
file group=bin hash=opt/my=file3 mode=0644 owner=root path=opt/my=file3
file group=bin hash="opt/my file2" mode=0644 owner=root path="opt/my file2"
file group=bin hash='opt/my"file4' mode=0644 owner=root path='opt/my"file4'
file group=bin hash="opt/my file1" mode=0644 owner=root path="opt/my file1"

When the package is published (see Publish the Package), the value of the hash attribute becomes the SHA-1 hash of the file contents, as noted in File Actions.

Add Necessary Metadata to the Generated Manifest

A package should define the following metadata. See Set Actions for more information about these values and how to set these values.

pkg.fmri

The name and version of the package as described in Package Name and Package Version. See Avoiding Conflicting Package Content for a discussion of package names and dependencies. The publisher name is added automatically when the package is published, as shown in Publish the Package. See Construct an Appropriate Package Version String for additional help setting your package version. See Oracle Solaris Package Versioning for a description of versioning in Oracle Solaris.

pkg.description

A description of the contents of the package.

pkg.summary

A one-line synopsis of the description.

variant.arch

Each architecture for which this package is suitable. If the entire package can be installed on any architecture, variant.arch can be omitted. Producing packages that have different components for different architectures is discussed in Allowing Variations.

info.classification

A grouping scheme. The supported values are shown in Classifying Packages. The example in this section specifies an arbitrary classification.

This example also adds a link action to /usr/share/man/index.d that points to the man directory under mysoftware. This link is discussed further in Add Any Facets or Actuators That Are Needed.

Rather than modifying the generated manifest directly, use pkgmogrify to edit the generated manifest. See Modifying Package Manifests Programmatically for a full description of using pkgmogrify to modify package manifests.

Create the following pkgmogrify input file to specify the changes to be made to the manifest. Name this file mypkg.mog. In this example, a macro is used to define the architecture, and regular expression matching is used to delete the /opt directory from the manifest.

set name=pkg.fmri value=mypkg@1.0
set name=pkg.summary value="This is an example package"
set name=pkg.description value="This is a full description of \
all the interesting attributes of this example package."
set name=variant.arch value=$(ARCH)
set name=info.classification \
    value=org.opensolaris.category.2008:Applications/Accessories
link path=usr/share/man/index.d/mysoftware target=/opt/mysoftware/man
<transform dir path=opt$->drop>

Run pkgmogrify on the mypkg.p5m.1 manifest with the mypkg.mog changes:

$ pkgmogrify -DARCH=`uname -p` mypkg.p5m.1 mypkg.mog | pkgfmt > mypkg.p5m.2

The output mypkg.p5m.2 file has the following content. The dir action for path=opt has been removed, and the metadata and link contents from mypkg.mog have been added to the original mypkg.p5m.1 contents.

set name=pkg.fmri value=mypkg@1.0
set name=pkg.summary value="This is an example package"
set name=pkg.description \
    value="This is a full description of all the interesting attributes of this 
example package."
set name=info.classification \
    value=org.opensolaris.category.2008:Applications/Accessories
set name=variant.arch value=i386
dir  path=opt/mysoftware owner=root group=bin mode=0755
dir  path=opt/mysoftware/bin owner=root group=bin mode=0755
file opt/mysoftware/bin/mycmd path=opt/mysoftware/bin/mycmd owner=root \
    group=bin mode=0644
dir  path=opt/mysoftware/lib owner=root group=bin mode=0755
file opt/mysoftware/lib/mylib.so.1 path=opt/mysoftware/lib/mylib.so.1 \
    owner=root group=bin mode=0644
dir  path=opt/mysoftware/man owner=root group=bin mode=0755
dir  path=opt/mysoftware/man/man1 owner=root group=bin mode=0755
file opt/mysoftware/man/man1/mycmd.1 path=opt/mysoftware/man/man1/mycmd.1 \
    owner=root group=bin mode=0644
link path=usr/share/man/index.d/mysoftware target=/opt/mysoftware/man

Construct an Appropriate Package Version String

The component version and branch version (see Package Version) of an IPS package version string have the following constraints:

  • The component version and branch version can consist only of integers and period characters (.). If your product version contains other characters, such as alphabetic characters or hyphen characters (-), select a version for the IPS package that conveys the same meaning using only integers and periods. For example, if your product version is P17-u4-r3, then 17.4.3 might work for the package version.

  • A sequence of more than one integer cannot begin with a zero (0). This format enables sorting by package version. For example, version 1.20 sorts newer than version 1.0.2, but 1.02 is invalid. If your product version 17.03 indicates the third test release of version 17 of the product, and the final released product will be version 17.0, then you could use package versions such as 16.99.3, 16.99.4, and so on for the test releases. Version 17.0 will be seen as newer than 16.99 versions, whereas 17.0 would not be newer than 17.0.3.

The component version and branch version are separated by a hyphen (-). Your custom packages are not required to have a branch version.

You can use the pkg.human-version attribute to provide your actual product version string as shown in the following example:

set name=pkg.human-version value="P17-u4-r3"

The value of the pkg.human-version attribute can be provided in addition to the package version in the package FMRI but cannot replace the package FMRI version. The pkg.human-version version string is used only for display purposes. See Set Actions for more information.

Evaluate Dependencies

Use the pkgdepend command to automatically generate dependencies for the package. The generated depend actions are defined in Depend Actions and discussed further in Specifying Package Dependencies.

Dependency generation is composed of two separate steps:

  1. Dependency generation. Determine the files on which the software depends. Use the pkgdepend generate command.

  2. Dependency resolution. Determine the packages that contain those files on which the software depends. Use the pkgdepend resolve command.

Generate Package Dependencies


Tip  -  Use pkgdepend to generate dependencies, rather than declaring depend actions manually. Manual dependencies can become incorrect or unnecessary as the package contents change over time. For example, when a file that an application depends on gets moved to a different package, any manually declared dependencies on the previous package would then be incorrect for that dependency.

Some manually declared dependencies might be necessary if pkgdepend is unable to determine dependencies completely. In such a case, you should add explanatory comments to the manifest.

In the following command, the -m option causes pkgdepend to include the entire manifest in its output. The -d option passes the proto directory to the command.

$ pkgdepend generate -md proto mypkg.p5m.2 | pkgfmt > mypkg.p5m.3

The output mypkg.p5m.3 file has the following content. The pkgdepend utility added notations about a dependency on libc.so.1 by both mylib.so.1 and mycmd. The internal dependency between mycmd and mylib.so.1 is silently omitted.

set name=pkg.fmri value=mypkg@1.0
set name=pkg.summary value="This is an example package"
set name=pkg.description \
    value="This is a full description of all the interesting attributes of this 
example package."
set name=info.classification \
    value=org.opensolaris.category.2008:Applications/Accessories
set name=variant.arch value=i386
dir  path=opt/mysoftware owner=root group=bin mode=0755
dir  path=opt/mysoftware/bin owner=root group=bin mode=0755
file opt/mysoftware/bin/mycmd path=opt/mysoftware/bin/mycmd owner=root \
    group=bin mode=0644
dir  path=opt/mysoftware/lib owner=root group=bin mode=0755
file opt/mysoftware/lib/mylib.so.1 path=opt/mysoftware/lib/mylib.so.1 \
    owner=root group=bin mode=0644
dir  path=opt/mysoftware/man owner=root group=bin mode=0755
dir  path=opt/mysoftware/man/man1 owner=root group=bin mode=0755
file opt/mysoftware/man/man1/mycmd.1 path=opt/mysoftware/man/man1/mycmd.1 \
    owner=root group=bin mode=0644
link path=usr/share/man/index.d/mysoftware target=/opt/mysoftware/man
depend fmri=__TBD pkg.debug.depend.file=libc.so.1 \
    pkg.debug.depend.reason=opt/mysoftware/bin/mycmd \
    pkg.debug.depend.type=elf type=require pkg.debug.depend.path=lib \
    pkg.debug.depend.path=opt/mysoftware/lib pkg.debug.depend.path=usr/lib
depend fmri=__TBD pkg.debug.depend.file=libc.so.1 \
    pkg.debug.depend.reason=opt/mysoftware/lib/mylib.so.1 \
    pkg.debug.depend.type=elf type=require pkg.debug.depend.path=lib \
    pkg.debug.depend.path=usr/lib

Resolve Package Dependencies

To resolve dependencies, pkgdepend examines the packages currently installed in the image used for building the software. By default, pkgdepend puts its output in mypkg.p5m.3.res.

$ pkgdepend resolve -m mypkg.p5m.3

When this command completes, the output mypkg.p5m.3.res file contains the following content. The pkgdepend utility has converted the notation about the file dependency on libc.so.1 to a package dependency on pkg:/system/library/libc, which delivers that file.

set name=pkg.fmri value=mypkg@1.0
set name=pkg.summary value="This is an example package"
set name=pkg.description \
    value="This is a full description of all the interesting attributes of this 
example package."
set name=info.classification \
    value=org.opensolaris.category.2008:Applications/Accessories
set name=variant.arch value=i386
dir  path=opt/mysoftware owner=root group=bin mode=0755
dir  path=opt/mysoftware/bin owner=root group=bin mode=0755
file opt/mysoftware/bin/mycmd path=opt/mysoftware/bin/mycmd owner=root \
    group=bin mode=0644
dir  path=opt/mysoftware/lib owner=root group=bin mode=0755
file opt/mysoftware/lib/mylib.so.1 path=opt/mysoftware/lib/mylib.so.1 \
    owner=root group=bin mode=0644
dir  path=opt/mysoftware/man owner=root group=bin mode=0755
dir  path=opt/mysoftware/man/man1 owner=root group=bin mode=0755
file opt/mysoftware/man/man1/mycmd.1 path=opt/mysoftware/man/man1/mycmd.1 \
    owner=root group=bin mode=0644
link path=usr/share/man/index.d/mysoftware target=/opt/mysoftware/man
depend fmri=pkg:/system/library/libc@11.4-11.4.14.0.1.5.0 type=require

Troubleshooting Resolving Package Dependencies

The pkgdepend resolve command takes a while to run because it loads a large amount of information about the image in which it is running. The pkgdepend utility can resolve many packages at once. If you are developing multiple packages, you can improve overall efficiency by listing all manifest files on one pkgdepend resolve command.

If the pkgdepend resolve output reports that a manifest file has an unresolved dependency, then you will also see the following information:

pkg.debug.depend.file

The file that pkgdepend is looking for to satisfy the dependency. This file is delivered by a different package, not by the package that is being built.

pkg.debug.depend.reason

The file in the package that is being built that depends on the file named by pkg.debug.depend.file.

pkg.debug.depend.type

The type of dependency of the file named by pkg.debug.depend.file; for example, elf.

pkg.debug.depend.path

The directories where pkgdepend is looking for the file named by pkg.debug.depend.file.

You might see multiple pkg.debug.depend.path entries for one dependency. For example, if the dependency is for a binary that the package being built is delivering, and that binary was linked against a library, a separate pkg.debug.depend.path entry is listed for each location where the compilation of the binary was told to look for libraries.

Take the following steps if pkgdepend resolve reports that a dependency is unresolved:

If the pkg.debug.depend.file file does not exist in this image:

  • Make sure that the IPS package that delivers the pkg.debug.depend.file file is installed in this image.

    If the package that delivers the pkg.debug.depend.file file is not installed because that package also is being developed, then include the manifests of both packages on the same pkgdepend resolve command.

    If the pkg.debug.depend.file file is not delivered by an IPS package (for example, it is provided by third-party software), then make sure the software that delivers the file is installed in this image.

  • If you are confident that this dependency will exist in images where this package will be installed, then you can tell pkgdepend not to look for this dependency. See Suppressing Automatic Dependency Generation to tell pkgdepend not to look for a particular dependency.

  • Verify that the pkg.debug.depend.reason file depends on the pkg.debug.depend.file file. For example, if the pkg.debug.depend.reason file is a sample script, modules used in that sample are not required to install and use the package that contains the sample. See Suppressing Automatic Dependency Generation to ignore such apparent dependencies.

If the pkg.debug.depend.file file exists in this image but the dependency is still unresolved, then the dependency is not in a location that is specified by a pkg.debug.depend.path entry. Add the location where the pkg.debug.depend.file file is being delivered to the list of directories where the pkg.debug.depend.reason file is being told to look.

  • Add the location in the package manifest. See Adding Dependency Search Paths.

  • Add the location in the dependent file. For example, add the location where the pkg.debug.depend.file file is being delivered to the -R flags of the compilation of the pkg.debug.depend.reason file.

Suppressing Automatic Dependency Generation

Use the pkg.depend.bypass-generate attribute of the file action to prevent generating specified dependencies for that file, as mentioned in the preceding steps.

Do not use pkg.depend.bypass-generate unless one of the following is true:

  • The automatically generated dependency is not actually a dependency of this package. For example, the dependency appears in sample code.

  • Though the dependency does not exist in this image where you are developing this package, you are confident that this dependency will exist in images where this package will be installed.

file path=dependent-file pkg.depend.bypass-generate=dependency-file
dependent-file

The pkg.debug.depend.reason file.

dependency-file

The pkg.debug.depend.file file.

The following is a partial example that omits common attributes:

file path=usr/app/myapp pkg.depend.bypass-generate=opt/3app/lib/library.so

You can also specify an attribute of the manifest, which applies to all files specified in the manifest.

set name=pkg.depend.bypass-generate value=dependency-file

When you use the pkg.depend.bypass-generate attribute, you will see a line such as the following in the manifest that is generated by pkgdepend resolve:

set name=pkg.depend.bypassed value=dependency-file
Adding Dependency Search Paths

The following methods can be used to add paths for pkgdepend to use to resolve dependencies:

  • Add a path to the PKGDEPEND_RUNPATH variable.

  • Specify a value for the pkg.depend.runpath attribute.

file path=dependent-file pkg.depend.runpath=dependency-path
dependent-file

The pkg.debug.depend.reason file.

dependency-path

The path to the dependency. Use : to add multiple search paths. Best practice is to add $PKGDEPEND_RUNPATH to the value.

The following is a partial example that omits common attributes:

file path=usr/app/myapp pkg.depend.runpath=usr/lib:$PKGDEPEND_RUNPATH

You can also specify an attribute of the manifest, which applies to all files specified in the manifest.

set name=pkg.depend.runpath value=dependency-paths

Add Any Facets or Actuators That Are Needed

A facet denotes an action that is not required but can be optionally installed. An actuator specifies system changes that must occur when the associated action is installed, updated, or removed. Facets are discussed in more detail in Allowing Variations, and actuators are discussed in more detail in Automating System Change as Part of Package Operations.

This example package delivers a man page in /opt/mysoftware/man/man1. This section shows how to add a facet tag to indicate that man pages are optional. The user could choose to install all of the package except the man page. (If the user sets the facet property doc.man=false as described in Controlling Installation of Optional Components in Updating Systems and Adding Software in Oracle Solaris 11.4, no actions tagged with facet.doc.man=true are installed from any package.)

To include the man page in the index, the svc:/application/man-index:default SMF service must be restarted when the package is installed. This section shows how to add the restart_fmri actuator to perform that task. The man-index service looks in /usr/share/man/index.d for symbolic links to directories that contain man pages, adding the target of each link to the list of directories it scans. To include the man page in the index, this example package includes a link from /usr/share/man/index.d/mysoftware to /opt/mysoftware/man. Including this link and this actuator is a good example of the self-assembly discussed in Software Self-Assembly and used throughout the packaging of the Oracle Solaris OS.

A set of pkgmogrify transforms that you can use are available in /usr/share/pkg/transforms. These transforms are used to package the Oracle Solaris OS, and are discussed in more detail in Modifying Package Manifests Programmatically.

The file /usr/share/pkg/transforms/documentation contains transforms similar to the transforms needed in this example to set the man page facet and restart the man-index service. Since this example delivers the man page to /opt, the documentation transforms must be modified as shown below. These modified transforms include the regular expression opt/.+/man(/.+)? which matches all paths beneath opt that contain a man subdirectory. Save the following modified transforms to /tmp/doc-transform:

<transform dir file link hardlink path=opt/.+/man(/.+)? -> \
    default facet.doc.man true>
<transform file path=opt/.+/man(/.+)? -> \
    add restart_fmri svc:/application/man-index:default>

Use the following command to apply these transforms to the manifest:

$ pkgmogrify mypkg.p5m.3.res /tmp/doc-transform | pkgfmt > mypkg.p5m.4.res

The input mypkg.p5m.3.res manifest contains the following three man-page-related actions:

dir  path=opt/mysoftware/man owner=root group=bin mode=0755
dir  path=opt/mysoftware/man/man1 owner=root group=bin mode=0755
file opt/mysoftware/man/man1/mycmd.1 path=opt/mysoftware/man/man1/mycmd.1 \
    owner=root group=bin mode=0644

After the transforms are applied, the output mypkg.p5m.4.res manifest contains the following modified actions:

dir  path=opt/mysoftware/man owner=root group=bin mode=0755 facet.doc.man=true
dir  path=opt/mysoftware/man/man1 owner=root group=bin mode=0755 \
    facet.doc.man=true
file opt/mysoftware/man/man1/mycmd.1 path=opt/mysoftware/man/man1/mycmd.1 \
    owner=root group=bin mode=0644 \
    restart_fmri=svc:/application/man-index:default facet.doc.man=true

Tip  -  For efficiency, these transforms could have been added when metadata was originally added, before evaluating dependencies.

Verify the Package

The last step before publication is to run pkglint on the manifest to find errors that can be identified before publication and testing. Some of the errors that pkglint can find would also be found either at publication time or when a user attempts to install the package, but of course you want to identify errors as early as possible in the package authoring process.

Examples of errors that pkglint reports include:

  • Delivering files already owned by another package.

  • Delivering files to reserved directories. See the list of reserved directories in Designing a Package.

  • Difference in metadata for shared, reference-counted actions such as directories. An example of this error is discussed at the end of Generate a Package Manifest.

Use the pkglint -L command to show the full list of checks that pkglint performs. Detailed information about how to enable, disable, and bypass particular checks is given in the pkglint(1) man page. The man page also details how to extend pkglint to run additional checks.

You can run pkglint in one of the following modes:

  • Directly on the package manifest. This mode is usually sufficient to quickly check the validity of your manifests.

  • On the package manifest, also referencing a package repository. Use this mode at least once before publication to a repository.

    By referencing a repository, pkglint can perform additional checks to ensure that the package interacts well with other packages in that repository.

The following output shows problems with the example manifest:

$ pkglint mypkg.p5m.4.res
Lint engine setup...
Starting lint run...
WARNING pkglint.action005.1       obsolete dependency check skipped: unable
to find dependency pkg:/system/library/libc@11.4-11.4.14.0.1.5.0 for
pkg:/mypkg@1.0

This warning is acceptable for this example. The pkglint.action005.1 warning says that pkglint could not find a package called pkg:/system/library/libc@11.4-11.4.14.0.1.5.0, on which this example package depends. The dependency package is in a package repository and could not be found since pkglint was called with only the manifest file as an argument.

In the following command, the -r option references a repository that contains the dependency package:

$ pkglint -c ./solaris-reference -r http://pkg.oracle.com/solaris/release mypkg.p5m.4.res

The -c option specifies a local directory used for caching package metadata from the lint (-l option, not shown) and reference (-r option) repositories. If -l or -r is specified, then -c must be specified. The -l and -r options can be specified multiple times.

If you run the pkglint command again on the same lint or reference repository, you can specify just the -c option with the same argument that you specified with -l or -r:

$ pkglint -c ./solaris-reference mypkg.p5m.4.res

Publish the Package

Publish your package to a local file-based repository. This repository is for developing and testing this new package. If you create a repository for general use, you should include additional steps such as creating a separate file system for the repository. For information about creating package repositories for general use, see Creating Package Repositories in Oracle Solaris 11.4.

To test the package with non-global zones, the repository location must be accessible through the system repository. Use the pkg publisher or pkg list command inside a non-global zone to confirm that the package is accessible.

Use the pkgrepo command to create a repository on your system:

$ pkgrepo create my-repository
$ ls my-repository
pkg5.repository

Set the default publisher for this repository. The default publisher is the value of the publisher/prefix property of the repository.

$ pkgrepo -s my-repository set publisher/prefix=mypublisher

Use the pkgsend publish command to publish the new package. If multiple pkgsend publish processes might be publishing to the same -s repository simultaneously, specifying the --no-catalog option is recommended because updates to publisher catalogs must be performed serially. Publication performance might be significantly reduced if the --no-catalog option is not used when multiple processes are simultaneously publishing packages. After publication is complete, the new packages can be added to the respective publisher catalogs by using the pkgrepo refresh command.

$ pkgsend -s my-repository publish -d proto mypkg.p5m.4.res
pkg://mypublisher/mypkg@1.0:20191020T005452Z
PUBLISHED

Notice that the repository default publisher has been applied to the package FMRI.

Verify that the new repository permissions, content, and signatures are correct:

$ pkgrepo verify -s my-repository

You can use the pkgrepo and pkg list commands to examine the repository:

$ pkgrepo info -s my-repository
PUBLISHER   PACKAGES STATUS           UPDATED
mypublisher 1        online           2013-07-20T00:54:52.758591Z
$ pkgrepo list -s my-repository
PUBLISHER   NAME                    O VERSION
mypublisher mypkg                     1.0:20191020T005452Z
$ pkg list -afv -g my-repository
FMRI                                                     IFO
pkg://mypublisher/mypkg@1.0:20191020T005452Z      ---

A value in the O column of pkgrepo list indicates whether the package is obsolete (o) or renamed (r).

Publishing the new package directly to an HTTP repository is not recommended since no authorization or authentication checks are performed on the incoming package when publishing over HTTP. Instead of publishing the package to an HTTP repository, deliver the already-published package to an HTTP repository as described in Deliver to a Package Repository. Publishing to HTTP repositories can be convenient on secure networks or when testing the same package across several systems when NFS or SMB access to the file repository is not possible. If you publish directly to an HTTP repository, that repository must be hosted on a system with a read/write instance of the svc:/application/pkg/server service (the value of the pkg/readonly property is false).

Sign the Package

If you want to sign your package, do that now, and then test the package and deliver the package to the general use repository or package archive.

The following command signs the package using the hash value of the package manifest. You can also specify your own signature key and certificate. See Signing IPS Packages for more information. Notice that the time stamp of the package is not changed.

$ pkgsign -s my-repository -a sha256 '*'
Signed pkg://mypublisher/mypkg@1.0:20191020T005452Z

Test the Package

The final step in package development is to install the package to test whether the published package has been packaged properly.

To test installation without requiring root privilege, assign the test user the Software Installation profile. Use the -P option of the usermod command to assign the test user the Software Installation profile.


Note -  If this image has child images (non-global zones) installed, you cannot use the -g option with the pkg install command to test installation of this package. You must configure the mypublisher publisher in the image.

The following pkg set-publisher command adds all publishers in the my-repository repository to the list of publishers configured in this image:

$ pkg publisher
PUBLISHER    TYPE    STATUS P LOCATION
solaris      origin  online F http://pkg.oracle.com/solaris/release/
$ pkg set-publisher -p my-repository
pkg set-publisher:
  Added publisher(s): mypublisher
$ pkg publisher
PUBLISHER    TYPE    STATUS P LOCATION
solaris      origin  online F http://pkg.oracle.com/solaris/release/
mypublisher  origin  online F file:///home/username/my-repository/

Use the -nv options with the pkg install command to see what the install command will do without making any changes to the image. The following command actually installs the package:

$ pkg install mypkg
           Packages to install:  1 
       Create boot environment: No
Create backup boot environment: No
            Services to change:  1

DOWNLOAD                                  PKGS       FILES   XFER (MB)   SPEED
Completed                                  1/1         3/3     0.0/0.0  787k/s

PHASE                                          ITEMS
Installing new actions                         16/16
Updating package state database                 Done
Updating image state                            Done
Creating fast lookup database                   Done
Reading search index                            Done
Updating search index                            1/1

Examine the software that was delivered on the system:

$ find /opt/mysoftware
/opt/mysoftware
/opt/mysoftware/bin
/opt/mysoftware/bin/mycmd
/opt/mysoftware/lib
/opt/mysoftware/lib/mylib.so.1
/opt/mysoftware/man
/opt/mysoftware/man/man1
/opt/mysoftware/man/man1/mycmd.1
/opt/mysoftware/man/man-index
/opt/mysoftware/man/man-index/term.dic
/opt/mysoftware/man/man-index/term.req
/opt/mysoftware/man/man-index/term.pos
/opt/mysoftware/man/man-index/term.exp
/opt/mysoftware/man/man-index/term.doc
/opt/mysoftware/man/man-index/.index-cache
/opt/mysoftware/man/man-index/term.idx

In addition to the binaries and man page, the system has also generated the man page indexes as a result of the actuator restarting the man-index service.

The pkg info command shows the metadata that was added to the package:

$ pkg info mypkg
          Name: mypkg
       Summary: This is an example package
   Description: This is a full description of all the interesting attributes of
                this example package.
      Category: Applications/Accessories
         State: Installed
     Publisher: mypublisher
       Version: 1.0
 Build Release: 5.11
        Branch: 0
Packaging Date: July 20, 2013 00:54:52 AM 
          Size: 12.95 kB
          FMRI: pkg://mypublisher/mypkg@1.0:20191020T005452Z

The pkg search command returns hits when querying for files that are delivered by mypkg:

$ pkg search -l mycmd
INDEX      ACTION VALUE                    PACKAGE
basename   file   opt/mysoftware/bin/mycmd pkg:/mypkg@1.0

Deliver the Package

IPS provides three different ways to deliver a package so that users can install the package:

Local file-based repository

Users access this repository over the local network. The publisher origin is the path to the repository, such as /net/host1/export/ipsrepo.

Remote HTTP-based repository

Users access this repository over HTTP or HTTPS. The publisher origin is an address such as http://pkg.example.com/.

Package archive

A package archive is a standalone file. The publisher origin is the path to the archive file, such as /net/host1/export/ipsarchive.p5p.

In each of these cases, the package was already published using the pkgsend publish command as described in Publish the Package. Use the pkgrecv command to retrieve the package to an existing repository or package archive for general use. See the pkgrecv(1) man page for more information. See Creating Package Repositories in Oracle Solaris 11.4 for information about how to create and maintain a repository for general use.

Deliver to a Package Repository

The following example shows how to deliver the new package from the test repository to a local file repository that has been set up for general use. The get and send sizes are zero because the package in this example is small.

$ pkgrecv -s my-repository -d /net/host1/export/ipsrepo mypkg
Processing packages for publisher mypublisher ...
Retrieving and evaluating 1 package(s)...
PROCESS                                         ITEMS   GET (MB)   SEND (MB)
Completed                                         1/1    0.0/0.0     0.0/0.0

Verify the presence of the package in the new repository:

$ pkgrepo info -s /net/host1/export/ipsrepo
PUBLISHER   PACKAGES STATUS           UPDATED
solaris     4455     online           2013-07-09T23:41:24.312974Z
mypublisher 1        online           2013-07-22T20:57:36.951042Z
$ pkgrepo list -p mypublisher -s /net/host1/export/ipsrepo
PUBLISHER   NAME                    O VERSION
mypublisher mypkg                     1.0:20191020T005452Z

Use the same pkgrecv command to deliver the package to an HTTP or HTTPS repository. In this case, specify the value of the pkg/inst_root property of the appropriate pkg/server service instance as the -d argument. This repository is served to users by the svc:/application/pkg/server service, which runs pkg.depotd. See the pkg.depotd(8) man page for more information.

If this image has no child images (non-global zones), users can use the -g option to install the new package, as shown in the following command. The -g option adds the mypublisher publisher to the list of publishers configured in this image.

$ pkg install -g /net/host1/export/ipsrepo mypkg

If this image does have child images, users must configure the mypublisher publisher in the image, as shown in the following command.

$ pkg set-publisher -p /net/host1/export/ipsrepo

Deliver as a Package Archive File

A package archive is a standalone file that contains publisher information and one or more packages provided by that publisher. Delivering packages as a package archive is convenient for users who cannot access your package repositories. Package archives can be easily downloaded from a web site, copied to a USB key, or burned to a DVD.

The pkgrecv command can add packages to package archives from package repositories or add packages to package repositories from package archives. When adding packages to a package repository from a package archive, note that a package archive does not contain repository configuration such as a default publisher prefix. Most pkgrepo subcommands do not work with package archives. The pkgrepo list command works with package archives.

The following command creates a package archive of the mypkg package. Because this archive does not yet exist, you must specify the -a option. By convention, package archives have the file extension .p5p.

$ pkgrecv -s my-repository -a -d myarchive.p5p mypkg
Retrieving packages for publisher mypublisher ...
Retrieving and evaluating 1 package(s)...
DOWNLOAD                                  PKGS       FILES   XFER (MB)   SPEED
Completed                                  1/1         3/3     0.0/0.0  782k/s

ARCHIVE                                              FILES   STORE (MB)
myarchive.p5p                                        14/14      0.0/0.0

If this image has no child images (non-global zones), users can use the -g option to install the new package, as shown in the following command. The -g option adds the mypublisher publisher to the list of publishers configured in this image.

$ pkg install -g myarchive.p5p mypkg

If this image does have child images, users must configure the mypublisher publisher in the image, as shown in the following command.

$ pkg set-publisher -p myarchive.p5p

Package archives can be set as sources of local publishers in non-global zones.

Using Package Repositories and Archives

Use the pkgrepo command to list the newest available packages from a repository or archive:

$ pkgrepo list -s my-repository '*@latest'
PUBLISHER   NAME                                          O VERSION
mypublisher mypkg                                           1.0:20191020T005452Z
$ pkgrepo list -s myarchive.p5p '*@latest'
PUBLISHER   NAME                                          O VERSION
mypublisher mypkg                                           1.0:20191020T005452Z

This output can be useful for constructing scripts to create archives with the latest versions of all packages from a given repository.