const fs = require("fs"); const path = require("path"); const child_process = require("child_process"); let totalGitRepPath = new Set(); const InputRepURLJsonName = "RepUrls.json"; const PluginDirName = "Plugins"; const dirNameBlackList = [ "node_modules", "dist", "Build", "Content", "Binaries", "Config", "DerivedDataCache", "Intermediate", "pipeline", "Saved", ".vs", "ThirdParty", ] class RepItem { constructor(inPath, inUrl) { this.path = inPath; // 仓库名称 this.url = inUrl; // 仓库地址 } } class RepUrls{ RepItems = []; } // 拉取 Git 仓库最新代码到指定路径 function pullGitRepository(repositoryUrl, localPath) { if (fs.existsSync(localPath)) { // 切换路径 我发现不切换路径 经常会出现一些 bug process.chdir(localPath); // 路径已存在则拉取最新代码 console.log(`Pull ${repositoryUrl} to ${localPath}...`); // 只检查 并提示 仍然尝试 Pull 操作 checkEditFileRep(localPath); child_process.exec("git pull", localPath, (error, stdout, stderr) => { totalGitRepPath.delete(localPath); let logContent = `update repo dir ${localPath} update log -> ${stdout.trim()}, error -> ${stderr.trim()}, remain count = ${totalGitRepPath.size}`; if (error) { console.log('\x1B[31m%s\x1B[0m', logContent); } else { console.log(logContent); } }); } else { // 路径不存在则克隆仓库 console.log(`Clone ${repositoryUrl} to ${localPath}...`); child_process.exec(`git clone ${repositoryUrl} ${localPath}`, (error, stdout, stderr) => { let logContent = `clone repo dir ${localPath} update log -> ${stdout.trim()}, error -> ${stderr.trim()}`; if (error) { console.log("'\x1B[31m%s\x1B[0m',", logContent); }else{ console.log(logContent); } }); } } // 获取路径下所有文件夹 function getAllChildrenDir(inPath) { if(inPath === undefined || inPath === null || !fs.existsSync(inPath)) { return []; } return fs.readdirSync(inPath, { withFileTypes: true }).filter(dirent => dirent.isDirectory()).map(dirent => dirent.name); } // 获取路径下所有文件 function getAllChildrenFile(inPath) { if(inPath === undefined || inPath === null || !fs.existsSync(inPath)) { return []; } return fs.readdirSync(inPath, { withFileTypes: true }).filter(dirent => dirent.isFile()).map(dirent => dirent.name); } // 判断是否存在被修改的文件 function checkEditFileRep(inPath) { if(inPath === undefined || inPath === null || !fs.existsSync(inPath)) { return false; } try { // `git -C "${inPath}" status --porcelain`, const output = child_process.execSync( `git -C "${inPath}" diff --name-only`, { encoding: 'utf-8' } ); if(output.trim().length > 0) { console.log("'\x1B[31m%s\x1B[0m',", `${inPath} 存在被修改的文件 无法更新 使用 git restore 还原文件: ${output.trim()}`); totalGitRepPath.delete(inPath); } return output.trim().length <= 0; } catch (error) { console.error(`检查子目录失败: ${error.message}`); return false; } } function findAllGitRep(inPath) { console.log(`find path: ${inPath}`); let childrenDirs = getAllChildrenDir(inPath); if(childrenDirs.indexOf(".git") !== -1) { // 如果当前目录下有 .git 目录,则认为是一个 Git 仓库 totalGitRepPath.add(inPath); } childrenDirs.forEach((dir) => { if(!dir || dir.trim().startsWith(".") || dirNameBlackList.includes(dir.trim())) { // 跳过隐藏目录 return; } // console.log(`Checking directory: ${dir} in ${inPath}`); let childPath = path.join(inPath, dir); findAllGitRep(childPath); }); } function updateAllRep(allPath) { allPath.forEach((inPath) => { if(inPath === undefined) { return; } pullGitRepository("", inPath); }); } function updateRep() { let rootPath = __dirname; findAllGitRep(rootPath); updateAllRep(totalGitRepPath); } function cloneRep() { let rootPath = __dirname; let inputRepURLJsonFile = path.join(rootPath, InputRepURLJsonName); if(!fs.existsSync(inputRepURLJsonFile)) { let temp = new RepUrls(); temp.RepItems = [new RepItem("cpp", "https://xxx.com/test/url.git")]; fs.writeFileSync(inputRepURLJsonFile, JSON.stringify(temp, null, 4), "utf-8"); console.error(`找不到 ${InputRepURLJsonName} 文件,已生成该文件,请填充内容`); return; } let repUrls = JSON.parse(fs.readFileSync(inputRepURLJsonFile, "utf-8")); repUrls.RepItems.forEach((item) => { let url = item.url; let relativePath = item.path; if(!url || url.trim() === "") { console.error(`无效的 Git 仓库 URL: ${url}`); return; } let locationPath = path.join(rootPath, PluginDirName, relativePath); let localPath = path.join(locationPath, path.basename(url, ".git")); pullGitRepository(url, localPath); }); } function main() { if(process.argv.length < 3) { console.log("请输入 clone 或者 update 来选择下载或更新 Git 仓库"); return; } let param = process.argv[2].toLowerCase(); if(param === "update") { // 更新 Git 仓库 updateRep(); } else if(param === "clone") { // 克隆 Git 仓库 cloneRep(); } else { console.error(`无效的参数 "${param}",请输入 clone 或 update`); return; } } main();