It’s a joke that developers only know about three quantities: zero, one, or n. In other words, once you write the code to handle two, you’ve already written the code to handle millions.
That applies to WiX’s Burn chainer engine as well: Burn is designed to handle any number of packages, all of which could be installed in a chain. That design differs from one many are familiar with: The fire-and-forget bootstrapper that installs some number of prerequisites before kicking off “the real installer.” Three important words there are “the,” “real,” and “installer.”
“The” real installer
As a rule, bootstrappers installing their prerequisites and then launch “the” .msi package in full UI mode. That works in a lot of cases, but what happens when there isn’t a “the” package but two or three or more? You don’t need a huge product to take advantage of multiple .msi packages. For example, language packs – separate .msi packages with the localizable resources for a particular language – are a great way of handling localization. But you’re guaranteed to have multiple .msi packages, one for your language-neutral resources and one for localized resources.
Supporting only a single main .msi package was a non-starter for Burn. It’s far too limiting in this day and age.
Obviously, a phased bootstrapper could also support multiple non-prerequisite packages. I’m not aware of any that do.
The “real” installer
Fire-and-forget bootstrappers force users to be attentive to the installation over multiple phases. Users rarely care about the anally-retentive distinction between a program and its prerequisites. They just know that installing a program using a bootstrapper requires them to sit at their machine while all the prerequisites are installed before they get to go through another (subtly different) user interface to install the “real” software.
Burn rejects the phased model of installation: All packages, prerequisites or “real,” are installed as part of a single chain of packages. User interaction happens before any packages are installed (modulo progress bars of questionable reliability, error messages, or happy shiny success messages).
The real “installer”
The “forget” part of fire-and-forget is important: Without leaving a “trace” on the system, fire-and-forget bootstrappers don’t involve themselves with maintenance operations like uninstall and repair.
Burn registers an entry in ARP (aka Programs & Features) so that uninstall affects the whole chain, prerequisite and multiple packages alike. You might not want to remove bigger prerequisites like the .NET Framework but leaving behind other prerequisites is kinda rude – at best; prerequisites that aren’t shared shouldn’t be left behind at all.
Repair is sometimes forgotten (intentionally or otherwise). Burn supports repair across the whole chain and makes it optional for packages like the .NET Framework.
If Burn’s so powerful, just make it an option
When we were designing Burn, we knew all about existing bootstrappers but rejected the fire-and-forget, single-package model. It was too limiting in 2008 and it’s even more limiting now. Obviously, however, lots of folks don’t need the firepower of this fully armed and operational battle chainer. That said, there’s nothing but time preventing you from going all-in with the Burn model
Burn partly supports the phased install model. You can set the
MsiPackage/@DisplayInternalUI attribute to
yes to instruct Burn that when it installs that package, its UI should be shown.
@DisplayInternalUI is effective only during install, however; during repair and uninstall, only the bootstrapper application is shown.
There is currently no option to support the “forget” model: Burn always writes an ARP entry for the bundle. Because Burn caches packages by default, it’s important that users have an entry point to uninstall the bundle, which also removes the cached packages and persisted bundle data.
It would be a significant amount of work to mold Burn into something that supports both models. And it would be a mistake. “Just make it an option” is one of the most common ways to create software that is unnecessarily complex and crufty. All code paths end up taxed with the extra complexity.
Instead, imagine a new bootstrapper core – let’s call it Fire, shall we? – built on top of existing Burn services like the planning, download, and install engines. It’s likely less work that throwing in a bunch of switches to the existing Burn engine.
It’s not a sin for a piece of software to not be everything to everybody. There are alternatives, including a bunch of existing bootstrappers. Building a new Fire engine (see what I did there?) would be an interesting bit of work. I like the Burn engine, so I’m not planning on doing it. But you could.