Files
svn/tech/client/交接文档/谭健交接文档/Script/ProjectScript/Subpackage/subpackage/ItemHandler.ts
2025-08-04 10:46:00 +08:00

189 lines
8.9 KiB
TypeScript

import fs from 'fs';
import path from 'path';
import { SubpackageConfig } from './Config';
import { Utils } from './Utils';
const START_VERSION = 1000;
export type ItemInfo = { md5: Utils.FileMD5[], version: number, size: { version: number, size: number }[] };
export type ItemHandlerResult = { info: ItemInfo, pickFiles: string[] };
export class ItemHandler {
private resourcesDir: string;
private assetsOutputDir: string;
private zipCacheOutputDir: string;
private zipOutputDir: string;
private versionCacheDir: string;
private config: SubpackageConfig;
constructor(projectDir: string, mode: string, config: SubpackageConfig) {
this.config = config;
const buildDir = path.join(projectDir, 'build');
const outputBaseDir = path.join(buildDir, 'subpackage');
Utils.log(`-------------------------------------------Make package [${this.config.key}] handler environment---------------------------------------------------`, Utils.LogLevel.Particular);
this.assetsOutputDir = path.join(outputBaseDir, 'assets', config.key);
Utils.log(`Make package [${this.config.key}] assets dir: ${this.assetsOutputDir}`, Utils.LogLevel.Particular);
Utils.rmdir(this.assetsOutputDir);
Utils.mkdir(this.assetsOutputDir);
this.zipCacheOutputDir = path.join(outputBaseDir, 'cache', config.key);
Utils.log(`Make package [${this.config.key}] zip cache dir: ${this.zipCacheOutputDir}`, Utils.LogLevel.Particular);
Utils.rmdir(this.zipCacheOutputDir);
Utils.mkdir(this.zipCacheOutputDir);
this.zipOutputDir = path.join(outputBaseDir, 'build');
Utils.log(`Make package [${this.config.key}] zip dir: ${this.zipOutputDir}`, Utils.LogLevel.Particular);
Utils.mkdir(this.zipOutputDir);
this.versionCacheDir = path.join(projectDir, 'tools', 'subpackage', mode, config.key);
Utils.log(`Make package [${this.config.key}] info dir: ${this.versionCacheDir}`, Utils.LogLevel.Particular);
Utils.mkdir(this.versionCacheDir);
this.resourcesDir = path.join(buildDir, 'jsb-default', 'res');
Utils.log(`-------------------------------------------Make package [${this.config.key}] handler environment finished------------------------------------------\n\n`, Utils.LogLevel.Particular);
}
private readExistVersion(): number[] {
const versions: number[] = [];
const versionDirs = fs.readdirSync(this.versionCacheDir);
for (const versionDir of versionDirs) {
// try {
const version = parseInt(versionDir);
versions.push(version);
// } catch (error: unknown) {
// continue;
// }
}
return versions.sort((a: number, b: number): number => { return a - b; });
}
private pickFile(dir: string, cache: string[]): string[] {
cache = cache || [];
const files = fs.readdirSync(dir);
for (let i = 0; i < files.length; i++) {
const subFileName = files[i];
const subFilePath = path.join(dir, subFileName)
const stat = fs.statSync(subFilePath);
if (stat.isDirectory()) {
this.pickFile(subFilePath, cache);
} else {
const fileName = subFileName.substring(0, subFileName.indexOf('.'));
const nameIndex = this.config.uuids.indexOf(fileName);
if (nameIndex < 0) continue;
// this.config.uuids.splice(nameIndex, 1);
Utils.log(`Pick package [${this.config.key}] file: ${subFilePath}`, Utils.LogLevel.Particular);
const outAssetBundleDir = path.join(this.assetsOutputDir, dir.replace(this.resourcesDir, 'res'))
Utils.mkdir(outAssetBundleDir);
fs.copyFileSync(subFilePath, path.join(outAssetBundleDir, subFileName));
cache.push(subFilePath)
}
}
return cache;
}
private readInfo(version: number): ItemInfo | null {
const infoFilePath: string = path.join(this.versionCacheDir, version.toString(), `${this.config.key}.json`);
if (!fs.existsSync(infoFilePath)) return null;
const subpackageInfoContent = fs.readFileSync(infoFilePath);
const info: ItemInfo = JSON.parse(subpackageInfoContent.toString());
return info;
}
private writeInfo(md5: Utils.FileMD5[], version: number, size: { version: number, size: number }[]): void {
const info: ItemInfo = { md5, version, size }
const infoContent = JSON.stringify(info);
let infoFilePath = path.join(this.versionCacheDir, version.toString(), `${this.config.key}.json`);
Utils.mkdir(path.dirname(infoFilePath));
fs.writeFileSync(infoFilePath, infoContent);
}
public async handle(): Promise<ItemHandlerResult> {
Utils.log(`-----------------------------------------------------Handle package [${this.config.key}] start-----------------------------------------------------`);
//筛选文件
const pickFiles: string[] = [];
this.pickFile(this.resourcesDir, pickFiles);
const md5 = Utils.md5dir(this.assetsOutputDir);
//读取版本缓存
const existVersions = this.readExistVersion();
//初始化前一版本数据
let lastItemInfo: ItemInfo = { md5: [], version: START_VERSION, size: [] };
let lastVersion = START_VERSION;
let result: ItemHandlerResult;
if (existVersions.length) {
lastVersion = existVersions[existVersions.length - 1];
Utils.log(`Package [${this.config.key}] last version: ${lastVersion}`, Utils.LogLevel.Particular);
lastItemInfo = this.readInfo(lastVersion) || lastItemInfo;
lastVersion = lastItemInfo.version;
} else {
Utils.log(`Package [${this.config.key}] not have version cache`, Utils.LogLevel.Particular);
}
//对比前一版本
const lastMD5CompareResult = Utils.fileMD5Compare(lastItemInfo.md5, md5);
Utils.log(`Package [${this.config.key}] compare with last: added=${lastMD5CompareResult.added.length}, deleted:${lastMD5CompareResult.deleted.length}, same:${lastMD5CompareResult.same.length}, changed:${lastMD5CompareResult.changed.length}`,
Utils.LogLevel.Particular);
const isChanged = lastMD5CompareResult.changed.length || lastMD5CompareResult.added.length;
if (!isChanged) {
Utils.log(`Package [${this.config.key}] no changes`);
result = { info: lastItemInfo, pickFiles };
} else {
Utils.log(`Package [${this.config.key}] changed`);
const newVersion = lastVersion + 1;
const size: { version: number, size: number }[] = [];
for (const version of existVersions) {
Utils.log(`Pick package [${this.config.key}] assets for version ${version} to ${newVersion}`);
const versionInfo = this.readInfo(version);
if (!versionInfo) continue;
//对比文件
const versionCompareResult = Utils.fileMD5Compare(versionInfo.md5, md5);
Utils.log(`Package [${this.config.key}] compare with version ${version}: added=${versionCompareResult.added.length}, deleted:${versionCompareResult.deleted.length} , same:${versionCompareResult.same.length}, changed:${versionCompareResult.changed.length}`,
Utils.LogLevel.Particular);
//只压缩changed和added
const files = versionCompareResult.changed.concat(versionCompareResult.added);
const zipCacheDir = path.join(this.zipCacheOutputDir, `${version}_${newVersion}`);
Utils.mkdir(zipCacheDir);
for (const fileMD5 of files) {
const outPath = path.join(zipCacheDir, fileMD5.path.replace(this.assetsOutputDir, ''))
Utils.mkdir(path.dirname(outPath));
fs.copyFileSync(fileMD5.path, outPath);
}
const zipOutFile = path.join(this.zipOutputDir, `${this.config.key}_${version}_${newVersion}.zip`);
await Utils.zipdir(zipCacheDir, zipOutFile);
Utils.rmdir(zipCacheDir);
const zipStat = fs.statSync(zipOutFile);
size.push({ version, size: zipStat.size });
}
const zipOutFile = path.join(this.zipOutputDir, `${this.config.key}_${newVersion}.zip`);
await Utils.zipdir(this.assetsOutputDir, zipOutFile);
Utils.rmdir(this.assetsOutputDir);
const zipStat = fs.statSync(zipOutFile);
size.push({ version: 0, size: zipStat.size });
this.writeInfo(md5, newVersion, size);
result = { info: { version: newVersion, size, md5 }, pickFiles };
}
Utils.log(`-----------------------------------------------------Handle package [${this.config.key}] end-------------------------------------------------------\n\n`);
return result;
}
}