webassembly: Implement runCLI() for a Node-based CLI.

This allows running MicroPython webassembly from the command line using:

    node micropython.mjs

Signed-off-by: Damien George <damien@micropython.org>
pull/13583/head
Damien George 2024-02-01 17:46:34 +11:00
rodzic 9b090603a0
commit 625b17a410
1 zmienionych plików z 92 dodań i 0 usunięć

Wyświetl plik

@ -154,3 +154,95 @@ export async function loadMicroPython(options) {
}
globalThis.loadMicroPython = loadMicroPython;
async function runCLI() {
const fs = await import("fs");
let heap_size = 128 * 1024;
let contents = "";
let repl = true;
for (let i = 2; i < process.argv.length; i++) {
if (process.argv[i] === "-X" && i < process.argv.length - 1) {
if (process.argv[i + 1].includes("heapsize=")) {
heap_size = parseInt(process.argv[i + 1].split("heapsize=")[1]);
const suffix = process.argv[i + 1].substr(-1).toLowerCase();
if (suffix === "k") {
heap_size *= 1024;
} else if (suffix === "m") {
heap_size *= 1024 * 1024;
}
++i;
}
} else {
contents += fs.readFileSync(process.argv[i], "utf8");
repl = false;
}
}
if (process.stdin.isTTY === false) {
contents = fs.readFileSync(0, "utf8");
repl = false;
}
const mp = await loadMicroPython({
heapsize: heap_size,
stdout: (data) => process.stdout.write(data),
linebuffer: false,
});
if (repl) {
mp_js_init_repl();
process.stdin.setRawMode(true);
process.stdin.on("data", (data) => {
for (let i = 0; i < data.length; i++) {
mp_js_process_char(data[i]).then((result) => {
if (result) {
process.exit();
}
});
}
});
} else {
try {
mp.runPython(contents);
} catch (error) {
if (error.name === "PythonError") {
if (error.type === "SystemExit") {
// SystemExit, this is a valid exception to successfully end a script.
} else {
// An unhandled Python exception, print in out.
console.error(error.message);
}
} else {
// A non-Python exception. Re-raise it.
throw error;
}
}
}
}
// Check if Node is running (equivalent to ENVIRONMENT_IS_NODE).
if (
typeof process === "object" &&
typeof process.versions === "object" &&
typeof process.versions.node === "string"
) {
// Check if this module is ron from the command line.
//
// See https://stackoverflow.com/questions/6398196/detect-if-called-through-require-or-directly-by-command-line/66309132#66309132
//
// Note:
// - `resolve()` is used to handle symlinks
// - `includes()` is used to handle cases where the file extension was omitted when passed to node
const path = await import("path");
const url = await import("url");
const pathToThisFile = path.resolve(url.fileURLToPath(import.meta.url));
const pathPassedToNode = path.resolve(process.argv[1]);
const isThisFileBeingRunViaCLI = pathToThisFile.includes(pathPassedToNode);
if (isThisFileBeingRunViaCLI) {
runCLI();
}
}