Saturday 7 July 2012

Scripting in Installer Packages


In my previous post, I discussed about creating packages to deploy your application bundles. However, installation of some applications is more complex and requires many actions other than copying the payload. For example, you want to check if a particular application is already installed on the system before installing your application.  For all these tasks, you can use the preinstall, postinstall and Distribution scripts which are included in the package and run by the installer during the installation. After the Installer application finishes checking installation requirements, it performs an install through distinct operations, known as install operations. You can define all but one of these operations, which copy payloads to their installation destinations. You should not use install operations to fix install problems, such as incorrect ownership and access permissions. You should use install operations only when other managed-install features, such as installation requirements, are not adequate for the chore you need to perform as part of installing a package.
Install operations allow you to configure the destination environment before the payload is copied to the file system and to perform additional processing afterward. Install operation executables must be named according to the install operation you want to define. The files can be binary files or text files containing shell scripts. All install operations are optional.

You can use following arguments and environment variables which are available to install operation executables.
  • $1: Full path to the installation package the Installer application is processing. For example: /Volumes/Users/Vikrams/Desktop/TestPkg.pkg
  • $2: Full path to the installation destination. For example: /Applications
  • $3: Installation volume (or mount point) to receive the payload. For example: /Volumes/Tools
  • $4: The root directory for the system: /
  • $SCRIPT_NAME: Filename of the operation executable. For example: preflight
  • $PACKAGE_PATH: Full path to the installation package. Same as $1.
  • $INSTALLER_TEMP: Scratch directory used by Installer to place its temporary work files. Install operations may use this area for their temporary work, too, but must not overwrite any Installer files. The Installer application erases this directory at the end of the install. For example: /private/tmp/.vikrams.pkg.234.install

     Your script must return 0 on success and any other number to denote failure. The name of the scripts must be “preinstall” and “postinstall”. You can see some sample scripts below-
--------------------------------------------------------------
#!/bin/sh
#This is a sample preinstall or postinstall script.
#Your logic goes here.
if [ your_logic_returns_false ]
then
     exit -1
fi
exit 0
--------------------------------------------------------------

Lines starting with # are comments. First line #!/bin/sh is called “Shebang” and denotes that it is a shell script. Any return value other than 0 denotes failure. If you return anything other than 0, your installation will stop with a failure message.


Scripting Quickies 

Let’s discuss about some common and some complex scenarios where a lot of people can get stuck:

  • I have some resources which need to be accessible from the preinstall and postinstall scripts.
    •  In older style packages (bundles), since the path inside the package was accessible, we kept the resources in the resources directory and had access to them using PACKAGE_PATH/Contents/Resources/ path. In case of flat packages, the installer extracts the scripts directory to some temporary directory while running. So, we can keep any resource with the scripts while packaging and when the installer is run, these resources will be present in the same directory from where the scripts are run. In this way, we can access any resource from preinstall and postinstall scripts.
  • How can I perform installation requirements check?
    • Bundle packages supported installation check using InstallationCheck script. However, flat packages no longer support InstallationCheck script. In flat packages, this installation check phase has moved to the Distribution file. You can write Javascript functions and assign them to be called during installation-check phase. Your distribution file should contain<installation-check script=”your_function()” /> and if your function returns false, the installation will not proceed.
  • Can I perform installation requirements check for component packages?
    • No, you must use a Distribution package if you intend to perform InstallationCheck or VolumeCheck.



Apart from preinstall and postinstall scripts, a lot of functionality goes in the Distribution script. I will cover all the aspects of a typical Distribution file in the next post.