diff --git a/flake.nix b/flake.nix index b1ce508..9b586a7 100644 --- a/flake.nix +++ b/flake.nix @@ -7,12 +7,20 @@ flake-utils.url = "github:numtide/flake-utils"; }; - outputs = { nixpkgs, rust-overlay, flake-utils, ... }: + outputs = { + nixpkgs, + rust-overlay, + flake-utils, + ... + }: flake-utils.lib.eachDefaultSystem (system: let pkgs = import nixpkgs { inherit system; - overlays = [ (import rust-overlay) ]; + + overlays = [ + rust-overlay.overlays.default + ]; }; rust = pkgs.rust-bin.stable.latest.default.override { @@ -21,104 +29,236 @@ "clippy" ]; }; - in { + in + { devShells.default = pkgs.mkShell { packages = with pkgs; [ rust + # Database postgresql - postgis - + postgresqlPackages.postgis sqlx-cli + # GIS gdal geos proj + # Build dependencies pkg-config openssl ]; shellHook = '' + set -e + + # ------------------------------------------------------------ + # Local PostgreSQL + # ------------------------------------------------------------ + export PGDATA="$PWD/.pgdata" export PGHOST="$PWD/.pgsocket" export PGPORT="5433" + export PGDATABASE="county_sprints" export PGUSER="county_sprints" mkdir -p "$PGHOST" + # ------------------------------------------------------------ + # Initialise PostgreSQL cluster + # ------------------------------------------------------------ + if [ ! -f "$PGDATA/PG_VERSION" ]; then - echo "initialising PostgreSQL..." + echo + echo "==> Initialising local PostgreSQL cluster" initdb \ --auth=trust \ --no-locale \ - "$PGDATA" >/dev/null - - cat >> "$PGDATA/postgresql.conf" </dev/null fi - if ! pg_ctl -D "$PGDATA" status >/dev/null 2>&1; then + # ------------------------------------------------------------ + # Configure PostgreSQL + # ------------------------------------------------------------ + + # Always write our development settings. This means changing + # the flake also updates an already existing local cluster. + cat > "$PGDATA/postgresql.conf" </dev/null 2>&1 + then + echo + echo "==> Starting local PostgreSQL" + pg_ctl \ -D "$PGDATA" \ -o "-k $PGHOST -p $PGPORT" \ -l "$PGDATA/postgresql.log" \ - start >/dev/null + start \ + >/dev/null + + # Wait until PostgreSQL actually accepts connections. + for i in $(seq 1 30); do + if pg_isready \ + -h "$PGHOST" \ + -p "$PGPORT" \ + >/dev/null 2>&1 + then + break + fi + + sleep 0.2 + done fi + # ------------------------------------------------------------ + # Create application role + # ------------------------------------------------------------ + if ! psql \ -h "$PGHOST" \ -p "$PGPORT" \ -d postgres \ - -tAc "SELECT 1 FROM pg_roles WHERE rolname='$PGUSER'" | + -tAc \ + "SELECT 1 + FROM pg_roles + WHERE rolname = '$PGUSER'" | grep -q 1 then - createuser \ - -h "$PGHOST" \ - -p "$PGPORT" \ - "$PGUSER" - fi + echo + echo "==> Creating PostgreSQL role '$PGUSER'" - if ! psql \ - -h "$PGHOST" \ - -p "$PGPORT" \ - -d postgres \ - -tAc "SELECT 1 FROM pg_database WHERE datname='$PGDATABASE'" | - grep -q 1 - then - createdb \ - -h "$PGHOST" \ - -p "$PGPORT" \ - -O "$PGUSER" \ - "$PGDATABASE" - fi - - if ! psql \ - -h "$PGHOST" \ - -p "$PGPORT" \ - -d "$PGDATABASE" \ - -tAc "SELECT 1 FROM pg_extension WHERE extname='postgis'" | - grep -q 1 - then psql \ -h "$PGHOST" \ -p "$PGPORT" \ - -d "$PGDATABASE" \ - -c "CREATE EXTENSION postgis;" >/dev/null + -d postgres \ + -v ON_ERROR_STOP=1 \ + -c \ + "CREATE ROLE \"$PGUSER\" LOGIN;" fi + # ------------------------------------------------------------ + # Create application database + # ------------------------------------------------------------ + + if ! psql \ + -h "$PGHOST" \ + -p "$PGPORT" \ + -d postgres \ + -tAc \ + "SELECT 1 + FROM pg_database + WHERE datname = '$PGDATABASE'" | + grep -q 1 + then + echo + echo "==> Creating PostgreSQL database '$PGDATABASE'" + + psql \ + -h "$PGHOST" \ + -p "$PGPORT" \ + -d postgres \ + -v ON_ERROR_STOP=1 \ + -c \ + "CREATE DATABASE \"$PGDATABASE\" OWNER \"$PGUSER\";" + fi + + # ------------------------------------------------------------ + # Make sure the application role owns the database + # ------------------------------------------------------------ + + psql \ + -h "$PGHOST" \ + -p "$PGPORT" \ + -d postgres \ + -v ON_ERROR_STOP=1 \ + -c \ + "ALTER DATABASE \"$PGDATABASE\" OWNER TO \"$PGUSER\";" \ + >/dev/null + + # ------------------------------------------------------------ + # PostGIS + # ------------------------------------------------------------ + + echo + echo "==> Checking PostGIS" + + psql \ + -h "$PGHOST" \ + -p "$PGPORT" \ + -d "$PGDATABASE" \ + -v ON_ERROR_STOP=1 \ + -c \ + "CREATE EXTENSION IF NOT EXISTS postgis;" \ + >/dev/null + + # ------------------------------------------------------------ + # DATABASE_URL for sqlx / application + # ------------------------------------------------------------ + export DATABASE_URL="postgresql://$PGUSER@/$PGDATABASE?host=$PGHOST&port=$PGPORT" + # ------------------------------------------------------------ + # Environment + # ------------------------------------------------------------ + + export RUST_BACKTRACE=1 + + if [ -z "''${RUST_LOG:-}" ]; then + export RUST_LOG="info" + fi + + # ------------------------------------------------------------ + # Info + # ------------------------------------------------------------ + echo - echo "========================================" - echo " county-sprints development environment" - echo "========================================" - echo "DATABASE_URL=$DATABASE_URL" + echo "==============================================" + echo " Landkreis-Sprints development environment" + echo "==============================================" + echo + echo "Rust:" + rustc --version + echo + echo "PostgreSQL:" + psql \ + -h "$PGHOST" \ + -p "$PGPORT" \ + -d "$PGDATABASE" \ + -tAc "SELECT version();" | + sed 's/^/ /' + echo + echo "PostGIS:" + psql \ + -h "$PGHOST" \ + -p "$PGPORT" \ + -d "$PGDATABASE" \ + -tAc "SELECT PostGIS_Full_Version();" | + sed 's/^/ /' + echo + echo "DATABASE_URL:" + echo " $DATABASE_URL" + echo + echo "Run:" + echo " sqlx migrate run" + echo " cargo test" + echo " cargo run" echo ''; };