Question

Q: How can I create an update installer?

Can I make an installer to update my application?

Response

Support for upgrade installations is a frequently requested feature. There are basically two parts to an upgrade:

  • a) Common to all installations: Activities such as copying files, upgrading Add/Remove programs settings or upgrading the uninstaller. InstallBuilder provides support for most of this automatically.
  • b) Unique to each installation: Activities such as backing up an existing database, populating it with new data, etc.

When most installers refer to upgrade functionality, they refer to a), when in reality the most critical part for a successful upgrade tends to be b), which cannot be easily automated.


Contents

* What differentiates upgrade installers from normal installers?
* Setting the installer to upgrade installation mode
* Can I install only a subset of the files in the upgrade (only those that have changed)?
* I am trying to create a "smart" installer which includes upgrade functionality. How can I prevent the installation of files related to upgrade installations when performing a normal installation?
* Using built-in functionality to check for newer versions of the product on startup
* How to detect the previous installation directory


What differentiates upgrade installers from normal installers?

Upgrade installers do not create a new uninstaller. Instead, the new installed files will be appended to the existing uninstaller, and persistent variables and parameters from the upgrade installer will be as well registered in the exiting uninstaller.

Additionally, on Windows an upgrade installer will not create a new entry on the ARP (Add/Remove Programs) Menu. Instead, it will update the "version" field for the existing entry of the application. Also, it will not create a new entry into the Start Menu.


Setting the installer to upgrade installation mode

It is currently possible to create an upgrade installer by setting the <installationType> project property to "upgrade" as follows:


<project>
  ...
  <installationType>upgrade</installationType>
  ...
</project>

Another approach is to switch the installer to upgrade mode at run time, using a <setInstallerVariable> action to set the "installationType" installer variable to "upgrade". This approach allows you to create a "smart" installer which starts in normal installation mode and is capable of switching to upgrade mode under certain conditions, such as detecting an existing installation.


The following example detects an existing installation by checking the existence of the ${installdir} directory: for this purpose we use the <fileTest> rule.


 <project>
 ...
   <preInstallationActionList>
      <!-- detect existing installation, then switch to upgrade mode and display a note. -->
      <actionGroup>
         <actionList>
            <showInfo>
               <text>An existing installation has been detected in ${installdir}.</text>
            </showInfo>
            <setInstallerVariable name="allowComponentSelection" value="0" />
            <setInstallerVariable name="installationType" value="upgrade" />
            ...
            <!-- it also is possible to enable/disable components here:
                 <componentSelection select="customcomponentname"/>
                 <componentSelection deselect="customcomponentname"/>
                 or to perform additional actions related to the upgrade installer -->
            ...
         </actionList>
         <!-- We assume an existing installation if ${installdir} directory exists -->
         <ruleList>
            <fileTest condition="exists" path="${installdir}" />
         </ruleList>
      </actionGroup>
      ...
   </preInstallationActionList>
   ...
</project>

Other approaches can be used to detect an existing installation, such as reading a Windows registry key with <registryGetKey> or checking if the value of a system environment variable (${env(PATH)}, for instance) contains a particular value: this can be done using the <compareText> rule.


Can I install only a subset of the files in the upgrade (only those that have changed)?

By default an upgrade installer (as well as a regular installer) will overwrite existing files on disk. You can customize this global behavior by using the project property 'overwritePolicy', which can take the following values:

- 'always' : an existing file on disk will always be overwritten.

- 'never' : an exiting file on disk will never be overwritten.

- 'onlyIfNewer' : an existing file on disk will only be overwritten in case it have an older timestamp than the file to be installed.


<project>
  ...
  <overwritePolicy>onlyIfNewer</overwritePolicy>
  ...
</project>

I am trying to create a "smart" installer which includes upgrade functionality. How can I prevent the installation of files related to upgrade installations when performing a normal installation?

One approach to solve this could be to include the files related to upgrade installations in a separate component, which will be disabled for normal installations and enabled for upgrade installations. You can enable and disable components inside an action list using the <componentSelection> action:


<project>
  ...
  <preInstallationActionList>
     ...
     <!-- For an upgrade installation -->
     <componentSelection>
        <select>upgradecomponent</select>
        <deselect>default,datacomponent</deselect>
        <ruleList>
           ...
        </ruleList>
      </componentSelection>
     <!-- For a normal installation -->
     <componentSelection>
        <select>default,datacomponent</select>
        <deselect>upgradecomponent</deselect>
        <ruleList>
           ...
        </ruleList>
     </componentSelection>
     ...
  </preInstallationActionList>
  ...
</project>

Using built-in functionality to check for newer versions of the product on startup

You can make your installers check for the latest version in a specified URL. For that you will need to use the following tags in your xml project file:

  <project>
    ...
    <!-- versionId should be a positive integer number, and less than the
         version number you will use in the update.xml file below described -->
    <versionId></versionId>
    <checkForUpdates>1</checkForUpdates>
    <updateInformationURL>http://updates.yourcompany.com/update.xml</updateInformationURL>
    ...
  </project>

The updateInformationURL points to a xml file with the update information and should match the following structure:


 <installerInformation>
     <versionId>2000</versionId>
     <version>4.0.1</version>
     <platformFileList>
         <platformFile>
             <filename>program-4.0.1.exe</filename>
             <platform>windows</platform>
             <md5></md5>
         </platformFile>
         <platformFile>
             <filename>program-4.0.1.bin</filename>
             <platform>linux</platform>
             <md5></md5>
         </platformFile>
     </platformFileList>
     <downloadLocationList>
         <downloadLocation>
             <url>http://updates.yourcompany.com/download/</url>
         </downloadLocation>
         <downloadLocation>
             <url>ftp://updates.yourcompany.com/download/</url>
         </downloadLocation>
     </downloadLocationList>
 </installerInformation>

The versionId will be compared with the current installer versionId. Finally you can specify a list with the download URL where the full download URL will be downloadLocation + filename.


How to detect the previous installation directory

On Windows, BitRock InstallBuilder automatically creates a registry entry for your program. You can use the <registryGet> action (for instance during the <initializationActionList>)

     <registryGet>
         <key>HKEY_LOCAL_MACHINE\Software\xyz\abc</key>
         <name>Location</name>
         <variable>installdir</variable>
         <ruleList>
             <platformTest type="windows" />
         </ruleList>
     </registryGet>

xyz: name of your company, corresponds to the <vendor> property of the installer responsible for the installation that you want to upgrade. Defaults to "Name of your company".
abc: product name, corresponds to the <fullName> property of the installer responsible for the installation that you want to upgrade.
installdir: an installer variable where the resulting value of the registry key will be stored, in this case it matches the standard "installdir" parameter. If the registry key does not exist, then installdir's value will be set to empty and the value shown on screen will be taken from the installdir parameter <default> tag.


Currently we cannot detect an existing installation on Mac or Linux. This is because they lack the concept of a central registry (it could be emulated using the RPM database or writing in a central location, but it is not entirely reliable and would require administrative privileges). What we suggest in this case, is to check the default installation directory and only prompt the user for the installation directory in case the software is not found there.


       <directoryParameter>
             <name>installdir</name>
             <description>Installation Directory</description>
             <explanation></explanation>
             <value></value>
             <default>/path/to/default/value</default>
             <allowEmptyValue>0</allowEmptyValue>
             <mustBeWritable>0</mustBeWritable>
             <mustExist>0</mustExist>
             <width>30</width>
             <ruleList>
             <fileTest>
                   <condition>not_exists</condition>
                   <path>${installdir}</path>
             </fileTest>
             </ruleList>
       </directoryParameter>