Skip to content

Commit

Permalink
[Lara-JS] Adds new, separate codepath for classic CLI
Browse files Browse the repository at this point in the history
- This codepath does not fork a new process, seems to solve issues of the application hanging when errors, and problems when CMake package launched node mode;
  • Loading branch information
joaobispo committed Nov 13, 2024
1 parent b76565a commit 922ae10
Show file tree
Hide file tree
Showing 2 changed files with 93 additions and 15 deletions.
35 changes: 27 additions & 8 deletions Lara-JS/src-code/Weaver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { isJavaError } from "./JavaError.js";
import { promisify } from "util";
import { isValidFileExtension } from "./FileExtensions.js";
import WeaverMessageFromLauncher from "./WeaverMessageFromLauncher.js";
import assert from "assert";

let directExecution = false;

Expand Down Expand Up @@ -100,11 +101,19 @@ export class Weaver {
javaWeaver.setScriptEngine(new NodeJsEngine());
javaWeaver.setEventTrigger(new JavaEventTrigger());

const isClassicCli =
args.configClassic !== undefined && args.configClassic !== null;

let datastore;
if (args._[0] === "classic") {
if (isClassicCli) {
//if (args._[0] === "classic") {
try {
assert(args.configClassic instanceof Array);
console.log("FLAGS: " + args.configClassic);

datastore = JavaLaraI.convertArgsToDataStore(
args._.slice(1),
//args._.slice(1),
args.configClassic,
javaWeaver
).get();
args.scriptFile = datastore.get("aspect").toString();
Expand Down Expand Up @@ -139,7 +148,6 @@ export class Weaver {

// Needed only for side-effects over the datastore
new JavaLaraIDataStore(null, datastore, javaWeaver); // nosonar typescript:S1848

JavaSpecsSystem.programStandardInit();

Weaver.javaWeaver = javaWeaver;
Expand All @@ -165,16 +173,26 @@ export class Weaver {
await import(file);
}

if (typeof args.scriptFile !== "string") {
throw new Error(
"Script file '" +
args.scriptFile +
"' is not a string: " +
typeof args.scriptFile
);
}

const scriptFile = args.scriptFile;

Weaver.debug("Executing user script...");
if (
typeof args.scriptFile === "string" &&
fs.existsSync(args.scriptFile) &&
isValidFileExtension(path.extname(args.scriptFile))
fs.existsSync(scriptFile) &&
isValidFileExtension(path.extname(scriptFile))
) {
// import is using a URL converted to string.
// The URL is used due to a Windows error with paths. See https://stackoverflow.com/questions/69665780/error-err-unsupported-esm-url-scheme-only-file-and-data-urls-are-supported-by
// The conversion of the URl back to a string is due to a TS bug. See https://github.com/microsoft/TypeScript/issues/42866
await import(pathToFileURL(path.resolve(args.scriptFile)).toString())
await import(pathToFileURL(path.resolve(scriptFile)).toString())
.then(() => {
Weaver.debug("Execution completed successfully.");
})
Expand All @@ -192,7 +210,7 @@ export class Weaver {
Weaver.debug(error);
});
} else {
throw new Error("Invalid file path or file type.");
throw new Error("Invalid file path or file type: " + scriptFile);
}
}

Expand Down Expand Up @@ -257,6 +275,7 @@ waitForMessage(eventEmitter)

if (directExecution) {
Weaver.start();

await Weaver.executeScript(
messageFromParent.args,
messageFromParent.config
Expand Down
73 changes: 66 additions & 7 deletions Lara-JS/src-code/WeaverLauncher.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ import {
} from "./ChildProcessHandling.js";
import WeaverConfiguration from "./WeaverConfiguration.js";
import WeaverMessageFromLauncher from "./WeaverMessageFromLauncher.js";
import { writeFileSync } from "fs";

import { Weaver } from "./Weaver.js";

listenForTerminationSignals();

Expand All @@ -28,7 +31,46 @@ export default class WeaverLauncher {
this.debug = Debug(`WeaverLauncher:${this.config.weaverPrettyName}:main`);
}

async execute(customArgs: string | undefined = undefined): Promise<void> {
/*
executeSync(customArgs: string[] | undefined = undefined): void {
const cliArgs = customArgs ?? hideBin(process.argv);
if (cliArgs.length > 0 && cliArgs[0] === "classic") {
const weaverArgs = cliArgs.slice(1);
console.log(
`Executing ${this.config.weaverPrettyName} script in classic CLI mode...`
);
}
await execute(customArgs);
}
*/

async execute(customArgs: string[] | undefined = undefined): Promise<void> {
const cliArgs = customArgs ?? hideBin(process.argv);

if (cliArgs.length > 0 && cliArgs[0] === "classic") {
const weaverArgs = cliArgs.slice(1);

return new Promise<void>((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,
} as Arguments);
} catch (error) {
console.error(error);
}
});
}

await this.generateConfig(customArgs).parse();
}

Expand Down Expand Up @@ -63,6 +105,21 @@ export default class WeaverLauncher {
}

protected async executeWeaver(args: Arguments) {
// Check if Classic CLI
const isClassicCli =
args.configClassic !== undefined && args.configClassic !== null;

// If classic CLI, do not spawn processes, execute directly
if (isClassicCli) {
await Weaver.setupWeaver(args, this.config);

Weaver.start();

await Weaver.executeScript(args, this.config);
Weaver.shutdown();
process.exit(0);
}

if (this.midExecution) return;
this.midExecution = true;
const activeProcess = Object.values(getActiveChildProcesses())[0];
Expand All @@ -81,11 +138,13 @@ export default class WeaverLauncher {
}
}

const child = fork(
this.config.weaverFileName
? fileURLToPath(import.meta.resolve(this.config.weaverFileName))
: path.join(dirname(fileURLToPath(import.meta.url)), "Weaver.js")
);
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,
Expand All @@ -95,7 +154,7 @@ export default class WeaverLauncher {
this.midExecution = false;
}

protected generateConfig(args: string | undefined = undefined) {
protected generateConfig(args: string[] | undefined = undefined) {
return yargs(args ?? hideBin(process.argv))
.scriptName(this.config.weaverName)
.command({
Expand Down

0 comments on commit 922ae10

Please sign in to comment.