Wednesday, February 28, 2007

Creating a multiplatform installer (with IzPack)

Hello once again.
As promised, today I'll talk about how to create your multiplatform installer for your Eclipse Rich Client Application without having to add all the folders PDE (Plugin Development Environment) created.

First of all, understand that what I'll explain for IzPack can be used for any other installer you like. Just search for a feature similar to the one I quote in your installer and you should have no problem.
Now that this is explained, let's get started:
First of all, part of your jobs is already done thanks to the eRCP imposed architecture. I'm talking about having your project split in several parts that are almost completly independent. This is very useful since it'll allow your user to choose the plugins he wishes to install.
This reminds me of something: feature != plugins.
Your update site or your product uses a set of plugins and call it a feature if you followed most of the tutorials. This doesn't means your installer must care about your feature definitions.
The feature definition will allow your update system to know which updates it should look for and which features are considered "new features". This means that if your application is running without any feature and you ask for an update, it'll show you the core feature (which you obviously already have since you're running your application) as a "new feature" to be installed. That can be explained by the fact that sites only know about features and never look to plugins.

Therefore, a good practice is to have your core feature as a required package in your installer. Any other feature you would like the user to update through the update system should also be joined as a package in your installer. However, if you wish to offer the user the choice to install only one plugin regardless what is its feature, you can do it without further consequences. Your application will work without a problem and with this plugin activated.

So, you have decided what will be the packages available in your installer. You must know what license you'll use and you can have a couple shortcuts because it's always useful.

Now let's produce the XML file that will explain to IzPack how it should work.
Your first section of the IzPack XML should be the something like:

<info>
<appname>Your App</appname>
<appversion>@{version}</appversion>
<authors>
<author name="Tarantulus Corp." email="archimedesproject@googlegroups.com" />
</authors>
<url>http://www.archimedes.org.br/</url>
<webdir>http://arquimedes.sf.net/update</webdir>
</info>


No big secret on that. It defines mainly the first screen post language choose. Excepting 'webdir' all those fields are shown in that screen. The 'webdir' is the addressed used to search for the package if you are about to create an online installer. This is mainly the only thing that changes from a local installer to an online installer in IzPack.
The second part of your XML should be:

<guiprefs width="640" height="480" resizable="no">
<modifier key="useButtonIcons" value="yes" />
<modifier key="useLabelIcons" value="yes" />
<modifier key="langDisplayType" value="native" />
<modifier key="headingPanelCounter" value="progressbar" />
<modifier key="headingPanelCounterPos" value="inNavigationPanel" />
</guiprefs>

This is a bit more obscure. The first lines are quite easy to understand. 'landDisplayType' is not that easy however. It sets how the installer will show the options of language to the user on the first screen of your installer. In this case, native tells the software to use the system's locale to write the languages. 'headingPanelCounter' and 'headingPanelCounterPos' defines how the steps remaining and the current step should be shown to the user. If those lines are not present, nothing will be displayed.

Next you have:

<resources>
<res id="installer.langsel.img" src="installer.png" />
<res id="LicencePanel.licence" src="license.txt" />
<res id="shortcutSpec.xml" src="shortcutSpec.xml" />
<res id="packsLang.xml_eng" src="packsLang_eng.xml" />
</resources>


Okay. Now we're talking! First of all, the image to be shown in the first screen of the installer is the one on the first line. The license that will be displayed to the user and that he will be forced to accept unless it quites the install. Beware, this license should be in a text format because IzPack will display it as a text only file. The last lines regard the shortcut creation and the internationalization of this installer. Take a look on the official documentation and this should be enough.

The next part is what will define the flow of your IzPack installer:

<panels>
<panel classname="HelloPanel" />
<panel classname="LicencePanel" />
<panel classname="PacksPanel" />
<panel classname="TargetPanel" />
<panel classname="InstallPanel" />
<panel classname="ShortcutPanel" />
<panel classname="FinishPanel" />
</panels>

Those panels are available by default in IzPack. You can, however, create your own panels as well as install new ones created by the community and available mainly at IzPack's site (http://www.izforge.com/izpack).

At last, the last part is the most important one. The one that will specify each pack of your application:

<packs>
<pack name="Core" id="core" required="yes">
<description>The core of Your App.</description>
<fileset dir="@{deployDir}/win32.win32.x86/YourAppName/" targetdir="$INSTALL_PATH">
<include name="startup.jar" />
<include name="configuration/config.ini" />
<include name="features/org.eclipse.rcp*/**/*" />
<include name="features/your.company.project.feature*/**/*" />
<include name="plugins/**/*" />
<exclude name="plugins/your.company.project.*.jar" />
<exclude name="plugins/org.eclipse.swt.*linux*.jar" />
<exclude name="plugins/org.eclipse.opengl.linux*/*" />
<exclude name="plugins/org.eclipse.opengl.linux*/**/*" />
</fileset>

<fileset dir="@{deployDir}/linux.gtk.x86/YourAppName/" targetdir="$INSTALL_PATH">
<include name="icon.xpm" />
<include name="yourapp" />
<include name="about.html" />
<include name="libcairo-swt.so" />
<include name="about_files/**/*" />
<include name="plugins/org.eclipse.swt.*linux*.jar" />
<include name="plugins/org.eclipse.opengl.linux*/**/*" />
<os name="linux" />
</fileset>
<fileset dir="@{deployDir}/macosx.carbon.ppc/YourAppName/" targetdir="$INSTALL_PATH">
<include name="yourapp.app/**/*" />
<include name="plugins/org.eclipse.swt.*macos*.jar" />
<include name="plugins/org.eclipse.opengl.macos*/**/*" />
<os family="osx" />
</fileset>
<fileset dir="@{deployDir}/win32.win32.x86/YourAppName/" targetdir="$INSTALL_PATH">
<include name="yourapp.exe" />
<include name="plugins/org.eclipse.swt.*win32*.jar" />
<include name="plugins/org.eclipse.opengl.win32*/**/*" />
<os family="windows" />
</fileset>

<!-- The windows scripts -->
<executable targetfile="$INSTALL_PATH/yourapp.exe" stage="never">
<os family="windows" />
</executable>

<!-- The Linux scripts -->
<executable targetfile="$INSTALL_PATH/yourapp" stage="never">
<os name="linux" />
</executable>
</pack>
</packs>


Each <pack> must have one or more files registered. Those can be added using the file tag (when you want to work with one specific file) or the fileset tag (when you want to work with folders) as shown. The fileset accepts both <include> and <exclude> tags which allows you to easily create exceptions in your folders. Also, all those tags accept <os> that will be interepreted as a mark to tell the installer on which OSs those files should be unpacked. This is mainly how you separate things. The first fileset defined in the example above is the one that grabs all non-OS specific files from the RCP. The next 3 filesets are used to select os specific files as the 'os' tag shows.

At last, the <executable> tag marks the file you target as executable. This means a double click or a command will try to run those files. This is required because the installer will zip all the files in jars and loose all kind of permissions over the file on install. So it needs to know which files should be diferent from the read and write permissions.

All this should allow you to create a simple multi platform installer for your eRCP application. Once this is done, you'll probably want to add the <locale> tag to add internationalization support to your installer and then you'll need to create some language specific XML with pack descriptions translations and everything else.

A last tip, beware to export all of your features and plugins when you are in Eclipse. You'll need all the files available on your deployDir to make the installer work well.

The next post will discuss about how to create all the application, the installer and transfer all to a website using one simple script. This allows a much quicker and constant deploy of your software to your users. Expect it done for saturday or sunday.

See you guys soon. Bye bye.

5 comments:

Kiril said...

Cool, but where is shortcutSpec.xml?

Hugo "NighT" Corbucci said...

My mistake.
Sorry. All the files are available at:
https://incubadora.fapesp.br:8043/svn/archimedes/br.org.archimedes.izpack/

But here follows the shortcutSpec.xml:

<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>

<shortcuts>

<skipIfNotSupported />

<programGroup defaultName="Tarantulus\Archimedes"
location="applications||startMenu" />

<shortcut name="Archimedes" programGroup="yes" desktop="yes"
applications="no" startMenu="no" startup="no"
target="$INSTALL_PATH\Archimedes.exe" workingDirectory="$INSTALL_PATH"
commandLine="" description="Starts Archimedes"
initialState="noShow">

<createForPack name="Core" />
</shortcut>

<shortcut name="Uninstaller" programGroup="yes" desktop="no"
applications="no" startMenu="no" startup="no"
target="$JAVA_HOME/bin/java.exe" workingDirectory="$INSTALL_PATH\Uninstaller\"
commandLine="-jar uninstaller.jar"
iconFile="%SystemRoot%\system32\SHELL32.dll" iconIndex="31"
description="Uninstalls Archimedes">

<createForPack name="Core" />
</shortcut>

</shortcuts>

And here is the unix version:

<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>

<shortcuts>
<programGroup defaultName="Archimedes"
location="applications" />
<shortcut name="Archimedes" programGroup="yes" desktop="yes"
applications="no" startMenu="yes" startup="no"
target="$INSTALL_PATH/Archimedes" iconFile="$INSTALL_PATH/icon.xpm"
iconIndex="0" workingDirectory="$INSTALL_PATH/"
description="Starts Archimedes" type="Application" encoding="UTF-8"
terminal="false" KdeSubstUID="false" initialState="normal"
categories="" createForAll="true">
<createForPack name="Core" />
</shortcut>

<shortcut name="Archimedes Uninstaller" programGroup="yes"
desktop="no" applications="no" startMenu="yes" startup="no"
target="$JAVA_HOME/bin/java"
commandLine="-jar uninstaller.jar"
iconFile="trashcan_empty" iconIndex="0"
workingDirectory="$INSTALL_PATH/Uninstaller/" description="Starts Archimedes"
type="Application" encoding="UTF-8" terminal="false"
KdeSubstUID="false" initialState="normal" categories=""
createForAll="true">
<createForPack name="Core" />
</shortcut>
</shortcuts>

AlfaOmega83 said...

Hi,First of all tnx for the good guide.unfortunately the link to incubadora doesn't work(access denied)....where i can find the .xml code?

Hugo Corbucci said...

The incubadora is letting me down for a while now.
I migrated all the files to a new SVN server (http://svn.archimedes.org.br/public/). The files for this post should be available at: http://svn.archimedes.org.br/public/mainarchimedes/rcparchimedes/br.org.archimedes.izpack/trunk/

Please warn me if you find any problem.

Anonymous said...

Good Afternoon

Thanks for sharing, I have digged this post