add build.ts
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -6,6 +6,7 @@
|
|||||||
.AppleDouble
|
.AppleDouble
|
||||||
.LSOverride
|
.LSOverride
|
||||||
bundles/*.bundle.ts
|
bundles/*.bundle.ts
|
||||||
|
bundles/*.bundle.ts.source-meta
|
||||||
|
|
||||||
# Icon must end with two \r
|
# Icon must end with two \r
|
||||||
Icon
|
Icon
|
||||||
|
|||||||
@@ -1,10 +1,22 @@
|
|||||||
#!/usr/bin/env runts -- --allow-import
|
#!/usr/bin/env runts -- --allow-all
|
||||||
|
|
||||||
import {log} from "../libraries/deno-commons-mod.ts";
|
import {log, term} from "../libraries/deno-commons-mod.ts";
|
||||||
|
|
||||||
// deno bundle --allow-import hello_world.ts -o helloworld-bundle-2.bundle.ts
|
// deno bundle --allow-import hello_world.ts -o helloworld-bundle-2.bundle.ts
|
||||||
async function main() {
|
async function main() {
|
||||||
log.info("Hello World!");
|
log.success("Hello World!");
|
||||||
|
console.log(term.auto("\n[bg_white][black]Message:\n"));
|
||||||
|
console.log(
|
||||||
|
term.auto(
|
||||||
|
"[[[[bg_green][bold][red] MESSAGE [///] [green][bold]Hello[//] [red]world[/]. [under] under [/] [bold]BOLD[/]]]]",
|
||||||
|
),
|
||||||
|
);
|
||||||
|
console.log(term.auto("\n[bg_white][black]Prints as:\n"));
|
||||||
|
console.log(
|
||||||
|
term.auto(
|
||||||
|
"[bg_green][bold][red] MESSAGE [///] [green][bold]Hello[//] [red]world[/]. [under] under [/] [bold]BOLD[/]",
|
||||||
|
),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
main().catch(console.error);
|
main().catch(console.error);
|
||||||
|
|||||||
@@ -16,6 +16,15 @@
|
|||||||
"publish_time": 1758209484774,
|
"publish_time": 1758209484774,
|
||||||
"update_time": 1758209484774
|
"update_time": 1758209484774
|
||||||
},
|
},
|
||||||
|
"build.ts": {
|
||||||
|
"script_name": "build.ts",
|
||||||
|
"script_length": 4555,
|
||||||
|
"script_sha256": "b70337218e8e164ba58c47ede81fdd9015ae81dd7c2658214720cf3e6fd27794",
|
||||||
|
"script_full_url": "https://git.hatter.ink/hatter/ts-scripts/raw/branch/main/single-scripts/build.ts",
|
||||||
|
"single_script_file": true,
|
||||||
|
"publish_time": 1770564482429,
|
||||||
|
"update_time": 1770564482429
|
||||||
|
},
|
||||||
"cal-bun.ts": {
|
"cal-bun.ts": {
|
||||||
"script_name": "cal-bun.ts",
|
"script_name": "cal-bun.ts",
|
||||||
"script_length": 427,
|
"script_length": 427,
|
||||||
|
|||||||
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