run/src/run.ts

69 lines
1.8 KiB
TypeScript

import { difference, Sys } from "../deps.ts";
export class Runner {
constructor(readonly sys = Sys) {
}
// Run a tool by its name and args
async run(args: string[]) {
const app = args.shift();
if (!app) {
throw new Error("Usage: run app [args...]");
}
const flags_txt = await this.downloadText(
`https://code.thunderk.net/typescript/${app}/raw/branch/master/config/run.flags`,
);
const flags = flags_txt.split(/\s+/).filter((arg) => arg);
if (flags.some((arg) => !arg.startsWith("--"))) {
throw new Error(`Bad run flags: ${flags}`);
}
if (!await this.checkStamp(app)) {
console.log("Reloading sources...");
flags.unshift("--reload");
}
const uri =
`https://code.thunderk.net/typescript/${app}/raw/branch/master/cli.ts`;
await this.sys.run({
cmd: ["deno", "run"].concat(flags).concat([uri]).concat(args),
}).status();
}
// Download a remote text content (empty if not a 200 response)
async downloadText(uri: string): Promise<string> {
const response = await fetch(uri);
if (response.status == 200) {
const result = await response.text();
return result;
} else {
return "";
}
}
// Check an app timestamp, returning true if it is valid
async checkStamp(app: string): Promise<boolean> {
const path = `/tmp/thunderk-run-${app}.stamp`;
try {
const stat = await this.sys.stat(path);
if (stat.isFile && stat.mtime) {
const age = difference(stat.mtime, new Date()).days ?? 0;
if (age < 1) {
return true;
}
}
} catch {
}
await this.sys.writeTextFile(path, "");
return false;
}
}
// Run a remote program, by its name and args
export async function run(args: string[], sys = Sys) {
const runner = new Runner(sys);
await runner.run(args);
}