fix: repair Docker installer asset fetch

This commit is contained in:
Pi Web Agent
2026-07-08 20:45:56 +00:00
parent 856ba7345b
commit 829b3508a4
3 changed files with 79 additions and 4 deletions
@@ -0,0 +1,5 @@
---
"@jmfederico/pi-web": patch
---
Fix the Docker runtime installer so one-line installs can fetch Docker assets into a fresh install directory.
+6 -4
View File
@@ -231,12 +231,14 @@ dotenv_quote() {
} }
fetch_url() { fetch_url() {
url=$1 # POSIX sh function variables are global, so keep these names distinct
target=$2 # from caller state such as write_asset's target path.
fetch_url_source=$1
fetch_url_output=$2
if command -v curl >/dev/null 2>&1; then if command -v curl >/dev/null 2>&1; then
curl -fsSL "$url" -o "$target" curl -fsSL "$fetch_url_source" -o "$fetch_url_output"
elif command -v wget >/dev/null 2>&1; then elif command -v wget >/dev/null 2>&1; then
wget -qO "$target" "$url" wget -qO "$fetch_url_output" "$fetch_url_source"
else else
die "curl or wget is required to fetch Docker assets" die "curl or wget is required to fetch Docker assets"
fi fi
+68
View File
@@ -82,6 +82,37 @@ describe("Docker command assets", () => {
expect(devCompose).toContain("COMPOSE_PROJECT_NAME: ${COMPOSE_PROJECT_NAME:-pi-web-dev}"); expect(devCompose).toContain("COMPOSE_PROJECT_NAME: ${COMPOSE_PROJECT_NAME:-pi-web-dev}");
}); });
dockerCommandIt("fetches remote installer assets without clobbering the write target", async () => {
const installDir = join(tempDir, "remote-runtime");
const fakeDocker = await installFakeDocker();
await installFakeCurl(fakeDocker.binDir);
await installFakeUname(fakeDocker.binDir, "Darwin");
const home = join(tempDir, "home");
const socketPath = join(home, ".docker", "run", "docker.sock");
await withUnixSocket(socketPath, async () => {
await execUtf8("sh", [
join(repoRoot, "docker", "install.sh"),
"--install-dir", installDir,
"--data-dir", join(installDir, "data"),
"--asset-ref", "test-assets",
"--skip-compose",
], {
...cleanProcessEnv(),
PATH: `${fakeDocker.binDir}:${process.env["PATH"] ?? ""}`,
HOME: home,
FAKE_DOCKER_LOG: fakeDocker.logPath,
PI_WEB_DOCKER_ASSET_BASE: "https://assets.example.test/docker",
});
});
expect(await readFile(join(installDir, "Dockerfile"), "utf8")).toContain("COPY pi-web-docker /usr/local/bin/pi-web-docker");
expect(await readFile(join(installDir, "pi-web-docker"), "utf8")).toContain("Usage: pi-web-docker");
const env = await readFile(join(installDir, ".env"), "utf8");
expect(env).toContain(`PI_WEB_DOCKER_INSTALL_DIR=${installDir}`);
expect(env).toContain("PI_WEB_DOCKER_REF=test-assets");
});
dockerCommandIt("runs status through Docker Compose in the foreground", async () => { dockerCommandIt("runs status through Docker Compose in the foreground", async () => {
const installDir = await createRuntimeInstall(); const installDir = await createRuntimeInstall();
const fakeDocker = await installFakeDocker(); const fakeDocker = await installFakeDocker();
@@ -492,6 +523,43 @@ exit 9
return { binDir, logPath }; return { binDir, logPath };
} }
async function installFakeCurl(binDir: string): Promise<void> {
const curlPath = join(binDir, "curl");
await writeFile(curlPath, `#!/usr/bin/env sh
set -eu
asset_root=${shellSingleQuote(join(repoRoot, "docker"))}
output=
url=
while [ "$#" -gt 0 ]; do
case "$1" in
-o)
shift
output=\${1:-}
;;
-*)
;;
*)
url=$1
;;
esac
if [ "$#" -gt 0 ]; then
shift
fi
done
[ -n "$url" ] || { printf '%s\n' "fake curl missing URL" >&2; exit 2; }
[ -n "$output" ] || { printf '%s\n' "fake curl missing -o output" >&2; exit 2; }
case "$url" in
*/docker/*) rel=\${url##*/docker/} ;;
*) printf 'unexpected fake curl url: %s\n' "$url" >&2; exit 2 ;;
esac
src=$asset_root/$rel
[ -f "$src" ] || { printf 'missing fake curl asset: %s\n' "$src" >&2; exit 2; }
mkdir -p "$(dirname "$output")"
cp "$src" "$output"
`, "utf8");
await chmod(curlPath, 0o755);
}
async function installFakeUname(binDir: string, osName: string): Promise<void> { async function installFakeUname(binDir: string, osName: string): Promise<void> {
const unamePath = join(binDir, "uname"); const unamePath = join(binDir, "uname");
await writeFile(unamePath, `#!/usr/bin/env sh await writeFile(unamePath, `#!/usr/bin/env sh