whiskers.git / flake.nix
1{
2  description = "whiskers: Rust core + Android shell for a talking cat on a Fire tablet";
3
4  inputs = {
5    nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
6  };
7
8  outputs =
9    { nixpkgs, ... }:
10    let
11      system = "x86_64-linux";
12      pkgs = nixpkgs.legacyPackages.${system};
13
14      # celld, Deno Land's self-hosted Durable Objects host, from its release binary: the
15      # asset's sha256 is the one GitHub publishes for it, and the build attests to commit f2bf648
16      # (`gh attestation verify celld-x86_64-unknown-linux-gnu.gz --repo denoland/celld`, 2026-10-05).
17      # Not in nixpkgs. Used by `celld dev` for backend/worker.
18      celld = pkgs.stdenv.mkDerivation rec {
19        pname = "celld";
20        version = "0.6.1";
21        src = pkgs.fetchurl {
22          url = "https://github.com/denoland/celld/releases/download/v${version}/celld-x86_64-unknown-linux-gnu.gz";
23          hash = "sha256-eaglPP9dTopKn3omEeOTOQ9/6QJfAOiEZ4dbAHxEhms=";
24        };
25        dontUnpack = true;
26        nativeBuildInputs = [ pkgs.autoPatchelfHook ];
27        buildInputs = [ pkgs.stdenv.cc.cc.lib ];
28        installPhase = ''
29          install -d $out/bin
30          gzip -dc $src > $out/bin/celld
31          chmod 755 $out/bin/celld
32        '';
33        meta.mainProgram = "celld";
34      };
35
36      # whiskersd, the service the tablet talks to, built from the workspace so nixos-config can run it as a real
37      # service (modules/whiskers/service.nix there). Only what the build reads is in the source: a change to the
38      # Android app, the website or the docs leaves this derivation, and so the running service, alone.
39      #
40      # The jevcrates submodule is in the source only when this flake is fetched with submodules, so a consumer takes
41      # it as `git+file:///home/nixos/whiskers?submodules=1` and a local build is `nix build '.?submodules=1#whiskersd'`.
42      # Without them the build stops at the first path dependency instead of building something else.
43      mkWhiskersd = rustPlatform: rustPlatform.buildRustPackage {
44        pname = "whiskersd";
45        version = "0.0.0";
46        src = pkgs.lib.fileset.toSource {
47          root = ./.;
48          fileset = pkgs.lib.fileset.unions [
49            ./Cargo.toml
50            ./Cargo.lock
51            ./crates
52            ./third-party
53          ];
54        };
55        cargoLock = {
56          lockFile = ./Cargo.lock;
57          # jevcrates takes rustls-rustcrypto from git (no release has the version it needs); the hash is the
58          # fetched tree, so it moves with the rev pinned in Cargo.lock.
59          outputHashes."rustls-rustcrypto-0.0.2-alpha" = "sha256-tkaRZgDoaP0cuajGcfNvayKh2xgXxhJ6YXLCrSZ3JUE=";
60        };
61        cargoBuildFlags = [ "-p" "whiskersd" ];
62        cargoTestFlags = [ "-p" "whiskersd" ];
63        meta.mainProgram = "whiskersd";
64      };
65      whiskersd = mkWhiskersd pkgs.rustPlatform;
66      # The same, linked statically against musl, so one file runs on any x86-64 Linux with no nix store: this is
67      # what a release carries. `nix build '.?submodules=1#whiskersd-static'`.
68      whiskersd-static = mkWhiskersd pkgs.pkgsStatic.rustPlatform;
69    in
70    {
71      packages.${system} = { inherit celld whiskersd whiskersd-static; };
72
73      devShells.${system} = rec {
74        # The toolchain is mise's, written in mise.toml (Rust, the Android SDK and NDK, JDK, Gradle, wasm-bindgen,
75        # wrangler, hk, pitchfork, fnox, usage); anyone can use it without nix: see README.md. This shell only wraps
76        # it: mise itself, plus the native things a downloaded toolchain cannot bring (a C compiler and linker,
77        # pkg-config, OpenSSL for crates that link it, curl, unzip and bzip2 for the fetch scripts, git).
78        #
79        # Entering it puts whatever `mise install` has already installed on PATH (it does not install anything
80        # itself: the first install is large). Downloaded programs are ordinary dynamically linked binaries; this
81        # machine's NixOS runs them through nix-ld (NIX_LD below tells nix-ld where its libraries are). Where
82        # nix-ld is not enabled, use `nix develop .#fhs`.
83        default = pkgs.mkShell {
84          packages = [
85            pkgs.mise
86            pkgs.gcc
87            pkgs.pkg-config
88            pkgs.openssl
89            pkgs.curl
90            pkgs.unzip
91            pkgs.bzip2
92            pkgs.git
93            pkgs.cacert
94          ];
95          NIX_LD_LIBRARY_PATH = pkgs.lib.makeLibraryPath [ pkgs.stdenv.cc.cc.lib pkgs.zlib pkgs.openssl ];
96          shellHook = ''
97            root="$(git rev-parse --show-toplevel 2>/dev/null || pwd)"
98            if [ -f "$root/mise.toml" ]; then
99              export MISE_TRUSTED_CONFIG_PATHS="$root''${MISE_TRUSTED_CONFIG_PATHS:+:$MISE_TRUSTED_CONFIG_PATHS}"
100              eval "$(mise env -s bash 2>/dev/null)" || true
101            fi
102          '';
103        };
104
105        # The same, inside an FHS root (bubblewrap), for a machine without nix-ld: downloaded programs find
106        # /lib64/ld-linux-x86-64.so.2 and the usual libraries where they expect them.
107        fhs = (pkgs.buildFHSEnv {
108          name = "whiskers-fhs";
109          targetPkgs = p: [
110            p.mise p.gcc p.pkg-config p.openssl p.curl p.unzip p.bzip2 p.git p.cacert p.zlib p.stdenv.cc.cc.lib
111          ];
112          runScript = "bash";
113        }).env;
114
115        # The names these shells had before the toolchain moved to mise.toml.
116        web = default;
117        backend = default;
118        android = default;
119        android-emu = default;
120      };
121    };
122}