Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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-<process.arch>` 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-<process.arch>` 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.

Expand Down
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
40 changes: 34 additions & 6 deletions scripts/build-bootstrap-python.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -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'
Expand Down Expand Up @@ -99,29 +105,34 @@ 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) {
return plat.startsWith('win-')
}

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)
}
}
Expand Down Expand Up @@ -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}`)

Expand Down
Loading