Install Binary Manual
Install Binary Manual
Install Binary Manual
1: Binary Manual
Copyright 2003-2007 Wincent Colaiuta
May 30, 2007
Contents
1 Introduction 2
1.1 Disclaimer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
1.2 Core ideas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
1.2.1 Install steps . . . . . . . . . . . . . . . . . . . . . . . . . . 3
1
5 Advanced configuration 43
5.1 Using environment variables in shell scripts . . . . . . . . . . . . . . 43
5.1.1 Inherited environment variables . . . . . . . . . . . . . . . . 43
5.1.2 Custom environment variables . . . . . . . . . . . . . . . . 44
5.2 Redirecting output to the console via STDERR . . . . . . . . . . . 45
5.3 Using plutil to check the configuration plist . . . . . . . . . . . . . 45
List of Figures
1 Sample WOInstallerStepReadMe step . . . . . . . . . . . . . . . . . 5
2 Sample WOInstallerStepLicense step . . . . . . . . . . . . . . . . . 6
3 Sample WOInstallerStepShell step . . . . . . . . . . . . . . . . . . 7
4 Sample WOInstallerStepDomain step . . . . . . . . . . . . . . . . . 8
5 Sample WOInstallerStepCopyFiles step . . . . . . . . . . . . . . . . 10
6 Sample WOInstallerStepFinish step . . . . . . . . . . . . . . . . . . 12
7 Sample WOInstallerStepUninstall step . . . . . . . . . . . . . . . . 14
8 Dialog displayed when installer is run on incompatible OS . . . . . . 20
List of Tables
1 Typical environment variables passed to shell scripts . . . . . . . . . 44
1 Introduction
This is the Binary Manual for Install, written for licensees holding a current Binary-
only license for Install. It is a technical document whose intended audience comprises
2
programmers and developers with knowledge of XML plist files1 , Mac OS X bundles2
and with (optional) experience in shell programming.
The document strives to be clear, concise, comprehensive and unambiguous. If
you identify a specific aspect that should be clarified or corrected please contact
Wincent at win@wincent.com.
1.1 Disclaimer
Please read this manual carefully and in its entirety before starting to work with
Install. Install is a powerful program that can run with root privileges to perform
many tasks, including copying and deleting files, moving files to the Trash, adding
or removing login items, and running shell scripts. As such, configuration should
only by attempted by people thoroughly familiar with the operation of the software.
The software and related documents and materials are provided “as is” without
any express, implied or statutory warranty of any kind. In no event shall Wincent or
its officers, employees, directors, subsidiaries, representatives, affiliates and agents
have any liability to you or any other third party, for any lost profits, lost data, loss
of use or costs of procurement of substitute goods or services, or for any indirect,
special or consequential damages arising out of the license agreement.
For more detailed information about this disclaimer, please see the Install Li-
cense.
3
they would typically appear in an installation sequence. Detailed information about
how to define the steps in the plist file appears in Section 3.
4
Figure 1: Sample WOInstallerStepReadMe step
step after having proceeded beyond it, then Install will not re-display the sheet, but
will proceed directly to the next step (Install only requires the user to agree to the
license agreement once per run).
of a given script. In order to ensure that the Install user interface remains responsive
during script execution, scripts are run in a separate thread, and a progress indicator
appears along with a status string in the main Install window (as shown in Figure 3)
whenever a script is being run.
As a WOInstallerStepReadMe step subclass, the WOInstallerStepShell
step requires an RTFD or RTF document to display (with an appropriate “.rtf”
or “.rtfd” file extension), and you can turn the document background and scroll
bars on or off. If one or more of your scripts is to execute with root privileges then
it is recommended that your WOInstallerStepShell document alert the user that
they will have to enter a valid administrator username and password before the
step can complete. The user can authenticate as an administrator at any time by
clicking the padlock icon in the lower left corner of the Install main window, but
Install will automatically prompt the user if authentication is required but has not
yet been obtained. If authentication will be required Install will ask for it prior to
running any of the scripts in the WOInstallerStepShell step. Having obtained
authentication, it then runs all of the scripts in the step, launching the appropriate
scripts with root privileges and running the others without privilege elevation. In
this way the prompt for authentication appears as soon as the user clicks the “Con-
tinue” button, and not at some intermediate point (for example, in the middle of
five or ten-script sequence) to avoid confusing the user.
Where multiple shell scripts are specified, they are executed in the order that they
appear in the configuration file. The same is true for shell scripts executed within the
WOInstallerStepCopyFiles and WOInstallerStepUninstall steps that will be
6
Figure 3: Sample WOInstallerStepShell step
work to launch commands with elevated privileges. Install itself does not run with root privileges,
but it can launch subprocesses which do.
7
Figure 4: Sample WOInstallerStepDomain step
choice presented as shown in Figure 4 which asks them to “Choose where to install
the software”: either, “Install only for the current user”, or, “Install for all users on
this machine”.
If you do not specify a WOInstallerStepDomain step in your configuration,
Install will use the User installation domain as default, although you can override this
and force Install to use the Global domain as a default (as described in Section 3.4
on page 20). You may optionally override the default text displayed in the top third
of the Install main window by supplying an appropriate RTF or RTFD with custom
text. You may wish to do this if you prefer to use text that features the actual name
of the software to be installed, rather than generic text such as “Choose where to
install the software” and “If you choose to install only for the current user, the
software will be installed in your home directory”.
Preinstall kill processes You may specify a list of target processes using bundle
identifiers (for example, com.apple.systempreferences) which must be
quit before installation can continue. You decide whether to quit the processes
by sending them a “quit” Apple Event (which would mean that the target
application could provide the user with a chance to save or apply any unsaved
work or changes before exiting) or by sending them with a SIGTERM or
8
SIGHUP signal. The attempt to quit target processes occurs in a separate
thread to ensure that the Install user interface remains responsive throughout.
Install effectively enters an idle state while waiting for target processes to
exit because it waits for notification from the operating system that this has
occurred (in other words, it does not do any polling). Install employs this
technique for all processes, even faceless background applications that can
not normally be detected using the Cocoa APIs. It is sensible to kill older
versions of the software to be installed (if you are attempting an upgrade),
or other processes that might be accessing files which you wish to modify,
remove or overwrite as part of the installation. You can specify any number
of processes.
Preinstall trash files and folders Install can effectively be used not only for clean
installations, but for upgrades as well. In this substep you could remove old
versions of the software before installing the new versions. Items in the Global
domain are Deleted using root privileges and items in the User domain and
moved to the Trash. Once again this occurs in a separate thread to guarantee
responsiveness. You can specify any number of files or folders.
Remove login items You can remove login items during this substep, which may
be useful to you if, for example, you want to upgrade any old versions of
your software that may be present on the target system and plan on removing
references to the old version in the login items and later replacing them with
references to the newly installed version. You can specify any number of
login items. You can also optionally specify a User domain only or Global
domain only key in order to remove a given item only under certain types
of installations.
Run preflight scripts In this substep, prior to any files being copied, you can run
shell scripts much as you can in the WOInstallerStepShell step; with or
without root privileges, an optional custom shell setting, and optional ar-
guments. Like the WOInstallerStepShell step you can control Install’s
behaviour in response to the different exit codes. You can specify any num-
ber of scripts, and they will be executed in the order in which they appear
in the configuration plist. Script execution occurs in a separate thread to
maintain user interface responsiveness.
Install files and folders This is the substep in which the files and folders are copied
to the target machine in the locations that you specify, in accordance with
whether the user has opted to install into the Global domain or the User
domain. Files to be copied into the Global domain are copied with root privi-
leges, and files to be copied into the User domain are copied without elevated
privileges. In both cases Macintosh-specific filesystem information such as re-
source forks and metadata is preserved when writing to an HFS+ target disk.
Once again, this substep occurs in a separate thread to maintain responsive-
ness. You may specify any number of files and folders in the configuration
plist. The order in which items are copied is not defined.
9
Figure 5: Sample WOInstallerStepCopyFiles step
Run postflight scripts In this substep, after all the files or folders have been suc-
cesfully copied, you can specify one or more postflight scripts that will be run
to perform post-installation tasks. As is the case with the preflight scripts,
you can run scripts with or without root privileges, a custom shell, and op-
tional arguments, and you can specify Install’s response to possible exit codes.
You can specify any number of scripts, which will be executed in a separate
thread, in the order specified in the configuration file.
Add login items As a counterpart to the Remove login items substep above,
the Add login items substep can be used to add one or more files or appli-
cations to the installing user’s login items. There is no limit to the number
of login items that you may specify in the Install configuration file. And like
the Remove login items substep you may also optionally specify a Global
domain only or User domain only key.
10
WOInstallerStepFinish The WOInstallerStepFinish step is a highly-recommended
step which should appear as the final step in any Install configuration. It is used
to display information to the user and can can be used to launch installed ap-
plications or open documentation. In fact, it can open (or launch) any set of
files with any application that you optionally specify. It is another subclass of
WOInstallerStepReadMe that requires you to specify an RTFD or RTF document
(with corresponding file extension, “.rtfd” or “.rtf”) providing information to
the user as shown in Figure 6. As with the parent class, you can instruct the
WOInstallerStepFinish step to show or not show a background, and include or
not include a scrollbar.
You may also run a single shell script from within this step, with or without root
privileges. Note that you may only run one such script in this step, unlike the other
shell-script-capable steps in which you can specify a sequence of scripts to run. Also,
unlike the other steps, there is no progress indicator in the Install user interface to
indicate that the script is running (although the script does run in a separate thread
for the usual reasons), so you should endeavour to make sure that your script is
quick to run. The principal purposes for running a script in this step are to launch
installed programs with root privileges, if appropriate (a valid example would be
launching a background daemon process with elevated privileges), or to advise the
user to logout (or even initiate a logout, using AppleScript and the osascript
command line tool).
As visible in Figure 6, the WOInstallerStepFinish step is capable of displaying
three buttons. In the example, the rightmost button has been assigned the custom
label, “Launch”. The purpose of this button is described under Primary button
action section in the configuration file. If you do not specify a Primary button
action then the button retains its default label (“Continue”) but is ghosted. In
this case, the action causes a shell script to be run with root privileges which in
turn launches the installed server daemon. The script must return an exit code of
0 (zero) to indicate success, otherwise Install will consider the operation to have
failed and will terminate with a warning dialog.
The leftmost button has been given the custom label of “Help” and when clicked
will open the help files using the application specified in the configuration file, as
defined in the Secondary button action section of the configuration. If you
do not specify a Secondary button action then the secondary button will not
appear in the user interface.
Note that for each button action you can specify a set of files to open and
applications to launch them with, or you can specify a single shell script to launch,
but you cannot do both types of operation within a single button action. In all
cases, after the action has been successfully completed, Install quits, so you should
take care when writing the RTFD (or RTF) file for the WOInstallerStepFinish
step that you make it clear to the user that for each button they might choose to
click, the final result will be that the installer will exit.
The WOInstallerStepFinish step is technically not compulsory, in that In-
stall will function correctly even without such a step, but it is highly recommended
because the absence of such as step is likely to be highly confusing to the user.
For example, if a WOInstallerStepCopyFiles step were the last step in the in-
11
Figure 6: Sample WOInstallerStepFinish step
stallation, Install would immediately exit as soon as the step successfully finishes,
effectively disappearing from the screen, which the user may incorrectly perceive as
a crash.
12
postflight scripts substeps, and scripts are executed in the order that
they appear in the configuration file.
• Scripts can be run with or without root privileges, you can specify a custom
shell and optional arguments, and scripts must return an exit code of 0 (zero)
or Install will consider the operation to have failed.
• You can specify any number of login items to be removed in the Remove
login items substep.
The Uninstall trash files and folders substep differs slightly in terms of
how it is described in the configuration plist file. This is because at the time the
WOInstallerStepUninstall step is initiated the target domain (Global or User)
has not been defined and so Install cannot know exactly which files will need to be
removed. Therefore, the user is presented with a list of possible files (or folders) to
remove as shown in Figure 7 and uses checkboxes to indicate which files or folders
should be uninstalled and which files or folders left alone. For each item that
might be removed, you define whether or not the checkbox should start off checked
by default and whether the item will require a valid administrator user name and
password to remove. A general rule is that files in the Global domain will require
elevated privileges (and be marked with a padlock icon in the user interface) while
files in the User domain will not. Install makes sure that the list shown to the user
only contains files and folders actually present on the users system. In general it is
advisable to encourage the user to leave items such as preference files for installed
software intact (by specifying that these items should not have their checkboxes
checked by default).
Once the user has clicked “Continue” to initiate the uninstallation, Install begins
the necessary operations in a separate thread and updates the file listing in real time
to show what substep is underway and which file or folder is in the process of being
deleted (or has successful been deleted). On success, the user may exit by pressing
“Quit”, or press the “Go Back” button to be returned to the first Install step (usually
a WOInstallerStepReadMe step) and if desired re-install the software immediately.
13
Figure 7: Sample WOInstallerStepUninstall step
14
a further, invisible folder called .localized which contains a number of strings
files. These strings files allow the Finder to display a localized title for the Files.
localized directory. If you look at the folder in the Finder, you might see its
name as “Files” (the Finder hides the “.localized” extension). As an example, if
your system language is set to Spanish, you would see the filename as “Archivos”,
which is the Spanish word for “Files”.
If, however, you have your Finder preferences set so that file extensions are
always shown, then you will not see the localized variant of the folder name and
you will only ever see it as “Files”.
The reason Install goes to such trouble to localize the name of a folder buried
inside the application bundle is that Install itself features a “Reveal files on disk. . . ”
menu item which users can use to expose the folder and browse it using the Finder.
This can be useful for users who are simply curious, for situations in which expert
users wish to do a manual (drag and drop) installation, and for cases where a copy
operation during an installation fails and Install advises the user to reveal the files
on disk and attempt the copy manually.
Man.pdf The first file to be defined in the configuration plist, and so it must
be stored in the first subfolder inside the Files.localized direc-
tory; in other words, at Install.app/Contents/Resources/Files.
localized/0/Man.pdf. The configuration plist specifies that it should
be placed in ~/Documents/DXP Documents/ for User domain installs
and in /Users/Shared/Documents/DXP Documents/ for Global do-
main installs. In both cases, Install will create the target directory if
15
required and create any other necessary intermediary directories along
the way.
DXP.app The second file to be defined in the configuration plist, and so it must be
stored in the second subfolder inside Files.localized, which is means
that it will be stored at Install.app/Contents/Resources/Files.
localized/1/DXP.app. The configuration plist specifies that it should
be stored in /Applications/ or in ~/Applications/ depending on
the installation domain. Note that in this case the item being installed is
actually a directory (an application bundle) but it is still only considered
as a single item, and therefore is compliant with the Install requirement
that each folder inside Files.localized only contain a single item.
FAQ.pdf The third file defined in the configuration plist, and so it must be stored
at Install.app/Contents/Resources/Files.localized/2/FAQ.pdf.
The configuration specifies that it should be installed into /Users/Shared/Documents/DXP
Documents/ or ~/Desktop/ depending on the installation domain.
The example configuration templates then contain the following comment. This
is to disuade users from looking inside the Install bundle and editing the plist file
manually. Because Install bases its actions on the contents of the configuration
file, and because it engages in potentially destructive actions – including copying
and deleting files, moving files to the Trash, adding and removing login items, and
running shell scripts, with or without root privileges – it is important that the end
user does not attempt to manipulate the settings. Only a licensed developer fully
familiar with the Install documentation and plist configuration file format should
attempt to edit the file.
16
The next element and only element in the file is an array containing a sets of
installation instructions. This array and its contents will be discussed in the following
sections. In the example below, a comment shows where the installation instructions
should appear. The final entries in the file are the closing </array> and <plist>
tags.
<array>
<!-- the installation instructions go here -->
</array>
</plist>
<array>
<dict>
<!-- first set of installation instructions -->
</dict>
<dict>
<!-- second set of installation instructions -->
</dict>
<dict>
<!-- third set of installation instructions -->
</dict>
</array>
A simpler configuration file might have only one set of installation instructions:
<array>
<dict>
<!-- first and only set of installation instructions -->
</dict>
</array>
17
3.2 Major components within each set of installation instruc-
tions
Within each set of installation instructions there are up to four possible major
components.
The four components are siblings, in that they appear at the same level within the
configuration plist, as illustrated in the following skeleton example:
<key>Target OS version</key>
<dict>
<!-- target OS specification -->
</dict>
<key>Default installation domain</key>
<string><!-- Global or User --></string>
<key>Install check</key>
<array>
<!-- check for pre-existing installation -->
</array>
<key>Installation steps</key>
<array>
<!-- the steps that comprise an installation -->
</array>
<key>Uninstall step</key>
<dict>
18
<!-- how to perform an uninstall -->
</dict>
<key>Target OS version</key>
<dict>
<key>Maximum system version</key>
<string>0x00001030</string>
<key>Minimum system version</key>
<string>0x00001020</string>
</dict>
The Target OS version dictionary is itself optional. If you decide to include it,
within the dictionary you must specify at least one of Minimum system version
and Maximum system version. By combining these entries you can create quite
sophisticated installations customised for specific versions of the OS.
The following example would ensure that the software is only installed on Jaguar
and above:
<key>Target OS version</key>
<dict>
<key>Minimum system version</key>
<string>0x00001020</string>
</dict>
The following example would ensure that the software is installed on any version of
Jaguar, but not on Panther or above:
<key>Target OS version</key>
<dict>
<key>Maximum system version</key>
<string>0x00001028</string>
<key>Minimum system version</key>
<string>0x00001020</string>
</dict>
The following example would ensure that the software is only installed on Mac OS
X 10.3.1:
19
Figure 8: Dialog displayed when installer is run on incompatible OS
<key>Target OS version</key>
<dict>
<key>Maximum system version</key>
<string>0x00001031</string>
<key>Minimum system version</key>
<string>0x00001031</string>
</dict>
In your installers you can use any number of customised sets of installation instruc-
tions tailored to specific versions of the OS, or you can just use a single set for all
versions.
The ordering of items in the configuration plist file is important. The installer
will search through the file looking at each set of installation instructions. If it finds
a set of instructions without a Target OS version dictionary, it will stop scanning
and proceed using those instructions. Otherwise, it continues scanning, and when-
ever it encounters a Target OS version dictionary it tests to see with the target
machine falls within the boundaries specified by Minimum system version and/or
Maximum system version. On the first successful match, the installer stops scan-
ning and proceeds using those instructions. If no successful matches are found, the
installer displays a dialog as shown in Figure 8 explaining that the software cannot
be installed.
The other possible case is the User case, in which Install will by default install items
for the current user only.
20
<key>Default installation domain</key>
<string>User</string>
If you do not specify a Default installation domain then Install will use the
User domain as the default. As such, you only need to specify the Default
installation domain when you wish to force Install to use the Global domain as
the default; in all other cases you may omit it. If you wish to allow the user to choose
the installation domain, then your installer should include a WOInstallerStepDomain
step.
<key>Install check</key>
<array>
<string>/Users/Shared/Install Manual.pdf</string>
<string>~/Desktop/Install Binary Manual.pdf</string>
<string>~/Desktop/Install Website.webloc</string>
</array>
You can include any number of files or folders in the array, and you may use ~ as a
shorthand to signify the user’s home directory. There is no need to escape spaces
that may appear in the paths of the files.
You can safely omit the Install check array from your configuration if you
desire but if you do so then your custom installer will not offer any uninstallation
functionality. If you do include the Install check array then it is compulsory
to also supply the Uninstall step dictionary, which contains the instructions for
how to perform the uninstallation. If you fail to supply the dictionary and the user
clicks the “Uninstall” button Install will log an error message to the console, and if
the user attempts to continue with the uninstall operation Install will “perform” an
uninstallation which consists of zero substeps (in other words, it will appear to the
user that the uninstallation has succeeded instantly, but Install will not have many
any changes to the target machine). Detailed information on the Uninstall step
specification appears in Section 3.7 on page 39.
21
most important component of the configuration file because it defines the steps
which will be executed in running the installer. If you fail to provide such an array
then Install will log an error message to the console and refuse to launch.
A basic skeleton for the Installation steps array is the following:
<key>Installation steps</key>
<array>
<!-- first installation step (show ReadMe) -->
<!-- second step (show License) -->
<!-- third step (check system requirements) -->
<!-- fourth step (choose target domain) -->
<!-- fifth step (copy files etc) -->
<!-- sixth step (show Finish document) -->
</array>
Steps are executed in the order in which they appear in the array. It is recommended
although it is not compulsory that you always include a WOInstallerStepReadMe
step as the first step in any installation, so that you can provide information to
the user and offer them the opportunity to uninstall as well (the “Uinstall” but-
ton will only appear in the first installation step, and only if that step is of class
WOInstallerStepReadMe).
Similarly, it is also strongly recommend that you include a WOInstallerStepFinish
step as the last installation step, so that you can present the user with notification
that the installation finished successfully and provide them with the opportunity to
launch the installed software, read the documentation, or perform some other task.
If you do not specify a WOInstallerStepFinish step then the installer will simply
exit after completing the installation, providing no notification to the user. You
may only specify one WOInstallerStepFinish step, and it must be the last item
in the array of steps.
The WOInstallerStepCopyFiles step is compulsory, and is the step which
actually does the work of installing the software. It is in theory possible to include
multiple WOInstallerStepCopyFile steps in your installation, but it is generally
much better to specify all of the needed tasks in a single WOInstallerCopyFiles
step.
The other possible steps, WOInstallerStepLicense, WOInstallerStepShell
and WOInstallerStepDomain are optional. You should include no more than one
WOInstallerStepLicense step, and no more than one WOInstallerStepDomain
step in your configuration. In the case of the WOInstallerStepShell step, it
is permitted to include multiple different steps of this class, but in general it is
advisable for reasons of clariy to incorporate all of the needed functionality in a
single step (the step can run multiple shell scripts).
In every case, a step is defined by a dictionary. The following sections describe
the formats used for creating dictionaries corresponding to each installer step class.
3.6.1 WOInstallerStepReadMe
A basic WOInstallerStepReadMe step dictionary might look like this:
22
<dict>
<key>Document</key>
<string>ReadMe</string>
<key>Show background</key>
<false/>
<key>Show scrollbar</key>
<false/>
<key>Step class</key>
<string>WOInstallerStepReadMe</string>
<key>Step name</key>
<string>Introduction</string>
</dict>
Step name The name of the step as it should appear in the steps listing on the
left-hand side of the Install main window. This key/object pair is compulsory.
If you omit it, an unattractive blank entry will appear in the listing.
3.6.2 WOInstallerStepLicense
WOInstallerStepLicense is a subclass of WOInstallerStepReadMe, which means
that it inherits the capabilities and settings of its parent class. You may use the
same key/object pairs as described in Section 3.6.1 above. A sample dictionary
might be:
23
<dict>
<key>Document</key>
<string>License</string>
<key>Step class</key>
<string>WOInstallerStepLicense</string>
<key>Step name</key>
<string>License</string>
</dict>
Note that in the example provided above, the dictionary does not specify values for
Show background and Show scrollbar, and so the default values of true and true
are used. This is usually approriate for license documents because they tend to be
too long to fit within the Install main window without scrolling.
3.6.3 WOInstallerStepShell
The WOInstallerStepShell class is a subclass of WOInstallerStepReadMe and
so inherits its capabilities and settings while adding some important additions. The
basic structure of the WOInstallerStepShell step dictionary is shown in the fol-
lowing skeleton dictionary:
<dict>
<key>Document</key>
<string>Requirements</string>
<key>Scripts</key>
<array>
<!-- an array of scripts -->
</array>
<key>Step class</key>
<string>WOInstallerStepShell</string>
<key>Step name</key>
<string>Requirements</string>
</dict>
24
Document As per WOInstallerStepReadMe.
Show background As per WOInstallerStepReadMe, but with one important dif-
ference: If this key/object pair is omitted from the configuration, then a
default value of false will be used (unlike WOInstallerStepReadMe which
uses a value of true as the default). The reason for this is that the primary
function of the WOInstallerStepShell step is to perform operations on the
machine, not to provide the user with large amounts of information, and so a
default no-background/no-scrollbar appearance is better suited.
Show scrollbar As per WOInstallerStepReadMe, but the default value is false
rather than true.
Scripts An array of scripts to run, using the order in which they appear in the array.
The script definition format is described below.
Step class A string indicating the class of the step, in this case WOInstallerStepShell.
This key/object pair is compulsory. If you omit it Install will throw a WOMalformedPlistException
and exit.
Step name As per WOInstallerStepReadMe.
Note that the Show background and Show scrollbar fields in the example above
are omitted, and so Install would automatically use the default values (false and
false).
Script definition format Each script defined in the script array is specified by a
dictionary. The dictionary should contain a key/object pair for identifying which
script to run, and optional key/object pairs specifying which shell to use, arguments
to be supplied to the script, whether root privileges are required, and how to respond
to exit codes. This is an example dictionary:
<dict>
<key>Shell</key>
<string>/usr/bin/perl</string>
<key>Script filename</key>
<string>preinstall-test.sh</string>
<key>Script arguments</key>
<array>
<string>Hello world</string>
<string>from Install</string>
</array>
<key>Run script with root privileges</key>
<true/>
<key>Error handling</key>
<array>
<!-- error handling dictionary 0 -->
<!-- error handling dictionary 1 -->
25
<!-- error handling dictionary 2 -->
</array>
</dict>
The following key/object pairs may appear in the dictionary:
Shell A string defining the shell to be used to execute the shell script. You should
take care to only define a shell which you know is available on the target
version of Mac OS X to which you are installing. For example, /bin/sh is
available on all versions (as an alias), /bin/tcsh is Apple’s default on Mac OS
X 10.2, /bin/bash is Apple’s default on Mac OS X 10.3, and /usr/bin/perl
should be available on both. This key/object pair is optional, and if not
specified Install will use a default value of /bin/sh.
Script filename A string containing the filename of the script to be executed. The
script should be stored in the Resources folder of the Install application
bundle. Install will use a language-specific variant if one is available. This
key/object pair is compulsory.
Script arguments An array of strings containing arguments to be passed to the
script. It is not necessary to escape spaces within the argument strings. There
is no arbitrary limit to the number of arguments that can be supplied. This
key/object pair is optional.
Run script with root privileges A boolean indicating whether the script should be
run with root privileges. If true, it is recommended to advise the user in that
they will be asked for a valid administrator username and password. This can
be done in the Document that corresponds to the WOInstallerStepShell
step. The Run script with root privileges key/object pair is optional,
and if omitted Install uses a default value of false.
Error handling An array of error handling dictionaries, each dictionary specifying
how should respond to a particular exit code. The format for an error handling
dictionary is discussed below. The Error handling key/object pair is itself
optional. If you omit it, Install will consider non-zero exit codes to be fatal
errors and will terminate the installation; exit codes of 0 (zero) are considered
to indicate success and the installation proceeeds.
Script error handling arrays A script error handling array comprises one or more
error handling dictionaries. A basic error handling dictionary could look like this:
<dict>
<key>Exit code</key>
<integer>1</integer>
<key>Text to display on error</key>
<string>You must shut down filesharing.</string>
<key>Error Type</key>
<string/>Non-fatal</key>
</dict>
26
The following key/object pairs may appear in the dictionary:
Exit code An integer showing the exit code to which the dictionary corresponds.
This key/object pair is compulsory. You can even define an “error handling
dictionary” even for scripts that execute successfully, that is with an exit code
of 0 (zero). In this case Install will show the custom message that you specify
using the Text to display on error key (below). Generally, however, it is
best to let Install use the default behaviour by not providing an error handler
for the exit code 0 (zero) case, in which case Install merely continues without
notifying the user. If you do not define an error handling dictionary for a
particular non-zero exit code and Install encounters that exit code, the error
is considered to be fatal and installation terminates.
Text to display on error A string specifying the text to be displayed to the user
if this error occurs. This key/object pair is optional. If you do not specify it,
Install will supply a reasonable default.
Error type A string value indicating whether the error should be considered as:
Success (installation continues; if Text to display on error is provided
then the user is shown the text and presented with a “Continue” button);
Non-fatal (noted as an error, but installation continues; once again, if Text
to display on error is provided then the user is presented with a “Con-
tinue” button); Can retry (the user can choose to either retry or quit); and
Fatal (installation halts). In the case of the Can retry error type, if the
user does elect to retry after a script produces an error code, only the failed
script is retried, not any other scripts that have been previously executed with
success. This key/object pair is optional. If it is omitted then Install will
assume that an exit code of zero implies Success and a non-zero exit code
implies a Fatal error. Note that in all cases where the exit code is non-zero,
a message will be displayed to the user and the user will be required to click
a button (“Continue”, “Retry” or “Quit” depending on the context). Where
the exit code is zero, a message will only be displayed if you explicitly provide
one, or mark the exit code as Fatal or Can Retry (although doing so is not
recommended because in UNIX operating systems the exit code of zero is
traditionally considered to signify success).
3.6.4 WOInstallerStepDomain
The WOInstallerStepDomain subclass should look like the following example:
<dict>
<key>Step class</key>
<string>WOInstallerStepDomain</string>
<key>Step name</key>
<string>Choose location</string>
</dict>
27
Alternatively, if you wish to override the default text displayed in the top third of
the Install main window you can specify an RTF or RTFD document as illustrated:
<dict>
<key>Document</key>
<string>ChooseLocation</string>
<key>Step class</key>
<string>WOInstallerStepDomain</string>
<key>Step name</key>
<string>Choose location</string>
</dict>
3.6.5 WOInstallerStepCopyFiles
The WOInstallerStepCopyFiles step class is the most sophisticated of the In-
stall classes. It comprises a number of substeps that are executed in this or-
der, if present: Preinstall kill processes, Preinstall trash files and
folders, Remove login items, Run preflight scripts, Install files and
folders, Run postflight scripts and Add login items.
None of the substeps are compulsory, although clearly the Install files and
folders substep is generally an essential requirement to produce and installer
that does any useful work. Each of the substeps is identified by a key inside the
WOInstallerStepCopyFiles dictionary. A sample skeleton dictionary which uses
all of the substeps is:
<dict>
<key>Document</key>
<string>ReadMe</string>
<key>Preinstall kill processes</key>
28
<array>
<!-- processes to quit before proceeding -->
</array>
<key>Preinstall trash files and folders</key>
<dict>
<!-- items to remove -->
</dict>
<key>Remove login items</key>
<array>
<!-- login items to remove -->
</array>
<key>Run preflight scripts</key>
<array>
<!-- scripts to run before installing -->
</array>
<key>Install files and folders</key>
<array>
<!-- files and folder to be installed -->
</array>
<key>Run postflight scripts</key>
<array>
<!-- scripts to run after installing -->
</array>
<key>Add login items</key>
<array>
<!-- login items to add -->
</array>
<key>Step class</key>
<string>WOInstallerStepCopyFiles</string>
<key>Step name</key>
<string>Introduction</string>
</dict>
29
Remove login items An array of login items to remove, as defined on page 32.
Run preflight scripts An array of preflight scripts to run before installing files and
folders onto the target machine, as defined on page 33.
Install files and folders An array of files and folders to install, as defined on
page 34.
Run postflight scripts An array of postflight scripts to run after installing files and
folders onto the target machine, as defined on page 35.
Add login items An array of login items to add, as defined on page 35.
Step class A string indicating the class of the step, in this case WOInstallerStepCopyFiles.
This key/object pair is compulsory. If you omit it Install will throw a WOMalformedPlistException
and exit.
Step name As per WOInstallerStepReadMe.
The following paragraphs document the formats used to define the various possi-
ble substeps within a WOInstallerStepCopyFiles step. Note that each substep
is defined as an array, with the exception of the Preinstall trash files and
folders step which is defined as a dictionary.
Preinstall kill processes The following sample shows how to define a Preinstall
kill processes array:
<array>
<dict>
<key>Identifier</key>
<string>com.apple.systempreferences</string>
<key>Method</key>
<string>Apple Event</string>
</dict>
<dict>
<!-- a second process to kill -->
</dict>
<dict>
<!-- a third process to kill -->
</dict>
</array>
Within the array, each process to be terminated is defined by a dictionary that may
contain the following key/object pairs:
Identifier A string specifying the process to be quit in terms of its bundle identifier.
This key/object pair is compulsory. If you omit it Install will not even attempt
to terminate the target process.
30
Method A string specifying the method by which the target process shall be ter-
minated. This key/object pair is compulsory. If you omit it Install will not
be able to terminate the target process and will proceed with the installation
anyway, which will probably not produce the intended results. The allowed
values are:
Apple Event This method sends a “quit” Apple Event to the target process,
thus providing the user with the opportunity to save or apply any unsaved
changes prior to the process terminating. You should only specify this
method for target processes which know how to handle the “quit” Apple
Event (this is true of most foreground applications; it may not be true
of faceless background processes or UNIX-style daemon processes).
SIGHUP This method sends the SIGHUP signal to the target process.
SIGTERM This method sends the SIGTERM signal to the target process.
Note that you can specify any number of processes to terminate by adding a dic-
tionary for each process to the Preinstall kill processes array. The order
in which processes will be terminated is not defined, because Install issues all of
the termination commands at once and then waits to receive notification from the
operating system that the processes in question have terminated.
The design is such that even if Install must wait for an extended interval (for
example, while a user makes some final changes and then saves their work in
an application targetted for termiantion) all of the other processes defined in the
Preinstall kill processes array will effectively be terminated as soon as pos-
sible, without any bottlenecks caused by the need to wait for user intervention.
Preinstall trash files and folders Here is a sample Preinstall trash files
and folders dictionary:
<dict>
<key>User domain files</key>
<array>
<string>~/Library/Finalize</string>
<string>~/Library/Caches/Finalize</string>
<!-- additional items to remove -->
</array>
<key>Global domain files</key>
<array>
<string>/Library/Finalize</string>
<string>/Library/Caches/Finalize</string>
<!-- additional items to remove -->
</array>
</dict>
The dictionary contains only two keys, User domain files and Global domain
files, each defining a corresponding array of strings listing the files and folders
which should be removed.
31
User domain files An array of strings identifying files that should be removed prior
to installing in the User domain. This key/object pair is optional. If you omit
it, Install will not remove any files prior to installing in the User domain.
Global domain files An array of strings identifying files that should be removed
prior to installing in the Global domain. This key/object pair is optional. If
you omit it, Install will not remove any files prior to installing in the Global
domain (although it may remove files in the User domain if you listed any in
the User domain files array; see below for more information).
Remove login items The following sample shows how to define a Remove login
items array:
<array>
<dict>
<key>Absolute path</key>
<string>/Applications/Example.app</string>
</dict>
<dict>
<key>Item name</key>
<string>Example.app</string>
<key>User domain only</key>
<true/>
</dict>
<dict>
<!-- third login item to remove -->
</dict>
</array>
The Remove login items array may contain any number of dictionaries, each
defining one login item that should be removed. The only key/object pair in each
dictionary is the following:
32
Absolute path A string containing the absolute path to the login item to be re-
moved. Tilde expansion is not performed. Either this key/object pair or the
alternative Item name pair is compulsory. If you omit both then Install will
throw a WOMalformedPlistException. Absolute paths are recommended
instead of mere item names (without paths) because there is less scope for
accidental removal of a similarly named item. For example, if you wish to
install a faceless background application called Helper.app which should
launch at login, it is best to specify the path in absolute terms so that your
choice of name will not clash with the that of an application made by another
developer who had the same idea of using something called Helper.app. In
keeping, when you add login items you should also always use absolute paths.
Item name A string containing the name of the item to be removed with no path
information. You must specify either this key/object pair or the Absolute
path pair discussed above. You should use this alternative with caution so as
to avoid the unintended removal of items which may share the name as your lo-
gin item. It is possible to specify both an Item name and an Absolute path
but in general it is only necessary to specify one (for example, it would be
redundant to specify /Applications/Example.app as an Absolute path
if you also specified Example.app as an Item name).
User domain only An optional boolean value that you may specify to ensure that
a given item is removed only in User domain installations. If you do not
specify this key/object pair then Install uses a default value of False.
Global domain only An optional boolean value that you may specify to ensure
that a given item is removed only in Global domain installations. If you do
not specify this key/object pair then Install uses a default value of False. You
may not specify both the User domain only and the Global domain only
values as True.
You may wonder why the items to be added are defined as dictionaries and not
as simple strings. The answer lies in the fact that defining things in this way, the
dicitionaries used in setting up the Remove login items substep can be regarded
as subsets of the dictionaries used later on in the Add login items substep. The
former only ever contain one key/object pair, but the latter can make use of an
additional key/object pair. See the description of Add login items on page 35 for
more information.
Run preflight scripts The following sample shows how to define a Run preflight
scripts array:
<array>
<dict>
<key>Script filename</key>
<string>preflight.sh</string>
</dict>
33
<dict>
<!-- second preflight script to run -->
</dict>
<dict>
<!-- third preflight script to run -->
</dict>
</array>
The Run preflight scripts array is simply an array of script definition dictio-
naries, as already described in Script definition format on page 25.
The example above shows the simplest script definition possible, because it only
contains one key; the Script filename key. In this case Install would use the
default values for Shell (/bin/sh/), and Run script with root privileges
(false), and would execute the script without passing any arguments.
Install files and folders The following sample shows how to define a Install
files and folders array:
<array>
<dict>
<key>Name</key>
<string>Read Me 2004-01-01.pdf</string>
<key>User domain location</key>
<string>~/Desktop</string>
<key>Global domain location</key>
<string>/Users/Shared</string>
</dict>
<dict>
<!-- second item to install -->
</dict>
</array>
The Install files and folders array contains one or more dictionaries, each
dictionary defining which file should be installed and where it should be placed
depending on whether the install is to be in the Global domain or in the User domain.
As already stated, the actual order in which files are copied is undefined, but the
ordering of dictionaries within the configuration plist must correspond to the folder
numbering used inside the Resources/Files.localized/ folder inside the Install
application bundle. In the example above, the first file (Read Me 2004-01-01.
pdf) would be stored inside folder 0 (zero) and the second item would be stored in
folder 1. See Section 2.2 on page 14 for more information.
The dictionaries contained in the Install files and folders array may con-
tain the following key/object pairs:
Name A string containing the exact name of the file or folder to be installed. This
key/object pair is compulsory.
34
User domain location A string defining the folder into which the item should be
installed when installing into the User domain. If the folder does not already
exist Install will create it and any other intermediary folders as necessary. This
key/object pair is compulsory.
Global domain location A string defining the folder into which the item should be
installed when isntalling into the Global domain. Once again, if the folder does
not already exist Install will create it. When installing into the Global domain
items are copied using root privileges and so it becomes possible (and it is of
course necessary) to write into shared locations such as /Library or elsewhere
outside of the user’s home folder. This key/object pair is only optional if
your installer configuration does not contain a WOInstallerStepDomain step
(because in this case Install defaults to installing in the User domain).
Run postflight scripts Postflight scripts are defined in exactly the same manner
as preflight scripts (see Run preflight scripts above for more information). This
is a sample of a Run postflight scripts array which contains two basic script
definitions:
<array>
<dict>
<key>Script filename</key>
<string>postflight-1.sh</string>
</dict>
<dict>
<key>Script filename</key>
<string>postflight-2.sh</string>
</dict>
</array>
Add login items The following sample shows how to define a Add login items
array:
<array>
<dict>
<key>Absolute path</key>
<string>/Applications/Example.app</string>
<key>Hide on launch</key>
<true/>
</dict>
<dict>
<!-- second login item to add -->
</dict>
<dict>
<!-- third login item to add -->
</dict>
</array>
35
The Add login items array may contain any number of dictionaries, each defining
one login item that should be added. The dictionary is a superset of the dictio-
nary used in the Remove login items substep. The dictionary may contain the
following key/object pairs:
Note that unlike the Remove login items substep, the is no Item name key used
in the Add login items substep.
3.6.6 WOInstallerStepFinish
The WOInstallerStepFinish class is a subclass of WOInstallerStepReadMe and
so inherits its capabilities and settings while adding some important additions. The
basic structure of the WOInstallerStepFinish step dictionary is shown in the
following skeleton dictionary:
<dict>
<key>Document</key>
<string>Finish</string>
<key>Show background</key>
<false/>
<key>Show scrollbar</key>
<false/>
<key>Step class</key>
<string>WOInstallerStepFinish</string>
<key>Step name</key>
<string>Finish</string>
<key>Primary button action</key>
<dict>
<!-- the primary button action -->
</dict>
<dict>
<!-- the secondary button action -->
</dict>
</dict>
36
Document As per WOInstallerStepReadMe.
Show background As per WOInstallerStepReadMe.
Show scrollbar As per WOInstallerStepReadMe.
Step class A string indicating the class of the step, in this case WOInstallerStepFinish.
This key/object pair is compulsory. If you omit it Install will throw a WOMalformedPlistException
and exit.
Step name As per WOInstallerStepReadMe.
Primary button action An optional dictionary that defines an action to be per-
formed when the user clicks the right-most button (usually labelled “Con-
tinue”) in the Install main window.
Secondary button action An optional dictionary that defines an action to be per-
formed when the user clicks the left-most button (the “Uninstall” button) in
the Install main window.
You may specify a custom Primary button action, a custom Secondary button
action, or both. Where you do not specify an custom action the button in question
will remain inactive and have no effect. In all cases there is a “Quit” button in the
Install main window that the user can use upon finishing the installation. The follow
section describes how to define custom button actions in the configuration plist.
Assigning a primary and secondary button action The custom button action
format is identical for both the Primary button action and Secondary button
action keys. In each action you may specify either a single shell script to run (not
an array of scripts), or an item (or items) on the filesystem to open (optionally
specifying an application with wich to perform the open operation). You may not
specify both a shell script and a Launch directive within the same button action
definition.
<dict>
<key>Button text</key>
<string>Launch</string>
<key>Launch</key>
<array>
<dict>
<key>Open</key>
<string>Manual.pdf</string>
<key>Global domain location</key>
<string>/Users/Shared</string>
<key>User domain location</key>
37
<string>~/Desktop</string>
<key>With</key>
<string>/Applications/Preview.app</string>
</dict>
</array>
</dict>
The Launch-based custom button action dictionary must contain the following
key/object pairs:
Button text A string specifying the text to appear inside the button. This key/object
pair is compulsory. If you do not define it, Install will hide or otherwise disable
the button.
Launch An array of dictionaries, each dictionary defining an item that is to be
launched. The first three key/object pairs to be used in each dictionary match
those used in the Install files and folders substep of the WOInstallerStepCopyFiles
step. These keys are Name, Global domain location and User domain
location. The Name specifies the name of the item to be opened. Global
domain location specifies the folder in which the item resides (if installed
into the Global domain) and the User domain location specifies the folder
in which the item resides if installed into the User domain. A fourth, optional,
key is the With key, which is used to specify an application with which to
open the file. If you omit the With key then Install will open the file as if you
had double-clicked it in the Finder.
38
3.7 The Uninstall step
The WOInstallerStepUninstall step is an independent step which never appears
within a normal sequence of WOInstallerStep steps, but is triggered when the
following conditions are true:
• The Uninstall step dictionary is present and correctly specified in the con-
figuration plist file.
• The Install check dictionary is also present and correctly specified in the
configuration plist file, so that Install knows how to determine whether a
pre-existing installation already exists on the target machine.
• The first step in the configuration file is of class WOInstallerStepReadMe
(the “Uninstall” button will only be shown if this is true).
• Files or folders which indicate the existence of a pre-existing installation are
found on the target machine at run time.
<dict>
<key>Uninstall kill processes</key>
<array>
<!-- processes to be terminated -->
</array>
<key>Run preflight scripts</key>
<array>
<!-- scripts to be executed -->
</array>
<key>Uninstall trash files and folders</key>
<array>
<!-- items to delete/move to the Trash -->
</array>
<key>Remove login items</key>
<array>
<!-- login items to be removed -->
39
</array>
<key>Run postflight scripts</key>
<array>
<!-- scripts to be executed -->
</array>
</dict>
40
this Uninstall trash files and folders substep array has a unique format,
as illustrated in the following example:
<array>
<dict>
<key>Item</key>
<string>/Users/Shared/ABCD Manual.pdf</string>
<key>Remove by default</key>
<true/>
<key>Administrator privileges required</key>
<true/>
</dict>
<dict>
<!-- second item to remove -->
</dict>
</array>
As shown above, the Uninstall trash files and folders array should contain
one or more dictionaries, each dictionary defining the item that should be removed.
Each dictionary may contain the following key/object pairs:
Item A string containing the full path of the object to be removed. This key/object
pair is compulsory.
Remove by default A boolean indicating whether or not the item should be re-
moved in a default uninstallation procedure. If true, the checkbox next to the
item in the listing of items to be removed will be pre-selected. If false, the
checkbox will not be pre-selected. This key/object pair is optional and if you
elect not to supply it then Install will assume a default value of false.
Administrator privileges required A boolean indicating whether an item will re-
quire a valid administrator user name and password to remove. Generally such
items will be those that you have previously installed into the Global domain
using root privileges. When the boolean is true, the item will be displayed with
a small padlock icon in the listing of items to be removed. This key/object
pair is optional and in its absence Install assumes a default value of false.
41
3.7.5 Run postflight scripts
The following is a sample showing how to define a Run postflight scripts array. Once
again, the format exactly matchs that of the Run postflight scripts substep of the
WOInstallerStepCopyFiles class (fully documented on page 35).
<array>
<dict>
<key>Script filename</key>
<string>postflight.sh</string>
</dict>
</array>
• “Step name” strings, which appear in the Install user interface in the list view
on the left hand side of the main window;
• “Text to display on error” strings, which you may (optionally) supply
if your installer runs any shell scripts;
• Custom “Button text” strings, which you can specify in your WOInstallerStepFinish
step.
There are two possible approaches to the localization of these strings; either you
can localize the InstallConfig.plist file itself, providing a different file for each
language variant, or you can provide a separate, InstallConfig.strings file,
which contains only the user-visible strings from the configuration file.
The advantage of using the latter method is that it simplifies the task of localiza-
tion for translators. They no longer have to deal with a complicated configuration
file which may be difficult for them to understand; and there is little or no risk
of them editing a part of the file which they should not edit, nor of overlooking
something which they should.
The binary distribution of Install itself shows how to employ this later method.
If you look inside the Install application bundle itself, or if you examine the sample
files included with the distribution, you will see that the following points apply and
the result is a Spanish localization of the user-visible strings in the configuration
plist file:
42
• Each user-visible string in the configuration file (whether it be a “Step name”,
“Text to display on error” or “Button text” string) has been identi-
fied and is used as a key in a language-specific InstallConfig.strings file
stored in the Spanish.lproj subdirectory of the Resources folder.
• For each key in the InstallConfig.strings file (on the left hand side of
the equals sign), a Spanish equivalent is provided (on the right hand side); the
formatting of this file is identical to that of a standard Localizable.strings
file.
• Like all strings files, the InstallConfig.strings file is saved using UTF-
16 encoding.
5 Advanced configuration
This section of the manual provides some additional information that may be of
use to developers wishing to embed shell scripts within their custom versions of
the Install application and run those scripts from within WOInstallerStepShell,
WOInstallerStepCopyFiles or WOInstallerStepUninstall steps. It also dis-
cusses the use of the plutil command line tool to verify plist integrity.
43
Table 1: Typical environment variables passed to shell scripts
Variable Example value
BASH /bin/sh
EUID 501
HOME /Users/wincent
HOSTNAME sol.local
HOSTTYPE powerpc
MACHTYPE powerpc-apple-darwin7.0
PPID 8498
PWD /Install.app/Contents/Resources
SHELL /bin/bash
SHLVL 1
TERM dumb
UID 501
USER wincent
has those privileges; Install itself continues to run with its previous level of unelevated
privileges.
Table 1 shows a subset of some of the typical environment variables that you
could expect to have set in the environment of your shell script, along with some
sample values for those variables. These particular values were taken from my
production machine, running Mac OS X 10.3.2. It is reasonable to expect that you
might obtain other variables and other variables under different systems, so you
should test to be sure that you have access to the environment variables you require
on the target system onto which you plan to deploy your software.
44
begin your scripts with a command such as cd to change directory to the
SCRIPTDIRECTORY if you want to make use of relative paths inside the script.
INSTALLATIONDOMAIN Install sets this variable to indicate whether the instal-
lation is to take place (or has taken place) in the Global domain or the User
domain. The possible values of the variable are “Global” and “User”. Note
that if you do not provide a WOInstallerStepDomain step, or if you run a
script prior to that step, then the value of the INSTALLATIONDOMAIN envi-
ronment variable will be the default value (“User”). Also note that this value
has no meaning for the WOInstallerStepUninstall step because users do
not elect an uninstallation domain; rather they choose which files shall be
removed using checkboxes for items in the list.
#!/bin/bash
exit 0
This example shows one way of directing output through STDERR when using Perl:
#!/usr/bin/perl
exit 0;
/usr/bin/plutil InstallConfig.plist
launched by typing a command in the Terminal such as Install.app/Contents/MacOS/Install
then the PWD will match the setting of the parent shell in which the command was typed).
45
In response, plutil scans the file and parses it to see if it is a valid plist. It
can provide helpful diagnostic information that can quickly point out what specific
problems might exist in your configuration file. This is an example of the information
provided by the tool:
InstallConfig.plist:
XML parser error:
Encountered unknown tag ditc on line 5
Old-style plist parser error:
Expected terminating ’>’ for data at line 1
Note that the plutil utility only checks to see if your plist is a validly formatted
XML plist document. The utility has no knowledge of Install’s application-specific
requirements (such as which keys are compulsory and which keys are optional) and
so cannot help you to troubleshoot configuration files which are valid XML plists
but which nevertheless deviate from the requirements prescribed in this manual. For
more information about the capabilities of plutil, consult the plutil man page.
You may also elect to install for the current user only, in which case the items will
be placed in the ~/Developer/ folder rooted in your home directory.
46
6.1 Creating a copy of the Install application bundle
When preparing an installer it is recommended that you work within a temporary
working area on your disk. For the purposes of illustration, the examples used in
this section through to Section 6.9 will assume that the working area is a folder
inside your home directory at ~/work/, and that you have installed the Developers
Kit in /Developer/.
Your first step should be to make a clean copy of the Install application bundle
on which to work, by making a copy of the master version of Install.app stored
in /Developer/Applications/Install/ and placing it inside your work area.
This could be done by using “drag-and-drop” in the Finder, or by using the CpMac
command line tool as follows:
/Developer/Tools/CpMac -r \
/Developer/Applications/Install/Install.app \
~/work/
This command is broken up across three lines for readability. Note that CpMac
is used instead of the conventional UNIX cp command, because the former can
preserve resource forks and other Macintosh-specific information (see the CpMac
man page for more information). Although Install itself does not by default include
any files with resource forks, it is a good to establish a habit of using CpMac for
copying installers, because you may later add files inside the installer bundle which
do contain resource forks (custom folder icons are a common example of files that
need resource forks on Mac OS X).
/usr/bin/open ~/work/Install.app/Contents/Resources
• Install.app/Contents/Resources/Files.localized/0/File 1
• Install.app/Contents/Resources/Files.localized/1/File 2
• Install.app/Contents/Resources/Files.localized/2/File 3
• Install.app/Contents/Resources/Files.localized/3/Folder 1
• Install.app/Contents/Resources/Files.localized/4/Folder 2
47
You can only place a single item inside each numbered subfolder, but it can be a file
or a folder containing other times. Sometimes you will wish to group items together
into a folder if they are going to eventually reside together as a group inside that
folder on the target marchine. At other times you might wish to split these files up
so that they can be installed or removed separately, even if their ultimate destination
will be inside the same folder on the target machine.
48
6.5 Preparing shell scripts
If you are sufficiently familiar with shell scripting you may decide to prepare some
scripts for execution during the installation. It is beyond the scope of this document
to teach how to write shell scripts, but for users already familiar with scripting
Section 5 does offer some information about environment variables passed to scripts
and redirecting output to the console.
The completed scripts do not need to have their execute permissions set, because
Install will run them by invoking a shell and passing the script path as an argument
to the shell.
You should place the completed scripts inside the application bundle at Install.
app/Contents/Resources/, or if you have prepared localized variations, in the
corresponding lproj folders.
49
• Likewise, ensure that every item defined in Installation steps has the
correct Step class defined.
• If you include an Uninstall step, remember that you must also include an
Install check array.
6.8 Testing
The next and final phase is to test that your customized Install application works
as you expect. Run your installer from the command line as follows:
cd ~/work
Install.app/Contents/MacOS/Install
By invoking the application from the command line you will be able to readily see
any messages that Install may output to the console. This may be helpful if you
need to diagnose problems. You can also easily find out the exit status once Install
finishes running by immediately typing:
echo $?
If Install returns a non-zero exit code then this indicates an abnormal exit. If
Install does not even launch then you may have provided an invalid plist file. See
Section 5.3 for advice on using Apple’s plutil utility to check plist validity.
In addition to watching the console output, you can also run Install and select
“Show log” from the Install “File” menu to see how Install reports its own activity.
As with any software, you should rigorously test your Install application before
deploying it. The following are common-sense some suggestions for testing:
50
• If you define an Install check array, test that the “Uninstall” button ap-
pears whenever you first launch the installer on a system with a pre-existing
installation. Conversely, the button should not appear if there is no pre-
existing installation.
• If you allow the user to install the Global domain or the User domain, test
installing to both domains.
• If you define an Uninstall step, test that it works as expected. This means
that you should test to see if you can uninstall software previously installed
to the Global domain, as well as testing to see if you can uninstall software
previously installed to the User domain (if you allow the user to choose do-
mains).
• Test installing onto a “clean” system (without a pre-existing install), and test
installing onto a “non-clean” system (overwriting a previous install).
• If you define a WOInstallerStepFinish step with custom button actions,
test that the button actions work as expected. Test after installing to the
Global domain, and also after installing to the User domain (if you allow the
user to choose domains).
• If you provide localized variations of any files, perform the tests while running
the installer under each different language that you support.
The above is not an exhaustive list, but it gives some indication of the key permu-
tations that should be covered in a minimal testing run. Remember that because
Install is a software deployment tool specifically designed to perform operations such
as copying and deleting files, which are often irreversible operations, extreme care
should be taken to ensure that your configuration performs exactly as you intend.
6.9 Packaging
Once you have completed your testing you need only package your installer for
distribution. Common packaging methods include Disk Images and Zip archives. It
is recommended that you only use the later format if your software is destined for
users of Mac OS X 10.3 or above, because previous versions of the OS do not offer
an in-built means for decompressing those archives.
Although the phases described in this section are all that is required to produce
a working installer, you may also wish to see Section 7 below, which covers some
additional, optional customizations you may wish to make to your installer before
packaging it for final distribution. This customizations include providing a custom
icon file, renaming the application bundle, or adding your own copyright notices.
51
are entirely optional and are not required to produce a functioning installer. For
information on the kind of configuration essential to produce a working installer,
consult Section 6.
Under the Install Binary-only license agreement you are granted the right to
modify the Install application bundle within certain limits. The main limitation
is that you are not permitted to strip any copyright notices from Install. Install
itself, both in binary and source code form, is copyright (c) 2003-2004 by Wincent
Colaiuta, all rights reserved. You retain authorship of and copyright to any permitted
modications that you make to Install. What this means in practical terms is that.
• You may rename the Install application bundle itself. For example, you may
wish to rename it from Install.app to Install Our Product.app.
• If you choose to rename the bundle you are not obliged to maintain the word
“Install” in the title.
• You may add your own copyright atttribution to the CFBundleGetInfoString
and NSHumanReadableCopyright fields in the Install InfoPlist.strings
file (or files, depending on whether localized variants exist), but you may not
remove or edit the existing copyright attributions to Wincent Colaiuta in those
fields. For example, you may wish to add you own copyright to the original
string (“Install version 1.1, Copyright 2003-2004 Wincent Colaiuta.”) so that
it reads, “Install version 1.1, Copyright 2003-2004 Wincent Colaiuta. Product
Name version 2.0, Copyright 2004 Our Company.” Any such change will be
reflected in the version and copyright information shown about the installer
in the Finder and/or in the “About Install” window.
• You may not change the CFBundleName or the CFBundleShortVersionString
fields in the InfoPlist.strings file, nor may you alter or remove the
CFBundleSignature field in the Info.plist file.
• You may replace the Install icon file with a custom icon of your own.
• You may not edit the Install MainMenu.nib file or otherwise make alterations
which have the effect of disabling, removing or altering the “Install website. . . ”
Menu Item in the Install Menu.
• You may edit, and optionally convert to RTFD format, the Credits.rtf file
that is used to construct the “About Install” window when the corresponding
Menu Item is selected; but you must preserve the text in the file which at-
tributes “Installer engineering and design” to “Wincent Colaiuta”. You may
not remove the file unless you replace it with an equivalent RTFD file con-
taining the same attribution. You may add additional lines to the file which
attribute authorship for your own products to the corresponding authors, and
if you have made modifications to Install as permitted under the license (in the
case of the Binary-only license permitted modifications are generally limited to
configuration and the provision of resources such as documents, shell scripts
52
and other materials) then you may add a line such as “Installer modifica-
tions” or “Installer customization” attributing authorship of the modifications
or customizaton to, for example, “Our Company”.
• You are not required to provide an attribution to Wincent in your product
documentation, in-program text, supporting materials or website, although
any such reference you might make to Wincent and to the Install website
(install.wincent.com) would be appreciated.
• You may not modify nor reverse engineer the binary data of the Install exe-
cutable itself (stored inside the bundle as Install.app/Contents/MacOS/
Install),
For further information about your rights and obligations under the license, please
consult the license.
53
Index
Absolute path, 33, 36 Method, 31
Add login items, 10, 30, 35
Administrator privileges required, 41 Name, 34
Apple Event, 31 NSHumanReadableCopyright, 52
Apple Events, 12
Objective-C, 3
bundles, 3
button actions plist files, 3
primary, 14 plutil, 45
secondary, 14 Preinstall kill processes, 8, 29, 30
Button text, 38 Preinstall trash files and folders, 9, 29,
31
CFBundleGetInfoString, 52 present working directory, 44
CFBundleName, 52 Primary button action, 14, 37
CFBundleShortVersionString, 52 PWD, 44
CFBundleSignature, 52
Cocoa, 3 Remove by default, 41
copyright, 52 Remove login items, 9, 13, 30, 32
CpMac, 47 resource forks, 47
Run postflight scripts, 10, 13, 30, 35, 42
Default installation domain, 18, 20 Run preflight scripts, 9, 12, 30, 33, 40
Document, 23–25, 28, 29, 37 Run script, 38
Run script with root privileges, 26
environment variables, 43
Error handling, 26 Script arguments, 26
Error type, 27 Script filename, 26
Exit code, 27 SCRIPTDIRECTORY, 44
Scripts, 25
Global domain files, 32 definition format, 25
Global domain location, 35 Secondary button action, 14, 37
Global domain only, 33, 36 Shell, 26
Shell scripts
Hide on launch, 36 error handling arrays, 26
Show background, 23–25, 37
Identifier, 30 Show scrollbar, 23–25, 37
Install check, 18, 21 SIGHUP, 12, 31
Install files and folders, 9, 30, 34 SIGTERM, 12, 31
Installation steps, 18, 21 standard error, 45
INSTALLATIONDOMAIN, 45 STDERR, 45
Item, 41 Step class, 23–25, 28, 30, 37
Item name, 33 Step name, 23–25, 28, 30, 37
support files, 13
Launch, 38
localization, 14 Target OS version, 18
54
Text to display on error, 27
WOInstallerStepCopyFiles, 8, 28
WOInstallerStepDomain, 7, 27
WOInstallerStepFinish, 11, 36
WOInstallerStepLicense, 4, 23
WOInstallerStepReadMe, 4, 22
WOInstallerStepShell, 5, 24
WOInstallerStepUninstall, 12, 39
XML, 3
55