{ description = "Aggregate and sync events between CalDAV, Google Calendar and iCal feeds"; inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; # pimsync is built from source rather than taken from nixpkgs, which trails # the releases calcalist has been read against. Being an input rather than a # `fetchFromSourcehut` call makes it substitutable: a fork or a working tree # can be swapped in at install time with # `--override-input pimsync-src git+file:///path/to/pimsync`, without the # committed flake naming anything that exists on one machine only. # # The rev is the commit v0.6.0 points at: nix cannot peel an annotated tag, # and resolving the ref alone fails. inputs.pimsync-src = { url = "git+https://git.sr.ht/~whynothugo/pimsync?ref=refs/tags/v0.6.0&rev=a111a44cd9e65c031ce9801fdced912057e4a4a0"; flake = false; }; outputs = { self, nixpkgs, pimsync-src, }: let systems = [ "x86_64-linux" "aarch64-linux" ]; forEachSystem = nixpkgs.lib.genAttrs systems; cargoToml = builtins.fromTOML (builtins.readFile ./Cargo.toml); in { packages = forEachSystem ( system: let pkgs = import nixpkgs { inherit system; }; # pimsync's Cargo.toml carries no version — the binary learns its own # from `git describe`, which has nothing to describe inside the # store. So it is assembled: the newest changelog heading for the # release, and the input's revision for the tree it came from. That # second half is what distinguishes an overridden fork from the # upstream release it descends from, and a suffixed version is # pimsync's own convention for a build off a tag. pimsyncVersion = let lines = pkgs.lib.splitString "\n" (builtins.readFile "${pimsync-src}/CHANGELOG.rst"); isRelease = line: builtins.match "v[0-9]+\\.[0-9]+\\.[0-9]+" line != null; newest = pkgs.lib.findFirst isRelease (throw "no release heading found in pimsync's CHANGELOG.rst") lines; release = pkgs.lib.removePrefix "v" newest; in "${release}-${pimsync-src.dirtyShortRev or pimsync-src.shortRev}"; pimsync = pkgs.rustPlatform.buildRustPackage { pname = "pimsync"; version = pimsyncVersion; src = pimsync-src; cargoLock = { lockFile = "${pimsync-src}/Cargo.lock"; # pimsync pins a few dependencies to git revisions, and vstorage # — which the fork swaps in — keeps libdav and libjmap as # submodules of its own. Naming those revisions in # `outputHashes` fetches them without submodules and vendors # two empty directories; the builtin fetcher recurses properly. # The revisions come from the lock file, so evaluation stays # pure, and there is no hash here to go stale when a fork moves. allowBuiltinFetchGit = true; }; env.PIMSYNC_VERSION = pimsyncVersion; nativeBuildInputs = [ pkgs.pkg-config ]; buildInputs = [ pkgs.sqlite ]; doCheck = false; }; in rec { calcalist = pkgs.rustPlatform.buildRustPackage { pname = "calcalist"; version = cargoToml.package.version; src = pkgs.lib.cleanSource ./.; cargoLock.lockFile = ./Cargo.lock; # tests/caldav.rs spins up radicale and pimsync as real # processes; it's a dev-time integration gate (devbox run # check), not something a package build should re-run. doCheck = false; nativeBuildInputs = [ pkgs.makeWrapper ]; # Ensures the pimsync calcalist finds is the one it was tested # against, regardless of what else is on the user's PATH. postInstall = '' wrapProgram $out/bin/calcalist \ --prefix PATH : ${pkgs.lib.makeBinPath [ pimsync ]} ''; meta = { description = cargoToml.package.description; license = pkgs.lib.licenses.mit; mainProgram = "calcalist"; platforms = pkgs.lib.platforms.linux; }; }; default = calcalist; } ); apps = forEachSystem (system: rec { calcalist = { type = "app"; program = "${self.packages.${system}.calcalist}/bin/calcalist"; }; default = calcalist; }); }; }