aminal/windows.md

7.1 KiB

Windows dev env setup and build instructions:

  1. Setup choco package manager https://chocolatey.org/docs/installation
  2. Use choco to install golang and mingw choco install golang mingw

Setting aminal GoLang build env and directories structures for the project:

cd %YOUR_PROJECT_WORKING_DIR%
mkdir go\src\github.com\liamg
cd go\src\github.com\liamg
git clone https://github.com/liamg/aminal.git

set GOPATH=%YOUR_PROJECT_WORKING_DIR%\go
set GOBIN=%GOPATH%/bin
set PATH=%GOBIN%;%PATH%

cd aminal
go get
windres -o aminal.syso aminal.rc
go build
go install

Look for the aminal.exe built binary under your %GOBIN% path

Building an installer for automatic updates:

In addition to the above commands:

go get github.com/josephspurrier/goversioninfo/cmd/goversioninfo
go get golang.org/x/sys/windows
go get github.com/jteeuwen/go-bindata/...

Install NSIS and place it on the PATH:

choco install nsis
set PATH=%PATH%;%ProgramFiles(x86)%\NSIS\Bin

Ensure signtool.exe is on the PATH. For instance, on Windows 10:

set PATH=%PATH%;%ProgramFiles(x86)%\Windows Kits\10\bin\10.0.17763.0\x64

Copy your code signing certificate to go\src\github.com\liamg\windows\codesigning_certificate.pfx.

Set the WINDOWS_CODESIGNING_CERT_PW to the password of your code signing certificate:

set WINDOWS_CODESIGNING_CERT_PW=PASSWORD

Compile Aminal and build the installer:

mingw32-make installer-windows

This produces several files in bin/windows. Their purpose is explained below.

How Aminal's automatic update mechanism works (on Windows)

Aminal uses a technology called Google Omaha for automatic updates on Windows. It's the same technology which Google use to auto-update Chrome. For a quick introduction, see this Google Omaha tutorial.

Aminal has an online installer. This is a 1 MB executable, which was created using Google Omaha. Suppose it's called OnlineInstaller.exe. When a user runs it, the following things happen:

  • OnlineInstaller.exe installs Aminal's version of Google Omaha on the user's system. In particular, this creates two AminalUpdateTask... tasks in the Windows Task Scheduler. They're set up to run once per day in the background and check for updates.
  • OnlineInstaller.exe contacts Aminal's update server and asks "what is the latest version?". The server responds with the URL to an offline installer and some command line parameters. Say this offline installer is called install-aminal-0.9.0.exe.
  • OnlineInstaller.exe downloads install-aminal-0.9.0.exe and invokes it with the given command line arguments, typically -install.
  • install-aminal-0.9.0.exe performs the following steps:
    • It installs Aminal 0.9.0 into %LOCALAPPDATA%\Aminal.
    • It sets some registry keys in HKCU\Software\Aminal. This lets the AminalUpdateTask... tasks know which version of Aminal is installed.
    • It creates a Start menu shortcut for starting Aminal.

When the update tasks run, you will see AminalUpdate.exe in the Windows Task Manager. They use the registry to send the current Aminal version to the update server and ask "is there a new version?". If yes, the server again responds with the URL to an .exe and some command line parameters. In Aminal's current setup, this too is install-aminal-0.9.0.exe (if the user had, say, Aminal 0.8.9 installed). But this time the command line flag is -update. The .exe again installs the current version of Aminal and updates the registry.

The offline installer install-aminal-0.9.0.exe is actually what's produced by the mingw32-make installer-windows command in the previous section. It is placed at bin/windows/AminalSetup.exe and supports the command line flags -install, -update or none. In the last case (i.e. when invoked without arguments), it acts as a normal offline installer to be invoked by the user, and does not set Omaha's registry keys. The source code for this installer lies in windows/installer/installer.go.

Due to the asynchronous nature of the update tasks, it can happen that Aminal is running while a new version is being downloaded / installed. To prevent this from breaking Aminal's running instance, Aminal's install dir %LOCALAPPDATA%\Aminal contains the following hierarchy:

  • Aminal.exe
  • Versions/
    • 0.9.0/
      • Aminal.exe

The top-level Aminal.exe is a launcher that always invokes the latest version. When an update is downloaded / installed, it is placed in a new subfolder of Versions/. For instance:

  • Aminal.exe
  • Versions/
    • 0.9.0/
    • 0.9.1/

The next time the top-level Aminal.exe is invoked, it runs Versions/0.9.1/Aminal.exe.

The code for this top-level launcher is in windows/launcher/launcher.go. Its binary (and the current version subdirectory) is produced in bin/windows when you do mingw32-make installer-windows.

Forcing updates

By default, Aminal's (/Omaha's) update tasks only run once per day. To force an immediate update, perform the following steps:

  • Delete the registry key HKCU\Software\Aminal\Updated\LastChecked.
  • Run the task AminalUpdateTask...UA in the Windows Task Scheduler. Press F5. You'll see its result change to 0x41301. This means it's currently running. You'll also see AminalUpdate.exe in the Task Scheduler. Keep refreshing with F5 until both disappear.

Uninstalling Aminal

The installer above adds an uninstaller to the user's Add or remove programs panel in Windows. When the user goes to the Control Panel and uninstalls Aminal this way, the install directory and start menu entries are removed. Further, the registry key HKCU\Software\Aminal\Clients\{35B0CF1E-FBB0-486F-A1DA-BE3A41DDC780} is removed. What's not removed immediately is Omaha. (So you'll still see the update tasks in the Task Scheduler.) But! The next time the update tasks run, they realize by looking at the registry that Aminal is no longer installed and uninstall themselves (and Omaha).

To work around some potential permission issues, the uninstaller is not implemented in Go (like the installer and launcher above). But via NSIS. The source code is in windows/Uninstaller.nsi. It's an "installer" whose sole purpose is to generate bin/windows/Aminal/uninstall.exe.

Releasing a new version via automatic updates

To release a new version, update the VERSION fields in Makefile. Then, invoke mingw32-make installer-windows. Log into the Omaha update server, add a new Version for Aminal that mirrors the one you set in Makefile. You'll need to add a trailing .0 to the version number on the server, because Omaha uses four-tuples for versions (0.9.1.0 instead of 0.9.1). As the "File" for the version, upload bin/windows/AminalSetup.exe. Add two "Action"s: One for Event install, one for event update. In both cases, instruct the server to Run AminalSetup.exe. For the install Event, supply Arguments -install. For the update Event, supply Arguments -update.

Once you have done this, the background update tasks on your users' systems will (over the next 24 hours) download and install the new version of Aminal from the server.