ecliptic

Packaging

One code base, three platforms. packaging/release.sh builds the package for the platform it runs on, into dist/, with a sha256 beside it and the version's section of CHANGELOG.md as notes-vX.Y.Z.md. The version lives once, in the workspace Cargo.toml.

Platform Package What is in it
Linux ecliptic-vX.Y.Z-<arch>-linux.tar.gz the binary, ecliptic.desktop (with StartupWMClass), the icon at every hicolor size (packaging/icons), install.sh, LICENSE, README, CHANGELOG
macOS ecliptic-vX.Y.Z-macos.dmg ecliptic.app, a universal binary (aarch64 and x86_64, joined with lipo), Info.plist and the .icns from packaging/macos/, with an Applications link in the image
Windows ecliptic-vX.Y.Z-x86_64-windows.zip and .msi the exe (its icon and version block from packaging/windows/ecliptic.rc, compiled by build.rs), LICENSE, README, CHANGELOG; the MSI (packaging/windows/ecliptic.wxs, WiX 3) installs per user under %LOCALAPPDATA%\Programs\ecliptic with a Start Menu shortcut

The demo archive (packaging/demo.sh) is Linux only: its record.sh needs Xvfb. It holds the demo build, demo/promo.tour (the tour it plays, packaging/demo/README.md lists the steps) and record.sh.

The one-line installers

install.sh (POSIX sh, Linux and macOS) and install.ps1 (Windows) at the root of the repository are what the README's one-liners fetch, and every release carries a copy. They follow what rustup's, cargo-dist's and Deno's installers do: options as flags (--version, --prefix, --apps, --base-url, --help; -Version and -BaseUrl in PowerShell) and as environment variables for the piped form; curl or wget, https only, TLS 1.2 or newer, a few retries; the latest release from the redirect of releases/latest (GitHub's API in PowerShell); the package verified against its .sha256 with sha256sum, shasum or openssl (Get-FileHash); a temporary directory removed on any exit; a refusal on musl (the binary needs glibc), on Windows from a Unix shell, and on an unknown processor; and a check that what was installed runs. PowerShell forces TLS 1.2 for Windows PowerShell 5.1, silences the progress bar that slows its downloads, reads the real processor from a 32-bit shell, treats msiexec's 3010 as success, and puts the install folder on the session's PATH so the command works at once. Installing is the same as by hand: the tarball's own install.sh, ditto of the .app out of the mounted .dmg (plus an ecliptic symlink in ~/.local/bin), msiexec /qn of the MSI. Nothing needs sudo, and neither script edits a shell profile: it says when the directory is not on PATH. The packaging jobs run both scripts against the packages they just built (served from dist/ over HTTP) and start what they installed, so a release is published only once its installers have worked on each platform.

The release workflow

.github/workflows/ci.yml tests every push on Ubuntu, macOS and Windows (the toolbox, Linux only, is tested on Ubuntu). On a vX.Y.Z tag it checks the tag against Cargo.toml, runs release.sh on ubuntu-22.04, ubuntu-22.04-arm, macos-latest and windows-latest, and a final job attaches everything to the GitHub release with the notes and one SHA256SUMS file. The Linux packages come from the oldest supported Ubuntu on purpose: a binary runs only on a glibc at least as new as the one it was built against, so building on 22.04 sets the floor at glibc 2.35 (Ubuntu 22.04, Debian 12, Fedora 36 and later). The binary also loads fontconfig, freetype, expat, libpng, brotli, bzip2 and zlib, which every desktop installation has.

To cut a release: set the version in Cargo.toml, move the changelog's Unreleased section under ## [X.Y.Z] - date, commit, git tag -a vX.Y.Z, push the branch and the tag.

Signing

  • macOS: release.sh signs the app ad hoc (codesign --sign -, no --deep, which is deprecated and unneeded for one executable) unless APPLE_SIGNING_IDENTITY names a Developer ID certificate in the keychain, in which case it signs with the hardened runtime and a secure timestamp, as notarization requires. With APPLE_ID, APPLE_PASSWORD (an app-specific password) and APPLE_TEAM_ID set as well, it notarizes the disk image with notarytool and staples the ticket. Put those in the repository's secrets and export them in the macOS packaging job to ship a notarized build. Until then: Apple silicon runs nothing unsigned, which the ad hoc signature covers; a browser download is quarantined, and since macOS 15 (Sequoia) the only way past Gatekeeper for it is System Settings → Privacy & Security → Open Anyway after the first refused launch (control-click → Open no longer works); a curl download, which is what install.sh does, is not quarantined and opens at once.
  • Windows: nothing signs the exe or the MSI; SmartScreen warns once on a browser download (install.ps1 unblocks the file it verified). A code-signing certificate would go in a signtool step after release.sh.

Checking a platform without it

From Linux, cargo check -p ecliptic --tests --target x86_64-pc-windows-gnu and --target aarch64-apple-darwin (after rustup target add) compile the app for those platforms without linking, which catches a Linux assumption. With MinGW installed, cargo build --release --target x86_64-pc-windows-gnu links a real ecliptic.exe, and Wine runs it: wine target/x86_64-pc-windows-gnu/release/ecliptic.exe --version, or the whole window on a private X display.