ql-publish
Version:
159 lines (141 loc) • 5.24 kB
JavaScript
const config = require('../config/config.js')[process.env.NODE_ENV];
const logger = require('../utils/logger');
const { Client } = require('ssh2');
const readline = require("readline");
const path = require("path");
const readStreamByFile = async (sftp, remoteFilePath) => {
return new Promise((resolve) => {
console.log(`准备读取文件: ${remoteFilePath}`);
// 创建读取流
const readStream = sftp.createReadStream(remoteFilePath, {
encoding: 'utf8' // 以UTF-8编码读取
});
let fileContent = '';
// 收集文件内容
readStream.on('data', (chunk) => {
fileContent += chunk;
});
// 读取完成处理
readStream.on('end', () => {
try {
// 解析JSON数据
const jsonData = JSON.parse(fileContent);
console.log('文件内容解析成功:');
resolve(jsonData)
} catch (parseErr) {
logger.error('JSON解析失败:', parseErr);
console.log('原始文件内容:', fileContent);
process.exit(1);
}
});
// 处理读取错误
readStream.on('error', (err) => {
logger.error('读取文件时发生错误:', err);
process.exit(1);
});
})
}
const isHasDir = (sftp, dirPath) => {
return new Promise(resolve => {
sftp.stat(dirPath, (err) => {
resolve(!err);
})
})
}
const authProjectName = () => {
return new Promise((resolve) => {
// 创建readline接口
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
// 向用户提问
rl.question(`${process.env.NODE_ENV}环境:是否确认删除map映射文件 ${config.path} 项目? (输入 y 继续) `, (answer) => {
// 检查用户输入是否为'y'(不区分大小写)
if (answer.trim().toLowerCase() === 'y') {
resolve(true);
} else {
logger.error('❌ 发布程序终止');
resolve(false);
}
// 关闭接口
rl.close();
});
})
}
const deleteFileByMapJson = async (sftp, currentSourceDir, mtime) => {
// 获取源目录中的所有项目
const items = await new Promise((resolve, reject) => {
sftp.readdir(currentSourceDir, (err, list) => {
if (err) {
reject(new Error(`读取目录失败 ${currentSourceDir}: ${err.message}`));
} else {
resolve(list);
}
});
});
// 处理每个项目
for (const item of items) {
const sourcePath = path.posix.join(currentSourceDir, item.filename);
if (item.attrs.isDirectory()) {
// 如果是目录,递归处理
await deleteFileByMapJson(sftp, sourcePath, mtime);
} else {
// 删除文件
if (mtime >= item.attrs.mtime) {
// console.log(`删除文件: ${sourcePath}`,);
await sftp.unlink(sourcePath);
}
}
}
}
async function run() {
if (!await authProjectName()) {
process.exit(1);
}
let conn, sftp;
try {
logger.warn('连接到服务器...');
// 连接到服务器
conn = new Client();
await new Promise((resolve, reject) => {
conn.on('ready', resolve);
conn.on('error', (err) => reject(new Error(`❌ 服务器连接失败: ${err.message}`)));
conn.connect(config);
});
logger.info('✅ 已成功连接到服务器');
// 初始化SFTP
sftp = await new Promise((resolve, reject) => {
conn.sftp((err, sftpClient) => {
if (err) {
reject(new Error(`SFTP初始化失败: ${err.message}`));
} else {
resolve(sftpClient);
}
});
});
// 没有项目目录,直接返回
if (!await isHasDir(sftp, config.path)) {
logger.warn('✅ 新项目,无需清理旧文件')
return
}
// 没有map文件,直接返回
if (!await isHasDir(sftp, `${config.path}/fileMap.json`)) {
logger.warn('✅ 没有map映射文件,无需清理旧文件')
return
}
const { mtime } = await readStreamByFile(sftp, `${config.path}/fileMap.json`);
logger.warn('正在删除文件...')
await deleteFileByMapJson(sftp, config.path, mtime);
await deleteFileByMapJson(sftp, config.path, mtime);
logger.success(`✅ ${process.env.NODE_ENV}环境,根据map删除映射文件成功!`)
} catch (err) {
logger.error('❌ 过程出错:', err.message);
} finally {
// 关闭连接
if (sftp) sftp.end();
if (conn) conn.end();
// console.log('连接已关闭');
}
}
run();