99 lines
4.3 KiB
JavaScript
99 lines
4.3 KiB
JavaScript
/**
|
|
* Post-install convenience: make a Java runtime available for the Firebase
|
|
* Firestore emulator (used by `pnpm -F mnswpr dev` / `db:start`). The emulator is
|
|
* a Java program and firebase-tools does not bundle a JRE.
|
|
*
|
|
* Installs a Temurin JRE 21 into the user's home (~/.local) WITHOUT sudo and
|
|
* symlinks `java` into ~/.local/bin (already on most PATHs). Properties:
|
|
* - idempotent: does nothing if `java` is already on PATH
|
|
* - non-fatal: never fails `pnpm install` — on any problem it warns, exits 0
|
|
* - opt-out: set SKIP_JRE_SETUP=1 (also auto-skips when CI is set)
|
|
* Only Linux/macOS on x64/arm64 are auto-handled; anything else prints manual
|
|
* instructions (see apps/mnswpr/README.md).
|
|
*/
|
|
import { spawnSync } from 'node:child_process'
|
|
import { existsSync, mkdirSync, readdirSync, rmSync, symlinkSync, writeFileSync } from 'node:fs'
|
|
import { homedir, tmpdir, platform, arch } from 'node:os'
|
|
import { join } from 'node:path'
|
|
|
|
const log = msg => console.log(`[ensure-java] ${msg}`)
|
|
const warn = msg => console.warn(`[ensure-java] ${msg}`)
|
|
|
|
// This is a convenience, never a blocker — always exit 0.
|
|
try {
|
|
await main()
|
|
} catch (err) {
|
|
warn(`skipped (${err?.message || err}).`)
|
|
warn('The Firestore emulator needs Java 11+ — install it manually, see apps/mnswpr/README.md.')
|
|
}
|
|
process.exit(0)
|
|
|
|
async function main() {
|
|
if (process.env.SKIP_JRE_SETUP) return log('SKIP_JRE_SETUP set — skipping.')
|
|
if (process.env.CI) return log('CI detected — skipping JRE setup.')
|
|
if (hasJava('java')) return log('Java already on PATH — nothing to do.')
|
|
|
|
const adoptOs = { linux: 'linux', darwin: 'mac' }[platform()]
|
|
const adoptArch = { x64: 'x64', arm64: 'aarch64' }[arch()]
|
|
if (!adoptOs || !adoptArch) {
|
|
warn(`no auto-install for ${platform()}/${arch()} — install a JRE 21 manually (apps/mnswpr/README.md).`)
|
|
return
|
|
}
|
|
if (!hasTool('tar')) {
|
|
warn('`tar` not found — cannot unpack the JRE. Install Java manually (apps/mnswpr/README.md).')
|
|
return
|
|
}
|
|
|
|
const prefix = process.env.JAVA_SETUP_PREFIX || join(homedir(), '.local')
|
|
const libDir = join(prefix, 'lib')
|
|
const binDir = join(prefix, 'bin')
|
|
mkdirSync(libDir, { recursive: true })
|
|
mkdirSync(binDir, { recursive: true })
|
|
|
|
const url = `https://api.adoptium.net/v3/binary/latest/21/ga/${adoptOs}/${adoptArch}/jre/hotspot/normal/eclipse`
|
|
log(`no Java found — downloading Temurin JRE 21 (${adoptOs}/${adoptArch})…`)
|
|
const res = await fetch(url, { redirect: 'follow' })
|
|
if (!res.ok) throw new Error(`download failed: HTTP ${res.status}`)
|
|
const tgz = join(tmpdir(), `temurin-jre-21-${adoptOs}-${adoptArch}.tar.gz`)
|
|
writeFileSync(tgz, Buffer.from(await res.arrayBuffer()))
|
|
|
|
const before = new Set(readdirSync(libDir))
|
|
const untar = spawnSync('tar', ['xzf', tgz, '-C', libDir], { stdio: 'inherit' })
|
|
rmSync(tgz, { force: true })
|
|
if (untar.status !== 0) throw new Error('tar extraction failed')
|
|
|
|
// the top-level dir the tarball created (e.g. jdk-21.0.11+10-jre); on re-runs
|
|
// it already exists, so fall back to the newest matching dir.
|
|
const jreDir = readdirSync(libDir).find(d => !before.has(d) && /jdk.*jre/i.test(d))
|
|
|| readdirSync(libDir).filter(d => /jdk.*jre/i.test(d)).sort().pop()
|
|
if (!jreDir) throw new Error('could not locate the unpacked JRE directory')
|
|
|
|
// java is at bin/java (linux) or Contents/Home/bin/java (macOS)
|
|
const javaBin = [
|
|
join(libDir, jreDir, 'bin', 'java'),
|
|
join(libDir, jreDir, 'Contents', 'Home', 'bin', 'java')
|
|
].find(existsSync)
|
|
if (!javaBin) throw new Error('java binary not found in the unpacked JRE')
|
|
|
|
for (const tool of ['java', 'keytool']) {
|
|
const src = javaBin.replace(/java$/, tool)
|
|
const dst = join(binDir, tool)
|
|
if (existsSync(src)) { rmSync(dst, { force: true }); symlinkSync(src, dst) }
|
|
}
|
|
if (!hasJava(join(binDir, 'java'))) throw new Error('the installed java did not run')
|
|
|
|
log(`installed JRE 21 → ${join(libDir, jreDir)}`)
|
|
log(`linked java → ${join(binDir, 'java')}`)
|
|
if (!(process.env.PATH || '').split(':').includes(binDir)) {
|
|
warn(`${binDir} is not on your PATH — add it (e.g. in ~/.profile) so \`java\` is found.`)
|
|
}
|
|
}
|
|
|
|
function hasJava(bin) {
|
|
const r = spawnSync(bin, ['-version'], { stdio: 'ignore' })
|
|
return !r.error && r.status === 0
|
|
}
|
|
function hasTool(name) {
|
|
const r = spawnSync(name, ['--version'], { stdio: 'ignore' })
|
|
return !r.error
|
|
}
|