mirror of
https://github.com/priyanshujain/margin-calendar.git
synced 2026-10-02 11:07:04 +00:00
replace the aur package with a nix flake
This commit is contained in:
1 parent
958931f5ef
commit
a88055cbbd
11 files changed
+231
-107
No files matched your search
@@ -68,3 +68,14 @@ jobs:
|
||||
- name: Test
|
||||
working-directory: src-tauri
|
||||
run: cargo test
|
||||
|
||||
# The flake at whatever release nix/release.json pins. A broken flake or lock, or a deb that no
|
||||
# longer patches against current nixpkgs, shows up here rather than at the next release.
|
||||
nix:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v7
|
||||
|
||||
- uses: cachix/install-nix-action@v31
|
||||
|
||||
- run: nix build .#margin-calendar --print-build-logs
|
||||
@@ -180,72 +180,57 @@ jobs:
|
||||
done
|
||||
gh release edit "$TAG" --repo "$REPO" --draft=false --latest
|
||||
|
||||
# Arch gets its own package rather than the AppImage. The AppImage carries Ubuntu's GTK stack,
|
||||
# which cannot talk to a modern Wayland compositor and silently falls back to Xwayland; a package
|
||||
# linked against the system webkit2gtk runs as a native Wayland client. Runs after publish so it
|
||||
# Nix is the Linux package. The AppImage carries Ubuntu's GTK stack, which cannot talk to a modern
|
||||
# Wayland compositor and silently falls back to Xwayland; the Nix package relinks the published deb
|
||||
# against nixpkgs' webkit2gtk and runs as a native Wayland client. Runs after publish so the flake
|
||||
# can only ever point at a release that survived the manifest check.
|
||||
aur:
|
||||
nix:
|
||||
needs: [prepare, publish]
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
# The tag, not main, so the template and the licence are the ones this release shipped.
|
||||
# main rather than the tag: the pin lands on main, and the tag was cut before the artifact
|
||||
# it needs the hash of existed.
|
||||
- uses: actions/checkout@v7
|
||||
with:
|
||||
ref: ${{ needs.prepare.outputs.tag }}
|
||||
ref: main
|
||||
|
||||
- name: Render the PKGBUILD for this release
|
||||
- name: Pin the flake to this release
|
||||
env:
|
||||
VERSION: ${{ needs.prepare.outputs.version }}
|
||||
REPO: ${{ github.repository }}
|
||||
run: |
|
||||
URL="https://github.com/$REPO/releases/download/v$VERSION/Margin.Calendar_${VERSION}_amd64.deb"
|
||||
# From the published asset, so the checksum is of the artifact users will actually fetch.
|
||||
# From the published asset, so the hash is of the artifact users will actually fetch.
|
||||
curl -fsSL --retry 3 -o package.deb "$URL"
|
||||
SHA=$(sha256sum package.deb | cut -d' ' -f1)
|
||||
# The PKGBUILD fetches the licence from the tag, so checksum the copy at that same tag.
|
||||
LICENSE_SHA=$(sha256sum LICENSE | cut -d' ' -f1)
|
||||
sed -e "s/@VERSION@/$VERSION/g" \
|
||||
-e "s/@SHA256@/$SHA/g" \
|
||||
-e "s/@LICENSE_SHA256@/$LICENSE_SHA/g" \
|
||||
packaging/aur/PKGBUILD.in > PKGBUILD
|
||||
echo "pkgver $VERSION, deb $SHA, licence $LICENSE_SHA"
|
||||
HASH="sha256-$(openssl dgst -sha256 -binary package.deb | base64)"
|
||||
jq -n --arg v "$VERSION" --arg h "$HASH" '{version: $v, hash: $h}' > nix/release.json
|
||||
cat nix/release.json
|
||||
|
||||
- name: Generate .SRCINFO
|
||||
# makepkg is Arch-only and refuses to run as root, hence the container. It runs as the
|
||||
# runner's own uid so nothing in the bind-mounted checkout changes owner; chowning it to a
|
||||
# container user left the workspace unwritable for the push step. --printsrcinfo parses the
|
||||
# PKGBUILD, it does not build anything.
|
||||
run: |
|
||||
docker run --rm --user "$(id -u):$(id -g)" -e HOME=/tmp -v "$PWD:/w" -w /w \
|
||||
archlinux:base-devel makepkg --printsrcinfo > .SRCINFO
|
||||
cat .SRCINFO
|
||||
- uses: cachix/install-nix-action@v31
|
||||
|
||||
- name: Push to the AUR
|
||||
# Building it is the check: a wrong hash, a library autoPatchelf cannot find or a broken flake
|
||||
# stops here rather than on someone's machine.
|
||||
- name: Build the package
|
||||
run: nix build .#margin-calendar --print-build-logs
|
||||
|
||||
- name: Commit the pin
|
||||
env:
|
||||
AUR_SSH_PRIVATE_KEY: ${{ secrets.AUR_SSH_PRIVATE_KEY }}
|
||||
VERSION: ${{ needs.prepare.outputs.version }}
|
||||
run: |
|
||||
if [ -z "$AUR_SSH_PRIVATE_KEY" ]; then
|
||||
echo "::warning::AUR_SSH_PRIVATE_KEY is not set, so the AUR package was built but not published. The release itself is unaffected."
|
||||
exit 0
|
||||
fi
|
||||
mkdir -p ~/.ssh && chmod 700 ~/.ssh
|
||||
printf '%s\n' "$AUR_SSH_PRIVATE_KEY" > ~/.ssh/aur
|
||||
chmod 600 ~/.ssh/aur
|
||||
ssh-keyscan -t ed25519,rsa aur.archlinux.org >> ~/.ssh/known_hosts 2>/dev/null
|
||||
export GIT_SSH_COMMAND="ssh -i ~/.ssh/aur -o IdentitiesOnly=yes"
|
||||
git clone ssh://[email protected]/margin-calendar-bin.git aur
|
||||
cp PKGBUILD .SRCINFO aur/
|
||||
cd aur
|
||||
# A package that does not exist yet clones as an empty repo, where the local branch name
|
||||
# is whatever git defaults to. The AUR only accepts master.
|
||||
git checkout -B master
|
||||
git config user.name "github-actions[bot]"
|
||||
git config user.email "github-actions[bot]@users.noreply.github.com"
|
||||
git add PKGBUILD .SRCINFO
|
||||
if git diff --cached --quiet; then
|
||||
echo "AUR is already at this version, nothing to push."
|
||||
exit 0
|
||||
fi
|
||||
git commit -m "margin-calendar-bin $VERSION"
|
||||
git push origin master
|
||||
git add nix/release.json
|
||||
git commit -m "point the nix package at v$VERSION"
|
||||
for attempt in 1 2 3 4 5; do
|
||||
git fetch origin main
|
||||
git rebase origin/main
|
||||
if git push origin HEAD:main; then
|
||||
break
|
||||
fi
|
||||
if [ "$attempt" = "5" ]; then
|
||||
echo "::error::main kept advancing; could not push the nix pin after 5 attempts. The release is published; rerun this job."
|
||||
exit 1
|
||||
fi
|
||||
echo "main advanced; rebasing and retrying ($attempt)…"
|
||||
sleep 3
|
||||
done
|
||||
@@ -42,3 +42,7 @@ xcuserdata/
|
||||
# Screenshots & Playwright MCP artifacts
|
||||
.playwright-mcp/
|
||||
/*.png
|
||||
|
||||
# Nix build output
|
||||
/result
|
||||
/result-*
|
||||
@@ -6,9 +6,10 @@ fits without scrolling, and on a desktop the whole thing is drivable from the ke
|
||||
It is a sibling to [margin](https://github.com/priyanshujain/margin) and shares its stack and its
|
||||
visual language.
|
||||
|
||||
`just install` builds it and installs it on the machine you are on. Setup and the Google OAuth
|
||||
client it needs are in [docs/setup.md](docs/setup.md), and the extra clients a phone build needs
|
||||
are in [docs/mobile.md](docs/mobile.md). How releases are cut is in
|
||||
[docs/release.md](docs/release.md). The product decisions are in [docs/design.md](docs/design.md),
|
||||
how it is built is in [docs/architecture.md](docs/architecture.md), and the conventions it follows
|
||||
are in [docs/conventions.md](docs/conventions.md).
|
||||
`just install` builds it and installs it on the machine you are on. On Linux,
|
||||
`nix profile install github:priyanshujain/margin-calendar` installs the released build instead.
|
||||
Setup and the Google OAuth client it needs are in [docs/setup.md](docs/setup.md), and the extra
|
||||
clients a phone build needs are in [docs/mobile.md](docs/mobile.md). How releases are cut and how
|
||||
the Nix package is made are in [docs/release.md](docs/release.md). The product decisions are in
|
||||
[docs/design.md](docs/design.md), how it is built is in [docs/architecture.md](docs/architecture.md),
|
||||
and the conventions it follows are in [docs/conventions.md](docs/conventions.md).
|
||||
@@ -133,7 +133,7 @@ Closing the window on macOS hides it rather than quitting, the way WhatsApp and
|
||||
process stays in the Dock with sync running, a Dock click brings the window back, and Cmd+Q
|
||||
quits. Both halves live in `lib.rs`. Linux has no traffic lights, so that padding is
|
||||
conditional, and closing the window there quits. Linux builds need `libwebkit2gtk-4.1-dev` and
|
||||
ship as AppImage and deb.
|
||||
ship as AppImage and deb, and the deb is what the Nix package in `nix/package.nix` relinks.
|
||||
|
||||
## Order of work
|
||||
|
||||
|
||||
+34
-14
@@ -36,27 +36,47 @@ targets, at which point the publish gate wants `windows-x86_64` too.
|
||||
Phones do not come from this pipeline at all. The store is their update channel, and what building
|
||||
for one takes is in [mobile.md](mobile.md).
|
||||
|
||||
## Arch
|
||||
## Linux
|
||||
|
||||
Arch gets its own package, `margin-calendar-bin` on the AUR, pushed by the release workflow after
|
||||
the manifest check passes. It is worth the extra moving part: the AppImage bundles Ubuntu's GTK
|
||||
stack, and a bundled `libwayland-client` cannot talk to a current compositor, so on Hyprland the
|
||||
AppImage silently falls back to Xwayland. The packaged build links against the system
|
||||
Linux installs come from Nix rather than from the AppImage. The AppImage bundles Ubuntu's GTK
|
||||
stack, and a bundled `libwayland-client` cannot talk to a current compositor, so on Hyprland it
|
||||
silently falls back to Xwayland. The Nix package relinks the published `.deb` against nixpkgs' own
|
||||
`webkit2gtk-4.1` and runs as a native Wayland client.
|
||||
|
||||
Installing, and later updating:
|
||||
|
||||
```
|
||||
nix profile install github:priyanshujain/margin-calendar
|
||||
nix profile upgrade margin-calendar
|
||||
```
|
||||
|
||||
On NixOS or under home-manager, add `github:priyanshujain/margin-calendar` as a flake input and
|
||||
either put `margin-calendar.packages.x86_64-linux.default` in the package list or apply
|
||||
`margin-calendar.overlays.default` and use `pkgs.margin-calendar`. Updating is then
|
||||
`nix flake update margin-calendar` and a rebuild.
|
||||
|
||||
"Check for updates" inside a Nix install still checks. It reports the newer version and the
|
||||
upgrade command rather than installing anything, because the package's wrapper sets
|
||||
`MARGIN_CALENDAR_PACKAGED_BY=nix` and the app asks for that before it would touch its own binary,
|
||||
which in the store it could not replace anyway.
|
||||
|
||||
It is a binary package by necessity rather than laziness. The Google OAuth client is embedded at
|
||||
compile time from a file that is deliberately not in the repo, so anything built from source on
|
||||
someone else's machine would run and then tell them Google Calendar is not set up. The PKGBUILD
|
||||
therefore repackages the published `.deb`, whose payload is already a normal `/usr` tree.
|
||||
someone else's machine would run and then tell them Google Calendar is not set up.
|
||||
`nix/package.nix` therefore unpacks the published `.deb`, whose payload is already a normal `/usr`
|
||||
tree, and `autoPatchelfHook` points its libraries at nixpkgs.
|
||||
|
||||
`packaging/aur/PKGBUILD.in` is the template. The workflow fills in the version and the sha256 of
|
||||
the artifact that was actually published, generates `.SRCINFO` with `makepkg` in an Arch container,
|
||||
and pushes to `ssh://[email protected]/margin-calendar-bin.git` using `AUR_SSH_PRIVATE_KEY`.
|
||||
Without that secret the job renders the package, says so, and does not fail the release.
|
||||
`nix/release.json` is the pin: the version and the hash of the `.deb` that was actually published.
|
||||
The `nix` job in the release workflow writes it after the manifest check passes, builds the package
|
||||
once to prove the pin is good, and commits it to main. That commit is what Nix users consume:
|
||||
`github:priyanshujain/margin-calendar` means main, and main means the latest release that built. A
|
||||
tag's own flake still points at the release before it, because the tag is cut before the artifact
|
||||
exists. If the job fails, the release is out and Nix stays a version behind until the job is rerun.
|
||||
|
||||
The `license=('custom')` line is a placeholder for the fact that this repo has no licence file at
|
||||
all. Nothing stops the package publishing, but a package on the AUR that nobody has licensed is
|
||||
worth fixing before anyone else builds on it.
|
||||
The flake is x86_64-linux only, which is the one Linux target the release builds. `flake.lock`
|
||||
pins nixpkgs for anyone installing through the flake directly; the overlay uses whatever nixpkgs
|
||||
the host already has. CI builds the package on every push, so a nixpkgs bump that breaks the
|
||||
patching shows up before a release does.
|
||||
|
||||
## What the build needs
|
||||
|
||||
|
||||
Generated
+27
@@ -0,0 +1,27 @@
|
||||
{
|
||||
"nodes": {
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1788316716,
|
||||
"narHash": "sha256-bc7rSpXIdn9QWGNqfWcPZWOhEVF8NoeAZkWq0XWnf/k=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "3ed67ec0a4d3c7ab4ae1f04f8ee8df07bfa506a2",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "NixOS",
|
||||
"ref": "nixos-unstable",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"root": {
|
||||
"inputs": {
|
||||
"nixpkgs": "nixpkgs"
|
||||
}
|
||||
}
|
||||
},
|
||||
"root": "root",
|
||||
"version": 7
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
{
|
||||
description = "Margin Calendar, a calendar for Google Calendar";
|
||||
|
||||
inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
|
||||
|
||||
outputs =
|
||||
{ self, nixpkgs }:
|
||||
let
|
||||
system = "x86_64-linux";
|
||||
pkgs = nixpkgs.legacyPackages.${system};
|
||||
in
|
||||
{
|
||||
overlays.default = final: prev: {
|
||||
margin-calendar = final.callPackage ./nix/package.nix { };
|
||||
};
|
||||
|
||||
packages.${system} = {
|
||||
margin-calendar = pkgs.callPackage ./nix/package.nix { };
|
||||
default = self.packages.${system}.margin-calendar;
|
||||
};
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
# The Linux package: the deb the release workflow published, relinked against nixpkgs' own GTK and
|
||||
# WebKit so it runs as a native Wayland client. It is a binary package by necessity: the Google
|
||||
# OAuth client is embedded at compile time from a file that is deliberately not in the repo, so
|
||||
# anything built from source here would run and then say Google Calendar is not set up.
|
||||
{
|
||||
lib,
|
||||
stdenv,
|
||||
fetchurl,
|
||||
dpkg,
|
||||
autoPatchelfHook,
|
||||
wrapGAppsHook3,
|
||||
cairo,
|
||||
dbus,
|
||||
gdk-pixbuf,
|
||||
glib,
|
||||
glib-networking,
|
||||
gsettings-desktop-schemas,
|
||||
gtk3,
|
||||
libsoup_3,
|
||||
webkitgtk_4_1,
|
||||
xdg-utils,
|
||||
}:
|
||||
|
||||
let
|
||||
release = lib.importJSON ./release.json;
|
||||
in
|
||||
stdenv.mkDerivation {
|
||||
pname = "margin-calendar";
|
||||
inherit (release) version;
|
||||
|
||||
src = fetchurl {
|
||||
url = "https://github.com/priyanshujain/margin-calendar/releases/download/v${release.version}/Margin.Calendar_${release.version}_amd64.deb";
|
||||
inherit (release) hash;
|
||||
};
|
||||
|
||||
unpackPhase = ''
|
||||
runHook preUnpack
|
||||
dpkg-deb -x $src .
|
||||
runHook postUnpack
|
||||
'';
|
||||
|
||||
nativeBuildInputs = [
|
||||
dpkg
|
||||
autoPatchelfHook
|
||||
wrapGAppsHook3
|
||||
];
|
||||
|
||||
buildInputs = [
|
||||
cairo
|
||||
dbus
|
||||
gdk-pixbuf
|
||||
glib
|
||||
glib-networking
|
||||
gsettings-desktop-schemas
|
||||
gtk3
|
||||
libsoup_3
|
||||
webkitgtk_4_1
|
||||
];
|
||||
|
||||
installPhase = ''
|
||||
runHook preInstall
|
||||
mkdir -p $out
|
||||
cp -r usr/bin usr/share $out/
|
||||
mv "$out/share/applications/Margin Calendar.desktop" $out/share/applications/margin-calendar.desktop
|
||||
runHook postInstall
|
||||
'';
|
||||
|
||||
# The app opens the Google consent page and "Report an issue" through xdg-open. The variable is
|
||||
# how it knows the store owns the binary, so "Check for updates" points at Nix instead of trying
|
||||
# to replace itself.
|
||||
preFixup = ''
|
||||
gappsWrapperArgs+=(
|
||||
--prefix PATH : ${lib.makeBinPath [ xdg-utils ]}
|
||||
--set MARGIN_CALENDAR_PACKAGED_BY nix
|
||||
)
|
||||
'';
|
||||
|
||||
meta = {
|
||||
description = "A calendar for Google Calendar";
|
||||
longDescription = "A calendar where the grid owns the window and the day always fits without scrolling.";
|
||||
homepage = "https://github.com/priyanshujain/margin-calendar";
|
||||
license = lib.licenses.mit;
|
||||
sourceProvenance = [ lib.sourceTypes.binaryNativeCode ];
|
||||
platforms = [ "x86_64-linux" ];
|
||||
mainProgram = "margin-calendar";
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"version": "0.0.4",
|
||||
"hash": "sha256-ZYrpxD0/7AxIeBMmYHufZU0I6/m2JWPMMSBk4CkJWd8="
|
||||
}
|
||||
@@ -1,37 +0,0 @@
|
||||
# Maintainer: PJ <[email protected]>
|
||||
|
||||
# The template the release workflow renders. @VERSION@ and @SHA256@ are filled in from the release
|
||||
# that has just published, so the PKGBUILD on the AUR always points at an artifact that exists.
|
||||
#
|
||||
# A binary package rather than one built from source, and that is forced rather than lazy: the
|
||||
# Google OAuth client is embedded at compile time from a file that is not in the repo, so anything
|
||||
# built from source on a stranger's machine runs and then says Google Calendar is not set up.
|
||||
|
||||
pkgname=margin-calendar-bin
|
||||
pkgver=@VERSION@
|
||||
pkgrel=1
|
||||
pkgdesc="A calendar for Google Calendar, where the grid owns the window and the day fits without scrolling"
|
||||
arch=('x86_64')
|
||||
url="https://github.com/priyanshujain/margin-calendar"
|
||||
license=('MIT')
|
||||
depends=('webkit2gtk-4.1' 'gtk3')
|
||||
provides=('margin-calendar')
|
||||
conflicts=('margin-calendar')
|
||||
# Prebuilt and already linked: stripping it again buys nothing and risks the binary.
|
||||
options=('!strip' '!debug')
|
||||
source=("${pkgname}-${pkgver}.deb::${url}/releases/download/v${pkgver}/Margin.Calendar_${pkgver}_amd64.deb"
|
||||
"LICENSE-${pkgver}::https://raw.githubusercontent.com/priyanshujain/margin-calendar/v${pkgver}/LICENSE")
|
||||
noextract=("${pkgname}-${pkgver}.deb")
|
||||
sha256sums=('@SHA256@'
|
||||
'@LICENSE_SHA256@')
|
||||
|
||||
package() {
|
||||
bsdtar -xOf "${pkgname}-${pkgver}.deb" data.tar.gz | bsdtar -xf - -C "${pkgdir}"
|
||||
# The bundler names it after the product, spaces and all. Everything that reads this directory
|
||||
# copes with that, and nothing that reads it enjoys it.
|
||||
mv "${pkgdir}/usr/share/applications/Margin Calendar.desktop" \
|
||||
"${pkgdir}/usr/share/applications/margin-calendar.desktop"
|
||||
# MIT is not one of the licences Arch keeps in /usr/share/licenses/common, so every package
|
||||
# under it has to carry its own copy.
|
||||
install -Dm644 "LICENSE-${pkgver}" "${pkgdir}/usr/share/licenses/${pkgname}/LICENSE"
|
||||
}
|
||||
Reference in new issue
Block a user