Skip to content

Commit a44465d

Browse files
committed
Improve binary spawn errors
1 parent dc3aad6 commit a44465d

2 files changed

Lines changed: 134 additions & 32 deletions

File tree

cli/release/index.js

Lines changed: 67 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -490,22 +490,14 @@ async function checkForUpdates(runningProcess, exitListener) {
490490

491491
await downloadBinary(latestVersion)
492492

493-
const newChild = spawn(CONFIG.binaryPath, process.argv.slice(2), {
494-
stdio: 'inherit',
495-
detached: false,
496-
})
493+
const newChild = spawnInstalledBinary({ detached: false })
497494

498495
newChild.on('exit', (code, signal) => {
499496
resetTerminal()
500497
printCrashDiagnostics(code, signal)
501498
process.exit(signal ? 1 : (code || 0))
502499
})
503500

504-
newChild.on('error', (err) => {
505-
console.error('Failed to start codebuff:', err.message)
506-
process.exit(1)
507-
})
508-
509501
return new Promise(() => {})
510502
}
511503
} catch (error) {
@@ -561,13 +553,77 @@ function printCrashDiagnostics(code, signal) {
561553
console.error('')
562554
}
563555

564-
async function main() {
565-
await ensureBinaryExists()
556+
function getInstalledBinaryStatus() {
557+
try {
558+
const stats = fs.statSync(CONFIG.binaryPath)
559+
return stats.isFile() ? `yes (${formatBytes(stats.size)})` : 'no'
560+
} catch {
561+
return 'no'
562+
}
563+
}
564+
565+
function printSpawnFailure(err) {
566+
resetTerminal()
567+
const code = err && err.code ? ` (${err.code})` : ''
568+
569+
console.error(`Failed to start ${packageName}: ${err.message}${code}`)
570+
console.error('')
571+
console.error('System info:')
572+
console.error(` Platform: ${process.platform} ${process.arch}`)
573+
console.error(` Node: ${process.version}`)
574+
console.error(` Binary: ${CONFIG.binaryPath}`)
575+
console.error(` Exists: ${getInstalledBinaryStatus()}`)
576+
577+
if (process.platform === 'win32') {
578+
console.error('')
579+
console.error(
580+
'On Windows, this can happen when Windows Security or antivirus blocks',
581+
)
582+
console.error(
583+
'or quarantines the downloaded executable, or when the binary requires',
584+
)
585+
console.error('CPU instructions that are not available on this machine.')
586+
}
587+
588+
console.error('')
589+
console.error('Try deleting the downloaded files and running again:')
590+
console.error(` ${CONFIG.configDir}`)
591+
console.error('')
592+
}
593+
594+
function spawnInstalledBinary(options = {}) {
595+
if (!fs.existsSync(CONFIG.binaryPath)) {
596+
try {
597+
if (fs.existsSync(CONFIG.metadataPath)) fs.unlinkSync(CONFIG.metadataPath)
598+
} catch {
599+
// best effort
600+
}
601+
const error = new Error(
602+
`downloaded binary is missing at ${CONFIG.binaryPath}`,
603+
)
604+
error.code = 'BINARY_MISSING'
605+
printSpawnFailure(error)
606+
process.exit(1)
607+
}
566608

567609
const child = spawn(CONFIG.binaryPath, process.argv.slice(2), {
568610
stdio: 'inherit',
611+
...options,
612+
})
613+
614+
child.on('error', (err) => {
615+
printSpawnFailure(err)
616+
process.exit(1)
569617
})
570618

619+
return child
620+
}
621+
622+
async function main() {
623+
await ensureBinaryExists()
624+
625+
const child = spawnInstalledBinary()
626+
571627
const exitListener = (code, signal) => {
572628
resetTerminal()
573629
printCrashDiagnostics(code, signal)
@@ -576,11 +632,6 @@ async function main() {
576632

577633
child.on('exit', exitListener)
578634

579-
child.on('error', (err) => {
580-
console.error('Failed to start codebuff:', err.message)
581-
process.exit(1)
582-
})
583-
584635
setTimeout(() => {
585636
checkForUpdates(child, exitListener)
586637
}, 100)

freebuff/cli/release/index.js

Lines changed: 67 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -477,22 +477,14 @@ async function checkForUpdates(runningProcess, exitListener) {
477477

478478
await downloadBinary(latestVersion)
479479

480-
const newChild = spawn(CONFIG.binaryPath, process.argv.slice(2), {
481-
stdio: 'inherit',
482-
detached: false,
483-
})
480+
const newChild = spawnInstalledBinary({ detached: false })
484481

485482
newChild.on('exit', (code, signal) => {
486483
resetTerminal()
487484
printCrashDiagnostics(code, signal)
488485
process.exit(signal ? 1 : (code || 0))
489486
})
490487

491-
newChild.on('error', (err) => {
492-
console.error('Failed to start freebuff:', err.message)
493-
process.exit(1)
494-
})
495-
496488
return new Promise(() => {})
497489
}
498490
} catch (error) {
@@ -548,13 +540,77 @@ function printCrashDiagnostics(code, signal) {
548540
console.error('')
549541
}
550542

551-
async function main() {
552-
await ensureBinaryExists()
543+
function getInstalledBinaryStatus() {
544+
try {
545+
const stats = fs.statSync(CONFIG.binaryPath)
546+
return stats.isFile() ? `yes (${formatBytes(stats.size)})` : 'no'
547+
} catch {
548+
return 'no'
549+
}
550+
}
551+
552+
function printSpawnFailure(err) {
553+
resetTerminal()
554+
const code = err && err.code ? ` (${err.code})` : ''
555+
556+
console.error(`Failed to start ${packageName}: ${err.message}${code}`)
557+
console.error('')
558+
console.error('System info:')
559+
console.error(` Platform: ${process.platform} ${process.arch}`)
560+
console.error(` Node: ${process.version}`)
561+
console.error(` Binary: ${CONFIG.binaryPath}`)
562+
console.error(` Exists: ${getInstalledBinaryStatus()}`)
563+
564+
if (process.platform === 'win32') {
565+
console.error('')
566+
console.error(
567+
'On Windows, this can happen when Windows Security or antivirus blocks',
568+
)
569+
console.error(
570+
'or quarantines the downloaded executable, or when the binary requires',
571+
)
572+
console.error('CPU instructions that are not available on this machine.')
573+
}
574+
575+
console.error('')
576+
console.error('Try deleting the downloaded files and running again:')
577+
console.error(` ${CONFIG.configDir}`)
578+
console.error('')
579+
}
580+
581+
function spawnInstalledBinary(options = {}) {
582+
if (!fs.existsSync(CONFIG.binaryPath)) {
583+
try {
584+
if (fs.existsSync(CONFIG.metadataPath)) fs.unlinkSync(CONFIG.metadataPath)
585+
} catch {
586+
// best effort
587+
}
588+
const error = new Error(
589+
`downloaded binary is missing at ${CONFIG.binaryPath}`,
590+
)
591+
error.code = 'BINARY_MISSING'
592+
printSpawnFailure(error)
593+
process.exit(1)
594+
}
553595

554596
const child = spawn(CONFIG.binaryPath, process.argv.slice(2), {
555597
stdio: 'inherit',
598+
...options,
599+
})
600+
601+
child.on('error', (err) => {
602+
printSpawnFailure(err)
603+
process.exit(1)
556604
})
557605

606+
return child
607+
}
608+
609+
async function main() {
610+
await ensureBinaryExists()
611+
612+
const child = spawnInstalledBinary()
613+
558614
const exitListener = (code, signal) => {
559615
resetTerminal()
560616
printCrashDiagnostics(code, signal)
@@ -563,11 +619,6 @@ async function main() {
563619

564620
child.on('exit', exitListener)
565621

566-
child.on('error', (err) => {
567-
console.error('Failed to start freebuff:', err.message)
568-
process.exit(1)
569-
})
570-
571622
setTimeout(() => {
572623
checkForUpdates(child, exitListener)
573624
}, 100)

0 commit comments

Comments
 (0)