(version: string, platform: string, quiet: boolean)
| 1137 | } |
| 1138 | |
| 1139 | function ensureDockerImage(version: string, platform: string, quiet: boolean): string { |
| 1140 | const tag = dockerImageTagForPlatform(version, platform); |
| 1141 | |
| 1142 | if (dockerImageExists(tag)) { |
| 1143 | if (!quiet) console.log(c.dim(` Docker image: ${tag} (cached)`)); |
| 1144 | return tag; |
| 1145 | } |
| 1146 | |
| 1147 | if (!quiet) console.log(c.dim(` Building Docker image: ${tag} (${platform})...`)); |
| 1148 | |
| 1149 | const dockerfilePath = resolveDockerfilePath(); |
| 1150 | |
| 1151 | // Copy Dockerfile to a temp build context so docker build has a clean context |
| 1152 | const tmpDir = join(tmpdir(), `hyperframes-docker-${Date.now()}`); |
| 1153 | mkdirSync(tmpDir, { recursive: true }); |
| 1154 | writeFileSync(join(tmpDir, "Dockerfile"), readFileSync(dockerfilePath)); |
| 1155 | |
| 1156 | // Platform is now derived from the host arch (see resolveDockerPlatform). |
| 1157 | // Apple Silicon and other arm64 hosts get a native linux/arm64 build; the |
| 1158 | // Dockerfile skips chrome-headless-shell on arm64 and falls back to system |
| 1159 | // chromium because chrome-headless-shell ships linux64 only. |
| 1160 | // |
| 1161 | // TARGETARCH is passed explicitly rather than relying on BuildKit's |
| 1162 | // automatic platform args because the legacy builder (and some BuildKit |
| 1163 | // configurations like colima 0.6.x) leaves it unset, which would defeat |
| 1164 | // the arch conditional in the Dockerfile. |
| 1165 | const targetArch = platform === "linux/arm64" ? "arm64" : "amd64"; |
| 1166 | try { |
| 1167 | execFileSync( |
| 1168 | "docker", |
| 1169 | [ |
| 1170 | "build", |
| 1171 | "--platform", |
| 1172 | platform, |
| 1173 | "--build-arg", |
| 1174 | `HYPERFRAMES_VERSION=${version}`, |
| 1175 | "--build-arg", |
| 1176 | `TARGETARCH=${targetArch}`, |
| 1177 | "-t", |
| 1178 | tag, |
| 1179 | tmpDir, |
| 1180 | ], |
| 1181 | { stdio: quiet ? "pipe" : "inherit", timeout: 600_000 }, |
| 1182 | ); |
| 1183 | } catch (error: unknown) { |
| 1184 | const message = normalizeErrorMessage(error); |
| 1185 | throw new Error(`Failed to build Docker image: ${message}`); |
| 1186 | } finally { |
| 1187 | rmSync(tmpDir, { recursive: true, force: true }); |
| 1188 | } |
| 1189 | |
| 1190 | if (!quiet) console.log(c.dim(` Docker image: ${tag} (built)`)); |
| 1191 | return tag; |
| 1192 | } |
| 1193 | |
| 1194 | /** |
| 1195 | * Resolves the Docker `--platform` for this host and enforces the constraints |
no test coverage detected