Files
2025-08-04 10:46:00 +08:00

156 lines
5.7 KiB
TypeScript

import fs from 'fs';
import path from 'path';
import archiver from 'archiver';
import crypto from 'crypto';
const BASE64_KEYS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
const HEXCHAR = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f']
var BASE64_VALUES = new Array(123);
for (let i = 0; i < 123; ++i) BASE64_VALUES[i] = 64;
for (let i = 0; i < 64; ++i) BASE64_VALUES[BASE64_KEYS.charCodeAt(i)] = i;
var _t = ['', '', '', ''];
var uuidTemplate = _t.concat(_t, '-', _t, '-', _t, '-', _t, '-', _t, _t, _t);
var indices = uuidTemplate.map(function (value: string, index: number) { return value === '-' ? NaN : index; }).filter(isFinite);
export class Utils {
private static logLevel: Utils.LogLevel = 1;
public static mkdir(dir: string): void {
if (!fs.existsSync(dir)) {
let parentDir = path.dirname(dir);
this.mkdir(parentDir);
fs.mkdirSync(dir);
}
}
public static rmdir(dir: string): void {
if (!fs.existsSync(dir)) return;
let files = fs.readdirSync(dir);
for (let item of files) {
let itemPath = path.join(dir, item);
let stat = fs.statSync(itemPath);
stat.isDirectory() ? this.rmdir(itemPath) : fs.unlinkSync(itemPath);
}
fs.rmdirSync(dir);
}
public static zipdir(srcDir: string, outputFile: string): Promise<void> {
Utils.mkdir(path.dirname(outputFile));
var promise: Promise<void> = new Promise((resolve: () => void, reject: (reason?: any) => void) => {
let writeStream = fs.createWriteStream(outputFile);
let archive = archiver('zip', {
// encoding: 'utf-8',
// forceZip64: true,
zlib: { level: 9 }
});
writeStream.on('close', () => {
resolve();
});
archive.on('error', function (error: archiver.ArchiverError) {
reject(error)
})
archive.pipe(writeStream);
archive.directory(srcDir, false);
archive.finalize();
});
return promise;
}
public static md5dir(dir: string, md5?: Utils.FileMD5[]): Utils.FileMD5[] {
md5 = md5 || [];
let files = fs.readdirSync(dir);
for (let file of files) {
let filePath = path.join(dir, file);
let stat = fs.statSync(filePath);
if (stat.isDirectory()) {
this.md5dir(filePath, md5)
} else {
let buffer = fs.readFileSync(filePath);
let hash = crypto.createHash('md5');
hash.update(buffer);
let hex = hash.digest('hex');
md5.push({ path: filePath, md5: hex });
}
}
return md5;
}
public static fileMD5Compare(src: Utils.FileMD5[], dst: Utils.FileMD5[]): Utils.FileMD5CompareResult {
let result: Utils.FileMD5CompareResult = { added: [], deleted: [], changed: [], same: [] };
let srcCopy = src.concat([]);
let dstCopy = dst.concat([]);
let dstItem: Utils.FileMD5 | undefined;
while (dstItem = dstCopy.shift()) {
let foundItem: Utils.FileMD5 | undefined = undefined;
for (let j = 0, srcLenght = srcCopy.length; j < srcLenght; j++) {
let srcItem = srcCopy[j];
if (srcItem.path === dstItem.path) {
foundItem = srcItem;
srcCopy.splice(j, 1);
break;
}
}
if (!foundItem) {
result.added.push(dstItem);
} else {
foundItem.md5 === dstItem.md5 ? result.same.push(dstItem) : result.changed.push(dstItem)
}
}
result.deleted.push(...srcCopy);
return result;
}
public static setLogLevel(level: Utils.LogLevel): void {
Utils.logLevel = level;
}
public static log(text: string, level: Utils.LogLevel.Simple | Utils.LogLevel.Particular = Utils.LogLevel.Simple): void {
if (Utils.logLevel === Utils.LogLevel.Disable) return;
if (level <= Utils.logLevel) {
console.log(text);
}
}
public static toBase64(uuid: string) {
let j = 2;
let base64 = uuid.substring(0, j)
for (let i = 2; i < 22; i += 2) {
let hex1 = HEXCHAR.indexOf(uuid.charAt(indices[j++]));
let hex2 = HEXCHAR.indexOf(uuid.charAt(indices[j++]));
let hex3 = HEXCHAR.indexOf(uuid.charAt(indices[j++]));
let lhs = (hex1 << 2) | (hex2 >> 2);
let rhs = ((hex2 & 3) << 4) | hex3;
base64 += BASE64_KEYS.charAt(lhs);
base64 += BASE64_KEYS.charAt(rhs);
}
return base64;
}
public static toUUID(base64: string) {
let baselen = base64.length;
if (baselen < 22) {
return base64;
}
uuidTemplate[0] = base64[0];
uuidTemplate[1] = base64[1];
for (let i = 2, j = 2; i < 22; i += 2) {
let lhs = BASE64_VALUES[base64.charCodeAt(i)];
let rhs = BASE64_VALUES[base64.charCodeAt(i + 1)];
uuidTemplate[indices[j++]] = HEXCHAR[lhs >> 2];
uuidTemplate[indices[j++]] = HEXCHAR[((lhs & 3) << 2) | rhs >> 4];
uuidTemplate[indices[j++]] = HEXCHAR[rhs & 0xF];
}
return uuidTemplate.join('');
}
}
export namespace Utils {
export type FileMD5 = { path: string, md5: string };
export type FileMD5CompareResult = { added: FileMD5[], deleted: FileMD5[], changed: FileMD5[], same: FileMD5[] }
export enum LogLevel { Disable = 0, Simple = 1, Particular = 2 };
}