const fs = require('fs-extra');
|
const { execSync } = require('child_process');
|
const os = require('os');
|
const path = require('path');
|
const chalk = require('chalk');
|
|
// 获取当前脚本所在的目录
|
const scriptDir = __dirname;
|
const rootDir = path.resolve(scriptDir, '..');
|
const argv2 = process.argv[2];
|
const arg2 = argv2?.split(' ');
|
|
const customerList = arg2?.[0] ? (arg2[0] === 'pro' ? ['ch:pro'] : ['ch']) : ['ch'];
|
const publicDir = path.join(rootDir, 'public');
|
const distDir = path.join(rootDir, 'dist');
|
const customerListDir = path.join(rootDir, 'customer_list');
|
const customerProjectListDir = path.join(rootDir, 'src', 'views', 'project');
|
const homeDir = os.homedir();
|
// const deployEnv = process.argv[3];
|
|
const logColor = (text, color) => {
|
console.log(chalk[color](text));
|
};
|
|
const logError = (text) => {
|
logColor(text, 'red');
|
};
|
|
const logSuccess = (text) => {
|
logColor(text, 'green');
|
};
|
|
/**
|
* 检查文件是否存在
|
* @param {*} file
|
* @param {*} fileText
|
*/
|
const checkFileExist = (file, fileText) => {
|
// 验证源文件夹是否存在
|
if (!fs.existsSync(file)) {
|
console.error(chalk.red(`${fileText} "${file}" 不存在!`));
|
process.exit(1); // 退出脚本
|
}
|
};
|
|
const checkCustomerDirExist = (customer) => {
|
const customerDir = path.join(customerListDir, customer);
|
checkFileExist(customerDir, '客户文件夹');
|
};
|
|
/**
|
* 检查命令,是否加上用户名。以及用户文件夹是否存在
|
* @param {*} command
|
* @param {*} customer
|
*/
|
const checkCustomer = (command, customer) => {
|
if (!customer) {
|
console.error(chalk.red(`请正确使用命令 “${command} [customer]” `));
|
|
process.exit(1); // 退出脚本
|
}
|
checkCustomerDirExist(customer);
|
};
|
|
let tmpBakDir = '';
|
const moveProjectsToBakDir = (command) => {
|
const customer = customerList[0]?.split(':')[0];
|
checkCustomer(command, customer);
|
//#region ====================== 创建备份文件夹 ======================
|
let tmpBakRootDir = path.join(homeDir, 'Desktop');
|
if (!fs.existsSync(tmpBakRootDir)) {
|
tmpBakRootDir = homeDir;
|
}
|
tmpBakDir = path.join(tmpBakRootDir, 'bak_project_list');
|
|
fs.ensureDirSync(tmpBakDir);
|
fs.emptyDirSync(tmpBakDir);
|
//#endregion
|
|
const contents = fs.readdirSync(customerProjectListDir);
|
for (let index = 0; index < contents.length; index++) {
|
const item = contents[index];
|
if (item === customer) {
|
continue;
|
}
|
const itemPath = path.join(customerProjectListDir, item);
|
const stats = fs.statSync(itemPath);
|
if (stats.isDirectory()) {
|
const destBakDir = path.join(tmpBakDir, item);
|
fs.moveSync(itemPath, destBakDir, { overwrite: true });
|
}
|
}
|
};
|
|
const restoreProjectDir = () => {
|
const contents = fs.readdirSync(tmpBakDir);
|
for (let index = 0; index < contents.length; index++) {
|
const item = contents[index];
|
const itemPath = path.join(tmpBakDir, item);
|
const destProjectDir = path.join(customerProjectListDir, item);
|
fs.moveSync(itemPath, destProjectDir, { overwrite: true });
|
}
|
};
|
|
/**
|
* 复制文件到 public 文件夹中
|
* (只能复制一个客户文件配置)
|
* @param {*} command
|
* @param {*} customer
|
*/
|
function copyFile(command) {
|
const customer = customerList[0]?.split(':')[0];
|
checkCustomer(command, customer);
|
// 确保 public 文件,不存在则创建
|
fs.ensureDirSync(publicDir);
|
// 清空 public 文件夹
|
fs.emptyDirSync(publicDir);
|
|
// 使用 filter 过滤器,排除特定文件
|
const filter = (src, dest) => {
|
const fileName = path.basename(src);
|
// 排除特定文件
|
if (fileName === 'deploy.json') {
|
return false;
|
}
|
// 其他文件保留
|
return true;
|
};
|
|
const customerDir = path.join(customerListDir, customer);
|
|
// 复制源文件夹中的所有文件到 public 文件夹
|
fs.copySync(customerDir, publicDir, { filter });
|
}
|
|
/**
|
* 上传文件到服务器
|
* @param {*} command
|
*/
|
const uploadFiles = async () => {
|
let customerConfig = {};
|
for (let index = 0; index < customerList.length; index++) {
|
const item = customerList[index];
|
const customerSplit = item.split(':');
|
const customerName = customerSplit[0];
|
checkCustomerDirExist(customerName);
|
const deployJSON = path.join(customerListDir, customerName, 'deploy.json');
|
// 验证部署配置文件是否存在
|
checkFileExist(deployJSON, '配置文件');
|
// 读取 JSON 文件
|
const config = await fs.readJson(deployJSON).catch((err) => {
|
console.error(`读取配置文件“${deployJSON}”出错:`, err);
|
process.exit(1);
|
});
|
|
let deployConfig = null;
|
const deployEnv = customerSplit[1];
|
if (deployEnv === 'pro') {
|
deployConfig = config?.product;
|
} else {
|
deployConfig = config?.test;
|
}
|
if (!deployConfig || Object.values(deployConfig).some((item) => !item)) {
|
console.error(chalk.red(`${customerName} ${deployEnv} 配置不完整!`));
|
process.exit(1); // 退出脚本
|
}
|
// 缓存部署配置
|
customerConfig[item] = deployConfig;
|
}
|
for (const customerDeployName in customerConfig) {
|
if (Object.hasOwnProperty.call(customerConfig, customerDeployName)) {
|
const customerName = customerDeployName.split(':')[0];
|
const deployConfig = customerConfig[customerDeployName];
|
const remoteFolderPath = deployConfig.path;
|
// 获取用户临时目录
|
const userTempDir = os.tmpdir();
|
const timeStamp = new Date().getTime();
|
const uploadScriptFile = path.join(userTempDir, `psftpBatchFile${timeStamp}${customerDeployName}`);
|
// 构建 sftp 命令
|
const sftpCommand = 'psftp';
|
// 上传 dist 中的 assets 和 index.html
|
let uploadCommand = `put -r ${path.join(distDir, 'assets')} ${remoteFolderPath + '/assets'}
|
put ${path.join(distDir, 'index.html')} ${remoteFolderPath + '/index.html'}\n`;
|
|
const customerFolder = path.join(customerListDir, customerName);
|
// 客户文件夹中除 deploy.json 全部上传
|
try {
|
const contents = fs.readdirSync(customerFolder);
|
for (let index = 0; index < contents.length; index++) {
|
const item = contents[index];
|
if (item === 'deploy.json') {
|
continue;
|
}
|
const itemPath = path.join(customerFolder, item);
|
const remotePath = remoteFolderPath + `/${item}`;
|
const stats = fs.statSync(itemPath);
|
|
// 文件夹需要加 -r
|
if (stats.isDirectory()) {
|
uploadCommand += `put -r ${itemPath} ${remotePath}\n`;
|
// 文件不需要加
|
} else if (stats.isFile()) {
|
uploadCommand += `put ${itemPath} ${remotePath}\n`;
|
}
|
}
|
} catch (error) {
|
console.error(`读取“${customerFolder}”失败`, error);
|
}
|
|
try {
|
fs.writeFileSync(uploadScriptFile, uploadCommand);
|
const sftpArgs = [
|
`${deployConfig.username}@${deployConfig.host} -P ${deployConfig.port} -pw ${deployConfig.password} -b ${uploadScriptFile}`,
|
];
|
// 完整的执行命令
|
const fullCommand = `${sftpCommand} ${sftpArgs.join(' ')}`;
|
logSuccess(`正在上传【${customerName}】项目至服务器【${deployConfig.host}:${remoteFolderPath}】...`);
|
execSync(fullCommand, { stdio: ['pipe', 'inherit', 'inherit'] });
|
} catch (error) {
|
console.error(chalk.red(error));
|
} finally {
|
if (fs.existsSync(uploadScriptFile)) {
|
fs.unlinkSync(uploadScriptFile);
|
}
|
}
|
}
|
}
|
logSuccess(`🎉🎉🎉【${customerList.join(',')}】项目已成功部署!🎉🎉🎉`);
|
};
|
|
module.exports = {
|
customerList,
|
//#region ====================== 文件路径 ======================
|
rootDir,
|
scriptDir,
|
publicDir,
|
distDir,
|
customerListDir,
|
//#endregion
|
|
//#region ====================== 工具函数 ======================
|
checkCustomerDirExist,
|
//#endregion
|
checkCustomer,
|
copyFile,
|
uploadFiles,
|
|
//#region ====================== 打印 ======================
|
logError,
|
logSuccess,
|
//#endregion
|
|
moveProjectsToBakDir,
|
restoreProjectDir,
|
};
|