# ahab A wrapper around `docker compose` for our dockerized django projects, so the same commands work in every repository. ## installing You will need rust installed. Clone repo and run: ```bash cargo install --path . ``` To print the underlying docker commands as they run, build with debug assertions: ```bash cargo install --path . --debug ``` ## shell completion `ahab completions ` writes a completion script to stdout, for bash, elvish, fish, powershell or zsh: ```bash ahab completions zsh > ~/.local/share/zsh/completions/_ahab eval "$(ahab completions zsh)" # or one line in .zshrc, never goes stale ``` Completions are also generated during the build. They land in `target/*/build/*/out/` by default, and `SHELL_COMPLETIONS_DIR_` installs a single shell's file straight into place: ```bash SHELL_COMPLETIONS_DIR_ZSH=~/.local/share/zsh/completions \ SHELL_COMPLETIONS_DIR_FISH=~/.config/fish/completions \ cargo install --path . ``` `SHELL_COMPLETIONS_DIR` writes every shell into one directory instead. ## the compose file `ahab` does not pass `-f`. docker compose finds the file itself, so set docker's own `COMPOSE_FILE` when it is not in the working directory, including its `base.yaml:override.yaml` form. A project's `.env` is a good place for it, since docker reads that too: ``` COMPOSE_FILE=docker/docker-compose.yaml ``` ## service detection `ahab` finds the services it needs in `docker compose config`, so they can be named anything: - **postgres**: the service whose image is a postgres flavour, matching `postg`, `timescale`, `pgvector` or `citus` - **django**: the service that both builds an image and sets `DJANGO_SETTINGS_MODULE`. A worker sharing the same build and `env_file` matches too, so the one publishing ports wins If nothing matches, or two candidates cannot be told apart, `ahab` says so and lists the services it looked at rather than guessing. `POSTGRES_USER` and `POSTGRES_DB` are read off the detected postgres service, so `dropdb`, `createdb`, `pg_restore` and `pg_dump` use the role and database the project declares, falling back to `db` when it declares neither. ## django ```bash ahab django run # in a fresh container, through the entrypoint ahab django bash # shell in a fresh container ahab django manage # manage.py ahab django makemigrations ahab django migrate ahab django shell ahab django test ahab django make-command ``` ## postgres ```bash ahab postgres dump # pg_dump, custom format ahab postgres dump -F plain # pg_dump, plain sql ahab postgres import # drop, create, then restore ``` The format of a dump being imported is read from the file rather than its name. A custom format dump starts with `PGDMP` and a tar one with `toc.dat`, both of which go to `pg_restore`, as does a directory produced by `pg_dump -Fd`. Anything else is treated as sql and fed to `psql` with `ON_ERROR_STOP` and `--single-transaction`, so a bad file rolls back instead of half applying. A whole cluster dump from `pg_dumpall` is recognised by its header and handled differently again: it creates its own databases and carries role statements, so the database is dropped but not recreated, the dump goes to `psql` connected to `postgres`, and it runs without `ON_ERROR_STOP` because roles that already exist report errors that are expected. Gzipped dumps are decompressed on the way in, whichever of the three they hold. ## link `ahab link` moves untracked paths out of the repository into an out-of-repo store and symlinks them back, so a sandbox that mounts the repository sees a dangling symlink instead of the contents, while the host resolves it as before. ```bash ahab link add .env secrets/ # move out, leave symlinks behind ahab link check # what a sandbox can still read ahab link check --porcelain # ` `, for scripts ``` The store lives under `${XDG_DATA_HOME:-$HOME/.local/share}/ahab////`, derived from the git `origin` remote. ## configuration Currently `ahab` respects the following environment variables. - `AHAB_LINK_ROOT`: root of the out-of-repo store `ahab link` moves paths into - defaults to `${XDG_DATA_HOME:-$HOME/.local/share}/ahab`