not quite minimalistic enough  

Hey! A Python packaging rant!

burn.exe Considered Harmful, or, Why burn Should Burn

The WiX Toolset is a suite of applications for creating and working with Windows Installer packages (.msi files). Today, it is the most elegant way of creating installation packages for Windows, because it provides reproducibility, a logical structure, and, because it uses XML files instead of a GUI, the package definition can be trivially version controlled. All around, it is the optimal solution to a difficult problem.

Windows Installer has some support for installation UI, mostly to determine the installation directory and to select which optional features to include, but other things are possible. It is not the prettiest of UI libraries, neither in visual appearance nor in design technique, but it works, and, after all, an installation package’s UI does not have to be pretty as long as it works.

Recently, support was added to WiX for “bundles” with “bootstrapper applications”. Bundles are collections of MSI packages that are installed in a specific sequence. Conditions can be defined to decide whether any given package is installed at all. The final distributed output is an .exe file. This is a problem.

First, some background

The MSI file format is designed to make software package management, if not simple, then at least tractable. This situation is particular to Windows, because on other platforms with an integrated package manager (yum, apt, pkg, etc.), there is typically only one source of packages (the distribution’s own repository), and it is well understood that third-party packages do not usually work correctly. On Windows, with hundreds of thousands, if not millions, of developers producing their own packages, this model is clearly not viable. Microsoft’s answer was the MSI file format, because a well-designed MSI has a good chance of “being a good citizen” on the system it is installed on, and, possibly more important, the quality of a package can be assessed before it is installed (e.g. by running the ICEs against it or simply by looking through the tables for obvious issues).

An additional complication that mostly affects Windows, though it exists in some manner on all operating systems, is the Registry database. Installing a package usually both places files on the system and adds certain entries to the Registry, such as file type associations and non-user-specific application configuration data.

The price that the designer of an MSI package has to pay is a certain amount of restrictions. There are rules that a correctly designed package has to obey. Some of them are only checked when the package is validated, some are inherent in the structure of the MSI database and cannot be circumvented.

Windows Installer defines a set of “actions”, which are discrete steps in installing a package. Each action acts upon the system, using information from a set of database tables in the MSI file, to transform the system from one known state to another.

If you are not yet familiar with MSI, it is worthwhile to read the previous paragraph again. MSI, alone among all distribution package formats as far as I know, does not follow an imperative approach that describes how the target system should be changed by the installation, but instead uses a declarative model that describes how the system should be when the installation is finished. The knowledge of how to achieve the desired system state, which may involve, e.g., interdependent modifications that have to happen in a specific order, is provided by Windows Installer itself. The package author does not need to be overly concerned about it.

Enter the “custom action”. “Custom” actions are, as the name suggests, provided by the package author. They can basically do whatever they want, including things that the MSI developers deliberately did not make it possible to do.

Immediately after the first version of Windows Installer was released and Microsoft documented the MSI file format, various companies that had made a good living producing software for producing installation packages (Wise, InstallShield, etc.) started offering versions of their software that no longer created opaque SETUP.EXE files, but MSI files. Unfortunately, they either did not understand the reasons for MSI’s strict design or bowed to user demand; they introduced their own custom actions that, in a nutshell, turned the MSI model inside out by using Windows Installer only as an entrypoint to a “legacy” installation package written in their, by now obsolete, installation scripting language. InstallShield is a very good (or very bad) example of this. For several years, users lived in fear of seeing the words “InstallScript” anywhere, particularly in an installation error message. (InstallScript was a separate component from the actual installation package and had to be installed already, in the correct version, etc.; it was “DLL Hell” with setup components.)

There are some operations involved in installing certain kinds of packages that cannot be represented simply as state changes (like adding a file or a registry key can) but need to interact with other software already on the system, such as registering a plugin for something where the “something” only offers a registration helper application that must be called. For such things, custom actions are, regrettably, necessary. However, if something can be done without a custom action, it should be, no matter how convenient the custom action-based approach may appear in comparison.

Back to WiX

The central advantage of the MSI package format is that it is, essentially, data. It does not contain executable code, other than where the package author decides to include custom actions. By inspecting the Features table, you can learn what parts of the package are optional. The Directory table tells you if the package wants to install files anywhere outside its installation base (such as the Windows directory). In the Property table you find all the package metadata, such as version numbers. You can even adapt a package to your particular requirements by designing a transform (.MST file) that will be applied during installation but leave the original MSI file entirely untouched, giving you the opportunity – unheard of before the introduction of MSI – to actually change the result of the installation in ways not necessarily foreseen by the package author.

Most of all, the nature of the MSI package enables seamless deployment. You don’t have to dig up long-forgotten lists of command-line arguments supported by the setup.exe package of the day, you do not even need the ability to run an executable as part of your deployment at all. You simply tell your client management solution (or even a simple group policy object) to install a package, and that package is installed, perhaps with a transform or two.

burn’s bundles clearly were intended to do away with all that, and they succeeded fully, from start to finish. There is no seamless deployment anymore, because now you have to work with command line options again. There is no trivial transformation anymore, because that requires that the bootstrapper application pass your arguments (including the transform file name) to the actual MSI package it is intended for (and none other). It dares the package developer to design UI for prettiness instead of functionality by providing several predefined “themes” and support for custom ones. Finally, it abuses a feature intended for hiding required system components to prevent its bundled MSIs from showing up in the Control Panel’s applications list.

The WiX installer bundle itself is a perfect example of how not to do installation UI: It is entirely nonstandard, moves and blinks to maximally confuse the user, and is quite ugly on top of that. In an environment that does not support deployment of .exe packages (the vast majority of domains that only have group policy available), it is also essentially nondeployable. It does not even provide a download size advantage even though some parts of the bundle are optional and might be downloaded only if required, because the WiX project always ships the full set in a bundle of ~24 MiB (including some redundant files that would only appear once in an integrated package, but they apparently do not make much of a difference in size).

Conclusion

There is very little that can be done with bundles that a well-designed single MSI package cannot do, and what little there is, no installation package ever should do.

Do not use burn. It burns.

Written on May 31, 2019