Wednesday, July 1, 2009

WiX, because we can.

For today's post, I thought I might write on something that's not directly related to F#. Instead, this article deals with WiX, a piece software intended to help creating installers. WiX and F# do share their approach to writing programs, though, namely the declarative way.

First, I must say I am no expert in installers. I have built a couple rpm packages on Linux, and found the experience OK, but not particularly enjoyable. I have also used NullSoft Scriptable Install System (NSIS for short) for top10, and gave up with it. My main gripe is that NSIS is really more a scripting language, and not a particularly good one at that. I don't think it's worse than the other install systems out there, though I haven't tried them all. I did try WISE, for instance, but failed to install it. Now, that's irony...

The problem is that these tools try to solve the problem using a procedural approach. The programmer has to specify what to do during an installation, which typically includes copying files on the hard disk, setting up a few shortcuts, messing up with the registry. Specifying all this is a tedious task, but it's not even half the job. One must also specify what to do when the user decides to uninstall the software. Typically, this means clearing up the mess in the registry, removing the shortcuts, deleting files.

Obviously, it should be possible to deduce the uninstallation process from the installation process. It's not just a matter of convenience, but of correctness.

WiX attracted a bit of attention when it came out, being Open Source software produced by Microsoft. Another side of it worth of interest is that it uses a declarative approach to specifying installation procedures. Instead of writing the sequence of operations needed to (un)install software, one specifies what to install, and where. Which is the way it should be.

As attractive as it seems to be, I must say I am disappointed. The three full days of experimenting I have spent on WiX have been rather painful.

The first issue is that WiX is based on Windows Installer, a.k.a MSI, whose documentation is pretty hard to grasp for a newcomer. Part of the problem resides in the core design choices, which seem genuinely weird to me. An MSI installer is not a program, it's a database, which contains a description of a workflow, where the actions make up the installation procedure. Now, installations a probably some of the most linear processes one can think of, meaning workflows are complete overkill. Why one would use a database to store a workflow is another mystery.

WiX attempts to hide these layers of insanity. All you need to do to copy a file on the system is specify which file you want to copy, and where. WiX takes care of generating the code to undo the copy if it fails, as well as the code to remove the file when uninstalling.

Sadly, WiX only goes halfway. If your installation process happens to write over an existing file, the uninstallation process won't restore the original file. This must be handled manually, and requires a decent understanding of MSI, its workflows, custom actions and databases.

What's worse, WiX adds another layer of wickedness of its own, namely XML. That was probably the only technology missing in the stack...

In case you urgently need a headache, I suggest you go have a look at Suggested InstallExecuteSequence, which is the sequence of actions one should take to install software. That's 60 of them, no less. If that sounds like a lot, well it is. The catch is that the same sequence is used for uninstallation. Approximately half of these actions are active when installing, the other half being active while uninstalling. The question that immediately pops up is "why not use two separate sequences"? But then, one would not need conditions, such a shame...