# UGE / L2 / Intro to relational databases / Python project prototype # Author: Pacien TRAN-GIRARD # Licence: EUPL-1.2 { inputs = { nixpkgs.url = "github:NixOS/nixpkgs/nixos-21.11"; flake-utils.url = "github:numtide/flake-utils"; }; outputs = { self, nixpkgs, flake-utils }: flake-utils.lib.eachDefaultSystem (system: with import nixpkgs { inherit system; }; let python = python39; pythonWithDependencies = python.withPackages (ps: with ps; [ uvicorn # server for the web app fastapi # simple Python framework to build web apps aiofiles # to let fastapi serve static resources (CSS, JS, ...) python-multipart # to let fastapi handle form submissions jinja2 # HTML templating engine passlib # for account password hashing psycopg2 # PostgreSQL driver for Python embrace # bridges raw SQL queries to Python functions ]); develPackagesAndScripts = [ postgresql_13 # PostgreSQL server with the standard admin tools. python.pkgs.ipython # Interactive Python REPL for experimenting. heroku # CLI for the Heroku hosting platform. skopeo # Docker container upload utility. pwgen # Simple random token generator. # More pleasant alternative to psql, with colours and auto-completion. # Custom configuration to suppress irrelevant warnings and messages. (writeShellScriptBin "pgcli" '' ${pgcli}/bin/pgcli --pgclirc "${writeText "pgclirc" '' [main] keyring = False less_chatty = True ''}" "$@" '') # Script for initialising an independent development database. # This creates a default empty database name "postgres" and owned by the # current user. Data are stored in ./development_database/pgdata. (writeShellScriptBin "dev-initdb" '' initdb \ --no-locale \ --encoding UTF8 \ --auth-host reject \ --auth-local peer \ "$@" '') # Script for starting an independent development posgresql server. # Accepts connections only through a local UNIX-domain socket. (writeShellScriptBin "dev-postgres" '' postgres \ -h "" \ -k "$PGHOST" \ -d 2 \ "$@" '') # Script for starting the Uvicorn local development server. # `--reload-dir` arguments necessary to prevent the database directory # from triggering automatic application reload. # See: https://github.com/encode/uvicorn/issues/984 (writeShellScriptBin "dev-serve" '' uvicorn \ --reload-dir app \ --reload-dir templates \ --reload \ --app-dir app \ app:main \ "$@" '') ]; exportEnvVar = k: v: ''export ${k}="${v}"; echo ${k}=\"${v}\"''; exportDevelEnvVars = lib.mapAttrsToList exportEnvVar develEnvVars; develEnvVars = rec { PGDATA = "$PWD/development_database/pgdata"; PGHOST = "$PWD/development_database"; PGPORT = "5432"; PGDATABASE = "app"; DATABASE_URL = "postgresql:///${PGDATABASE}?host=${PGHOST}"; COOKIE_SECRET_KEY = "insecure for development"; }; in { packages = rec { # Minimal production server. # This includes only application files tracked by git. # Using `gunicorn` on top of `uvicorn` is recommended for bigger loads. server = writeShellScript "server" '' cd ${./.} ${pythonWithDependencies}/bin/uvicorn --app-dir app app:main "$@" ''; # Minimal docker image. # The Heroku hosting service assigns the `$PORT` dynamically. docker = dockerTools.streamLayeredImage { maxLayers = 2; name = "app-docker"; config.EntryPoint = writeShellScript "run.sh" '' ${server} --host 0.0.0.0 --port $PORT ''; }; }; devShell = mkShell rec { buildInputs = [ pythonWithDependencies ] ++ develPackagesAndScripts; shellHook = '' echo -e "\nDEVSHELL ENVIRONMENT VARIABLES:" ${lib.concatStringsSep "\n" exportDevelEnvVars} echo -e "\nDEVSHELL COMMANDS:" ls "${symlinkJoin { name = "env"; paths = buildInputs; }}/bin" # Use the default user shell instead of Bash $(${finger_bsd}/bin/finger $USER \ | ${gnugrep}/bin/grep -oP 'Shell: \K.*') exit $? ''; }; }); }