43 lines
1.4 KiB
JavaScript
43 lines
1.4 KiB
JavaScript
const childProcess = require('child_process');
|
||
|
||
function getExecutable(command) {
|
||
// Windows 全局安装的命令通常是 .cmd 文件,其他系统直接使用命令名。
|
||
return process.platform === 'win32' ? `${command}.cmd` : command;
|
||
}
|
||
|
||
function commandExists(command) {
|
||
// 使用系统自带的命令查找能力,避免为了检测 Yarn 引入额外依赖。
|
||
const lookupCommand = process.platform === 'win32' ? 'where.exe' : 'which';
|
||
const result = childProcess.spawnSync(lookupCommand, [getExecutable(command)], {
|
||
stdio: 'ignore',
|
||
});
|
||
return result.status === 0;
|
||
}
|
||
|
||
function ensureYarnAvailable(isCommandAvailable = commandExists) {
|
||
// 参数可注入是为了让测试覆盖 Yarn 存在和不存在两种情况。
|
||
if (!isCommandAvailable('yarn')) {
|
||
throw new Error('未检测到 Yarn,请先安装 Yarn');
|
||
}
|
||
}
|
||
|
||
function runYarn(args, cwd) {
|
||
ensureYarnAvailable();
|
||
const executable = getExecutable('yarn');
|
||
console.log(`执行: yarn ${args.join(' ')}`);
|
||
if (process.platform === 'win32') {
|
||
// Node.js 不能始终直接执行 yarn.cmd,因此交给 cmd.exe 解析,避免 spawnSync yarn ENOENT。
|
||
childProcess.execFileSync(process.env.ComSpec || 'cmd.exe', [
|
||
'/d',
|
||
'/s',
|
||
'/c',
|
||
executable,
|
||
...args,
|
||
], { cwd, stdio: 'inherit' });
|
||
return;
|
||
}
|
||
childProcess.execFileSync(executable, args, { cwd, stdio: 'inherit' });
|
||
}
|
||
|
||
module.exports = { commandExists, ensureYarnAvailable, runYarn };
|