{ description = "Noisebell - door monitor system"; inputs = { nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; agenix = { url = "github:ryantm/agenix"; inputs.nixpkgs.follows = "nixpkgs"; }; crane.url = "github:ipetkov/crane"; rust-overlay = { url = "github:oxalica/rust-overlay"; inputs.nixpkgs.follows = "nixpkgs"; }; }; outputs = { self, nixpkgs, agenix, crane, rust-overlay, }: let system = "x86_64-linux"; pkgs = import nixpkgs { inherit system; overlays = [ rust-overlay.overlays.default ]; }; rustToolchain = pkgs.rust-bin.stable.latest.default; craneLib = (crane.mkLib pkgs).overrideToolchain rustToolchain; src = pkgs.lib.cleanSourceWith { src = ./.; filter = path: type: (builtins.match ".*\.png$" path != null) || (craneLib.filterCargoSources path type); }; remoteArgs = { inherit src; pname = "noisebell"; version = "0.1.0"; strictDeps = true; doCheck = false; }; remoteArtifacts = craneLib.buildDepsOnly remoteArgs; buildRemoteMember = name: craneLib.buildPackage ( remoteArgs // { cargoArtifacts = remoteArtifacts; cargoExtraArgs = "-p ${name}"; } ); noisebell-cache = buildRemoteMember "noisebell-cache"; noisebell-discord = buildRemoteMember "noisebell-discord"; crossPkgs = import nixpkgs { inherit system; crossSystem.config = "aarch64-unknown-linux-gnu"; overlays = [ rust-overlay.overlays.default ]; }; piRustToolchain = pkgs.rust-bin.stable.latest.default.override { targets = [ "aarch64-unknown-linux-gnu" ]; }; piCraneLib = (crane.mkLib pkgs).overrideToolchain piRustToolchain; piArgs = { inherit src; pname = "noisebell-pi"; version = "0.1.0"; strictDeps = true; doCheck = false; CARGO_BUILD_TARGET = "aarch64-unknown-linux-gnu"; CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER = "${crossPkgs.stdenv.cc.targetPrefix}cc"; TARGET_CC = "${crossPkgs.stdenv.cc.targetPrefix}cc"; CC_aarch64_unknown_linux_gnu = "${crossPkgs.stdenv.cc.targetPrefix}cc"; HOST_CC = "${pkgs.stdenv.cc.nativePrefix}cc"; depsBuildBuild = [ crossPkgs.stdenv.cc ]; cargoExtraArgs = "-p noisebell"; }; piArtifacts = piCraneLib.buildDepsOnly piArgs; noisebell-pi = piCraneLib.buildPackage ( piArgs // { cargoArtifacts = piArtifacts; } ); flash-pi-sd = pkgs.writeShellApplication { name = "flash-pi-sd"; runtimeInputs = [ agenix.packages.${system}.default pkgs.coreutils pkgs.nix pkgs.parted pkgs.systemd pkgs.util-linux pkgs.zstd ]; text = '' set -euo pipefail PARTPROBE=${pkgs.parted}/bin/partprobe MOUNT=${pkgs.util-linux}/bin/mount UMOUNT=${pkgs.util-linux}/bin/umount MOUNTPOINT=${pkgs.util-linux}/bin/mountpoint FINDMNT=${pkgs.util-linux}/bin/findmnt UDEVADM=${pkgs.systemd}/bin/udevadm ZSTD=${pkgs.zstd}/bin/zstd if [ "$#" -ne 1 ]; then echo "usage: flash-pi-sd /dev/sdX" >&2 exit 1 fi device="$1" flake_path=${builtins.toString ./.} image_link="$(mktemp -u /tmp/noisebell-sd-image.XXXXXX)" mount_dir="$(mktemp -d)" secrets_dir="${builtins.toString ./secrets}" key_name="bootstrap-identity.age" rules_file="${builtins.toString ./secrets/secrets.nix}" cleanup() { if "$MOUNTPOINT" -q "$mount_dir"; then sudo "$UMOUNT" "$mount_dir" fi rm -rf "$mount_dir" rm -f "$image_link" } trap cleanup EXIT if [ ! -b "$device" ]; then echo "not a block device: $device" >&2 exit 1 fi boot_part="''${device}1" case "$device" in *[0-9]) boot_part="''${device}p1" ;; esac echo "Building bootstrap SD image..." nix build "$flake_path#nixosConfigurations.bootstrap.config.system.build.sdImage" -o "$image_link" image="$(echo "$image_link"/sd-image/*.img*)" if [ ! -f "$image" ]; then echo "failed to locate SD image under $image_link/sd-image" >&2 exit 1 fi echo "Flashing $image to $device..." if [ "''${image##*.}" = "zst" ]; then "$ZSTD" -d --stdout "$image" | sudo dd of="$device" bs=4M conv=fsync status=progress else sudo dd if="$image" of="$device" bs=4M conv=fsync status=progress fi sync sudo "$PARTPROBE" "$device" sudo "$UDEVADM" settle if "$FINDMNT" -rn "$boot_part" >/dev/null 2>&1; then sudo "$UMOUNT" "$boot_part" fi echo "Installing bootstrap age identity onto $boot_part..." sudo "$MOUNT" "$boot_part" "$mount_dir" ( cd "$secrets_dir" RULES="$rules_file" agenix -d "$key_name" ) | sudo tee "$mount_dir/noisebell-bootstrap.agekey" >/dev/null sudo chmod 600 "$mount_dir/noisebell-bootstrap.agekey" sync echo "Done. You can now move the card to the Pi and boot it." ''; }; in { packages.${system} = { inherit noisebell-cache noisebell-discord flash-pi-sd; default = noisebell-cache; }; packages.aarch64-linux = { noisebell = noisebell-pi; default = noisebell-pi; }; nixosModules = { cache = import ./remote/cache-service/module.nix noisebell-cache; discord = import ./remote/discord-bot/module.nix noisebell-discord; default = { imports = [ (import ./remote/cache-service/module.nix noisebell-cache) (import ./remote/discord-bot/module.nix noisebell-discord) ]; }; }; nixosConfigurations.pi = nixpkgs.lib.nixosSystem { system = "aarch64-linux"; modules = [ agenix.nixosModules.default (import ./pi/module.nix { pkg = noisebell-pi; rev = self.shortRev or "dirty"; }) ./pi/configuration.nix ./pi/hardware-configuration.nix ]; }; nixosConfigurations.bootstrap = nixpkgs.lib.nixosSystem { system = "aarch64-linux"; modules = [ agenix.nixosModules.default (import ./pi/module.nix { pkg = noisebell-pi; rev = self.shortRev or "dirty"; }) ./pi/bootstrap.nix ]; }; devShells.${system}.default = craneLib.devShell { packages = [ flash-pi-sd pkgs.nix pkgs.parted pkgs.rust-analyzer pkgs.systemd pkgs.util-linux pkgs.zstd agenix.packages.${system}.default ]; }; apps.${system}.flash-pi-sd = { type = "app"; program = "${flash-pi-sd}/bin/flash-pi-sd"; }; }; }