diff --git a/Makefile b/Makefile index 3a051817..b04ea614 100644 --- a/Makefile +++ b/Makefile @@ -39,7 +39,7 @@ deploy: check # Check for broken links link-check: - @./scripts/hugo.sh server --bind 127.0.0.1 --port 1313 >/tmp/capa-hugo.log 2>&1 & \ + @./scripts/hugo.sh server --port 1313 >/tmp/capa-hugo.log 2>&1 & \ pid=$$!; \ trap 'kill $$pid 2>/dev/null || true' EXIT; \ sleep 3; \ diff --git a/scripts/hugo.sh b/scripts/hugo.sh index bbb108d5..353ce33d 100755 --- a/scripts/hugo.sh +++ b/scripts/hugo.sh @@ -10,9 +10,55 @@ if ! command -v docker >/dev/null 2>&1; then exit 127 fi -project_dir=$(CDPATH= cd -- "$(dirname -- "$0")/.." && pwd) +project_dir=$(CDPATH='' cd -- "$(dirname -- "$0")/.." && pwd) hugo_image=${HUGO_IMAGE:-ghcr.io/gohugoio/hugo:v0.145.0} +if [ "${1:-}" = "server" ]; then + host_bind=127.0.0.1 + hugo_port=1313 + previous_arg= + + for arg in "$@"; do + case "$previous_arg" in + --bind) + host_bind=$arg + previous_arg= + continue + ;; + --port) + hugo_port=$arg + previous_arg= + continue + ;; + esac + + case "$arg" in + --bind|--port) + previous_arg=$arg + ;; + --bind=*) + host_bind=${arg#--bind=} + ;; + --port=*) + hugo_port=${arg#--port=} + ;; + esac + done + + if [ "$host_bind" = "localhost" ]; then + host_bind=127.0.0.1 + fi + + exec docker run --rm \ + --user "$(id -u):$(id -g)" \ + --env HOME=/tmp \ + --env HUGO_CACHEDIR=/tmp/hugo-cache \ + --env HUGO_ENV \ + --publish "$host_bind:$hugo_port:$hugo_port" \ + --volume "$project_dir:/project" \ + "$hugo_image" "$@" --bind 0.0.0.0 +fi + if [ "${HUGO_READ_ONLY:-0}" = "1" ]; then exec docker run --rm \ --user "$(id -u):$(id -g)" \ diff --git a/scripts/site-build.test.mjs b/scripts/site-build.test.mjs index f3def68d..189d7f5a 100644 --- a/scripts/site-build.test.mjs +++ b/scripts/site-build.test.mjs @@ -1,12 +1,19 @@ import assert from 'node:assert/strict'; -import { readFile } from 'node:fs/promises'; +import { execFile } from 'node:child_process'; +import { chmod, mkdtemp, readFile, rm, writeFile } from 'node:fs/promises'; +import { tmpdir } from 'node:os'; +import { join } from 'node:path'; +import { fileURLToPath } from 'node:url'; +import { promisify } from 'node:util'; import test from 'node:test'; +const execFileAsync = promisify(execFile); const makefile = await readFile(new URL('../Makefile', import.meta.url), 'utf8'); const workflow = await readFile(new URL('../.github/workflows/deploy.yml', import.meta.url), 'utf8'); const gitignore = await readFile(new URL('../.gitignore', import.meta.url), 'utf8'); const config = await readFile(new URL('../config.toml', import.meta.url), 'utf8'); const readme = await readFile(new URL('../README.md', import.meta.url), 'utf8'); +const hugoScript = fileURLToPath(new URL('./hugo.sh', import.meta.url)); test('production builds remove stale generated pages', () => { assert.match(makefile, /^build:\n\t.*--cleanDestinationDir/m); @@ -42,3 +49,39 @@ test('link checking crawls the rendered site and propagates failures', () => { assert.match(makefile, /linkinator http:\/\/localhost:1313 --recurse/); assert.doesNotMatch(makefile, /linkinator[^\n]*\|\| true/); }); + +test('Docker fallback publishes Hugo server ports to the requested host', async (t) => { + const binDir = await mkdtemp(join(tmpdir(), 'capa-hugo-test-')); + t.after(() => rm(binDir, { recursive: true, force: true })); + + const fakeDocker = join(binDir, 'docker'); + await writeFile(fakeDocker, '#!/bin/sh\nprintf "%s\\n" "$@"\n'); + await chmod(fakeDocker, 0o755); + + const { stdout } = await execFileAsync( + hugoScript, + ['server', '--bind', 'localhost', '--port', '1414'], + { + env: { + ...process.env, + PATH: `${binDir}:/usr/bin:/bin`, + }, + }, + ); + + assert.match(stdout, /^--publish\n127\.0\.0\.1:1414:1414$/m); + assert.match(stdout, /server\n--bind\nlocalhost\n--port\n1414\n--bind\n0\.0\.0\.0$/m); + + const allInterfaces = await execFileAsync( + hugoScript, + ['server', '--bind=0.0.0.0', '--port=1515'], + { + env: { + ...process.env, + PATH: `${binDir}:/usr/bin:/bin`, + }, + }, + ); + + assert.match(allInterfaces.stdout, /^--publish\n0\.0\.0\.0:1515:1515$/m); +});