Skip to content

Commit

Permalink
[autorelease] Expose filesystem snapshot on Exit.files.
Browse files Browse the repository at this point in the history
Without this it could be difficult to examine the cause of the failure
without resorting to parsing terminal output.
  • Loading branch information
whitequark committed Dec 9, 2023
1 parent 7903a20 commit 12231a3
Show file tree
Hide file tree
Showing 5 changed files with 47 additions and 6 deletions.
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@ Options:
- The `printLine` option is a function called for each line of text the application prints to the terminal (i.e. standard output and standard error), without the terminating `'\n'` character. The text printed to standard output and standard error is combined as it is being printed (without buffering). The default is `printLine: console.log`.
- The `decodeASCII` option determines whether the values corresponding to files in `filesOut` are always instances of [Uint8Array][] (if `decodeASCII: false`), or whether the values corresponding to text files will be strings (if `decodeASCII: true`). A file is considered a text file if it contains only bytes in range `0x20` to `0x7f` inclusive. The default is `decodeASCII: true`.

If the application returns a non-zero exit code, the exception `Exit` (exported alongside the `runX` function) is raised. This exception has two properties:
- The `code` property indicates the exit code. (Currently this is always 1 due to WebAssembly peculiarities.)
- The `files` property represents the state of the virtual filesystem after the application terminated. This property can be used to retrieve log files or other data aiding in diagnosing the error.

[Uint8Array]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Uint8Array


Expand Down
13 changes: 11 additions & 2 deletions lib/api-base.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,15 +25,24 @@ export class BaseApplication {
const wasmCommand = await this.instantiate(
(filename) => this.wasmModules[filename],
{ runtime: environment.exports });
let error = null;
try {
wasmCommand.run.run();
} catch (e) {
if (!(e instanceof Exit && e.code === 0))
if (!(e instanceof Exit))
throw e;
if (e instanceof Exit && e.code !== 0)
error = e;
}

for (const dirName of Object.keys(this._resources))
delete environment.root.files[dirName];
return directoryIntoTree(environment.root, { decodeASCII });
files = directoryIntoTree(environment.root, { decodeASCII });
if (error !== null) {
error.files = files;
throw error;
} else {
return files;
}
}
}
2 changes: 1 addition & 1 deletion package-in.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@yowasp/runtime",
"version": "__VERSION__",
"version": "3.1",
"description": "Common runtime for YoWASP packages",
"author": "Catherine <[email protected]>",
"license": "ISC",
Expand Down
4 changes: 2 additions & 2 deletions prepare.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@ import { execFileSync } from 'child_process';
import { readFileSync, writeFileSync } from 'fs';

const revCount = execFileSync('git', ['rev-list', 'HEAD'], {encoding: 'utf-8'}).split('\n').length - 1;
const packageJSON = JSON.parse(readFileSync('package-in.json', {encoding: 'utf-8'}));

let version = `3.0.${revCount - 1}`;
let version = `${packageJSON.version}.${revCount - 1}`;
if (!['true', '1', 'yes'].includes(process.env['RELEASE_BRANCH']))
version += '-dev';
console.log(`version ${version}`);

const packageJSON = JSON.parse(readFileSync('package-in.json', {encoding: 'utf-8'}));
packageJSON.version = version;
writeFileSync('package.json', JSON.stringify(packageJSON));
30 changes: 29 additions & 1 deletion test/yowasp_runtime_test/index.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Application } from '@yowasp/runtime';
import { Application, Exit } from '@yowasp/runtime';
import { instantiate } from './gen/copy.js';


Expand All @@ -17,3 +17,31 @@ if ((await yowaspRuntimeTest.run(['share/foo.txt', 'bar.txt'], {}))['bar.txt'] !

if ((await yowaspRuntimeTest.run(['baz.txt', 'bar.txt'], {'baz.txt': 'contents of baz'}))['bar.txt'] !== 'contents of baz')
throw 'test 2 failed';

let lines = [];
try {
await yowaspRuntimeTest.run(['xxx.txt'], {'yyy.txt': 'contents of yyy'}, {
printLine(line) { lines.push(line); }
});
throw 'test 3 failed (1)';
} catch (e) {
if (!(e instanceof Exit))
throw 'test 3 failed (2)';
if (!(Object.hasOwn(e, 'files') && e.files['yyy.txt'] === 'contents of yyy'))
throw 'test 3 failed (3)';
}
if (!(lines.length === 1 && lines[0] === "fopen:r: No such file or directory"))
throw 'test 3 failed (4)';

let files4 = await yowaspRuntimeTest.run([], {'a.txt': 'ABC', 'b.txt': '\x01'});
if (files4['a.txt'] !== 'ABC')
throw 'test 4 failed (1)';
if (!(files4['b.txt'] instanceof Uint8Array && files4['b.txt'].length === 1 && files4['b.txt'][0] === 1))
throw 'test 4 failed (2)';

let files5 = await yowaspRuntimeTest.run([], {'a.txt': 'ABC', 'b.txt': '\x01'}, { decodeASCII: false });
if (!(files5['a.txt'] instanceof Uint8Array && files5['a.txt'].length === 3 &&
files5['a.txt'][0] === 0x41 && files5['a.txt'][1] === 0x42 && files5['a.txt'][2] === 0x43))
throw 'test 5 failed (1)';
if (!(files5['b.txt'] instanceof Uint8Array && files5['b.txt'].length === 1 && files5['b.txt'][0] === 1))
throw 'test 5 failed (2)';

0 comments on commit 12231a3

Please sign in to comment.