# `hero-git` Docker Image This directory contains a reusable Docker image and entrypoint script used to build Hero / Horus binaries via the V-based **herolib** installers. It is designed for two main use cases: 1. **Local development / testing** – run the herolib CLI (`hero`) and Horus installers in a clean, reproducible environment. 2. **CI / Release builds** – build Horus binaries inside this image (using `horus_full_install.vsh`) and export them as release artifacts. --- ## Files ### `Dockerfile` The `Dockerfile` builds an Ubuntu-based image with all dependencies needed for `herolib` and its installers. Key points: * Base: `ubuntu:24.04` * Installs system tooling: * `ssh`, `wget`, `curl`, `unzip`, `build-essential`, `git`, `git-lfs` * `redis-server`, `libsqlite3-dev`, `libpq-dev`, `autoconf`, `libtool`, `net-tools`, `iputils-ping`, `rsync`, `mc`, `tmux`, `ufw`, `xz-utils` * Installs **V** compiler: * Downloads `v_linux.zip` from the official V GitHub releases * Unzips it and runs `./v symlink` so `v` is on the `PATH` * Installs **Bun** (used for the docusaurus docs template): * `curl -fsSL https://bun.sh/install | bash` * Clones: * `https://github.com/Incubaid/herolib` into `/opt/herolib` * `https://github.com/incubaid/docusaurus_template` into `/root/code/github/incubaid/docusaurus_template` * Warms Bun dependencies for the docusaurus template (for faster re-use): * `cd /root/code/github/incubaid/docusaurus_template/template && bun install` * Prepares directories: * `/root/.vmodules/incubaid` – used by V module resolution * `/root/ssh` – optional mount point for SSH keys * Copies `entrypoint.sh` into the image and marks it executable. The container’s entrypoint is set to the custom script `/bin/entrypoint.sh`. --- ### `entrypoint.sh` The entrypoint script is responsible for: 1. Starting **Redis** in the background. 2. Optionally configuring **SSH** (if keys are provided). 3. Selecting the correct `herolib` source (mounted or cloned). 4. Checking out the desired `herolib` branch. 5. Building the `hero` CLI with V and making it available as `/bin/hero`. 6. Finally, executing any command passed to `docker run`. #### Behavior in detail ```bash #!/bin/bash set -euo pipefail # Start Redis in the background redis-server --daemonize yes # Optional SSH setup: only if /root/ssh has keys if [ -d /root/ssh ] && compgen -G "/root/ssh/*" > /dev/null; then mkdir -p /root/.ssh cp -r /root/ssh/* /root/.ssh/ chmod 600 /root/.ssh/* eval "$(ssh-agent)" ssh-add /root/.ssh/* fi # Support optionally bind-mounting a local herolib into the container. # If /opt/herolib_mount exists, we use that; otherwise we use the cloned /opt/herolib rm -f /root/.vmodules/freeflowuniverse/herolib if [ -d "/opt/herolib_mount" ]; then ln -s /opt/herolib_mount/lib /root/.vmodules/incubaid/herolib cd /opt/herolib_mount else ln -s /opt/herolib/lib /root/.vmodules/incubaid/herolib cd /opt/herolib git fetch git checkout "${HEROLIB_REF:-development}" git pull fi cd cli echo "Building hero..." v -enable-globals hero.v > build.log 2>&1 || (cat build.log && exit 1) ln -s "$(realpath hero)" /bin/hero cd /root # If a command was provided to `docker run`, execute it as-is. # Example: docker run hero-git:latest bash -lc 'cd /opt/herolib && ./examples/installers/horus/horus_full_install.vsh' if [ "$#" -gt 0 ]; then exec "$@" else # No command passed → give an interactive shell exec bash fi ``` #### Important environment variables * `HEROLIB_REF` * Git ref (branch, tag, or commit) used when checking out `/opt/herolib`. * Default: `development`. * Example for CI: `HEROLIB_REF=development_nile_installers`. #### Optional mounts * `/opt/herolib_mount` * If you bind-mount your local `herolib` repo here, the container will use it instead of the cloned `/opt/herolib`. * Useful for local development when you want to test uncommitted changes. * `/root/ssh` * Optional directory containing SSH keys (e.g. `id_ed25519`) if you need to access private repositories. * If present and non-empty, keys are copied to `/root/.ssh` and added to an SSH agent. --- ## What this image is used for ### 1. Local development / experimentation You can drop into the container and manually run installers or commands against `herolib`: ```bash # Interactive shell with default branch docker run -it --rm hero-git:latest # Use a specific herolib ref docker run -it --rm -e HEROLIB_REF=development_nile_installers hero-git:latest # Mount a local herolib repo and use that instead of the cloned one docker run -it --rm \ -v "$PWD/herolib:/opt/herolib_mount" \ hero-git:latest ``` Inside the container you can then run: ```bash cd /opt/herolib ./examples/installers/horus/horus_full_install.vsh ``` ### 2. CI / Release builds for Horus In CI (e.g. the `release.yml` workflow), this image is used to build Horus binaries via the V-based installer script: * The workflow: 1. Ensures `hero-git:latest` is available on the self-hosted runner. 2. Creates a local directory (e.g. `hero-bin/`) on the runner. 3. Runs the container, mounting `hero-bin/` into `/root/hero/bin`. 4. Inside the container, executes `./examples/installers/horus/horus_full_install.vsh` from `/opt/herolib`. 5. The installer writes the compiled Horus binaries into `/root/hero/bin`, which appear on the host inside `hero-bin/`. 6. The workflow then packages those binaries into `.tar.gz` archives and uploads them as release artifacts. Example CI step: ```yaml - name: Run horus_full_install installer in container run: | set -euxo pipefail docker run --rm \ -v "$PWD/hero-bin:/root/hero/bin" \ -e HEROLIB_REF=development_nile_installers \ hero-git:latest \ bash -lc ' set -euxo pipefail cd /opt/herolib ./examples/installers/horus/horus_full_install.vsh echo "===== AFTER INSTALL, ls -R /root/hero =====" ls -R /root/hero || true ' ``` After this step, `hero-bin/` on the host should contain binaries like: * `supervisor` * `coordinator` * `horus` * `osiris` * `herorunner` * `runner_osiris` * `runner_sal` These are then packaged and attached to the Gitea release. --- ## How to build the image From the directory containing the `Dockerfile` and `entrypoint.sh`: ```bash # Build the image (force a clean rebuild) docker build --no-cache -t hero-git:latest . # Verify entrypoint contents docker run --rm --entrypoint cat hero-git:latest /bin/entrypoint.sh | tail -n 20 ``` You should see the `exec "$@"` block at the end of the script, which ensures that commands passed to `docker run` are executed as-is inside the container. --- ## How to run the image (examples) ### Basic interactive usage ```bash # Default branch (HEROLIB_REF=development) docker run -it --rm hero-git:latest # Specific herolib ref export HEROLIB_REF=development_nile_installers docker run -it --rm \ -e HEROLIB_REF=$HEROLIB_REF \ hero-git:latest ``` ### Build Horus binaries into a host directory ```bash mkdir -p hero-bin docker run --rm \ -v "$PWD/hero-bin:/root/hero/bin" \ -e HEROLIB_REF=development_nile_installers \ hero-git:latest \ bash -lc ' set -euxo pipefail cd /opt/herolib ./examples/installers/horus/horus_full_install.vsh ls -al /root/hero/bin ' ls -al hero-bin ``` You should now see the built Horus binaries on the host in `hero-bin/`. --- ## Summary * The `hero-git:latest` image encapsulates all dependencies required to build Horus via `herolib`. * `entrypoint.sh`: * Starts Redis * Optionally configures SSH * Selects and updates the `herolib` checkout * Builds the `hero` CLI once * Runs any command passed to the container (e.g. Horus installers) * CI uses this image to run `horus_full_install.vsh` and collect Horus binaries from `/root/hero/bin` for releases.