2016-12-11 22:37:25 +00:00
|
|
|
#!/usr/bin/env node
|
|
|
|
/**
|
|
|
|
* Usage:
|
|
|
|
* test-npm-package.js [--install] [--rebuild] <source> <test-arg>+
|
|
|
|
*
|
|
|
|
* Everything after the <source> directory gets passed to `npm run` to build
|
|
|
|
* the test command.
|
|
|
|
*
|
|
|
|
* If `--install` is passed, we'll run a full `npm install` before running the
|
|
|
|
* test suite. Same for `--rebuild` and `npm rebuild`.
|
|
|
|
*
|
|
|
|
* We always use the node used to spawn this script and the `npm` version
|
|
|
|
* bundled in `deps/npm`.
|
|
|
|
*
|
|
|
|
* If an additional `--logfile=<filename>` option is passed before `<source>`,
|
|
|
|
* the stdout output of the test script will be written to that file.
|
|
|
|
*/
|
|
|
|
'use strict';
|
|
|
|
const { spawn, spawnSync } = require('child_process');
|
|
|
|
const { createHash } = require('crypto');
|
|
|
|
const { createWriteStream, mkdirSync, rmdirSync } = require('fs');
|
|
|
|
const path = require('path');
|
|
|
|
|
|
|
|
const common = require('../test/common');
|
2018-03-12 06:39:36 +00:00
|
|
|
const tmpDir = require('../test/common/tmpdir');
|
2016-12-11 22:37:25 +00:00
|
|
|
|
|
|
|
const projectDir = path.resolve(__dirname, '..');
|
2017-06-03 19:37:01 +00:00
|
|
|
const npmBin = path.join(projectDir, 'deps', 'npm', 'bin', 'npm-cli.js');
|
2016-12-11 22:37:25 +00:00
|
|
|
const nodePath = path.dirname(process.execPath);
|
|
|
|
|
|
|
|
function spawnCopyDeepSync(source, destination) {
|
|
|
|
if (common.isWindows) {
|
2019-03-22 02:44:26 +00:00
|
|
|
mkdirSync(destination); // Prevent interactive prompt
|
2016-12-11 22:37:25 +00:00
|
|
|
return spawnSync('xcopy.exe', ['/E', source, destination]);
|
|
|
|
}
|
2020-04-08 16:58:03 +00:00
|
|
|
return spawnSync('cp', ['-r', `${source}/`, destination]);
|
2016-12-11 22:37:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
function runNPMPackageTests({ srcDir, install, rebuild, testArgs, logfile }) {
|
|
|
|
// Make sure we don't conflict with concurrent test runs
|
|
|
|
const srcHash = createHash('md5').update(srcDir).digest('hex');
|
2018-03-12 06:39:36 +00:00
|
|
|
tmpDir.path = `${tmpDir.path}.npm.${srcHash}`;
|
|
|
|
tmpDir.refresh();
|
2016-12-11 22:37:25 +00:00
|
|
|
|
2018-03-12 06:39:36 +00:00
|
|
|
const npmCache = path.join(tmpDir.path, 'npm-cache');
|
|
|
|
const npmPrefix = path.join(tmpDir.path, 'npm-prefix');
|
|
|
|
const npmTmp = path.join(tmpDir.path, 'npm-tmp');
|
|
|
|
const npmUserconfig = path.join(tmpDir.path, 'npm-userconfig');
|
|
|
|
const pkgDir = path.join(tmpDir.path, 'pkg');
|
2016-12-11 22:37:25 +00:00
|
|
|
|
|
|
|
spawnCopyDeepSync(srcDir, pkgDir);
|
|
|
|
|
|
|
|
const npmOptions = {
|
|
|
|
cwd: pkgDir,
|
|
|
|
env: Object.assign({}, process.env, {
|
|
|
|
'npm_config_cache': npmCache,
|
|
|
|
'npm_config_prefix': npmPrefix,
|
|
|
|
'npm_config_tmp': npmTmp,
|
|
|
|
'npm_config_userconfig': npmUserconfig,
|
|
|
|
}),
|
|
|
|
stdio: 'inherit',
|
|
|
|
};
|
|
|
|
|
|
|
|
if (common.isWindows) {
|
2018-03-12 06:39:36 +00:00
|
|
|
npmOptions.env.home = tmpDir.path;
|
2016-12-11 22:37:25 +00:00
|
|
|
npmOptions.env.Path = `${nodePath};${process.env.Path}`;
|
|
|
|
} else {
|
2018-03-12 06:39:36 +00:00
|
|
|
npmOptions.env.HOME = tmpDir.path;
|
2016-12-11 22:37:25 +00:00
|
|
|
npmOptions.env.PATH = `${nodePath}:${process.env.PATH}`;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (rebuild) {
|
|
|
|
spawnSync(process.execPath, [
|
|
|
|
npmBin,
|
|
|
|
'rebuild',
|
|
|
|
], npmOptions);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (install) {
|
|
|
|
spawnSync(process.execPath, [
|
|
|
|
npmBin,
|
|
|
|
'install',
|
|
|
|
'--ignore-scripts',
|
2017-06-03 19:37:01 +00:00
|
|
|
'--no-save',
|
2016-12-11 22:37:25 +00:00
|
|
|
], npmOptions);
|
|
|
|
}
|
|
|
|
|
|
|
|
const testChild = spawn(process.execPath, [
|
|
|
|
npmBin,
|
|
|
|
'--silent',
|
|
|
|
'run',
|
|
|
|
...testArgs,
|
|
|
|
], Object.assign({}, npmOptions, { stdio: 'pipe' }));
|
|
|
|
|
|
|
|
testChild.stdout.pipe(process.stdout);
|
|
|
|
testChild.stderr.pipe(process.stderr);
|
|
|
|
|
|
|
|
if (logfile) {
|
|
|
|
const logStream = createWriteStream(logfile);
|
|
|
|
testChild.stdout.pipe(logStream);
|
|
|
|
}
|
|
|
|
|
|
|
|
testChild.on('exit', () => {
|
2018-03-12 06:39:36 +00:00
|
|
|
tmpDir.refresh();
|
|
|
|
rmdirSync(tmpDir.path);
|
2016-12-11 22:37:25 +00:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
function parseArgs(args) {
|
|
|
|
let srcDir;
|
|
|
|
let rebuild = false;
|
|
|
|
let install = false;
|
|
|
|
let logfile = null;
|
|
|
|
const testArgs = [];
|
|
|
|
args.forEach((arg) => {
|
|
|
|
if (srcDir) {
|
|
|
|
testArgs.push(arg);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (arg === '--install') {
|
|
|
|
install = true;
|
|
|
|
} else if (arg === '--rebuild') {
|
|
|
|
rebuild = true;
|
|
|
|
} else if (arg[0] !== '-') {
|
|
|
|
srcDir = path.resolve(projectDir, arg);
|
|
|
|
} else if (arg.startsWith('--logfile=')) {
|
|
|
|
logfile = path.resolve(projectDir, arg.slice('--logfile='.length));
|
|
|
|
} else {
|
|
|
|
throw new Error(`Unrecognized option ${arg}`);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
if (!srcDir) {
|
|
|
|
throw new Error('Expected a source directory');
|
|
|
|
}
|
|
|
|
return { srcDir, install, rebuild, testArgs, logfile };
|
|
|
|
}
|
|
|
|
|
|
|
|
runNPMPackageTests(parseArgs(process.argv.slice(2)));
|