cadb
Version:
安卓/鸿蒙系统截图/录屏工具
450 lines (420 loc) • 13.7 kB
JavaScript
/**
* Created by Niki on 2025/2/13 16:52.
* Email: m13296644326@163.com
*/
const program = require('commander');
const {
listenAnyKeyInput,
processFile,
loadOrCollectProjectPathBatch,
} = require('../common/utils');
const {logRed, ctripHarmony, ztripHarmony} = require('../common/constants');
const {
doTextFetchHttps,
doTextPostFetchHttps,
} = require('../common/utils/doTextFetchHttps');
const _ = require('lodash');
const fs = require('fs');
const JSON5 = require('json5');
const moment = require('moment');
const {table: TableConsole} = require('table');
const path = require('path');
let ctripHarmonyPath = '';
let ztripHarmonyPath = '';
// 请求bundle info的url, 等待拼接projectId
const bundleUrl = 'https://mcd.release.ctripcorp.com/publish/project/';
const fetchVersionListUrl =
'https://mcd.release.ctripcorp.com/service/mcdConfig/get?appId=99999999';
const fetchVersionProjectUrl =
'https://mcd.release.ctripcorp.com/publish/projects';
program
.option('-c --noCache', 'drop local project path cache')
.action(args => {
run(args);
})
.parse(process.argv);
async function run(args) {
await loadLocalProjectPath(args);
const versionList = await fetchVersionList();
const targetVersionItem = await selectVersion(versionList);
const projectId = await fetchProjectId(targetVersionItem);
const bundleInfoList = await fetchBundleInfo(projectId);
const ztripPackageJsonPath = getPackageJsonPath();
const localPackageJsonInfo = readLocalHarmonyLibrary(ztripPackageJsonPath);
const {matchedLibraryList: upgradeVersionList, unmatchedLibraryList} =
createUpgradeVersionList(bundleInfoList, localPackageJsonInfo);
printVersionTable(upgradeVersionList);
await confirmGoOn();
await modifyPackageJson(upgradeVersionList);
await wait();
// 阅读携程项目, 获取新版本
const upgradeVersionListCtrip =
createUpgradeVersionListFromCtripProject(unmatchedLibraryList);
printCtripVersionTable(upgradeVersionListCtrip);
await modifyPackageJson(upgradeVersionListCtrip);
syncRnOhVersion();
printFinalHint();
setTimeout(() => {
process.exit();
}, 100);
}
async function loadLocalProjectPath(args) {
const {noCache} = args;
const pathList = await loadOrCollectProjectPathBatch(
[ctripHarmony, ztripHarmony],
noCache,
);
ctripHarmonyPath = pathList[0];
ztripHarmonyPath = pathList[1];
}
async function fetchVersionList() {
console.log('starting version info fetch');
console.log('version info fetch url: ', fetchVersionListUrl);
try {
const versionInfoRes = await doTextFetchHttps(fetchVersionListUrl);
const {success, message, clientVersions} = versionInfoRes;
if (!success) {
logRed('version info fetch failed: ' + message);
process.exit();
}
console.log('bundle info fetch success');
// console.log('res: ', JSON.stringify(clientVersions.slice(0, 4), null, 2))
return clientVersions.slice(0, 4);
} catch (err) {
console.log('version info fetch failed: ', err);
process.exit();
}
process.exit();
}
async function selectVersion(versionList) {
// 选择一个版本
console.log('\r\n请选择一个版本: ');
const tableHead = ['Index', 'Version'];
const list = [tableHead];
versionList.forEach((item, index) => {
list.push([index, item.version]);
});
const output = TableConsole(list);
console.log(output);
// 监听输入
const {controlCPress, key} = await listenAnyKeyInput();
if (controlCPress) {
console.log('quit task');
process.exit();
} else {
const index = parseInt(key, 10);
if (isNaN(index) || index < 0 || index >= versionList.length) {
logRed('请输入正确的序号');
process.exit();
}
console.log('选择的版本: ', versionList[index].version);
return versionList[index];
}
return null;
}
async function fetchProjectId(targetVersionItem) {
const {version, formalCode} = targetVersionItem;
console.log('starting project info fetch');
const body = {
appId: '99999999',
platform: 'Harmony',
version: {code: formalCode, name: version},
};
console.log('url: ', fetchVersionProjectUrl, 'body: ', body);
const info = await doTextPostFetchHttps(fetchVersionProjectUrl, body);
let {data: projectList = [], message, resultCode} = JSON.parse(info);
if (resultCode !== 200) {
logRed('project info fetch failed: ' + message);
process.exit();
}
console.log('project info fetch success');
projectList = projectList.map(item => {
const {id, baseInfo} = item;
const {
planName,
platform,
branch,
creator: {name: creatorName},
} = baseInfo;
return {
projectId: id,
planName,
creatorName,
platform,
branch,
};
});
// 打印版本表格
const tableHead = [
'Version Name',
'Platform',
'Id',
'Type',
'Creator',
'Branch',
];
const list = [tableHead];
projectList.forEach(item => {
const {projectId, planName, creatorName, platform, branch} = item;
list.push([version, platform, projectId, planName, creatorName, branch]);
});
const output = TableConsole(list);
console.log(output);
const find = _.find(projectList, item => {
// const {planName, platform, branch} = item;
const {planName, platform} = item;
// const isRelBranch = branch === `rel/${version}`;
return platform === 'Harmony' && planName === '集成版';
});
if (!find) {
logRed('未找到集成版的项目');
process.exit();
}
return find.projectId;
}
async function fetchBundleInfo(projectId) {
const fetchUrl = `${bundleUrl}${projectId}`;
console.log('starting bundle info fetch');
console.log('bundle info fetch url: ', fetchUrl);
try {
const bundleInfo = await doTextFetchHttps(fetchUrl);
console.log('bundle info fetch success');
if (_.isEmpty(bundleInfo?.data?.bundleList)) {
logRed('bundle info list is empty');
process.exit();
}
return bundleInfo.data.bundleList;
} catch (err) {
console.log('bundle info fetch failed: ', err);
process.exit();
}
process.exit();
}
function getPackageJsonPath() {
return path.join(ztripHarmonyPath, 'oh-package.json5');
}
function readLocalHarmonyLibrary(packageJsonPath) {
const json5Str = fs.readFileSync(packageJsonPath, 'utf8');
try {
const json5Data = JSON5.parse(json5Str);
console.log('项目: ', json5Data.name);
return json5Data;
} catch (err) {
console.log(err);
process.exit();
}
return null;
}
function createUpgradeVersionList(bundleInfoList, localPackageJsonInfo) {
const {overrides} = localPackageJsonInfo;
const matchedLibraryList = [];
const unmatchedLibraryList = [];
for (const lbName in overrides) {
const find = _.find(bundleInfoList, item => {
let lastName = lbName;
if (lbName.includes('/')) {
lastName = lbName.split('/')[1];
}
return lastName.toLowerCase() === item.bundleCode.toLowerCase();
});
const originVersion = overrides[lbName];
if (!find) {
if (/^\d/.test(originVersion)) {
logRed('匹配失败: ' + lbName);
unmatchedLibraryList.push({
name: lbName,
originVersion: originVersion,
});
}
} else {
const {latestVersion} = find;
const {bundleVersionName, markTime} = latestVersion;
const compareResult = compareVersions(originVersion, bundleVersionName);
if (compareResult >= 0) {
console.log('无需更新: ', lbName);
} else {
matchedLibraryList.push({
name: lbName,
originVersion: originVersion,
newVersion: bundleVersionName,
createTime: markTime,
});
}
}
}
return {matchedLibraryList, unmatchedLibraryList};
}
function compareVersions(versionA, versionB) {
const parseVersion = v => {
const parts = v.split(/[-+]/); // 根据 "-" 和 "+" 分隔版本号和预发布/构建标识
const versionNumbers = parts[0].split('.').map(Number); // 将版本号分解为数字数组
const prerelease = parts[1] || ''; // 预发布部分
return {versionNumbers, prerelease};
};
const vA = parseVersion(versionA);
const vB = parseVersion(versionB);
for (
let i = 0;
i < Math.max(vA.versionNumbers.length, vB.versionNumbers.length);
i++
) {
const numA = vA.versionNumbers[i] || 0; // 默认为0,如果缺失部分
const numB = vB.versionNumbers[i] || 0; // 默认为0,如果缺失部分
if (numA > numB) {
return 1;
} // versionA 大
if (numA < numB) {
return -1;
} // versionB 大
}
// 如果版本号部分相同,比较预发布部分
if (vA.prerelease && !vB.prerelease) {
return -1;
} // versionA 是预发布版,versionB 是正式的版本
if (!vA.prerelease && vB.prerelease) {
return 1;
} // versionB 是预发布版,versionA 是正式的版本
if (vA.prerelease && vB.prerelease) {
return vA.prerelease.localeCompare(vB.prerelease); // 预发布字符串进行比较
}
return 0; // 两个版本相同
}
function printVersionTable(upgradeVersionList) {
console.log('\r\n对比mcd最新版本依赖: ');
const tableHead = [
'Library Name',
'New Version',
'Compile Time',
'Local Old Version',
];
const list = [tableHead];
upgradeVersionList.forEach(item => {
const {newVersion, name, originVersion, createTime} = item;
list.push([
name,
newVersion,
`${moment(createTime, null, 'zh-cn').fromNow()}`,
originVersion,
]);
});
const output = TableConsole(list);
console.log(output);
}
async function confirmGoOn() {
console.log(
'\r\nstep3: 以上是将要自动更新的依赖情况, 请确认是否进入下一步(Press Any key to go on):',
);
const {controlCPress} = await listenAnyKeyInput();
if (controlCPress) {
console.log('quit task');
process.exit();
}
}
async function modifyPackageJson(upgradeVersionList) {
// '@ctbusiness/ctdevtools': '8.75.0-beta.20241015142902',
// const {newVersion, name, originVersion, createTime} = item;
const packageJsonPath = getPackageJsonPath();
console.log('\r\n开始写入新版本: \r\n');
await processFile(packageJsonPath, line => {
const trimLine = line.trim();
if (/(^(['"])(@[^'"/]+\/[^'"/]+))/.test(trimLine)) {
const lbName = RegExp.$1.replace('"', '').replace("'", '');
// console.log('lbName', lbName);
const find = _.find(upgradeVersionList, {name: lbName});
if (find) {
const left = line.split(trimLine)[0];
const {newVersion, originVersion} = find;
console.log(`${lbName}: ${originVersion} -> ${newVersion}`);
return `${left}"${lbName}": "${newVersion}",`;
}
}
return line;
});
}
function createUpgradeVersionListFromCtripProject(unmatchedLibraryList) {
const ctripPath = path.join(ctripHarmonyPath, 'oh-package.json5');
const ctripLibraryMap = readLocalHarmonyLibrary(ctripPath).overrides;
const upgradeVersionListCtrip = [];
for (const item of unmatchedLibraryList) {
const {name, originVersion} = item;
const ctripVersion = ctripLibraryMap[name];
if (!ctripVersion) {
logRed('匹配失败: ' + name);
continue;
}
const compareResult = compareVersions(originVersion, ctripVersion);
if (compareResult >= 0) {
console.log('无需更新: ', name);
continue;
}
upgradeVersionListCtrip.push({
name,
originVersion,
newVersion: ctripVersion,
});
}
return upgradeVersionListCtrip;
}
function printCtripVersionTable(upgradeVersionListCtrip) {
console.log('\r\n落后Ctrip_Harmony项目的依赖: ');
const tableHead = ['Library Name', 'Ctrip New Version', 'Ztrip Old Version'];
const list = [tableHead];
upgradeVersionListCtrip.forEach(item => {
const {newVersion, name, originVersion} = item;
list.push([name, newVersion, originVersion]);
});
const output = TableConsole(list);
console.log(output);
}
function syncRnOhVersion() {
const ctripModulePath = path.join(
ctripHarmonyPath,
'entry/Phone/src/main/module.json5',
);
const ztripModulePath1 = path.join(
ztripHarmonyPath,
'app_config/default/config.json5',
);
const ztripModulePath2 = path.join(
ztripHarmonyPath,
'app_config/travel/config.json5',
);
const json5Str = fs.readFileSync(ctripModulePath, 'utf8');
const ctripConfig = JSON5.parse(json5Str);
const ctripMeta = _.get(ctripConfig, 'module.metadata', []);
const find = _.find(ctripMeta, {name: 'rnoh_version'});
if (!find) {
console.log(`${ctripModulePath}下未找到 rnoh_version`);
return;
}
const rnohVersion = find.value;
modifyZtripModuleRnOhVersion(ztripModulePath1, rnohVersion);
console.log(
`\r\n已更新 ${ztripModulePath1} 下的 rnoh_version: ${rnohVersion}`,
);
modifyZtripModuleRnOhVersion(ztripModulePath2, rnohVersion);
console.log(`已更新 ${ztripModulePath2} 下的 rnoh_version: ${rnohVersion}`);
}
function modifyZtripModuleRnOhVersion(modulePath, rnohVersion) {
const json5Str = fs.readFileSync(modulePath, 'utf8');
const zConfig1 = JSON5.parse(json5Str);
zConfig1.metadata = zConfig1.metadata.map(t => {
if (t.name === 'rnoh_version') {
t.value = rnohVersion;
}
return t;
});
fs.writeFileSync(modulePath, JSON.stringify(zConfig1, null, 2));
}
function printFinalHint() {
console.log(
'\r\n!!! 后续请逐个分析 ctrip_harmony 项目的commit, 以同步其他改动',
);
}
function wait(duration) {
return new Promise((res, rej) => {
setTimeout(() => {
res();
}, duration);
});
}