UNPKG

@specs-feup/lara

Version:

A js port of the popular framework for building source-to-source compilers

188 lines 7.27 kB
import Debug from "debug"; import yargs from "yargs"; import * as path from "path"; import * as chokidar from "chokidar"; import { hideBin } from "yargs/helpers"; import { fork } from "child_process"; import { fileURLToPath } from "url"; import { dirname } from "path"; import { addActiveChildProcess, getActiveChildProcesses, listenForTerminationSignals, } from "./ChildProcessHandling.js"; import { Weaver } from "./Weaver.js"; listenForTerminationSignals(); export default class WeaverLauncher { debug; config; midExecution = false; constructor(config) { this.config = config; this.debug = Debug(`WeaverLauncher:${this.config.weaverPrettyName}:main`); } async execute(customArgs = undefined) { const cliArgs = customArgs ?? hideBin(process.argv); if (cliArgs.length > 0 && cliArgs[0] === "classic") { const weaverArgs = cliArgs.slice(1); return new Promise((resolve, reject) => { try { console.log(`Executing ${this.config.weaverPrettyName} script in classic CLI mode...`); // TODO: Avoid using a third-party data object (i.e., Arguments) in our main interface // TODO: Use instead the argument-handling launcher Java code instead of reimplementing it void this.main({ $0: weaverArgs[0], _: [], scriptFile: weaverArgs[0], configClassic: weaverArgs, }); } catch (error) { console.error(error); } }); } await this.generateConfig(customArgs).parse(); } static capitalizeFirstLetter(string) { return string.charAt(0).toUpperCase() + string.slice(1); } main(args) { this.debug(`${this.config.weaverPrettyName} execution arguments: %O`, args); void this.executeWeaver(args); if (args.watch) { for (const directory of args.watch) { this.debug(`Watching directory: ${directory}`); } chokidar .watch(args.watch, { ignoreInitial: true }) .on("all", (event, filepath) => { try { this.debug(`Source file event: ${WeaverLauncher.capitalizeFirstLetter(event)} '${filepath}'`); void this.executeWeaver(args); } catch (error) { console.error(error); } }); } } async executeWeaver(args) { // Check if Classic CLI const isClassicCli = args.configClassic !== undefined && args.configClassic !== null; // If classic CLI, do not spawn processes, execute directly if (isClassicCli) { try { await Weaver.setupWeaver(args, this.config); // After setup, DataStore should be initialized //const datastore = Weaver.getDatastore(); //console.log("DataStore: " + datastore); Weaver.start(); const success = await Weaver.executeScript(args, this.config).catch((reason) => { console.log(reason); return false; }); Weaver.shutdown(); if (success) { process.exit(0); } else { process.exit(-1); } } catch (error) { console.log(error); process.exit(-1); } } if (this.midExecution) return; this.midExecution = true; const activeProcess = Object.values(getActiveChildProcesses())[0]; if (activeProcess?.exitCode === null) { const promise = new Promise((resolve) => { activeProcess.once("exit", (code) => { resolve(code); }); }); if (activeProcess.kill()) { await promise; this.debug("Killed active process"); } else { throw new Error("Could not kill active process"); } } const weaverScript = this.config.weaverFileName ? fileURLToPath(import.meta.resolve(this.config.weaverFileName)) : path.join(dirname(fileURLToPath(import.meta.url)), "Weaver.js"); console.debug("Launcher weaver using the script '" + weaverScript + "'"); const child = fork(weaverScript); child.send({ config: this.config, args, }); addActiveChildProcess(child); this.midExecution = false; } generateConfig(args = undefined) { return yargs(args ?? hideBin(process.argv)) .scriptName(this.config.weaverName) .command({ command: "$0 [script-file]", describe: `Execute a ${this.config.weaverPrettyName} script`, builder: (yargs) => { return yargs .positional("script-file", { describe: `Path to ${this.config.weaverPrettyName} script file`, type: "string", }) .option("c", { alias: "config", describe: "Path to JSON config file", type: "string", config: true, }) .option("w", { alias: "watch", describe: "Watch the following directory for changes", type: "array", default: [], defaultDescription: "none", }); }, handler: (argv) => { try { console.log(`Executing ${this.config.weaverPrettyName} script...`); void this.main(argv); } catch (error) { console.error(error); } }, }) .command({ command: "init", describe: `Initialize a new ${this.config.weaverPrettyName} project`, handler: () => { // TODO: Implement console.log(`Initializing new ${this.config.weaverPrettyName} project...`); console.log("Did nothing. Not implemented yet."); }, }) .command("classic", `Execute ${this.config.weaverPrettyName} using the 'Classic' CLI`, (yargs) => { return yargs .strict(false) .parserConfiguration({ "unknown-options-as-args": true }); }, (argv) => { try { console.log(`Executing ${this.config.weaverPrettyName} with 'Classic' CLI...`); void this.main(argv); } catch (error) { console.error(error); } }) .help() .showHelpOnFail(true) .strict(true) .pkgConf(this.config.weaverName); } } //# sourceMappingURL=WeaverLauncher.js.map