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 { 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 { 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); }