Skip to content

Commit b91944c

Browse files
Save default.profraw after test completed (#504)
1 parent e861472 commit b91944c

File tree

3 files changed

+82
-19
lines changed

3 files changed

+82
-19
lines changed

Sources/CartonHelpers/StaticArchive.swift

Lines changed: 3 additions & 3 deletions
Large diffs are not rendered by default.

Sources/carton-release/HashArchive.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,8 @@ struct HashArchive: AsyncParsableCommand {
5050
let arguments = [
5151
"esbuild", "--bundle", "entrypoint/\(tsFilename)", "--outfile=static/\(filename)",
5252
"--external:node:url", "--external:node:path",
53-
"--external:node:module", "--external:playwright",
53+
"--external:node:module", "--external:node:fs/promises",
54+
"--external:playwright",
5455
"--format=esm",
5556
"--external:./JavaScriptKit_JavaScriptKit.resources/Runtime/index.mjs",
5657
]

entrypoint/intrinsics.ts

Lines changed: 77 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
// See the License for the specific language governing permissions and
1313
// limitations under the License.
1414

15-
import { WASI, File, OpenFile, ConsoleStdout, PreopenDirectory, WASIProcExit } from "@bjorn3/browser_wasi_shim";
15+
import { WASI, File, OpenFile, ConsoleStdout, PreopenDirectory, WASIProcExit, Inode, Directory } from "@bjorn3/browser_wasi_shim";
1616
import type { SwiftRuntime, SwiftRuntimeConstructor } from "./JavaScriptKit_JavaScriptKit.resources/Runtime/index";
1717
import { polyfill as polyfillWebAssemblyTypeReflection } from "wasm-imports-parser/polyfill";
1818
import type { ImportEntry } from "wasm-imports-parser";
@@ -48,6 +48,7 @@ export type InstantiationOptions = {
4848
module: WebAssembly.Module;
4949
args?: string[];
5050
env?: Record<string, string>;
51+
rootFs?: Map<string, Inode>;
5152
onStdout?: (chunk: Uint8Array) => void;
5253
onStdoutLine?: (line: string) => void;
5354
onStderr?: (chunk: Uint8Array) => void;
@@ -58,6 +59,7 @@ export type InstantiationOptions = {
5859

5960
export async function instantiate(rawOptions: InstantiationOptions, extraWasmImports?: WebAssembly.Imports): Promise<{
6061
instance: WebAssembly.Instance;
62+
rootFs: Map<string, Inode>;
6163
}> {
6264
const options: InstantiationOptions = defaultInstantiationOptions(rawOptions);
6365

@@ -85,11 +87,12 @@ export async function instantiate(rawOptions: InstantiationOptions, extraWasmImp
8587
});
8688

8789
const args = options.args || [];
90+
const rootFs = options.rootFs || new Map<string, Inode>();
8891
const fds = [
8992
new OpenFile(new File([])), // stdin
9093
stdout,
9194
stderr,
92-
new PreopenDirectory("/", new Map()),
95+
new PreopenDirectory("/", rootFs),
9396
];
9497

9598
// Convert env Record to array of "key=value" strings
@@ -177,7 +180,7 @@ export async function instantiate(rawOptions: InstantiationOptions, extraWasmImp
177180
}
178181
}
179182

180-
return { instance };
183+
return { instance, rootFs };
181184
}
182185

183186
function defaultInstantiationOptions(options: InstantiationOptions): InstantiationOptions {
@@ -206,8 +209,39 @@ function defaultInstantiationOptions(options: InstantiationOptions): Instantiati
206209

207210
type Instantiate = (options: Omit<InstantiationOptions, "module">, extraWasmImports?: WebAssembly.Imports) => Promise<{
208211
instance: WebAssembly.Instance;
212+
rootFs: Map<string, Inode>;
209213
}>;
210214

215+
async function extractAndSaveFile(rootFs: Map<string, Inode>, path: string): Promise<boolean> {
216+
const getFile = (parent: Map<string, Inode>, components: string[], index: number): Inode | undefined => {
217+
const name = components[index];
218+
const entry = parent.get(name);
219+
if (entry === undefined) {
220+
return undefined;
221+
}
222+
if (index === components.length - 1) {
223+
return entry;
224+
}
225+
if (entry instanceof Directory) {
226+
return getFile(entry.contents, components, index + 1);
227+
}
228+
throw new Error(`Expected directory at ${components.slice(0, index).join("/")}`);
229+
}
230+
231+
const components = path.split("/");
232+
const file = getFile(rootFs, components, 0);
233+
if (file === undefined) {
234+
return false;
235+
}
236+
if (file instanceof File) {
237+
const fs = await import("node:fs/promises");
238+
console.log(`Saved ${path} to ${process.cwd()}`);
239+
await fs.writeFile(path, file.data);
240+
return true;
241+
}
242+
return false;
243+
}
244+
211245
export async function testBrowser(instantiate: Instantiate, wasmFileName: string, args: string[], indexJsUrl: string, inPage: boolean) {
212246
if (inPage) {
213247
return await testBrowserInPage(instantiate, wasmFileName, args);
@@ -221,8 +255,8 @@ export async function testBrowser(instantiate: Instantiate, wasmFileName: string
221255
console.error(`Playwright is not available in the current environment.
222256
Please run the following command to install it:
223257
224-
$ npm install playwright && npx playwright install chromium
225-
`);
258+
$ npm install playwright && npx playwright install chromium
259+
`);
226260
process.exit(1);
227261
}
228262
})();
@@ -275,9 +309,9 @@ async function testBrowserInPage(instantiate: Instantiate, wasmFileName: string,
275309

276310
// There are 6 cases to exit test
277311
// 1. Successfully finished XCTest with `exit(0)` synchronously
278-
// 2. Unsuccessfully finished XCTest with `exit(non-zero)` synchronously
312+
// 2. Unsuccessfully finished XCTest with `exit(non - zero)` synchronously
279313
// 3. Successfully finished XCTest with `exit(0)` asynchronously
280-
// 4. Unsuccessfully finished XCTest with `exit(non-zero)` asynchronously
314+
// 4. Unsuccessfully finished XCTest with `exit(non - zero)` asynchronously
281315
// 5. Crash by throwing JS exception synchronously
282316
// 6. Crash by throwing JS exception asynchronously
283317

@@ -359,14 +393,42 @@ This usually means there are some dangling continuations, which are awaited but
359393
}
360394
});
361395

362-
await instantiate({ env, args: [wasmFileName].concat(args) }, {
363-
"wasi_snapshot_preview1": {
364-
// @bjorn3/browser_wasi_shim raises an exception when
365-
// the process exits, but we just want to exit the process itself.
366-
proc_exit: (code: number) => {
367-
procExitCalled = true;
368-
process.exit(code);
369-
},
396+
process.on("unhandledRejection", (error) => {
397+
if (error instanceof WASIProcExit && error.code == 0) {
398+
return;
399+
}
400+
throw error;
401+
})
402+
403+
const rootFs = new Map<string, Inode>();
404+
const onExit = new Promise<number>(async (resolve) => {
405+
try {
406+
await instantiate({ env, args: [wasmFileName].concat(args), rootFs }, {
407+
"wasi_snapshot_preview1": {
408+
// @bjorn3/browser_wasi_shim raises an exception when
409+
// the process exits, but we just want to exit the process itself.
410+
proc_exit: (code: number) => {
411+
procExitCalled = true;
412+
resolve(code);
413+
throw new WASIProcExit(code);
414+
},
415+
}
416+
});
417+
} catch (error) {
418+
if (error instanceof WASIProcExit) {
419+
resolve(error.code);
420+
} else {
421+
throw error;
422+
}
370423
}
371424
});
425+
let code = 1;
426+
try {
427+
code = await onExit;
428+
} finally {
429+
for (const path of ["default.profraw"]) {
430+
await extractAndSaveFile(rootFs, path);
431+
}
432+
process.exit(code);
433+
}
372434
}

0 commit comments

Comments
 (0)