D252 — Windows installs through install.ps1, not winget¶
Decision. Cartographer is installed, upgraded and removed on Windows with
install.ps1 at the repository root — irm …/install.ps1 | iex — the
counterpart of install.sh with the same contract: newest release
(pre-releases included), SHA-256 verified against sha256sums.txt, per-user
destination (%LOCALAPPDATA%\Cartographer\bin on the user PATH, no
administrator rights), upgrade-repair after an update, and an uninstall that
refuses while the Scheduled Tasks are registered. The winget channel is
withdrawn: no winget: block in .goreleaser.yaml, no WINGET_PKGS_TOKEN, no
fork of microsoft/winget-pkgs, and the submissions still open there were closed.
The release keeps shipping the Windows assets as zips, which is now what
install.ps1 reads. Supersedes
D218
(except for the zip format) and
D223.
Why. winget never delivered a single install. Every tag opened a pull request
into microsoft/winget-pkgs that sat in review for days — 0.13 through 0.16.1
never reached users through it — so the "only channel" was in practice the
hand-driven zip fallback of D223: six PowerShell steps with a checksum to compare
by eye, a PATH edit, a service stop before every upgrade, and a new window to
open before anything worked. That is the worst onboarding of the three platforms,
on the platform where it was supposed to be the simplest. A script in this
repository ships the moment a release does, is tested by our own CI, and does
what winget's portable install could not: repair a running service in place. The
cost is a second installer script to keep correct, which is exactly what D218
rejected; the Windows CI job running it end to end under both PowerShell editions
is what makes that cost acceptable now.
Alternatives rejected.
- Keep winget and wait for the review. Each release restarts the wait, and a 0.x project releases often; the channel would be permanently one or more versions behind, and the D223 fallback would stay the real path.
- Keep only the zip procedure (D223) as the one Windows path. Nothing new to maintain, but it is the slow, error-prone install this decision exists to remove: the checksum comparison and the service stop are exactly the steps a hand procedure skips.
- Scoop or Chocolatey. The same third-party review problem as winget (Chocolatey moderates every version), or a bucket of our own that users must add first — a second step for no capability the script lacks.
cartographer self-updatein the binary. Would cover upgrades only, still needs a first install, and would put a self-replacing executable on a platform that locks running binaries; the installer already solves both.
Consequences.
- Under
iexthe script runs in the user's own session, so it never callsexit(that closes the window) — failuresthrow— and sets$ErrorActionPreference/$ProgressPreferenceonly inside functions. It also patches the current process'sPATH, socartographerworks on the next line. - An update renames the running executable aside (
cartographer.exe.old) instead of stopping the service: Windows forbids overwriting or deleting a running image but allows renaming it. Leftover.oldfiles are deleted on the next run once nothing holds them.docs/getting-started.mdno longer tells anyone to stop the service before an upgrade. - The service task records the plain install path.
resolveStableBinPathno longer prefers a winget shim:install.ps1replaces the same file on every upgrade, so the pathservice installran from is already stable. - A missing
sha256sums.txtis an error on Windows, stricter thaninstall.sh: every release carrying Windows zips carries the file. - The Windows asset names are an interface.
cartographer-windows-{amd64,arm64}.zipcontainingcartographer.exe: renaming either breaks every existinginstall.ps1 update.test/install/goreleaser_guard.shpins the zip shape and the absence of awinget:block;test/install/windows/run.ps1runs the script against a real build on thetest-windowsjob, under PowerShell 7 and Windows PowerShell 5.1. - Nobody is left on winget: no submission was ever merged, so there is no installed base to migrate and no shim path in any registered task.