crootfast
Version:
大前端工程化命令行脚手架
374 lines (346 loc) • 10.3 kB
JavaScript
const shelljs = require('shelljs');
const spawn = require('cross-spawn');
const sudo = require('sudo-prompt');
const colors = require('colors');
const loading = require('loading-cli');
const package = require('../../package.json');
const { mlog } = require('./logWithLineInfo');
const { isWin } = require('../../lib/cmd');
// 通过 n 工具切换node的版本
function switchNodeVersion(version) {
return new Promise((resolve, reject) => {
const successResponse = responseFormat({
code: 200,
success: true,
message: `使用 n 工具,成功切换到 Node.js 版本 ${version}`
});
const catchResponse = responseFormat({
code: 4030,
message: `使用 n 工具,切换 Node.js 版本时出错 ${err}`
});
isWin().then(resp => {
if (resp) {
// executeCommand(
// 'n', `${version}`
// ).then(resp => {
// // let data = resp.data;
// // console.log('switchNodeVersion', data);
// resolve(successResponse);
// }).catch(err => {
// mlog(err);
// // console.log(err);
// reject(catchResponse);
// });
} else {
executeCommand(
'sudo', `n ${version}`
).then(resp => {
// let data = resp.data;
// console.log('switchNodeVersion', data);
resolve(successResponse);
}).catch(err => {
mlog(err);
// console.log(err);
reject(catchResponse);
});
}
});
});
};
// 启动命令
function executeCommand(command, args = "") {
// console.log(command, args);
if (command === "sudo") {
return sudoPromptChildProcess(args);
} else {
return childProcessSpawn(command, args);
}
};
// 基于 sudo-prompt 模块执行的子进程
function sudoPromptChildProcess(args) {
return new Promise((resolve, reject) => {
// 使用 sudo-prompt 执行命令
sudo.exec(`${args}`, { name: package.name }, (error, stdout, stderr) => {
if (error) {
reject(
responseFormat({
message: `Error: ${error.message} [基于 sudo-prompt 模块执行的子进程发生异常错误,执行参数为:${args}]`
})
);
return;
}
if (stderr) {
mlog(`[log stderr] ${stderr}`);
}
if (stdout) {
// console.log(`stdout: ${stdout}`);
resolve(
responseFormat({
code: 1020,
success: true,
data: {
stdout: stdout
}
})
);
} else {
resolve(
responseFormat({
code: 200,
success: true,
data: {
stdout: stdout
}
})
);
}
});
});
};
// 基于 child_process spawn 执行的命令
function childProcessSpawn(command, args) {
return new Promise((resolve, reject) => {
// 创建一个子进程
const child = spawn(command, args.split(" "));
// 从子进程的 stdout 获取数据并打印
child.stdout.on('data', (data) => {
data && console.log('[log stdout] ', data.toString());
resolve(
responseFormat({
code: 1020,
success: false,
message: "进行中",
data: {
stdout: data.toString()
}
})
);
});
// 从子进程的 stderr 获取数据并打印
child.stderr.on('data', (data) => {
mlog('[log stderr] ', data);
});
// 监听子进程的 'close' 事件
child.on('close', (code) => {
if (code !== 0) {
reject(new Error(`command "${command} ${args}" exited with wrong status code "${code}"`));
} else {
resolve(
responseFormat({
code: 200,
success: true,
message: `子进程执行命令已结束,执行命令为${command} ${args}`,
data: {
code
}
})
);
}
});
// 监听子进程的 'error' 事件
child.on('error', (err) => {
reject(
responseFormat({
message: err
})
);
});
});
};
// 基于 shelljs 执行命令
function shelljsChildProcessSpawn(command, args, hasClear = true) {
return new Promise((resolve, reject) => {
shelljs.exec(`${command} ${args}`, {
env: { ...process.env, $cwd: process.cwd() }
}, (code, stdout, stderr) => {
// console.log('Exit code:', code);
// console.log('Program output:', stdout);
// console.log('Program stderr:', stderr);
// console.log(command, args);
if (stdout) {
// 清除终端
hasClear && console.clear();
// console.log('[log stdout] ', stdout.toString());
resolve(
responseFormat({
code: 1020,
success: false,
message: "进行中",
data: {
stdout: stdout.toString()
}
})
);
}
if (stderr) {
console.log('[log stderr] ', stderr.toString());
// resolve();
}
if (code !== 0) {
reject(new Error(`command "${command} ${args}" exited with wrong status code "${code}"`));
process.exit(1);
} else {
resolve(
responseFormat({
code: 200,
success: true,
message: `子进程执行命令已结束,执行命令为${command} ${args}`,
data: {
code
}
})
);
}
});
});
};
// 安装指定的依赖包
function installPackage(command, params = [], pkgname = '') {
return new Promise((resolve, reject) => {
// 命令行参数
const args = params.split(" ");
// 创建一个子进程
const child = spawn(command, args);
console.log('[log info]', `正在执行 ${command} ${params} 命令。`);
// 从子进程的 stdout 获取数据并打印
child.stdout.on('data', (data) => {
console.log('[log stdout] ', colors.grey(`正在安装${pkgname},${data.toString()}。`));
});
// 从子进程的 stderr 获取数据并打印
child.stderr.on('data', (data) => {
console.log('[stderr log] ', colors.red(`安装中出现异常,${data.toString()}。`));
});
// 监听子进程的 'close' 事件
child.on('close', (code) => {
if (code !== 0) {
new Error(`command "${command} ${params}" exited with wrong status code "${code}"`);
process.exit(1);
// return reject();
} else {
console.log('[log stdout] ', colors.green(`${pkgname} 安装完成。`));
resolve(
responseFormat({
code: 200,
success: true
})
);
}
});
// 监听子进程的 'error' 事件
child.on('error', (err) => {
console.log('[error log] ', err);
});
});
};
// const memoryUsage = process.memoryUsage();
// 通过命令行执行命令
function commandLineInterface(cmd, params = [], logs = {}, hasClear = true) {
// const oLoad = loading(colors.green(` [log info] ${logs.start} \n`));
// oLoad.frame(["🕐", "🕑", "🕒", "🕓", "🕔", "🕕", "🕖", "🕗", "🕘", "🕙", "🕚"]);
// oLoad.start();
console.log(colors.green(`[log info] ${logs.start} \n`));
return new Promise((resolve, reject) => {
// 命令行参数
// const args = params;
// 创建一个子进程
const child = spawn(cmd, params, {
env: { ...process.env, $cwd: process.cwd() }
});
// console.log('\n\n\n\n\n\n\n\n\n\n\n\n\n\n');
// 从子进程的 stdout 获取数据并打印
child.stdout.on('data', (data) => {
// 清除终端
// hasClear && console.clear();
console.log('[log stdout]', handleOutput(`命令执行中, 日志信息: ${data.toString()}`));
// console.log(`Heap Used: ${memoryUsage.heapUsed / 1024 / 1024} MB`);
resolve(
responseFormat({
code: 1010,
success: true
})
);
});
// 从子进程的 stderr 获取数据并打印
child.stderr.on('data', (data) => {
console.log('[log stderr]', handleOutput(`提醒: ${data.toString()}`));
reject(
responseFormat({
code: 4100,
message: data.toString()
})
)
});
// 监听子进程的 'close' 事件
child.on('close', (code) => {
if (code !== 0) {
new Error(`command "${cmd} ${params.join("")}" exited with wrong status code "${code}"`);
process.exit(1);
// return reject();
} else {
console.log('[log close]', colors.green(`${logs.success ?? ''}`));
resolve(
responseFormat({
code: 200,
success: true
})
);
}
});
// 监听子进程的退出事件
child.on('exit', (code, signal) => {
// console.log(`子进程退出, 退出代码: ${code}`);
// 在这里进行必要的清理操作
child?.kill();
});
// 监听子进程的 'error' 事件
child.on('error', (err) => {
console.log('[error log] ', colors.red(err));
reject(
responseFormat({
message: err.message
})
)
});
});
};
// 返回数据格式
function responseFormat(configs = {}) {
let options = {
code: 4000,
success: false,
message: '',
data: {}
};
Object.assign(options, configs);
return options;
}
// 终端输出的文案的颜色设置
function handleOutput(output) {
const lines = output.split('\n');
const result = lines.map(line => {
if (line.startsWith('ERROR in') || line.trim().startsWith('Error') || line.trim().startsWith('Error:')) {
return colors.red(line);
}
if (line.startsWith('WARNING in') || line.trim().startsWith('WARNING') || line.trim().startsWith('WARNING:')) {
return colors.yellow(line);
}
return colors.green(line);
// if (inErrorBlock === 1) {
// if (line.trim() === '') {
// inErrorBlock = 0;
// }
// return colors.red(line);
// } else {
// return colors.green(line);
// }
});
return result.join('\n');
}
module.exports = {
switchNodeVersion,
executeCommand,
responseFormat,
installPackage,
commandLineInterface,
shelljsChildProcessSpawn
};