178 lines
4.9 KiB
TypeScript

#!/usr/bin/env -S deno run -A
/** Non-interactive entry: validate | generate | deploy */
import { parseArgs } from "@std/cli/parse-args";
import { join } from "@std/path";
import {
DEFAULT_BS_MANAGER_CAMPAIGNS,
DEFAULT_DIST_DIR,
DEFAULT_INVENTORY_PATH,
} from "./lib/paths.ts";
import { generateCampaignToDist } from "./lib/generate.ts";
import {
defaultInventoryTemplate,
readCampaignInventory,
writeCampaignInventory,
} from "./lib/inventory.ts";
import { deployCampaignFolder } from "./lib/deploy.ts";
import {
formatIssues,
validateGeneratedFolder,
validateInventory,
} from "./lib/validate.ts";
function usage(): string {
return `
ost-campaign tools (Deno)
Usage:
deno task validate [--inventory <path>] [--dist <campaignDir>]
deno task generate [--inventory <path>] [--dist-dir <distRoot>]
deno task deploy [--dist <campaignDir>] [--to <CustomCampaignsDir>] [--dry-run] [--name <folderName>]
Defaults:
inventory: ${DEFAULT_INVENTORY_PATH}
dist-root: ${DEFAULT_DIST_DIR}
deploy to: ${DEFAULT_BS_MANAGER_CAMPAIGNS}
Environment:
BS_MANAGER_CUSTOM_CAMPAIGNS Overrides default BSManager CustomCampaigns path
`.trim();
}
async function cmdValidate(invPath: string, distDir?: string): Promise<number> {
const inv = await readCampaignInventory(invPath);
const invIssues = validateInventory(inv);
console.log(invIssues.length ? formatIssues(invIssues) : "(inventory OK)");
let code = invIssues.some((x) => x.level === "error") ? 1 : 0;
if (distDir) {
try {
await Deno.stat(distDir);
} catch {
console.error(`Missing dist folder: ${distDir}`);
return 1;
}
const disk = await validateGeneratedFolder(inv, distDir);
if (disk.length) {
console.log("--- generated folder ---");
console.log(formatIssues(disk));
}
if (disk.some((x) => x.level === "error")) code = 1;
}
return code;
}
async function cmdGenerate(invPath: string, distRoot: string): Promise<number> {
const inv = await readCampaignInventory(invPath);
const invIssues = validateInventory(inv);
const errors = invIssues.filter((x) => x.level === "error");
if (errors.length) {
console.error(formatIssues(errors));
console.error("(fix inventory errors before generating)");
return 1;
}
const { outDir, missionCount } = await generateCampaignToDist(inv, distRoot);
console.log(`Wrote ${missionCount} missions to ${outDir}`);
return 0;
}
async function cmdDeploy(
distCampaignDir: string,
destParent: string,
dryRun: boolean,
folderName?: string,
): Promise<number> {
const { destDir, files } = await deployCampaignFolder({
srcDir: distCampaignDir,
destParentDir: destParent,
folderName,
dryRun,
});
if (dryRun) {
console.log(`Dry run: would copy ${files} files to ${destDir}`);
} else {
console.log(`Copied ${files} files -> ${destDir}`);
}
return 0;
}
async function seedInventoryIfMissing(path: string): Promise<void> {
try {
await Deno.stat(path);
} catch {
const tmpl = defaultInventoryTemplate();
await writeCampaignInventory(path, tmpl);
console.log(`Created starter inventory at ${path}`);
}
}
const parsed = parseArgs(Deno.args, {
alias: {
i: "inventory",
I: "inventory",
h: "help",
},
boolean: ["help", "dry-run"],
string: ["inventory", "dist", "dist-dir", "to", "name"],
});
if (parsed.help || parsed._.length === 0) {
console.log(usage());
Deno.exit(parsed.help ? 0 : 1);
}
const cmd = String(parsed._[0]);
(async () => {
const invPath = parsed.inventory ?? DEFAULT_INVENTORY_PATH;
if (cmd === "validate") {
try {
await Deno.stat(invPath);
} catch {
console.error(`Inventory not found: ${invPath}`);
Deno.exit(1);
}
let distDir: string | undefined = parsed.dist;
if (!distDir) {
try {
const inv = await readCampaignInventory(invPath);
const candidate = join(DEFAULT_DIST_DIR, inv.outputFolderName);
try {
await Deno.stat(candidate);
distDir = candidate;
} catch {
distDir = undefined;
}
} catch {
distDir = undefined;
}
}
Deno.exit(await cmdValidate(invPath, distDir));
}
if (cmd === "generate") {
await seedInventoryIfMissing(invPath);
const distRoot = parsed["dist-dir"] ?? DEFAULT_DIST_DIR;
Deno.exit(await cmdGenerate(invPath, distRoot));
}
if (cmd === "deploy") {
let distCampaignDir = parsed.dist;
const folderName = parsed.name;
await seedInventoryIfMissing(invPath);
if (!distCampaignDir) {
const inv = await readCampaignInventory(invPath);
distCampaignDir = join(DEFAULT_DIST_DIR, inv.outputFolderName);
}
const dry = parsed["dry-run"] === true;
const dest = parsed.to ?? DEFAULT_BS_MANAGER_CAMPAIGNS;
Deno.exit(await cmdDeploy(distCampaignDir, dest, dry, folderName));
}
console.error(`Unknown command: ${cmd}`);
console.log(usage());
Deno.exit(1);
})();