189 lines
8.9 KiB
TypeScript
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;
|
|
}
|
|
|
|
|
|
|
|
} |