diff --git a/libraries/deno-commons-mod.ts b/libraries/deno-commons-mod.ts index 4615f93..54e8abe 100644 --- a/libraries/deno-commons-mod.ts +++ b/libraries/deno-commons-mod.ts @@ -3,7 +3,7 @@ import {decodeBase64, encodeBase64} from "jsr:@std/encoding/base64"; import {dirname, fromFileUrl} from "https://deno.land/std/path/mod.ts"; -import {spawn} from "node:child_process"; +import {spawn, SpawnOptionsWithoutStdio} from "node:child_process"; // reference: https://docs.deno.com/examples/hex_base64_encoding/ // import { decodeBase64, encodeBase64 } from "jsr:@std/encoding/base64"; @@ -73,7 +73,7 @@ export class ProcessOutput { export async function execCommandAndStdout( command: string, args?: string[], - options?: Deno.CommandOptions, + options?: Deno.CommandOptions | SpawnOptionsWithoutStdio, ): Promise { const processOutput = await execCommand(command, args, options); processOutput.assertSuccess(); @@ -83,23 +83,56 @@ export async function execCommandAndStdout( export async function execCommand( command: string, args?: string[], - options?: Deno.CommandOptions, + options?: Deno.CommandOptions | SpawnOptionsWithoutStdio, ): Promise { - const opts = options || {}; - if (args) opts.args = args; - const cmd = new Deno.Command(command, opts); - const { code, stdout, stderr } = await cmd.output(); - return new ProcessOutput( - code, - new TextDecoder().decode(stdout), - new TextDecoder().decode(stderr), - ); + if (isDeno()) { + const opts = options || {}; + if (args) opts.args = args; + const cmd = new Deno.Command(command, opts); + const { code, stdout, stderr } = await cmd.output(); + return new ProcessOutput( + code, + new TextDecoder().decode(stdout), + new TextDecoder().decode(stderr), + ); + } + return await execCommandSpawn(command, args, options); +} + +async function execCommandSpawn( + command: string, + args: string[], + options?: SpawnOptionsWithoutStdio, +): Promise { + const ps = spawn(command, args, options); + return new Promise((resolve, reject) => { + let stdout = ""; + let stderr = ""; + ps.stdout.on("data", (data) => { + stdout += data.toString(); + }); + ps.stderr.on("data", (data) => { + stderr += data.toString(); + }); + ps.on("close", (code) => { + try { + const output = new ProcessOutput(code, stdout, stderr); + ps.stdin.end(); + resolve(output); + } catch (e) { + reject(e); + } + }); + ps.on("error", (err) => { + reject(err); + }); + }); } export async function execCommandShell( command: string, args?: string[], - options?: Deno.CommandOptions, + options?: Deno.CommandOptions | SpawnOptionsWithoutStdio, ): Promise { if (isDeno()) { const opts = options || {}; @@ -109,20 +142,27 @@ export async function execCommandShell( opts.stderr = "inherit"; const cmd = new Deno.Command(command, opts); return (await cmd.spawn().status).code; - } else { - return new Promise((resolve, reject) => { - const ps = spawn(command, args, { - shell: false, - stdio: ["inherit", "inherit", "inherit"], - }); - ps.on("close", (code) => { - resolve(code); - }); - ps.on("error", (err) => { - reject(err); - }); - }); } + return await execCommandShellSpwan(command, args, options); +} + +async function execCommandShellSpwan( + command: string, + args?: string[], + options?: SpawnOptionsWithoutStdio, +): Promise { + return new Promise((resolve, reject) => { + const ps = spawn(command, args, { + shell: false, + stdio: ["inherit", "inherit", "inherit"], + }); + ps.on("close", (code) => { + resolve(code); + }); + ps.on("error", (err) => { + reject(err); + }); + }); } export async function sleep(timeoutMillis: number): Promise {