add build.ts
This commit is contained in:
147
single-scripts/build.ts
Executable file
147
single-scripts/build.ts
Executable file
@@ -0,0 +1,147 @@
|
||||
#!/usr/bin/env runts -- --allow-all
|
||||
|
||||
import {execCommandShell, log, term, uint8ArrayToHexString,} from "https://script.hatter.ink/@35/deno-commons-mod.ts";
|
||||
import {parseArgs} from "jsr:@std/cli/parse-args";
|
||||
import {existsPath, stringifyPretty, writeStringToFile,} from "../libraries/deno-commons-mod.ts";
|
||||
import {readFileToString} from "https://global.hatter.ink/script/get/@1/deno-commons-1.6.0-mod.ts";
|
||||
|
||||
async function main() {
|
||||
const flags = parseArgs(Deno.args, {
|
||||
boolean: [
|
||||
"help",
|
||||
"no-min",
|
||||
"skip-sign",
|
||||
"force",
|
||||
],
|
||||
alias: {
|
||||
S: "skip-sign",
|
||||
M: "no-min",
|
||||
F: "force",
|
||||
},
|
||||
});
|
||||
|
||||
if (flags.help) {
|
||||
console.log(term.auto(`Usage:
|
||||
[blue][bold]build.ts[//] --help
|
||||
[blue][bold]build.ts[//] [--no-min] FILES`));
|
||||
return;
|
||||
}
|
||||
|
||||
if (flags._.length === 0) {
|
||||
log.error(`No files specified`);
|
||||
return;
|
||||
}
|
||||
flags.min = !flags["no-min"];
|
||||
|
||||
const filesCount = flags._.length;
|
||||
log.info(`Total ${filesCount} file(s)`);
|
||||
for (let i = 0; i < filesCount; i++) {
|
||||
const file = flags._[i];
|
||||
if (file.includes(".bundle.")) {
|
||||
log.warn(`Skip bundle file: ${file} #${i + 1} of ${filesCount}`);
|
||||
continue;
|
||||
}
|
||||
log.info(`Building file: ${file} #${i + 1} of ${filesCount}`);
|
||||
await buildFile(file, flags);
|
||||
}
|
||||
}
|
||||
|
||||
function getBundleFilename(file: string): string {
|
||||
const lastIndexOfDot = file.lastIndexOf(".");
|
||||
if (lastIndexOfDot === -1) {
|
||||
return `${file}.bundle.ts`;
|
||||
}
|
||||
return `${file.substring(0, lastIndexOfDot)}.bundle.${
|
||||
file.substring(lastIndexOfDot + 1)
|
||||
}`;
|
||||
}
|
||||
|
||||
async function sha256OfString(input: string): Promise<string> {
|
||||
const data = new TextEncoder().encode(input);
|
||||
const hashBuffer = await crypto.subtle.digest("SHA-256", data);
|
||||
return uint8ArrayToHexString(new Uint8Array(hashBuffer));
|
||||
}
|
||||
|
||||
interface SourceFileMeta {
|
||||
sha256: string;
|
||||
builtTime: number;
|
||||
min: boolean;
|
||||
}
|
||||
|
||||
async function writeBundleSourceSha256(
|
||||
sourceFile: string,
|
||||
bundleFile: string,
|
||||
flags: any,
|
||||
) {
|
||||
const sourceFileSha256 = `${bundleFile}.source-meta`;
|
||||
const sourceFileContent = await readFileToString(sourceFile);
|
||||
const sourceFileContentSha256 = await sha256OfString(sourceFileContent);
|
||||
await writeStringToFile(
|
||||
sourceFileSha256,
|
||||
stringifyPretty({
|
||||
sha256: sourceFileContentSha256,
|
||||
builtTime: Date.now(),
|
||||
min: flags.min,
|
||||
} as SourceFileMeta),
|
||||
);
|
||||
}
|
||||
|
||||
async function checkBundleSourceSha256(
|
||||
sourceFile: string,
|
||||
bundleFile: string,
|
||||
flags: any,
|
||||
) {
|
||||
const sourceFileSha256 = `${bundleFile}.source-meta`;
|
||||
if (!await existsPath(sourceFileSha256)) {
|
||||
return false;
|
||||
}
|
||||
const sourceFileSha256Content = await readFileToString(sourceFileSha256);
|
||||
const sourceFileSha256Meta = JSON.parse(
|
||||
sourceFileSha256Content,
|
||||
) as SourceFileMeta;
|
||||
if (sourceFileSha256Meta.min !== flags.min) {
|
||||
return false;
|
||||
}
|
||||
const sourceFileContent = await readFileToString(sourceFile);
|
||||
const sourceFileContentSha256 = await sha256OfString(sourceFileContent);
|
||||
return sourceFileContentSha256 === sourceFileSha256Meta.sha256;
|
||||
}
|
||||
|
||||
async function buildFile(file: string, flags: any) {
|
||||
const denoCmd = "deno";
|
||||
const bundleFile = getBundleFilename(file);
|
||||
const denoBundleArgs = ["bundle"];
|
||||
if (flags.min) {
|
||||
denoBundleArgs.push("--minify");
|
||||
}
|
||||
denoBundleArgs.push(file);
|
||||
denoBundleArgs.push("-o");
|
||||
denoBundleArgs.push(bundleFile);
|
||||
|
||||
const isSourceFileMatches = await checkBundleSourceSha256(
|
||||
file,
|
||||
bundleFile,
|
||||
flags,
|
||||
);
|
||||
if (isSourceFileMatches && !flags.force) {
|
||||
log.info(`Check file ${file} sha256 matches, skip build`);
|
||||
return;
|
||||
}
|
||||
if (isSourceFileMatches) {
|
||||
log.info(`Force build file is on`);
|
||||
}
|
||||
log.debug("Run deno build: ", denoCmd, denoBundleArgs);
|
||||
await execCommandShell(denoCmd, denoBundleArgs);
|
||||
if (flags["skip-sign"]) {
|
||||
log.warn(`Skip signature for file: ${bundleFile}`);
|
||||
} else {
|
||||
await execCommandShell("script-sign.rs", [bundleFile]);
|
||||
}
|
||||
await execCommandShell("chmod", ["+x", bundleFile]);
|
||||
await writeBundleSourceSha256(file, bundleFile, flags);
|
||||
}
|
||||
|
||||
await main();
|
||||
|
||||
// @SCRIPT-SIGNATURE-V1: yk-r1.ES256.20260208T232753+08:00.MEQCIDKxUBkD92GrszyWM6gC
|
||||
// jCNOVqcEMUdDKgs6TJlFhRbXAiBzlvmlHCXGFZBCcjjKBjmXDYqdbnfTp6D1wlSFyhK/sA==
|
||||
Reference in New Issue
Block a user