UNPKG

cadb

Version:

安卓/鸿蒙系统截图/录屏工具

365 lines (343 loc) 11 kB
/** * Created by Niki on 2025/2/18 15:51. * Email: m13296644326@163.com */ const program = require('commander'); const fs = require('fs'); const _ = require('lodash'); const { ctripHarmony, logRed, logGreen, ztripHarmony, shellConfigs, } = require('../common/constants'); const { collectUserInput, processFile, loadOrCollectProjectPathBatch, listenAnyKeyInput, } = require('../common/utils'); const path = require('path'); const JSON5 = require('json5'); const {table: TableConsole} = require('table'); const {buildHar} = require('../common/utils/harBuildUtil'); const execSync = require('child_process').execSync; let ctripHarmonyPath = ''; let ztripHarmonyPath = ''; const ctripBuildProfileFile = 'build-profile.json5'; // 比如CTFoundation/build/default/outputs/default/CTFoundation.har const harOutputDir = 'build/default/outputs/default'; const ztripTmpHarDir = 'libs/._tmp_copy'; program .option('-c --noCache', 'drop local project path cache') .option('-n, --name <name>', 'module name of the har') .action(args => { run(args); }) .parse(process.argv); async function run(args) { await loadLocalProjectPath(args); const targetHarItem = await getTargetHarItem(args); if (!targetHarItem) { quit(); return; } await beforeBuildTask(targetHarItem); const harPath = await doBuildHar(targetHarItem); if (!harPath) { quit(); return; } revertBuildOption(); const newHarPath = moveHar2Ztrip(harPath); const modifySuccess = await modifyPackageJson(newHarPath, targetHarItem); if (!modifySuccess) { quit(); return; } quit(); } function quit() { setTimeout(() => { process.exit(); }, 100); } async function loadLocalProjectPath(args) { const {noCache} = args; const pathList = await loadOrCollectProjectPathBatch( [ctripHarmony, ztripHarmony], noCache, ); ctripHarmonyPath = pathList[0]; ztripHarmonyPath = pathList[1]; } /** * 返回的对象的结构: * name: 携程项目build-profile.json5中的模块名, 比如CTFoundation * srcPath: 携程项目build-profile.json5中的模块相对路径, 比如./common/CTFoundation * moduleName: 解析后的项目名, 比如 ctfoundation * libraryName: 依赖名, 比如 @ctcommon/ctfoundation * versionName: 依赖版本名, 比如 8.78.4-beta.20250214105531 * versionCode: 依赖纯版本号, 比如 8.78.4, 可能为空 * * a.如果指定了module, 则校验后去编译指定module的har * b.如果未指定module, 则展示选择栏 * @param args * @returns {Promise<null>} */ async function getTargetHarItem(args) { const {name} = args; const buildProfile = readJson5( path.join(ctripHarmonyPath, ctripBuildProfileFile), ); const {modules} = buildProfile; let targetHarItem = null; const ztripLibraryList = loadZtripLibraryList(); const moduleWithZtrip = modules .filter(item => { return ztripLibraryList.some( t => t.moduleName.toLowerCase() === item.name.toLowerCase(), ); }) .map(item => { const find = _.find(ztripLibraryList, t => { return t.moduleName.toLowerCase() === item.name.toLowerCase(); }); if (!find) { return item; } return { ...item, ...find, }; }); if (name) { const find = _.find( moduleWithZtrip, t => t.name.toLowerCase() === name.toLowerCase(), ); if (find) { targetHarItem = find; } else { logRed('未找到指定module, 请传入正确的module name'); process.exit(); } } else { printModuleList(moduleWithZtrip); console.log('\r\n请输入要编译的module的序号: '); const inputContent = await collectUserInput(); if (!_.isNumber(Number(inputContent))) { logRed('请输入数字'); process.exit(); } const inputIndex = parseInt(inputContent, 10); if (inputIndex < 0 || inputIndex >= moduleWithZtrip.length) { logRed('Index out of bounds exception'); process.exit(); } targetHarItem = moduleWithZtrip[inputIndex]; } return targetHarItem; } /** * 1.校验ctrip项目的版本号, 建议等于当前依赖的版本 * 2.修改build-profile.json5, 干掉buildOption配置, 以关闭har字节码编译模式 */ async function beforeBuildTask(targetHarItem) { checkCtripVersionAndBranch(targetHarItem); removeBuildOption(); } /* 校验ctrip项目的版本号和分支 */ async function checkCtripVersionAndBranch(targetHarItem) { const {versionCode: lbVersionCode, name: lbName} = targetHarItem; if (lbVersionCode) { const projectVersionCode = readCtripProjectVersion(); console.log(`ctrip项目的版本号: ${projectVersionCode}`); if (projectVersionCode !== lbVersionCode) { const ctripBranchName = execSync('git rev-parse --abbrev-ref HEAD', { ...shellConfigs, cwd: ctripHarmonyPath, }).trim(); logRed( `\r\n风险提示: ztrip_harmony中${lbName}的版本号为${lbVersionCode}, 但是ctrip_harmony项目版本号为${projectVersionCode}, 分支为 ${ctripBranchName}`, ); console.log('版本号不一致可能导致编译失败, 若继续执行请输入y:'); const {controlCPress, key} = await listenAnyKeyInput(); if (controlCPress) { console.log('quit task'); process.exit(); } else { if (key.toLowerCase() !== 'y') { console.log('quit task'); process.exit(); } } } else { logGreen('依赖版本与ctrip_harmony项目版本号一致'); } } else { logRed(`从ztrip_harmony中未找到${lbName}的版本号`); } } /* 干掉buildOption配置 */ function removeBuildOption() { const buildProfilePath = path.join(ctripHarmonyPath, ctripBuildProfileFile); // 先复制原文件到bak, 以供编译完成后回滚 const bakPath = path.join(ctripHarmonyPath, `${ctripBuildProfileFile}-bak`); if (fs.existsSync(bakPath)) { fs.unlink(bakPath); } fs.copyFileSync(buildProfilePath, bakPath); const buildProfile = readJson5(buildProfilePath); const { app: {products}, } = buildProfile; _.find(products, {name: 'default'}).buildOption = {}; fs.writeFileSync( path.join(ctripHarmonyPath, ctripBuildProfileFile), JSON.stringify(buildProfile, null, 2), ); console.log(`已移除${buildProfilePath}中的buildOption配置`); } function revertBuildOption() { const buildProfilePath = path.join(ctripHarmonyPath, ctripBuildProfileFile); const bakPath = path.join(ctripHarmonyPath, `${ctripBuildProfileFile}-bak`); if (!fs.existsSync(bakPath)) { console.log('未找到bak文件, 无法回滚'); return; } fs.copyFileSync(bakPath, buildProfilePath); fs.unlinkSync(bakPath); console.log(`已回滚${buildProfilePath}中的buildOption配置`); } async function doBuildHar(targetHarItem) { const success = await buildHar(ctripHarmonyPath, targetHarItem.name); if (!success) { logRed('编译失败, 请检查'); return ''; } logGreen('编译成功'); return path.join( ctripHarmonyPath, targetHarItem.srcPath, harOutputDir, `${targetHarItem.name}.har`, ); } function moveHar2Ztrip(harPath) { const targetDir = path.join(ztripHarmonyPath, ztripTmpHarDir); if (!fs.existsSync(targetDir)) { fs.mkdirSync(targetDir); } const projectVersionCode = readCtripProjectVersion(); // 拼接版本号 const extName = path.extname(harPath); const pureName = path.basename(harPath, extName); const newName = `${pureName}_${projectVersionCode}${extName}`; const targetHarPath = path.join(targetDir, newName); fs.copyFileSync(harPath, targetHarPath); logGreen(`har已复制至: ${targetHarPath}`); return targetHarPath; } async function modifyPackageJson(newHarPath, targetHarItem) { const relativePath = `./${path.join( ztripTmpHarDir, path.basename(newHarPath), )}`; const localVersion = `file:${relativePath}`; const packageJsonPath = path.join(ztripHarmonyPath, 'oh-package.json5'); console.log('\r\n开始写入新版本: \r\n'); let success = false; await processFile(packageJsonPath, line => { const trimLine = line.trim(); if (/(^(['"])(@[^'"/]+\/[^'"/]+))/.test(trimLine)) { const lbName = RegExp.$1.replace('"', '').replace("'", ''); // console.log('lbName', lbName); if (lbName.includes('/')) { const baseName = lbName.split('/')[1]; if (baseName.toLowerCase() === targetHarItem.name.toLowerCase()) { if (success) { logRed('module name存在重复匹配'); process.exit(); } success = true; const left = line.split(trimLine)[0]; console.log('module name匹配成功:'); console.log(`${lbName}: -> ${localVersion}`); return `${left}"${lbName}": "${localVersion}",`; } } } return line; }); if (!success) { logRed('module name匹配失败'); } return success; } /** * moduleName: 解析后的项目名, 比如 ctfoundation * libraryName: 依赖名, 比如 @ctcommon/ctfoundation * versionName: 依赖版本名, 比如 8.78.4-beta.20250214105531 * versionCode: 依赖纯版本号, 比如 8.78.4, 可能为空 */ function loadZtripLibraryList() { // 读取ztrip的package.json5, 仅展示ztrip里面包含的依赖 const packageJsonZtrip = readJson5( path.join(ztripHarmonyPath, 'oh-package.json5'), ); const {overrides} = packageJsonZtrip; return Object.keys(overrides) .filter(key => { return key.startsWith('@ct') && key.includes('/'); }) .map(key => { let versionCode = ''; const versionName = overrides[key]; if (versionName.startsWith('file:')) { // 不带后缀的文件名 const fileName = path.basename(versionName, path.extname(versionName)); if (fileName.includes('_')) { versionCode = _.last(fileName.split('_')); } } else { versionCode = versionName.split('-')[0]; } return { libraryName: key, moduleName: key.split('/')[1], versionName, versionCode, }; }); } function readCtripProjectVersion() { const appConfigPath = path.join(ctripHarmonyPath, 'AppScope/app.json5'); console.log(`从${appConfigPath}中读取版本号`); const { app: {versionName}, } = readJson5(appConfigPath); return versionName; } function printModuleList(modules) { console.log(`\r\n${ctripHarmony}当前可编译的module: `); const tableHead = ['Index', 'Name', 'Path', 'Version in Ztrip']; const list = [tableHead]; modules.forEach((item, index) => { const {name, srcPath, versionName} = item; list.push([index, name, srcPath, versionName]); }); const output = TableConsole(list); console.log(output); } function readJson5(filePath) { const json5Str = fs.readFileSync(filePath, 'utf8'); try { return JSON5.parse(json5Str); } catch (err) { console.log(err); process.exit(); } return null; }