218 lines
6.7 KiB
JavaScript
218 lines
6.7 KiB
JavaScript
#!/usr/bin/env node
|
|
/**
|
|
* Orchestrate peardata binary builds.
|
|
*
|
|
* node scripts/make.cjs server # Linux server hosts (bare-build)
|
|
* node scripts/make.cjs client # all client hosts (electron-forge)
|
|
* node scripts/make.cjs both|all # server + client
|
|
*
|
|
* Env:
|
|
* PEARDATA_SERVER_HOSTS=linux-x64,linux-arm64
|
|
* PEARDATA_CLIENT_HOSTS=linux-x64,darwin-arm64,…
|
|
* PEARDATA_CLIENT_TIMEOUT_MS=600000 (raise when packaging QVAC natives)
|
|
* PEARDATA_SKIP_ELECTRON_PREDOWNLOAD=1
|
|
* PEARDATA_SKIP_QVAC=1 tools-only Electron client (no @qvac/sdk bundle)
|
|
*/
|
|
'use strict'
|
|
|
|
const path = require('path')
|
|
const { spawnSync } = require('child_process')
|
|
const {
|
|
SERVER_LINUX,
|
|
ALL_64,
|
|
parseHostList,
|
|
clientNpmScript,
|
|
hostToElectron,
|
|
hostSupportsQvacNative,
|
|
} = require('./hosts.cjs')
|
|
|
|
const root = path.resolve(__dirname, '..')
|
|
|
|
const SERVER_HOSTS = parseHostList(process.env.PEARDATA_SERVER_HOSTS, SERVER_LINUX)
|
|
const CLIENT_HOSTS = parseHostList(process.env.PEARDATA_CLIENT_HOSTS, ALL_64)
|
|
// QVAC native bundle + forge package is heavier than the old asar-only client
|
|
const CLIENT_TIMEOUT_MS = Number(
|
|
process.env.PEARDATA_CLIENT_TIMEOUT_MS ||
|
|
(process.env.PEARDATA_SKIP_QVAC === '1' ? 600_000 : 1_200_000)
|
|
)
|
|
|
|
function run(cmd, args, opts = {}) {
|
|
console.log(`\n$ ${cmd} ${args.join(' ')}\n`)
|
|
const t0 = Date.now()
|
|
const res = spawnSync(cmd, args, {
|
|
cwd: root,
|
|
stdio: 'inherit',
|
|
env: process.env,
|
|
shell: process.platform === 'win32',
|
|
...opts,
|
|
})
|
|
if (res.error) throw res.error
|
|
if (res.status !== 0) process.exit(res.status || 1)
|
|
console.log(`[make] ok in ${((Date.now() - t0) / 1000).toFixed(1)}s`)
|
|
}
|
|
|
|
function npmRun(script, env) {
|
|
run(process.platform === 'win32' ? 'npm.cmd' : 'npm', ['run', script], {
|
|
env: env ? { ...process.env, ...env } : process.env,
|
|
})
|
|
}
|
|
|
|
function makeServer(hosts = SERVER_HOSTS) {
|
|
for (const host of hosts) {
|
|
if (!SERVER_LINUX.includes(host)) {
|
|
console.error(`[make] refusing non-Linux server host: ${host}`)
|
|
process.exit(1)
|
|
}
|
|
}
|
|
console.log(`[make] server hosts (Linux only): ${hosts.join(', ')}`)
|
|
for (const host of hosts) {
|
|
run(process.execPath, [
|
|
path.join(root, 'scripts', 'bare-standalone.cjs'),
|
|
'--product',
|
|
'server',
|
|
'--host',
|
|
host,
|
|
])
|
|
}
|
|
}
|
|
|
|
function predownloadElectron(hosts) {
|
|
if (process.env.PEARDATA_SKIP_ELECTRON_PREDOWNLOAD === '1') {
|
|
console.log('[make] skip electron predownload (PEARDATA_SKIP_ELECTRON_PREDOWNLOAD=1)')
|
|
return
|
|
}
|
|
console.log('[make] pre-downloading Electron for client hosts…')
|
|
run(process.execPath, [path.join(root, 'scripts', 'predownload-electron.cjs')], {
|
|
env: {
|
|
...process.env,
|
|
PEARDATA_CLIENT_HOSTS: hosts.join(','),
|
|
},
|
|
})
|
|
}
|
|
|
|
function ensureBareRuntimes(hosts) {
|
|
if (process.env.PEARDATA_SKIP_QVAC === '1' || process.env.PEARDATA_SKIP_QVAC === 'true') {
|
|
console.log('[make] skip bare-runtime ensure (PEARDATA_SKIP_QVAC=1)')
|
|
return
|
|
}
|
|
// Only QVAC-native hosts need the platform bare binary in the client package
|
|
const need = hosts.filter((h) => hostSupportsQvacNative(h))
|
|
if (!need.length) return
|
|
console.log(`[make] ensuring bare-runtime platform packages: ${need.join(', ')}`)
|
|
run(process.execPath, [
|
|
path.join(root, 'scripts', 'ensure-qvac-bare-runtimes.cjs'),
|
|
'--hosts',
|
|
need.join(','),
|
|
])
|
|
}
|
|
|
|
function makeClient(hosts = CLIENT_HOSTS) {
|
|
console.log(`[make] client hosts: ${hosts.join(', ')}`)
|
|
npmRun('build:client-bundle')
|
|
predownloadElectron(hosts)
|
|
// Cross-host CI: npm ci never installs darwin/win32 optional bare-runtime-* packages.
|
|
// Install them before forge packages so the app ships the Bare worker binary.
|
|
ensureBareRuntimes(hosts)
|
|
|
|
for (const host of hosts) {
|
|
const script = clientNpmScript(host)
|
|
if (!script) {
|
|
console.error(`[make] no client script for host ${host}`)
|
|
process.exit(1)
|
|
}
|
|
const { platform, arch } = hostToElectron(host)
|
|
// QVAC Bare prebuilds are not published for every Electron host (e.g. no win32-arm64).
|
|
// Package a tools-only client there so the matrix still ships a binary.
|
|
const forceSkipQvac =
|
|
process.env.PEARDATA_SKIP_QVAC === '1' || !hostSupportsQvacNative(host)
|
|
if (forceSkipQvac && process.env.PEARDATA_SKIP_QVAC !== '1') {
|
|
console.log(
|
|
`[make] client ${host}: no @qvac/llm-llamacpp prebuild — PEARDATA_SKIP_QVAC=1 (tools-only)`
|
|
)
|
|
}
|
|
console.log(
|
|
`[make] client ${host} (filter prebuilds to ${platform}-${arch}, qvac=${forceSkipQvac ? 'off' : 'on'})`
|
|
)
|
|
const env = {
|
|
...process.env,
|
|
npm_config_build_from_source: 'false',
|
|
PEARDATA_SKIP_REBUILD: process.env.PEARDATA_SKIP_REBUILD || '1',
|
|
PEARDATA_PACKAGE_PLATFORM: platform,
|
|
PEARDATA_PACKAGE_ARCH: arch,
|
|
PEARDATA_SKIP_PREPACKAGE_BUNDLE: '1',
|
|
PEARDATA_SKIP_QVAC: forceSkipQvac ? '1' : process.env.PEARDATA_SKIP_QVAC || '0',
|
|
DEBUG:
|
|
process.env.DEBUG ||
|
|
(process.env.CI ? 'electron-packager,electron-forge:lifecycle' : ''),
|
|
}
|
|
|
|
console.log(
|
|
`[make] client timeout: ${(CLIENT_TIMEOUT_MS / 1000).toFixed(0)}s (PEARDATA_CLIENT_TIMEOUT_MS)`
|
|
)
|
|
const t0 = Date.now()
|
|
const res = spawnSync(
|
|
process.platform === 'win32' ? 'npm.cmd' : 'npm',
|
|
['run', script],
|
|
{
|
|
cwd: root,
|
|
stdio: 'inherit',
|
|
env,
|
|
shell: process.platform === 'win32',
|
|
timeout: CLIENT_TIMEOUT_MS,
|
|
killSignal: 'SIGKILL',
|
|
}
|
|
)
|
|
if (res.error) {
|
|
if (res.error.code === 'ETIMEDOUT') {
|
|
console.error(
|
|
`[make] FATAL: client package ${host} exceeded ${CLIENT_TIMEOUT_MS}ms — killed.`
|
|
)
|
|
process.exit(1)
|
|
}
|
|
throw res.error
|
|
}
|
|
if (res.status !== 0) {
|
|
console.error(`[make] client package ${host} failed with status ${res.status}`)
|
|
process.exit(res.status || 1)
|
|
}
|
|
console.log(`[make] ok ${host} in ${((Date.now() - t0) / 1000).toFixed(1)}s`)
|
|
}
|
|
}
|
|
|
|
function main() {
|
|
const mode = process.argv[2] || 'all'
|
|
const thisHost = `${process.platform}-${process.arch}`
|
|
|
|
switch (mode) {
|
|
case 'server':
|
|
makeServer()
|
|
break
|
|
case 'client':
|
|
makeClient()
|
|
break
|
|
case 'client-this':
|
|
makeClient([thisHost])
|
|
break
|
|
case 'both':
|
|
case 'all':
|
|
makeServer()
|
|
makeClient()
|
|
break
|
|
case 'client-all':
|
|
makeClient(ALL_64)
|
|
break
|
|
default:
|
|
console.error(`Unknown mode: ${mode}`)
|
|
console.error(
|
|
'Usage: node scripts/make.cjs [server|client|client-this|both|all|client-all]'
|
|
)
|
|
console.error(`Server (Linux): ${SERVER_LINUX.join(', ')}`)
|
|
console.error(`Client (all): ${ALL_64.join(', ')}`)
|
|
process.exit(1)
|
|
}
|
|
|
|
console.log('\n[make] complete')
|
|
}
|
|
|
|
main()
|