OSX legacy packaging redux¶
This is a summary of the information on older (bundle-type) OSX installers in the software delivery legacy guide.
This redux might help reading the original document, because I found the original hard to digest.
Packaging has changed from bundles to flat packages¶
The world the legacy guide describes is for standard packaging up to and including OSX 10.4.
In this world, all installation packages were bundles. To quote from the glossary of the legacy guide:
- bundle
- A structured directory hierarchy that stores files in a way that facilitates their retrieval.
This means all installation package types before OSX 10.5 are directories with a particular structure. These are the package types described in the legacy guide, and this document. Newer OSX will still install from these packages.
In the new world (OSX 10.5 and above), the standard package formats are
flat, meaning that the packages are archived up into single file xar
archives. There are two types of packages in this new world of flat:
- flat component packages (built by
pkgbuild
utility); - flat product archives (built by the
productbuild
utility). These contain component packages, but can customize the install experience with a XML Distribution definition file calledDistribution
. TheDistribution
file may contain Javascript code for checking installation requirements and customizing install options.
See OSX flat packages for details.
Now we forget about flat packages and go back to the world where all installer packages are bundles.
Manual and managed installs¶
The software delivery guide distinguishes between:
- Manual installs
- You provide a single directory or file that the user drags to their hard
disk. This is a typical install for an OSX
*.app
bundle, where the user drags the*.app
folder (bundle) to/Applications
- Managed installs
- Installs via a
.pkg
or.mpkg
installer. The install is “managed” because the installer automates the task of checking for dependencies, getting Administrator authentication from the user, and moving files to different parts of the file system.
The rest of this document is about managed installs.
Component and multi-component packages¶
There are two categories of installers, single component installers and multi-component installers. A single component installer can only have one component, but the multi-component installers can contain more than one component.
I will use installer and package to mean the same thing in this document. Both single and multi-component packages can be used as installers.
There is only one type of single-component installer – the component package.
There are two types of multi-component installers; metapackages and distribution packages (see below).
Therefore there are three types of installers / packages:
- component package (single component)
- metapackage (multi-component, older format)
- distribution package (multi-component, newer format)
Component package¶
The Apple term for a package / installer for a single component is a component package. Component packages can be used as installers, or as units for building multi-component packages.
A component package carries information and data for installing one particular component. A component package:
- has a
.pkg
directory extension for the package bundle; - installs on any version of OSX;
- usually contains a payload - directories and files to be installed at one particular location on disk;
- has a bundle structure where the
.pkg
directory contains a top-levelContents
directory, which in turn contains filesArchive.bom
,Archive.pax.gz
,Info.plist
,PkgInfo
, and directoryResources
.
This is one .pkg
component bundle from the Python.org installer:
Multi-component packages¶
There are two types of multi-component packages, the metapackage and the (newer) distribution package.
Metapackage¶
A metapackage:
- has a
.mpkg
directory extension for the package bundle; - installs on OSX 10.2 or later;
- has a bundle structure where the
.mpkg
directory contains a top-levelContents
directory, which in turn contains filesInfo.plist
,PkgInfo
, and directoriesResources
,Packages
.
Here’s is the .mpkg
bundle for the Python.org installer:
Each of the listed .pkg
component packages is also a bundle. In fact the
example component bundle contents is the
contents of PythonUnixTools-2.7.pkg
from the Python.org .mpkg
bundle
here.
Distribution package¶
A distribution package:
- has a
.mpkg
directory extension for the package bundle; - installs on OSX 10.4 or later;
- can customize install messages and options using XML elements and Javascript
code in the
distribution.dist
file. - has a bundle structure where the
.mpkg
directory contains a top-levelContents
directory, which in turn contains filedescription.dist
, and directoriesResources
,Packages
.
This is the contents of a distribution package I had lying around on my hard drive:
Hybrid package¶
Confusingly, it is also possible to make a package that is both a
metapackage and a distribution package. These packages have the contents of
a metapackage, but with the extra distribution.dist
file. The installer
runs as a metapackage on OSX < 10.4, and as a distribution package for OSX >=
10.4. For example, this is why the metapackage and distribution package
directory listings shown in the MacTech flat package article have the same
files.
Information in all package types¶
Apple distinguishes four types of information any package can contain:
- Product information : e.g. description, readme, license
- Package information : e.g. package identifier, package version
- Installation properties : e.g. system requirements, whether the installer requires Administrator permissions
- Install operations : one of pre-flight, pre-install, pre-upgrade, post-install, post-upgrade, post-flight (see Install operations).
Steps in an install¶
- Requirements check : the installer checks if the system and target installation volumes meet any requirements for the install
- Preinstall : installer runs pre-flight and pre-install / pre-upgrade operations; these may cancel the install by returning an exit code other than 0;
- Install / payload drop: installer copies payload(s) to target volume
- Save receipt : “Installer copies the component package file (with its
payload stripped) to the
/Library/Receipts
directory in the installation volume.” (software delivery legacy guide). - Postinstall : installer runs post-install / post-upgrade and post-flight operations.
Install operations¶
Install operations are operations run during the steps of an install, that can customize the behavior of the installer.
I’ll also call these pre / post operations.
The operations are run in the following order (see Steps in an install).
- Pre-flight : operation run after requirements check step. Implemented by preflight executable. Return value other than 0 cancels the install.
- Pre-install : operation run for a system on which there is no pre-existing receipt (see “Save receipt” step above). Implemented by preinstall executable. Return value other than 0 cancels the install.
- Pre-upgrade : operation run for a system on which there is a pre-existing receipt. Implemented by preupgrade executable. Return value other than 0 cancels the install.
There follows the install / payload drop step (above), then:
- Post-install : operation run for a system on which there is a pre-existing receipt. Implemented by postinstall executable.
- Post-upgrade : operation run after payload drop, for a system on which there is no pre-existing receipt. Implemented by postupgrade executable script.
- Post-flight : Implemented by postflight executable.
All these operations are optional.
The executables can be scripts or binaries, but must have their executable bit set.
See “Specifying install operations” in the software delivery legacy guide.
How the package types implement the install¶
Component packages, metapackages and distribution packages differ in their behavior when installing. They differ in the way they implement requirement checks and which operation executables they run.
Component package¶
Requirements check¶
A component package can have none or more of the following executables:
InstallationCheck
VolumeCheck
These scripts implement requirement checking for the “requirements check” step (Steps in an install).
If InstallationCheck
is present, it should return 0 if the system is
suitable for the install. If not, it should return another number, where the
number identifies a message to display (see the software delivery legacy
guide for details).
If VolumeCheck
is present, it should return 0 for any volume that is
suitable for the install. If a particular volume is not suitable, it should
return another number, where the number identifies a message to display (see
the software delivery legacy guide for details). The installer will run
VolumeCheck
on each available volume at install-time.
An install using a component package also runs these (optional) operations / executables:
pre / post operations¶
preflight
preinstall
orpreupgrade
(depending on whether a receipt is present)postinstall
orpostupgrade
(depending on whether a receipt is present)postflight
Metapackage¶
A metapackage can contain:
- component packages
- metapackages
I will call the containing metapackage the “top metapackage”.
Requirements check¶
InstallationCheck
for each component package;VolumeCheck
for each component package and each available volume.
The top metapackage cannot specify its own InstallationCheck
or
VolumeCheck
.
Pre-post operations¶
preflight
for top metapackagepreflight
for each component packagepreinstall
orpreupgrade
for top metapackagepreinstall
orpreupgrade
for each component packagepostinstall
orpostupgrade
for each component packagepostinstall
orpostupgrade
for top metapackagepostflight
for top metapackagepostflight
for each component package
Distribution package¶
Distribution packages can only contain component packages, not metapackages or other distribution packages.
Requirements check¶
Distribution packages implement their requirement checks with Javascript code
embedded in an XML file called distribution.dist
. This file can contain
Javascript code for checking whether the system is suitable for the install
(the Installation Check script) and code for checking whether a volume is
suitable for install (the Volume Check script). The requirements check
process is therefore:
- Run Installation Check Javascript.
- Run Volume Check Javascript on every volume.
Pre-post operations¶
preflight
for each component packagepreinstall
orpreupgrade
for each component packagepostinstall
orpostupgrade
for each component packagepostflight
for each component package
Unlike the metapackage, the distribution package cannot itself specify pre-post operations with scripts (they will be ignored if present).