UNPKG

vnu-jar

Version:

Provides the Nu Html Checker «vnu.jar» file

154 lines (141 loc) 5.15 kB
#!/usr/bin/env node 'use strict'; const { spawnSync, execSync } = require('child_process'); const { mkdirSync, existsSync, createWriteStream } = require('fs'); const { join, dirname, parse } = require('path'); const { Readable } = require('stream'); const fetch = globalThis.fetch || require('node-fetch'); function findNearestNodeModules(startDir) { let dir = startDir; const { root } = parse(startDir); while (true) { const candidate = join(dir, 'node_modules'); if (existsSync(candidate)) { return candidate; } if (dir === root) { throw new Error('Could not find a node_modules directory.'); } dir = dirname(dir); } } const NODE_MODULES_DIR = findNearestNodeModules(__dirname); const CACHE_DIR = join(NODE_MODULES_DIR, '.cache', 'vnu-jar', 'java'); const TEMURIN_VERSION = '17.0.17+10'; const TEMURIN_BASE_URL = `https://github.com/adoptium/temurin17-binaries/releases/download/jdk-${TEMURIN_VERSION}/`; function getJavaVersion(javaPath) { try { const result = spawnSync(javaPath, ['-version'], { encoding: 'utf8' }); const versionOutput = result.stderr || result.stdout || ''; const match = versionOutput.match(/version "(\d+)(?:\.(\d+))?/); if (match) { const majorVersion = parseInt(match[1], 10); return majorVersion; } } catch (err) { return null; } return null; } function findSystemJava() { const whichCmd = process.platform === 'win32' ? 'where' : 'which'; const result = spawnSync(whichCmd, ['java'], { encoding: 'utf8' }); if (result.status === 0 && result.stdout) { const javaPath = result.stdout.split(/\r?\n/)[0].trim(); const version = getJavaVersion(javaPath); if (version !== null && version >= 11) { return javaPath; } } return null; } function getPlatformArchiveName() { let arch = process.arch; let plat = 'linux'; if (process.platform === 'win32') { plat = 'windows'; } else if (process.platform === 'darwin') { plat = 'mac'; } if (plat === 'mac' && arch === 'arm64') { arch = 'aarch64'; } const ext = process.platform === 'win32' ? 'zip' : 'tar.gz'; const version = TEMURIN_VERSION.replace('+', '_'); return `OpenJDK17U-jre_${arch}_${plat}_hotspot_${version}.${ext}`; } async function downloadJava() { mkdirSync(CACHE_DIR, { recursive: true }); const archiveName = getPlatformArchiveName(); const url = TEMURIN_BASE_URL + archiveName; const archivePath = join(CACHE_DIR, archiveName); console.log(`Downloading Java 17 runtime from ${url}...`); const res = await fetch(url); if (!res.ok) { throw new Error(`Failed to download Java: ${res.status} ${res.statusText}`); } await new Promise((resolve, reject) => { const file = createWriteStream(archivePath); Readable.fromWeb(res.body) .pipe(file) .on('finish', resolve) .on('error', reject); }); if (process.platform === 'win32') { console.log('Extracting ZIP archive...'); const extractRes = spawnSync('powershell', [ '-NoProfile', '-NonInteractive', '-Command', 'Expand-Archive', '-Force', archivePath, CACHE_DIR ], { stdio: 'inherit' }); if (extractRes.status !== 0) { throw new Error('Failed to extract Java archive.'); } } else { console.log('Extracting tar.gz archive...'); const extractRes = spawnSync('tar', ['-xzf', archivePath, '-C', CACHE_DIR], { stdio: 'inherit' }); if (extractRes.status !== 0) { throw new Error('Failed to extract Java archive.'); } } console.log('Local Java runtime now installed.'); } function resolveLocalJavaExecutable() { let javaPath = join(CACHE_DIR, `jdk-${TEMURIN_VERSION}-jre`, 'bin', 'java'); if (process.platform === 'win32') { javaPath = join(CACHE_DIR, `jdk-${TEMURIN_VERSION}-jre`, 'bin', 'java.exe'); } else if (process.platform === 'darwin') { javaPath = join(CACHE_DIR, `jdk-${TEMURIN_VERSION}-jre`, 'Contents', 'Home', 'bin', 'java'); } if (!existsSync(javaPath)) { throw new Error('Local Java runtime not found after installation.'); } return javaPath; } async function ensureLocalJava() { if (!existsSync(CACHE_DIR)) { await downloadJava(); } return resolveLocalJavaExecutable(); } async function resolveJava() { const javaPath = findSystemJava(); if (javaPath) return javaPath; try { return resolveLocalJavaExecutable(); } catch (err) { console.error('Failed to resolve local Java runtime, falling back to ensureLocalJava():', err); } return ensureLocalJava(); } if (require.main === module) { void resolveJava().catch((err) => { console.error('Failed to resolve Java runtime:', err && err.stack ? err.stack : String(err)); process.exit(1); }); } module.exports = { resolveJava };