feat(phoenix): Respond to exit status codes

- Detect exit status of Puter apps, now that that's available.
- Store the exit status of each pipeline.
- Display a message when the exit status was non-zero.

That message is temporary, until we have a better way of displaying or
querying it, such as the `$?` shell variable.
This commit is contained in:
Sam Atkins 2024-05-23 12:55:53 +01:00
parent 7674da4cd2
commit 5de3052026
3 changed files with 25 additions and 9 deletions

View File

@ -160,6 +160,7 @@ export class ANSIShell extends EventTarget {
}
this.ctx.externs.out.write('error: ' + e.message + '\n');
console.log(e);
this.ctx.locals.exit = -1;
return;
}
}
@ -225,6 +226,13 @@ export class ANSIShell extends EventTarget {
const pipeline = await Pipeline.createFromAST(executionCtx, ast);
await pipeline.execute(executionCtx);
// Store exit code for the next pipeline
// TODO: This feels like a hacky way of doing this.
this.ctx.locals.exit = executionCtx.locals.exit;
if ( this.ctx.locals.exit ) {
this.ctx.externs.out.write(`Exited with code ${this.ctx.locals.exit}\n`);
}
}
expandPromptString (str) {

View File

@ -247,14 +247,14 @@ export class PreparedCommand {
if ( ! ctx.cmdExecState.valid ) {
ctx.locals.exit = -1;
await ctx.externs.out.close();
return;
return 1;
}
if ( ctx.cmdExecState.printHelpAndExit ) {
ctx.locals.exit = 0;
await printUsage(command, ctx.externs.out, ctx.vars);
await ctx.externs.out.close();
return;
return 0;
}
let execute = command.execute.bind(command);
@ -291,13 +291,14 @@ export class PreparedCommand {
command.name + ': ' +
e.message + '\x1B[0m\n'
);
exit_code = -1;
} else {
await ctx.externs.err.write(
'\x1B[31;1m' +
command.name + ': ' +
e.toString() + '\x1B[0m\n'
);
ctx.locals.exit = -1;
exit_code = -1;
}
if ( ! (e instanceof Exit) ) console.error(e);
}
@ -316,6 +317,8 @@ export class PreparedCommand {
await filesystem.write(path, outputMemWriters[i].getAsBlob());
}
return exit_code;
}
}
@ -348,7 +351,7 @@ export class Pipeline {
const valve = new Coupler(nextIn, pipeline_input_pipe.in);
nextIn = pipeline_input_pipe.out;
// TOOD: this will eventually defer piping of certain
// TODO: this will eventually defer piping of certain
// sub-pipelines to the Puter Shell.
for ( let i=0 ; i < preparedCommands.length ; i++ ) {
@ -381,9 +384,11 @@ export class Pipeline {
const command = preparedCommands[i];
commandPromises.push(command.execute());
}
await Promise.all(commandPromises);
const results = await Promise.all(commandPromises);
// TODO: Consider what to do about intermediate exit codes
ctx.locals.exit = results[results.length-1];
await coupler.isDone;
valve.close();
}
}
}

View File

@ -57,9 +57,12 @@ export class PuterAppCommandProvider {
// Wait for app to close.
const app_close_promise = new Promise((resolve, reject) => {
child.on('close', () => {
// TODO: Exit codes for apps
resolve({ done: true });
child.on('close', (data) => {
if ((data.statusCode ?? 0) != 0) {
reject(new Exit(data.statusCode));
} else {
resolve({ done: true });
}
});
});