Skip to content

Commit 0ae2187

Browse files
committed
feat(build-infra): add preflight-checks runner for DRY build validation
Create unified preflight checks module that combines disk space, compiler, and Python version checks with configurable options and error handling. New utilities: - runPreflightChecks: Configurable checks with result aggregation - runPreflightChecksOrExit: Convenience wrapper that exits on failure Configuration options: - disk: Check disk space (default: true, 5GB) - compiler: Check for C++ compiler with fallback list - python: Check Python version (default: 3.6+) - quiet: Suppress output - failFast: Exit on first failure (default: true) Benefits: - Eliminates ~165 lines of repeated preflight code across 12 builders - Consistent check patterns and error messages - Configurable checks per build script needs - Better error aggregation and reporting - Reusable across all builder packages Next: Update builder scripts to use shared preflight runner
1 parent 49d1a67 commit 0ae2187

File tree

2 files changed

+130
-0
lines changed

2 files changed

+130
-0
lines changed
Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
/**
2+
* @fileoverview Preflight checks runner for build scripts.
3+
* Provides a DRY way to run common pre-build validation checks.
4+
*/
5+
6+
import { logger } from '@socketsecurity/lib/logger'
7+
8+
import { printError, printSuccess } from './build-output.mjs'
9+
import {
10+
checkCompiler,
11+
checkDiskSpace,
12+
checkPythonVersion,
13+
} from './build-helpers.mjs'
14+
15+
/**
16+
* Run preflight checks for build scripts.
17+
*
18+
* @param {object} options - Check options
19+
* @param {boolean} [options.disk=true] - Check disk space
20+
* @param {number} [options.diskGB=5] - Required disk space in GB
21+
* @param {boolean} [options.compiler=false] - Check for C++ compiler
22+
* @param {string|string[]} [options.compilers] - Specific compiler(s) to check
23+
* @param {boolean} [options.python=false] - Check Python version
24+
* @param {string} [options.pythonVersion='3.6'] - Minimum Python version
25+
* @param {boolean} [options.quiet=false] - Suppress output
26+
* @param {boolean} [options.failFast=true] - Exit on first failure
27+
* @returns {Promise<{passed: boolean, failures: string[]}>}
28+
*/
29+
export async function runPreflightChecks(options = {}) {
30+
const {
31+
compiler = false,
32+
compilers,
33+
disk = true,
34+
diskGB = 5,
35+
failFast = true,
36+
python = false,
37+
pythonVersion = '3.6',
38+
quiet = false,
39+
} = options
40+
41+
const failures = []
42+
43+
if (!quiet) {
44+
logger.step('Running preflight checks')
45+
logger.log('')
46+
}
47+
48+
// Check disk space.
49+
if (disk) {
50+
const diskCheck = await checkDiskSpace('.', diskGB)
51+
if (!diskCheck.sufficient) {
52+
const msg = `Insufficient disk space: ${diskCheck.availableGB}GB available, ${diskGB}GB required`
53+
failures.push(msg)
54+
if (!quiet) {
55+
printError(msg)
56+
}
57+
if (failFast) {
58+
return { failures, passed: false }
59+
}
60+
}
61+
}
62+
63+
// Check compiler.
64+
if (compiler) {
65+
const compilerCheck = await checkCompiler(compilers)
66+
if (!compilerCheck.available) {
67+
const msg = compilers
68+
? `No C++ compiler found (tried: ${Array.isArray(compilers) ? compilers.join(', ') : compilers})`
69+
: 'No C++ compiler found'
70+
failures.push(msg)
71+
if (!quiet) {
72+
printError(msg)
73+
}
74+
if (failFast) {
75+
return { failures, passed: false }
76+
}
77+
}
78+
}
79+
80+
// Check Python.
81+
if (python) {
82+
const pythonCheck = await checkPythonVersion(pythonVersion)
83+
if (!pythonCheck.available) {
84+
const msg = `Python ${pythonVersion}+ not found`
85+
failures.push(msg)
86+
if (!quiet) {
87+
printError(msg)
88+
}
89+
if (failFast) {
90+
return { failures, passed: false }
91+
}
92+
}
93+
}
94+
95+
if (!quiet) {
96+
if (!failures.length) {
97+
printSuccess('All preflight checks passed')
98+
logger.log('')
99+
} else {
100+
printError(`${failures.length} preflight check(s) failed`)
101+
logger.log('')
102+
}
103+
}
104+
105+
return {
106+
failures,
107+
passed: !failures.length,
108+
}
109+
}
110+
111+
/**
112+
* Run preflight checks and exit on failure.
113+
*
114+
* @param {object} options - Check options
115+
* @returns {Promise<void>}
116+
*/
117+
export async function runPreflightChecksOrExit(options = {}) {
118+
const result = await runPreflightChecks(options)
119+
120+
if (!result.passed) {
121+
if (!options.quiet) {
122+
logger.error('Preflight checks failed')
123+
for (const failure of result.failures) {
124+
logger.error(` - ${failure}`)
125+
}
126+
}
127+
process.exit(1)
128+
}
129+
}

packages/build-infra/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
"./lib/emscripten-builder": "./lib/emscripten-builder.mjs",
1414
"./lib/extraction-cache": "./lib/extraction-cache.mjs",
1515
"./lib/patch-validator": "./lib/patch-validator.mjs",
16+
"./lib/preflight-checks": "./lib/preflight-checks.mjs",
1617
"./lib/rust-builder": "./lib/rust-builder.mjs",
1718
"./lib/script-runner": "./lib/script-runner.mjs",
1819
"./lib/tool-installer": "./lib/tool-installer.mjs"

0 commit comments

Comments
 (0)