diff --git a/package-lock.json b/package-lock.json index 0ddaee1..0842543 100644 --- a/package-lock.json +++ b/package-lock.json @@ -15,6 +15,7 @@ ], "dependencies": { "@pkgjs/parseargs": "^0.11.0", + "capture-console": "^1.0.2", "cli-columns": "^4.0.0", "columnify": "^1.6.0", "fs-mode-to-string": "^0.0.2", @@ -360,6 +361,15 @@ "node": ">= 8" } }, + "node_modules/argle": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/argle/-/argle-1.1.2.tgz", + "integrity": "sha512-2sQZC5HeeSH9cQEwnZZhmHiKfvJkQ6ncpf8zl9Hv629aiMUsOw8jzYqOhpaMleQGzpQ7avCwrwyqSW1f4t7v0Q==", + "dependencies": { + "lodash.isfunction": "^3.0.8", + "lodash.isnumber": "^3.0.3" + } + }, "node_modules/argparse": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", @@ -442,6 +452,16 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/capture-console": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/capture-console/-/capture-console-1.0.2.tgz", + "integrity": "sha512-vQNTSFr0cmHAYXXG3KG7ZJQn0XxC3K2di/wUZVb6yII6gqSN/10Egd3vV4XqJ00yCRNHy2wkN4uWHE+rJstDrw==", + "dependencies": { + "argle": "~1.1.1", + "lodash.isfunction": "~3.0.8", + "randomstring": "^1.3.0" + } + }, "node_modules/chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", @@ -881,7 +901,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, "engines": { "node": ">=8" } @@ -1096,6 +1115,16 @@ "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", "integrity": "sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==" }, + "node_modules/lodash.isfunction": { + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/lodash.isfunction/-/lodash.isfunction-3.0.9.tgz", + "integrity": "sha512-AirXNj15uRIMMPihnkInB4i3NHeb4iBtNg9WRWuK2o31S+ePwwNmDPaTL3o7dTJ+VXNZim7rFs4rxN4YU1oUJw==" + }, + "node_modules/lodash.isnumber": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz", + "integrity": "sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==" + }, "node_modules/log-symbols": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", @@ -1413,6 +1442,25 @@ "safe-buffer": "^5.1.0" } }, + "node_modules/randomstring": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/randomstring/-/randomstring-1.3.0.tgz", + "integrity": "sha512-gY7aQ4i1BgwZ8I1Op4YseITAyiDiajeZOPQUbIq9TPGPhUm5FX59izIaOpmKbME1nmnEiABf28d9K2VSii6BBg==", + "dependencies": { + "randombytes": "2.0.3" + }, + "bin": { + "randomstring": "bin/randomstring" + }, + "engines": { + "node": "*" + } + }, + "node_modules/randomstring/node_modules/randombytes": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.0.3.tgz", + "integrity": "sha512-lDVjxQQFoCG1jcrP06LNo2lbWp4QTShEXnhActFBwYuHprllQV6VUpwreApsYqCgD+N1mHoqJ/BI/4eV4R2GYg==" + }, "node_modules/readdirp": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", diff --git a/package.json b/package.json index a79ccb4..d421e0b 100644 --- a/package.json +++ b/package.json @@ -19,6 +19,7 @@ }, "dependencies": { "@pkgjs/parseargs": "^0.11.0", + "capture-console": "^1.0.2", "cli-columns": "^4.0.0", "columnify": "^1.6.0", "fs-mode-to-string": "^0.0.2", diff --git a/src/main_cli.js b/src/main_cli.js index 10e1e87..9f3106c 100644 --- a/src/main_cli.js +++ b/src/main_cli.js @@ -21,6 +21,41 @@ import { launchPuterShell } from './puter-shell/main.js'; import { NodeStdioPTT } from './pty/NodeStdioPTT.js'; import { CreateFilesystemProvider } from './platform/node/filesystem.js'; import { CreateEnvProvider } from './platform/node/env.js'; +import { parseArgs } from '@pkgjs/parseargs'; +import capcon from 'capture-console'; +import fs from 'fs'; + +const { values } = parseArgs({ + options: { + 'log': { + type: 'string', + } + }, + args: process.argv.slice(2), +}); +const logFile = await (async () => { + if (!values.log) + return; + return await fs.promises.open(values.log, 'w'); +})(); + + +// Capture console.foo() output and either send it to the log file, or to nowhere. +for (const [name, oldMethod] of Object.entries(console)) { + console[name] = async (...args) => { + let result; + const stdio = capcon.interceptStdio(() => { + result = oldMethod(...args); + }); + + if (logFile) { + await logFile.write(stdio.stdout); + await logFile.write(stdio.stderr); + } + + return result; + }; +} const ctx = new Context({ ptt: new NodeStdioPTT(),