Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Windows Installer: Upgrade to WiX Toolset 5 #929

Open
wants to merge 20 commits into
base: main
Choose a base branch
from

Conversation

jkarasti
Copy link
Contributor

@jkarasti jkarasti commented Sep 24, 2024

This upgrades tooling used to build the Dangerzone.msi installer to WiX Toolset 5.

The Major change in this, apart from what running wix convert on the old generated WiX authoring, is that the target directory for each component gets set in the Directory attribute of the component instead of a separate Directory element one level above in the XML hierarchy. All components get grouped under a ComponentGroup that gets referenced in the Feature tree, which makes things much simpler aswell.

There are still a couple of open questions:

Should AllowSameVersionUpgrades="yes" be removed?

According to the documentation setting it useful if the installer uses a fourth version number. But Dangerzone doesn't use one so it should be save to remove it. Running wix msi validate on the built msi also prints a warning about this.

What to set the value of InstallerVersion to?

In this its set to 200 to make 64 bit installer work, but it could also be removed or set to the default 500, which would cap the lowest version of windows Dangerzone supports to Windows 7.

Should Dangerzone also set a desktop icon?

This is also a possibility, but opinions vary is this is good practice or not. Also this should come with an option to not install the icon, but that would require developing some custom dialogs for the installer.

Customise the installer theming more?

This should probably be its own issue. The installer, while limited, allows for a bit customization, mainly by addind a banner image that would replace the red cd icon shown during install currently. The installer already uses a custom image shown at the start of the installation . For more, see:

https://wixtoolset.org/docs/tools/wixext/wixui/#replacing-the-default-bitmaps
https://stackoverflow.com/questions/48713061/how-do-you-change-the-red-cd-icon-on-wix

Caution

One unfortunate side effect this has is that installing the newer installer does not uninstall older versions of Dangerzone.
The root cause for this is a changed default for the Scope attribute in the Package element. In WiX 3 it was apparently
set to perUser by mistake and in WiX 4 its set to perMachine

One workaround for the uninstallation issue would be to set Scope="perUser" attribute in the Package element. But MSIs apparently have poor support for per user packages, though I havent figured out how exactly just yet.

Another solution could be to bite the bullet this once and guide users on Windows into uninstalling the older version of Dangerzone somehow, for example a blog post or a pinned issue, or maybe within Dangerzone itself. SInce this pull request also makes Dangerzone a proper 64 bit installation, the new version should install itself alongside the old one just fine without breaking anything. Though it'll show up twice in installed programs and the start menu, leaving it up to the user to discover older version is still installed and uninstall it. Not exactly the best user experience.

closes #602

WixCop.exe is a built in formatting tool that comes with WiX toolset v3. This fixes `wix convert` command not beins able to run
with:
dotnet-version: "8.x"
- name: Install WiX Toolset
run: dotnet tool install --global wix --version 5.0.1
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any clue if we can specify the major version (5) in our CI, so that we can catch regressions later on? Same goes for the wixext plugin below.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could set the version in an environment variable would that be enough?

  env:
    wix_version: 5.0.1
- name: Install WiX Toolset
   run: dotnet tool install --global wix --version $wix_version
- name: Add WiX UI extension
   run: wix extension add --global WixToolset.UI.wixext/$wix_version

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's not the duplication that worries me, but whether a future 5.1 Wix release breaks something. I'll give it a shot locally.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oops, yes, I started looking into the wrong thing. We could set the WiX version with a matrix stradegy. Something like:

strategy:
      matrix:
        wix_version: [5.0.0, 5.0.1]

- name: Install WiX Toolset
   run: dotnet tool install --global wix --version ${{ matrix.wix_version }}
- name: Add WiX UI extension
   run: wix extension add --global WixToolset.UI.wixext/${{ matrix.wix_version }}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, I was thinking of something like the following:

dotnet tool install --global wix --version 5.*
wix extension add --global WixToolset.UI.wixext/5

I just realized though that there's an open issue for the latter, and it won't fetch the latest 5.x.y release of WixToolset.UI.wixext (see wixtoolset/issues#8033)

Anyway, we can pin the extension version for now, but my suggestion is to always install the latest WiX version using dotnet tool install, if you agree.

Copy link
Contributor Author

@jkarasti jkarasti Sep 25, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Initially I hardcoded the version to avoid a situation where a developer installs WiX Toolset to release a new version of Dangerzone and then accidentally builds the windows installer with a newer version of WiX which breaks in unexpected ways. E.g See the whole Scope debacle.

We could drop the version numbers in CI to catch any regressions, but keep them in the build instructions to prevent accidentally upgrading WiX while doing a release. Or maybe even have two jobs in CI. One installs WiX without a version number to test for regressions and the other uses whichever version is used to build the current released installer and gets bumped when the installer is upgraded to a newer version of WiX,

Copy link
Contributor Author

@jkarasti jkarasti Sep 25, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And on that note, should I also remove the dotnet version? The setup-dotnet action picks whatever is the newest version installed in the runner if its not defined. I picked 8 since that's the version you'll get offered when downloading .NET SDK. On second thought, using the latest 8.x LTS release is probably the sensible thing to do.

Copy link
Contributor

@apyrgio apyrgio Sep 25, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Or maybe even have two jobs in CI. One installs WiX without a version number to test for regressions and the other uses whichever version is used to build the current released installer and gets bumped when the installer is upgraded to a newer version of WiX

Excellent, that's the best of both worlds. Our CI is undergoing a major change, so no need to do this in this PR. I'll create a separate issue to track it. For now, we can keep it as is.

install/windows/build-wxs.py Show resolved Hide resolved
@apyrgio
Copy link
Contributor

apyrgio commented Sep 25, 2024

Amazing work here @jkarasti. Not only did you manage to update our scripts to use WiX 5, but you broke down the changes in 20 (!) short and sweet commits. The changes make sense, and I'm testing them in a Windows box now.

Now, to your questions, here's my understanding:

Should AllowSameVersionUpgrades="yes" be removed?

My understanding is that previously, we specified * as the product code:

With this PR, we don't specify something, which means that the default behavior will trigger:

By default, a new ProductCode property will be generated with every build enabling major upgrades.

(from https://wixtoolset.org/docs/schema/wxs/package/#attributes)

So, if we remove AllowSameVersionUpgrades="yes", this means that we cannot simply rebuild the Dangerzone MSI, if Wix announces a CVE for instance (this has happened in the past btw). We will need to also bump the patch version of Dangerzone. This is not bad per se, but it's a limitation us devs need to be aware of.

What to set the value of InstallerVersion to?

Setting it to 200 - or even removing it, since it's the default - is fine. After all, Docker Desktop (well, WSL2) works from Windows 10 onwards, so we're capped by this requirement.

Should Dangerzone also set a desktop icon?

Not pressing, looks like a future improvement to me.

Customise the installer theming more?

Another future improvement, but thanks for the context. Once we merge the PR, we should refer to your links in a separate issue, as you have correctly mentioned.

BUILD.md Outdated Show resolved Hide resolved
@apyrgio
Copy link
Contributor

apyrgio commented Sep 25, 2024

FYI, I tested your branch and it works great. I can verify that the previous Dangerzone installation is not removed, which is a major bummer. I'll dig more around to figure out if we can do something about that.

@apyrgio
Copy link
Contributor

apyrgio commented Sep 25, 2024

I tested with Scope="perUser" and I get the following error:

image

This is similar to this SO post, in which they had to do some shenanigans to elevate their privileges on installation time.

I wonder, is there a way to detect that a similar package exists, and ask users to remove it from "Programs and Features", like we do in the MajorUpgrade element?

@jkarasti
Copy link
Contributor Author

jkarasti commented Sep 25, 2024

I tested with Scope="perUser" and I get the following error:

image

This is similar to this SO post, in which they had to do some shenanigans to elevate their privileges on installation time.

I wonder, is there a way to detect that a similar package exists, and ask users to remove it from "Programs and Features", like we do in the MajorUpgrade element?

I found this. maybe we could add some custom action to detect and block the installation, I haven't looked into it much yet. Also note that this is for WiX 3 since the HowTos for WiX 4 and up haven't been written yet, so some things might have changed.

@jkarasti
Copy link
Contributor Author

jkarasti commented Sep 25, 2024

Should AllowSameVersionUpgrades="yes" be removed?

My understanding is that previously, we specified * as the product code:

With this PR, we don't specify something, which means that the default behavior will trigger:

By default, a new ProductCode property will be generated with every build enabling major upgrades.

(from https://wixtoolset.org/docs/schema/wxs/package/#attributes)

Just to note: Setting the value of Id to * means WiX will generate a GUID automatically, so this is doesn't introduce a change in behaviour. See docs for WiX 3 here and here

So, if we remove AllowSameVersionUpgrades="yes", this means that we cannot simply rebuild the Dangerzone MSI, if Wix announces a CVE for instance (this has happened in the past btw). We will need to also bump the patch version of Dangerzone. This is not bad per se, but it's a limitation us devs need to be aware of.

Ah, I didn't consider needing to rebuild the installer with a same version number. The main motivation for removing it is to make validation pass without warnings. Looks like making AllowSameVersionUpgrades="yes" the default was considered for WiX 4, but doing it would set off the warning in every .msi built with WiX 4 and disabling it would disable many other checks in ICE61 aswell. See this episode of Rob Menschings excellent series on WiX Toolset 4. (This was a great resource with this upgrade. btw.)

So it comes down to being fully compliant with spec and potentionally needing to release a patch release exclusively for windows every now and then. Or keeping things as is and having the ability to patch the windows installer without a version bump.

Also. WiX Toolset 5 introduces a brand new feature: Files. I'm working on a new version of this PR that integrates the Files feature in the .wxs build script. In a nutshell, the whole file harversting, component, and directory generation dance in build-wxs.py (and ~3000 lines of code in the generated Dangerzone.wxs) could potentially be replaced with a sinle line:

<Files Include="exe.win-amd64-3.12\**" />

Also rename `root_el` to `wix_el`.

WiX version 5 uses the same namespace.
It's the new default name for it
- The Keywords and Description items move under a new SummaryInformation element.
- Shuffle things around so that elements previously under the product element are now under the Package element.
- Rename SummaryCodepage in SummaryInformation to Codepage and remove a duplicate Manufacturer item.
- Remove InstallerVersion and let WiX set it to default value. (500 a.k.a Windows 7)
Due to limitations of the xml.etree.ElementTree library, add the items in the root element as a dictionary
This is a new default and makes authoring slightly simpler without any functional changes.
- Rename variables to be more clear about what they do:
- reorganise code
- simplify a few checks
…pRef`

With this, all the files are organised into Components,
each of which points to a Directory defined in the StandardDirectory element.
This simplifies the Feature element considerable as only thing it needs to
include everything in the built msi is a reference to `ApplicationComponents`
- rename for clarity
- remove unnecessary checks
Also reduce duplication slightly by definig `build_dir`, `cx_freeze_dir` and `dist_dir`
- WiX Toolset v3 used to validate the msi package by default. In v5 that has moved to a new command, so add a new validation step to the script.
@jkarasti
Copy link
Contributor Author

Pushed a couple of changes:

Removed the InstallerVersion.

Let's trust the WiX developers keep the default at a sensibly old version of Windows.

Updated the build instructions.

Better be safe than sorry, so mention opening a new terminal before installing the WiX UI extension. Also made a couple of Smaller tweaks. I've still kept the harcoded version in place. Maybe there should be an extra step in the release instructions to check for newer version of WiX and either bump if it's a minor or a patch version, or plan the upgrade if there's a new major version with breaking changes.

I havent touched the AllowSameVersionUpgrades attribute yet.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Migrate to Wix 4 (windows building tool)
2 participants