sync-upstream
Version:
A tool for synchronizing code with upstream repositories with incremental updates and parallel processing.
125 lines (124 loc) • 5.21 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.getFileHash = getFileHash;
exports.getDirectoryHashes = getDirectoryHashes;
exports.saveHashes = saveHashes;
exports.loadHashes = loadHashes;
const node_crypto_1 = __importDefault(require("node:crypto"));
const node_path_1 = __importDefault(require("node:path"));
const fs_extra_1 = __importDefault(require("fs-extra"));
const ignore_1 = require("./ignore");
/**
* 计算文件的MD5哈希值
* @param filePath 文件路径
* @returns 文件的MD5哈希值
*/
async function getFileHash(filePath) {
try {
// 检查路径是否是文件
const stats = await fs_extra_1.default.stat(filePath);
if (!stats.isFile()) {
throw new Error(`路径 ${filePath} 不是文件,无法计算哈希值`);
}
const buffer = await fs_extra_1.default.readFile(filePath);
return node_crypto_1.default.createHash('md5').update(buffer).digest('hex');
}
catch (error) {
if (error.code === 'EISDIR') {
console.error(`错误: 尝试读取目录 ${filePath} 作为文件`);
}
else {
console.error(`计算文件 ${filePath} 哈希值时出错:`, error.message);
}
throw error; // 重新抛出错误,确保上层能捕获
}
}
/**
* 计算目录中所有文件的哈希值
* @param dirPath 目录路径
* @param ignorePatterns 忽略模式列表
* @returns 文件路径到哈希值的映射
*/
async function getDirectoryHashes(dirPath, ignorePatterns = [], shouldIgnore) {
try {
const hashes = {};
// 检查路径是否是目录
const stats = await fs_extra_1.default.stat(dirPath);
if (!stats.isDirectory()) {
throw new Error(`路径 ${dirPath} 不是目录,无法计算哈希值`);
}
const entries = await fs_extra_1.default.readdir(dirPath, { withFileTypes: true });
for (const entry of entries) {
try {
const entryPath = node_path_1.default.join(dirPath, entry.name);
const relativePath = node_path_1.default.relative(process.cwd(), entryPath);
// 规范化路径分隔符,确保在Windows上也能正确匹配
const normalizedPath = (0, ignore_1.normalizePath)(relativePath);
if (shouldIgnore(normalizedPath, ignorePatterns)) {
continue;
}
// 先检查条目是否是目录
if (entry.isDirectory()) {
const subHashes = await getDirectoryHashes(entryPath, ignorePatterns, shouldIgnore);
Object.assign(hashes, subHashes);
}
else {
// 额外检查,确保我们不会尝试将目录当作文件处理
try {
// 首先检查路径是否存在
if (!(await fs_extra_1.default.pathExists(entryPath))) {
console.warn(`警告: 条目 ${entry.name} 不存在,跳过`);
continue;
}
const entryStats = await fs_extra_1.default.stat(entryPath);
if (entryStats.isDirectory()) {
console.warn(`警告: 条目 ${entry.name} 被识别为文件,但实际是目录,跳过`);
continue;
}
if (!entryStats.isFile()) {
console.warn(`警告: 条目 ${entry.name} 既不是文件也不是目录,跳过`);
continue;
}
hashes[relativePath] = await getFileHash(entryPath);
}
catch (statError) {
console.error(`获取条目 ${entry.name} 状态时出错:`, statError.message);
continue; // 跳过此条目
}
}
}
catch (error) {
console.error(`处理条目 ${entry.name} 时出错:`, error.message);
// 继续处理其他条目,而不是中断整个过程
}
}
return hashes;
}
catch (error) {
console.error(`计算目录 ${dirPath} 哈希值时出错:`, error.message);
// 不再重新抛出错误,避免中断上层调用
return {};
}
}
/**
* 保存哈希值到文件
* @param filePath 保存哈希值的文件路径
* @param hashes 哈希值映射
*/
async function saveHashes(filePath, hashes) {
await fs_extra_1.default.writeJson(filePath, hashes, { spaces: 2 });
}
/**
* 从文件加载哈希值
* @param filePath 哈希值文件路径
* @returns 哈希值映射,如果文件不存在则返回空对象
*/
async function loadHashes(filePath) {
if (await fs_extra_1.default.pathExists(filePath)) {
return fs_extra_1.default.readJson(filePath);
}
return {};
}