PackFormatter/index.ts

176 lines
5.3 KiB
TypeScript
Raw Normal View History

2024-05-30 10:04:54 +00:00
import AdmZip from "adm-zip";
import prettyBytes from "pretty-bytes";
import { parseArgs } from "node:util";
import {
access,
copyFile,
cp,
lstat,
mkdir,
mkdtemp,
rm,
stat,
writeFile
} from "node:fs/promises";
import type { PathLike } from "node:fs";
import { tmpdir } from "node:os";
import { cwd } from "node:process";
import { resolve } from "node:path";
interface Override {
2024-05-30 19:11:45 +00:00
data?: string;
}
2024-05-30 10:04:54 +00:00
interface Info {
description: string;
exports: Array<["all"] | Array<string>>;
name: string;
url: string;
versions: Array<[mcVersion: string, packFormat: number]>;
overrides?: Record<string, Override>;
2024-05-30 10:04:54 +00:00
}
2024-05-30 19:21:33 +00:00
const { values: { indir: inDir, data: dataDir, revision: rev, outdir: outDir, info: infoPath, version: onlyVersion } } = parseArgs({
2024-05-30 10:04:54 +00:00
args: Bun.argv,
options: {
indir: {
type: "string",
short: "i",
default: cwd()
},
2024-05-30 19:11:45 +00:00
data: {
2024-05-30 10:04:54 +00:00
type: "string",
2024-05-30 19:11:45 +00:00
short: "d",
default: "data"
2024-05-30 10:04:54 +00:00
},
revision: {
type: "string",
short: "r"
},
outdir: {
type: "string",
short: "o",
default: "dist"
2024-05-30 19:06:16 +00:00
},
info: {
type: "string",
default: "info.json"
},
2024-05-30 19:21:33 +00:00
version: {
type: "string",
short: "v"
}
2024-05-30 10:04:54 +00:00
},
strict: true,
allowPositionals: true
});
const directoryExists = (path: PathLike) => access(path).then(() => lstat(path).then(d => d.isDirectory())).catch(() => false);
const dir = resolve(inDir!);
console.log("Building packs for:", dir);
if (!dir) {
console.log("No directory specified");
process.exit(1);
}
if (!await directoryExists(dir)) {
console.log(`Specified input directory "${inDir}" (${dir}) does not exist.`);
process.exit(1);
}
2024-05-30 19:06:16 +00:00
const info = await Bun.file(infoPath ?? "info.json").json() as Info;
2024-05-30 19:11:45 +00:00
const data = resolve(dir, dataDir!);
2024-05-30 10:04:54 +00:00
const dist = resolve(dir, outDir!);
2024-05-30 19:11:45 +00:00
if (!await directoryExists(data)) {
console.log(`Specified data directory "${dataDir}" (${data}) does not exist.`);
2024-05-30 10:04:54 +00:00
process.exit(1);
}
let revision = rev;
if (!revision) {
if (await directoryExists(`${dir}/.git`)) {
revision = (await Bun.$`git rev-parse --short HEAD`.cwd(dir).text().catch(() => "")).slice(0, -1);
if (!revision) {
console.log("Failed to get git revision.");
process.exit(1);
}
} else {
console.log("No revision specified and no git directory found.");
process.exit(1);
}
}
const tempDir = await mkdtemp(`${tmpdir()}/${info.name.toLowerCase().replaceAll(" ", "-")}`);
console.log("Temporary Directory:", tempDir);
let totalSize = 0;
async function createVersion(mcVersion: string, packFormat: number) {
2024-05-30 19:21:33 +00:00
if (onlyVersion && mcVersion !== onlyVersion) {
return;
}
2024-05-30 19:11:45 +00:00
let dataDir = data;
if (info.overrides) {
const override = info.overrides[mcVersion];
2024-05-30 19:11:45 +00:00
if (override?.data) {
dataDir = resolve(dir, override.data);
if (!await directoryExists(dataDir)) {
console.log(`[Override:${mcVersion}] Specified data directory "${override.data}" (${dataDir}) does not exist.`);
process.exit(1);
}
}
}
2024-05-30 10:04:54 +00:00
console.log("Building %s (pf: %d)", mcVersion, packFormat);
const mcmeta = {
pack: {
pack_format: packFormat,
description: info.description,
version: {
git: revision,
mc: mcVersion,
url: info.url
}
}
};
await mkdir(`${tempDir}/${mcVersion}`);
await writeFile(`${tempDir}/${mcVersion}/pack.mcmeta`, JSON.stringify(mcmeta, null, 4));
2024-05-30 19:11:45 +00:00
await copyFile(`${dataDir}/pack.png`, `${tempDir}/${mcVersion}/pack.png`);
await cp(`${dataDir}/assets`, `${tempDir}/${mcVersion}/assets`, { recursive: true });
2024-05-30 10:04:54 +00:00
const zip = new AdmZip();
await zip.addLocalFolderPromise(`${tempDir}/${mcVersion}`, {});
await zip.writeZipPromise(`${dist}/${info.name.replaceAll(" ", "")}-${mcVersion}.zip`);
const { size } = await stat(`${dist}/${info.name.replaceAll(" ", "")}-${mcVersion}.zip`);
totalSize += size;
console.log("%s built, size: %s", mcVersion, prettyBytes(size));
}
if (await directoryExists(dist)) {
await rm(dist, { recursive: true, force: true });
}
await mkdir(dist);
for (const [mcVersion, packFormat] of info.versions) {
await createVersion(mcVersion, packFormat);
}
await rm(tempDir, { recursive: true, force: true });
console.log("Total size: %s", prettyBytes(totalSize));
2024-05-30 19:21:33 +00:00
if (onlyVersion) {
console.log("Skipping exports due to version filter");
} else {
for (const ex of info.exports) {
const name = (ex[0] === "all" ? info.name : `${info.name}-${ex.join("-")}`).replaceAll(" ", "");
console.log("Exporting %s", name);
const zip = new AdmZip();
const versions = ex[0] === "all" ? info.versions.map(([mcVersion]) => mcVersion) : ex;
for (const version of versions) {
zip.addLocalFile(`${dist}/${info.name.replaceAll(" ", "")}-${version}.zip`);
}
await zip.writeZipPromise(`${dist}/${name}.zip`);
const { size } = await stat(`${dist}/${name}.zip`);
console.log("%s exported, size: %s", name, prettyBytes(size));
2024-05-30 10:04:54 +00:00
}
}
console.log("Done");