From 4cb1068e6b86aa3bd393c0028396736c71a721ff Mon Sep 17 00:00:00 2001 From: Benjamin Lu Date: Tue, 8 Sep 2026 15:44:57 -0700 Subject: [PATCH] fix(bootstrap): skip hosts with no published bootstrap instead of failing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit detectPlatform threw on Linux ARM64, and both dev hooks called it unconditionally, so `pnpm run init` (install && bootstrap) and `pnpm run dev:bootstrap` died with a stack trace on that host — while `predev` pointed the developer at `pnpm run bootstrap`, the command that threw. No bootstrap for a host is a fact, not an error: the app falls back to system git. Return null for such hosts and report it, and give the script the two modes the hooks needed — --check (warn only) and --if-missing (build when absent). Both package.json one-liners now just call it, so the host-to-directory mapping they had each copied lives only in detectPlatform. An explicit --platform with an unknown name still fails. --- README.md | 2 +- package.json | 4 +-- scripts/build-bootstrap-python.mjs | 40 +++++++++++++++++++++++++----- 3 files changed, 37 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index e92476fc0..f2a6f4df2 100644 --- a/README.md +++ b/README.md @@ -156,7 +156,7 @@ The app ships a minimal (~15–20 MB) standalone Python with `pygit2` baked in, | `pnpm run bootstrap` | Build locally via `scripts/build-bootstrap-python.mjs` (no system Python needed). Auto-detects the host platform and architecture; pass `--platform win-x64\|win-arm64\|mac-arm64\|linux-x64` for another. | | `pnpm run bootstrap:fetch` | Download a prebuilt archive from the [`bootstrap-v3`](https://github.com/Comfy-Org/Comfy-Desktop/releases/tag/bootstrap-v3) release (faster). Set `GITHUB_TOKEN` to authenticate. | -Both write to `bootstrap-python/{win-x64,win-arm64,mac-arm64,linux-x64}/` (gitignored). The directory must exist before `pnpm run dev` or `pnpm run build:*`. `win-arm64` is the native Windows on Arm build (NVIDIA RTX Spark, Snapdragon X); the app picks `win-` in dev and ToDesktop's `targetOverrides` select it for the arm64 installer. +Both write to `bootstrap-python/{win-x64,win-arm64,mac-arm64,linux-x64}/` (gitignored). The directory must exist before `pnpm run dev` or `pnpm run build:*`. Hosts outside that list — Linux ARM64 today — have no published bootstrap: the build script says so and exits 0, so `pnpm run init` still completes and the app falls back to system `git`. `win-arm64` is the native Windows on Arm build (NVIDIA RTX Spark, Snapdragon X); the app picks `win-` in dev and ToDesktop's `targetOverrides` select it for the arm64 installer. At runtime the main process picks a git backend in priority order ([`src/main/lib/ipc/index.ts`](src/main/lib/ipc/index.ts)): bootstrap pygit2 → standalone-install pygit2 → system `git`. Set `COMFY_FORCE_BOOTSTRAP_GIT=1` (or `pnpm run dev:bootstrap`) to verify the bundled path that ships to users without git. diff --git a/package.json b/package.json index 645d20607..884666635 100644 --- a/package.json +++ b/package.json @@ -19,9 +19,9 @@ "scripts": { "init": "pnpm install && pnpm run bootstrap", "init:dev": "pnpm run init && pnpm run dev", - "predev": "node -e \"const fs=require('fs'),p=process.platform==='win32'?'win-'+process.arch:process.platform==='darwin'?'mac-arm64':'linux-'+process.arch;if(!fs.existsSync('bootstrap-python/'+p))console.log('\\n\\x1b[33m⚠ Bootstrap python not found. Run \\\"pnpm run bootstrap\\\" for pre-install git support.\\x1b[0m\\n')\"", + "predev": "node scripts/build-bootstrap-python.mjs --check", "dev": "electron-vite dev", - "predev:bootstrap": "node -e \"const fs=require('fs'),p=process.platform==='win32'?'win-'+process.arch:process.platform==='darwin'?'mac-arm64':'linux-'+process.arch;if(!fs.existsSync('bootstrap-python/'+p)){console.log('Building bootstrap python...');require('child_process').execSync('node scripts/build-bootstrap-python.mjs',{stdio:'inherit'})}\"", + "predev:bootstrap": "node scripts/build-bootstrap-python.mjs --if-missing", "dev:bootstrap": "node -e \"process.env.COMFY_FORCE_BOOTSTRAP_GIT='1';require('child_process').execSync('electron-vite dev',{stdio:'inherit',env:process.env})\"", "build": "pnpm run typecheck && electron-vite build", "start": "electron-vite preview", diff --git a/scripts/build-bootstrap-python.mjs b/scripts/build-bootstrap-python.mjs index aa1bb4c81..b7dd4a9ab 100644 --- a/scripts/build-bootstrap-python.mjs +++ b/scripts/build-bootstrap-python.mjs @@ -11,8 +11,14 @@ * * Usage: * node build-bootstrap-python.mjs [--output DIR] [--platform PLATFORM] + * node build-bootstrap-python.mjs --check # warn if absent, build nothing + * node build-bootstrap-python.mjs --if-missing # build only when absent * * Platforms: win-x64, win-arm64, mac-arm64, linux-x64 + * + * Hosts outside that list (Linux ARM64 today) have no published bootstrap. + * That is not an error — the app falls back to system git — so every mode + * reports it and exits 0 rather than failing `pnpm run init`. */ import { spawnSync } from 'node:child_process' import { createWriteStream } from 'node:fs' @@ -99,15 +105,16 @@ const STRIP_FILES = new Set([ '_testcapi.pyd', '_tkinter.pyd', '_sqlite3.pyd', ]) +/** The bootstrap this host can run, or null when none is published for it. + * The running Node's architecture is the one the resulting Python must + * match. Never substitute linux-x64 on ARM64: that produces a bootstrap + * which exists but cannot execute on the target machine. */ function detectPlatform() { const sys = process.platform - // The running Node's architecture is the one the resulting Python must - // match. Do not silently substitute linux-x64 on ARM64: that produces a - // bootstrap which exists but cannot execute on the target machine. if (sys === 'win32') return process.arch === 'arm64' ? 'win-arm64' : 'win-x64' if (sys === 'darwin') return 'mac-arm64' if (sys === 'linux' && process.arch === 'x64') return 'linux-x64' - throw new Error(`Unsupported platform: ${sys} ${process.arch}`) + return null } function isWindowsPlatform(plat) { @@ -115,13 +122,17 @@ function isWindowsPlatform(plat) { } function parseArgs(argv) { - const args = { output: 'bootstrap-python', platform: null } + const args = { output: 'bootstrap-python', platform: null, check: false, ifMissing: false } for (let i = 0; i < argv.length; i++) { const a = argv[i] if (a === '--output') args.output = argv[++i] else if (a === '--platform') args.platform = argv[++i] + else if (a === '--check') args.check = true + else if (a === '--if-missing') args.ifMissing = true else if (a === '-h' || a === '--help') { - console.log('Usage: node build-bootstrap-python.mjs [--output DIR] [--platform PLATFORM]') + console.log( + 'Usage: node build-bootstrap-python.mjs [--output DIR] [--platform PLATFORM] [--check] [--if-missing]' + ) process.exit(0) } } @@ -292,10 +303,27 @@ function runPython(pythonPath, args, opts = {}) { async function main() { const args = parseArgs(process.argv.slice(2)) const plat = args.platform || detectPlatform() + if (!plat) { + console.log( + `No bootstrap python is published for ${process.platform} ${process.arch}. ` + + 'Skipping — Comfy Desktop falls back to system git.' + ) + return + } const platInfo = PLATFORM_MAP[plat] if (!platInfo) throw new Error(`Unknown platform: ${plat}`) const outputDir = path.join(args.output, plat) + if (args.check) { + if (!(await isDir(outputDir))) { + console.log( + '\n\x1b[33m⚠ Bootstrap python not found. Run "pnpm run bootstrap" for pre-install git support.\x1b[0m\n' + ) + } + return + } + if (args.ifMissing && (await isDir(outputDir))) return + console.log(`Building bootstrap Python for ${plat}`) console.log(` Python ${PYTHON_VERSION}, PBS release ${PBS_RELEASE}`)