71 lines
2.9 KiB
JavaScript
71 lines
2.9 KiB
JavaScript
#!/usr/bin/env node
|
|
|
|
import { cpSync, existsSync, mkdtempSync, mkdirSync, readFileSync, rmSync } from 'node:fs';
|
|
import { createRequire } from 'node:module';
|
|
import { tmpdir } from 'node:os';
|
|
import { dirname, join, resolve } from 'node:path';
|
|
import { spawnSync } from 'node:child_process';
|
|
import { fileURLToPath } from 'node:url';
|
|
|
|
const require = createRequire(import.meta.url);
|
|
const root = resolve(dirname(fileURLToPath(import.meta.url)), '..');
|
|
const expectedVersion = JSON.parse(readFileSync(join(root, 'package.json'), 'utf8')).dependencies?.npm;
|
|
const npmPackagePath = require.resolve('npm/package.json');
|
|
const npmPackage = JSON.parse(readFileSync(npmPackagePath, 'utf8'));
|
|
const npmCli = join(dirname(npmPackagePath), 'bin', 'npm-cli.js');
|
|
const destination = join(root, 'build', 'publish-runtime');
|
|
|
|
if (npmPackage.version !== expectedVersion) {
|
|
throw new Error(`Publish npm version mismatch: expected ${expectedVersion}, got ${npmPackage.version}`);
|
|
}
|
|
if (!npmPackage.bundleDependencies?.includes('proc-log')) {
|
|
throw new Error('Publish npm package does not declare its runtime dependencies as bundled dependencies');
|
|
}
|
|
|
|
const temporaryRoot = mkdtempSync(join(tmpdir(), 'makelore-publish-runtime-'));
|
|
try {
|
|
const packResult = spawnSync(process.execPath, [
|
|
npmCli,
|
|
'pack',
|
|
dirname(npmPackagePath),
|
|
'--ignore-scripts',
|
|
'--json',
|
|
'--pack-destination',
|
|
temporaryRoot,
|
|
], { cwd: root, encoding: 'utf8', shell: false });
|
|
if (packResult.status !== 0) {
|
|
throw new Error(`Unable to pack publish npm runtime: ${packResult.stderr || packResult.stdout}`);
|
|
}
|
|
const packMetadata = JSON.parse(packResult.stdout);
|
|
if (!Array.isArray(packMetadata) || packMetadata.length !== 1) {
|
|
throw new Error('npm pack returned unexpected metadata');
|
|
}
|
|
const filename = packMetadata[0]?.filename;
|
|
if (typeof filename !== 'string'
|
|
|| !/^[^/\\]+\.tgz$/.test(filename)
|
|
|| resolve(temporaryRoot, filename) !== join(temporaryRoot, filename)) {
|
|
throw new Error(`npm pack returned an unsafe filename: ${JSON.stringify(filename)}`);
|
|
}
|
|
mkdirSync(join(temporaryRoot, 'runtime'), { recursive: true });
|
|
await import('tar').then(({ x }) => x({
|
|
file: join(temporaryRoot, filename),
|
|
cwd: join(temporaryRoot, 'runtime'),
|
|
strip: 1,
|
|
}));
|
|
|
|
const stagedRuntime = join(temporaryRoot, 'runtime');
|
|
for (const dependency of npmPackage.bundleDependencies) {
|
|
if (!existsSync(join(stagedRuntime, 'node_modules', ...dependency.split('/'), 'package.json'))) {
|
|
throw new Error(`Packed npm runtime is missing bundled dependency ${dependency}`);
|
|
}
|
|
}
|
|
|
|
rmSync(destination, { recursive: true, force: true });
|
|
mkdirSync(dirname(destination), { recursive: true });
|
|
cpSync(stagedRuntime, destination, { recursive: true });
|
|
} finally {
|
|
rmSync(temporaryRoot, { recursive: true, force: true });
|
|
}
|
|
|
|
console.log(`Prepared self-contained npm ${npmPackage.version} runtime at ${destination}`);
|