{ description = "AIP service"; inputs = { nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; crane.url = "github:ipetkov/crane"; fenix = { url = "github:nix-community/fenix"; inputs.nixpkgs.follows = "nixpkgs"; inputs.rust-analyzer-src.follows = ""; }; }; outputs = { self, nixpkgs, crane, fenix }: let systems = [ "x86_64-linux" ]; forAllSystems = nixpkgs.lib.genAttrs systems; mkPackagesForSystem = system: let pkgs = import nixpkgs { inherit system; config = { allowUnfree = true; }; }; # Configure crane with stable Rust toolchain craneLib = (crane.mkLib pkgs).overrideToolchain fenix.packages.${system}.stable.toolchain; # Project source for crane src = pkgs.lib.cleanSourceWith { src = ./.; filter = path: type: (craneLib.filterCargoSources path type) || (pkgs.lib.hasInfix "/templates/" path) || (pkgs.lib.hasInfix "/static/" path) || (pkgs.lib.hasSuffix "/templates" path) || (pkgs.lib.hasSuffix "/static" path) || (pkgs.lib.hasInfix "/migrations/" path) || (pkgs.lib.hasSuffix "/migrations" path); }; commonArgs = { inherit src; version = "0.1.0"; strictDeps = true; pname = "aip"; name = "aip"; buildInputs = with pkgs; [ openssl pkg-config ]; nativeBuildInputs = with pkgs; [ pkg-config openssl.dev # Add sqlx-cli for migrations sqlx-cli ]; # Environment variables for OpenSSL OPENSSL_NO_VENDOR = 1; PKG_CONFIG_PATH = "${pkgs.openssl.dev}/lib/pkgconfig"; # Pass arguments to cargo build cargoExtraArgs = "--no-default-features --features embed,sqlite --bin aip"; }; cargoArtifacts = craneLib.buildDepsOnly commonArgs; aip = craneLib.buildPackage (commonArgs // { inherit cargoArtifacts; doCheck = false; CARGO_PROFILE = "release"; }); aip-client-management = craneLib.buildPackage (commonArgs // { inherit cargoArtifacts; doCheck = false; CARGO_PROFILE = "release"; cargoExtraArgs = "--no-default-features --features embed,sqlite --bin aip-client-management"; }); # Copy migration files migrationFiles = pkgs.stdenv.mkDerivation { name = "aip-migrations"; src = ./migrations; installPhase = '' mkdir -p $out/migrations cp -r * $out/migrations/ ''; }; # Copy static files staticFiles = pkgs.stdenv.mkDerivation { name = "aip-static"; src = ./static; installPhase = '' mkdir -p $out/static cp -r * $out/static/ ''; }; # Migration runner script migrationRunner = pkgs.writeShellScriptBin "run-migrations" '' set -e # Ensure /data directory exists and is writable mkdir -p /data chmod 755 /data if [ -z "$DATABASE_URL" ]; then echo "DATABASE_URL environment variable is required" exit 1 fi # Determine migration source based on database type if [[ "$DATABASE_URL" == sqlite* ]]; then MIGRATION_SOURCE="${migrationFiles}/migrations/sqlite" elif [[ "$DATABASE_URL" == postgres* ]]; then MIGRATION_SOURCE="${migrationFiles}/migrations/postgres" else echo "Unsupported database type in DATABASE_URL: $DATABASE_URL" exit 1 fi echo "Running migrations from $MIGRATION_SOURCE against $DATABASE_URL" ${pkgs.sqlx-cli}/bin/sqlx database create ${pkgs.sqlx-cli}/bin/sqlx migrate run --source "$MIGRATION_SOURCE" # Ensure the database file is writable by all users (SQLite only) if [[ "$DATABASE_URL" == sqlite* ]]; then DB_FILE=$(echo "$DATABASE_URL" | sed 's/sqlite:\/\///') if [ -f "$DB_FILE" ]; then chmod 666 "$DB_FILE" fi fi ''; # Docker image for deployment aipImg = pkgs.dockerTools.buildImage { name = "aip"; tag = "latest"; fromImage = pkgs.dockerTools.pullImage { imageName = "alpine"; imageDigest = "sha256:beefdbd8a1da6d2915566fde36db9db0b524eb737fc57cd1367effd16dc0d06d"; sha256 = "sha256-Sfb0quuaHgzxA7paz5P51WhdA35to39HtOufceXixz0="; }; copyToRoot = pkgs.buildEnv { name = "image-root"; paths = [ aip aip-client-management migrationRunner staticFiles pkgs.cacert pkgs.sqlx-cli ]; pathsToLink = [ "/bin" "/etc" "/static" ]; }; config = { Cmd = [ "/bin/sh" "-c" "if [ ! -f /data/aip.db ]; then /bin/run-migrations; fi && /bin/aip" ]; Env = [ "RUST_BACKTRACE=1" "RUST_LOG=info" "PORT=8080" "HTTP_STATIC_PATH=/static" ]; ExposedPorts = { "8080/tcp" = {}; }; }; }; in { inherit aip aip-client-management aipImg migrationRunner; default = aip; }; in { packages = forAllSystems mkPackagesForSystem; devShells = forAllSystems (system: let pkgs = import nixpkgs { inherit system; }; craneLib = (crane.mkLib pkgs).overrideToolchain fenix.packages.${system}.stable.toolchain; in { default = craneLib.devShell { packages = with pkgs; [ nixpkgs-fmt nil dive flyctl sqlite postgresql sqlx-cli ]; # Set up environment for development RUST_LOG = "info"; }; }); }; }