From f917d2e2c10e0a94e564a9016217e7ce27c8bbee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bartek=20Iwa=C5=84czuk?= Date: Mon, 13 Feb 2023 19:25:00 +0100 Subject: [PATCH] feat: Stabilize Deno.Command API (#17628) This commit stabilizes "Deno.Command" API with all its related APIs. "--unstable" flag is no longer required to use this API. --- cli/tsc/diagnostics.rs | 9 -- cli/tsc/dts/lib.deno.ns.d.ts | 212 ++++++++++++++++++++++++++++ cli/tsc/dts/lib.deno.unstable.d.ts | 218 ----------------------------- runtime/js/40_spawn.js | 215 ++++++++++++++-------------- runtime/js/90_deno_ns.js | 6 +- runtime/js/99_main.js | 29 ---- runtime/ops/spawn.rs | 104 -------------- 7 files changed, 318 insertions(+), 475 deletions(-) diff --git a/cli/tsc/diagnostics.rs b/cli/tsc/diagnostics.rs index 461cda7751..a865daa9d9 100644 --- a/cli/tsc/diagnostics.rs +++ b/cli/tsc/diagnostics.rs @@ -29,15 +29,6 @@ const UNSTABLE_DENO_PROPS: &[&str] = &[ "removeSignalListener", "shutdown", "umask", - "Child", - "ChildProcess", - "ChildStatus", - "SpawnOutput", - "command", - "Command", - "CommandOptions", - "CommandStatus", - "CommandOutput", "serve", "ServeInit", "ServeTlsInit", diff --git a/cli/tsc/dts/lib.deno.ns.d.ts b/cli/tsc/dts/lib.deno.ns.d.ts index d81e4afcd6..93e1b54a6a 100644 --- a/cli/tsc/dts/lib.deno.ns.d.ts +++ b/cli/tsc/dts/lib.deno.ns.d.ts @@ -3958,6 +3958,218 @@ declare namespace Deno { */ export function run(opt: T): Process; + /** Create a child process. + * + * If any stdio options are not set to `"piped"`, accessing the corresponding + * field on the `Command` or its `CommandOutput` will throw a `TypeError`. + * + * If `stdin` is set to `"piped"`, the `stdin` {@linkcode WritableStream} + * needs to be closed manually. + * + * @example Spawn a subprocess and pipe the output to a file + * + * ```ts + * const command = new Deno.Command(Deno.execPath(), { + * args: [ + * "eval", + * "console.log('Hello World')", + * ], + * stdin: "piped", + * }); + * const child = command.spawn(); + * + * // open a file and pipe the subprocess output to it. + * child.stdout.pipeTo(Deno.openSync("output").writable); + * + * // manually close stdin + * child.stdin.close(); + * const status = await child.status; + * ``` + * + * @example Spawn a subprocess and collect its output + * + * ```ts + * const command = new Deno.Command(Deno.execPath(), { + * args: [ + * "eval", + * "console.log('hello'); console.error('world')", + * ], + * }); + * const { code, stdout, stderr } = await command.output(); + * console.assert(code === 0); + * console.assert("hello\n" === new TextDecoder().decode(stdout)); + * console.assert("world\n" === new TextDecoder().decode(stderr)); + * ``` + * + * @example Spawn a subprocess and collect its output synchronously + * + * ```ts + * const command = new Deno.Command(Deno.execPath(), { + * args: [ + * "eval", + * "console.log('hello'); console.error('world')", + * ], + * }); + * const { code, stdout, stderr } = command.outputSync(); + * console.assert(code === 0); + * console.assert("hello\n" === new TextDecoder().decode(stdout)); + * console.assert("world\n" === new TextDecoder().decode(stderr)); + * ``` + * + * @category Sub Process + */ + export class Command { + constructor(command: string | URL, options?: CommandOptions); + /** + * Executes the {@linkcode Deno.Command}, waiting for it to finish and + * collecting all of its output. + * If `spawn()` was called, calling this function will collect the remaining + * output. + * + * Will throw an error if `stdin: "piped"` is set. + * + * If options `stdout` or `stderr` are not set to `"piped"`, accessing the + * corresponding field on {@linkcode Deno.CommandOutput} will throw a `TypeError`. + */ + output(): Promise; + /** + * Synchronously executes the {@linkcode Deno.Command}, waiting for it to + * finish and collecting all of its output. + * + * Will throw an error if `stdin: "piped"` is set. + * + * If options `stdout` or `stderr` are not set to `"piped"`, accessing the + * corresponding field on {@linkcode Deno.CommandOutput} will throw a `TypeError`. + */ + outputSync(): CommandOutput; + /** + * Spawns a streamable subprocess, allowing to use the other methods. + */ + spawn(): ChildProcess; + } + + /** + * The interface for handling a child process returned from + * {@linkcode Deno.Command.spawn}. + * + * @category Sub Process + */ + export class ChildProcess { + get stdin(): WritableStream; + get stdout(): ReadableStream; + get stderr(): ReadableStream; + readonly pid: number; + /** Get the status of the child. */ + readonly status: Promise; + + /** Waits for the child to exit completely, returning all its output and + * status. */ + output(): Promise; + /** Kills the process with given {@linkcode Deno.Signal}. + * + * @param [signo="SIGTERM"] + */ + kill(signo?: Signal): void; + + /** Ensure that the status of the child process prevents the Deno process + * from exiting. */ + ref(): void; + /** Ensure that the status of the child process does not block the Deno + * process from exiting. */ + unref(): void; + } + + /** + * Options which can be set when calling {@linkcode Deno.Command}. + * + * @category Sub Process + */ + export interface CommandOptions { + /** Arguments to pass to the process. */ + args?: string[]; + /** + * The working directory of the process. + * + * If not specified, the `cwd` of the parent process is used. + */ + cwd?: string | URL; + /** + * Clear environmental variables from parent process. + * + * Doesn't guarantee that only `env` variables are present, as the OS may + * set environmental variables for processes. + * + * @default {false} + */ + clearEnv?: boolean; + /** Environmental variables to pass to the subprocess. */ + env?: Record; + /** + * Sets the child process’s user ID. This translates to a setuid call in the + * child process. Failure in the set uid call will cause the spawn to fail. + */ + uid?: number; + /** Similar to `uid`, but sets the group ID of the child process. */ + gid?: number; + /** + * An {@linkcode AbortSignal} that allows closing the process using the + * corresponding {@linkcode AbortController} by sending the process a + * SIGTERM signal. + * + * Not supported in {@linkcode Deno.Command.outputSync}. + */ + signal?: AbortSignal; + + /** How `stdin` of the spawned process should be handled. + * + * Defaults to `"inherit"` for `output` & `outputSync`, + * and `"inherit"` for `spawn`. */ + stdin?: "piped" | "inherit" | "null"; + /** How `stdout` of the spawned process should be handled. + * + * Defaults to `"piped"` for `output` & `outputSync`, + * and `"inherit"` for `spawn`. */ + stdout?: "piped" | "inherit" | "null"; + /** How `stderr` of the spawned process should be handled. + * + * Defaults to `"piped"` for `output` & `outputSync`, + * and `"inherit"` for `spawn`. */ + stderr?: "piped" | "inherit" | "null"; + + /** Skips quoting and escaping of the arguments on windows. This option + * is ignored on non-windows platforms. + * + * @default {false} */ + windowsRawArguments?: boolean; + } + + /** + * @category Sub Process + */ + export interface CommandStatus { + /** If the child process exits with a 0 status code, `success` will be set + * to `true`, otherwise `false`. */ + success: boolean; + /** The exit code of the child process. */ + code: number; + /** The signal associated with the child process. */ + signal: Signal | null; + } + + /** + * The interface returned from calling {@linkcode Command.output} or + * {@linkcode Command.outputSync} which represents the result of spawning the + * child process. + * + * @category Sub Process + */ + export interface CommandOutput extends CommandStatus { + /** The buffered output from the child process' `stdout`. */ + readonly stdout: Uint8Array; + /** The buffered output from the child process' `stderr`. */ + readonly stderr: Uint8Array; + } + /** Option which can be specified when performing {@linkcode Deno.inspect}. * * @category Console and Debugging */ diff --git a/cli/tsc/dts/lib.deno.unstable.d.ts b/cli/tsc/dts/lib.deno.unstable.d.ts index 898343d800..e2abab26de 100644 --- a/cli/tsc/dts/lib.deno.unstable.d.ts +++ b/cli/tsc/dts/lib.deno.unstable.d.ts @@ -1407,224 +1407,6 @@ declare namespace Deno { */ export function upgradeHttpRaw(request: Request): [Deno.Conn, Uint8Array]; - /** **UNSTABLE**: New API, yet to be vetted. - * - * Create a child process. - * - * If any stdio options are not set to `"piped"`, accessing the corresponding - * field on the `Command` or its `CommandOutput` will throw a `TypeError`. - * - * If `stdin` is set to `"piped"`, the `stdin` {@linkcode WritableStream} - * needs to be closed manually. - * - * @example Spawn a subprocess and pipe the output to a file - * - * ```ts - * const command = new Deno.Command(Deno.execPath(), { - * args: [ - * "eval", - * "console.log('Hello World')", - * ], - * stdin: "piped", - * }); - * const child = command.spawn(); - * - * // open a file and pipe the subprocess output to it. - * child.stdout.pipeTo(Deno.openSync("output").writable); - * - * // manually close stdin - * child.stdin.close(); - * const status = await child.status; - * ``` - * - * @example Spawn a subprocess and collect its output - * - * ```ts - * const command = new Deno.Command(Deno.execPath(), { - * args: [ - * "eval", - * "console.log('hello'); console.error('world')", - * ], - * }); - * const { code, stdout, stderr } = await command.output(); - * console.assert(code === 0); - * console.assert("hello\n" === new TextDecoder().decode(stdout)); - * console.assert("world\n" === new TextDecoder().decode(stderr)); - * ``` - * - * @example Spawn a subprocess and collect its output synchronously - * - * ```ts - * const command = new Deno.Command(Deno.execPath(), { - * args: [ - * "eval", - * "console.log('hello'); console.error('world')", - * ], - * }); - * const { code, stdout, stderr } = command.outputSync(); - * console.assert(code === 0); - * console.assert("hello\n" === new TextDecoder().decode(stdout)); - * console.assert("world\n" === new TextDecoder().decode(stderr)); - * ``` - * - * @category Sub Process - */ - export class Command { - constructor(command: string | URL, options?: CommandOptions); - /** - * Executes the {@linkcode Deno.Command}, waiting for it to finish and - * collecting all of its output. - * If `spawn()` was called, calling this function will collect the remaining - * output. - * - * Will throw an error if `stdin: "piped"` is set. - * - * If options `stdout` or `stderr` are not set to `"piped"`, accessing the - * corresponding field on {@linkcode Deno.CommandOutput} will throw a `TypeError`. - */ - output(): Promise; - /** - * Synchronously executes the {@linkcode Deno.Command}, waiting for it to - * finish and collecting all of its output. - * - * Will throw an error if `stdin: "piped"` is set. - * - * If options `stdout` or `stderr` are not set to `"piped"`, accessing the - * corresponding field on {@linkcode Deno.CommandOutput} will throw a `TypeError`. - */ - outputSync(): CommandOutput; - /** - * Spawns a streamable subprocess, allowing to use the other methods. - */ - spawn(): ChildProcess; - } - - /** **UNSTABLE**: New API, yet to be vetted. - * - * The interface for handling a child process returned from - * {@linkcode Deno.Command.spawn}. - * - * @category Sub Process - */ - export class ChildProcess { - get stdin(): WritableStream; - get stdout(): ReadableStream; - get stderr(): ReadableStream; - readonly pid: number; - /** Get the status of the child. */ - readonly status: Promise; - - /** Waits for the child to exit completely, returning all its output and - * status. */ - output(): Promise; - /** Kills the process with given {@linkcode Deno.Signal}. - * - * @param [signo="SIGTERM"] - */ - kill(signo?: Signal): void; - - /** Ensure that the status of the child process prevents the Deno process - * from exiting. */ - ref(): void; - /** Ensure that the status of the child process does not block the Deno - * process from exiting. */ - unref(): void; - } - - /** **UNSTABLE**: New API, yet to be vetted. - * - * Options which can be set when calling {@linkcode Deno.command}. - * - * @category Sub Process - */ - export interface CommandOptions { - /** Arguments to pass to the process. */ - args?: readonly string[]; - /** - * The working directory of the process. - * - * If not specified, the `cwd` of the parent process is used. - */ - cwd?: string | URL; - /** - * Clear environmental variables from parent process. - * - * Doesn't guarantee that only `env` variables are present, as the OS may - * set environmental variables for processes. - * - * @default {false} - */ - clearEnv?: boolean; - /** Environmental variables to pass to the subprocess. */ - env?: Record; - /** - * Sets the child process’s user ID. This translates to a setuid call in the - * child process. Failure in the set uid call will cause the spawn to fail. - */ - uid?: number; - /** Similar to `uid`, but sets the group ID of the child process. */ - gid?: number; - /** - * An {@linkcode AbortSignal} that allows closing the process using the - * corresponding {@linkcode AbortController} by sending the process a - * SIGTERM signal. - * - * Not supported in {@linkcode Deno.Command.outputSync}. - */ - signal?: AbortSignal; - - /** How `stdin` of the spawned process should be handled. - * - * Defaults to `"inherit"` for `output` & `outputSync`, - * and `"inherit"` for `spawn`. */ - stdin?: "piped" | "inherit" | "null"; - /** How `stdout` of the spawned process should be handled. - * - * Defaults to `"piped"` for `output` & `outputSync`, - * and `"inherit"` for `spawn`. */ - stdout?: "piped" | "inherit" | "null"; - /** How `stderr` of the spawned process should be handled. - * - * Defaults to `"piped"` for `output` & `outputSync`, - * and `"inherit"` for `spawn`. */ - stderr?: "piped" | "inherit" | "null"; - - /** Skips quoting and escaping of the arguments on windows. This option - * is ignored on non-windows platforms. - * - * @default {false} */ - windowsRawArguments?: boolean; - } - - /** **UNSTABLE**: New API, yet to be vetted. - * - * @category Sub Process - */ - export interface CommandStatus { - /** If the child process exits with a 0 status code, `success` will be set - * to `true`, otherwise `false`. */ - success: boolean; - /** The exit code of the child process. */ - code: number; - /** The signal associated with the child process. */ - signal: Signal | null; - } - - /** **UNSTABLE**: New API, yet to be vetted. - * - * The interface returned from calling {@linkcode Command.output} or - * {@linkcode Command.outputSync} which represents the result of spawning the - * child process. - * - * @category Sub Process - */ - export interface CommandOutput extends CommandStatus { - /** The buffered output from the child process' `stdout`. */ - readonly stdout: Uint8Array; - /** The buffered output from the child process' `stderr`. */ - readonly stderr: Uint8Array; - } - /** **UNSTABLE**: New API, yet to be vetted. * * Returns the Operating System uptime in number of seconds. diff --git a/runtime/js/40_spawn.js b/runtime/js/40_spawn.js index f153b93a5c..f75d83f9ba 100644 --- a/runtime/js/40_spawn.js +++ b/runtime/js/40_spawn.js @@ -55,16 +55,19 @@ function spawnChildInner(opFn, command, apiName, { stderr, windowsRawArguments, }, apiName); - return new Child(illegalConstructorKey, { + return new ChildProcess(illegalConstructorKey, { ...child, signal, }); } -function createSpawnChild(opFn) { - return function spawnChild(command, options = {}) { - return spawnChildInner(opFn, command, "Deno.Command().spawn()", options); - }; +function spawnChild(command, options = {}) { + return spawnChildInner( + ops.op_spawn_child, + command, + "Deno.Command().spawn()", + options, + ); } function collectOutput(readableStream) { @@ -77,7 +80,7 @@ function collectOutput(readableStream) { return readableStreamCollectIntoUint8Array(readableStream); } -class Child { +class ChildProcess { #rid; #waitPromiseId; #unrefed = false; @@ -95,7 +98,6 @@ class Child { return this.#stdin; } - #stdoutPromiseId; #stdoutRid; #stdout = null; get stdout() { @@ -105,7 +107,6 @@ class Child { return this.#stdout; } - #stderrPromiseId; #stderrRid; #stderr = null; get stderr() { @@ -220,116 +221,106 @@ class Child { } } -function createSpawn(opFn) { - return function spawn(command, options) { - if (options?.stdin === "piped") { - throw new TypeError( - "Piped stdin is not supported for this function, use 'Deno.Command().spawn()' instead", - ); - } - return spawnChildInner(opFn, command, "Deno.Command().output()", options) - .output(); +function spawn(command, options) { + if (options?.stdin === "piped") { + throw new TypeError( + "Piped stdin is not supported for this function, use 'Deno.Command().spawn()' instead", + ); + } + return spawnChildInner( + ops.op_spawn_child, + command, + "Deno.Command().output()", + options, + ) + .output(); +} + +function spawnSync(command, { + args = [], + cwd = undefined, + clearEnv = false, + env = {}, + uid = undefined, + gid = undefined, + stdin = "null", + stdout = "piped", + stderr = "piped", + windowsRawArguments = false, +} = {}) { + if (stdin === "piped") { + throw new TypeError( + "Piped stdin is not supported for this function, use 'Deno.Command().spawn()' instead", + ); + } + const result = ops.op_spawn_sync({ + cmd: pathFromURL(command), + args: ArrayPrototypeMap(args, String), + cwd: pathFromURL(cwd), + clearEnv, + env: ObjectEntries(env), + uid, + gid, + stdin, + stdout, + stderr, + windowsRawArguments, + }); + return { + success: result.status.success, + code: result.status.code, + signal: result.status.signal, + get stdout() { + if (result.stdout == null) { + throw new TypeError("stdout is not piped"); + } + return result.stdout; + }, + get stderr() { + if (result.stderr == null) { + throw new TypeError("stderr is not piped"); + } + return result.stderr; + }, }; } -function createSpawnSync(opFn) { - return function spawnSync(command, { - args = [], - cwd = undefined, - clearEnv = false, - env = {}, - uid = undefined, - gid = undefined, - stdin = "null", - stdout = "piped", - stderr = "piped", - windowsRawArguments = false, - } = {}) { - if (stdin === "piped") { +class Command { + #command; + #options; + + constructor(command, options) { + this.#command = command; + this.#options = options; + } + + output() { + if (this.#options?.stdin === "piped") { throw new TypeError( - "Piped stdin is not supported for this function, use 'Deno.Command().spawn()' instead", + "Piped stdin is not supported for this function, use 'Deno.Command.spawn()' instead", ); } - const result = opFn({ - cmd: pathFromURL(command), - args: ArrayPrototypeMap(args, String), - cwd: pathFromURL(cwd), - clearEnv, - env: ObjectEntries(env), - uid, - gid, - stdin, - stdout, - stderr, - windowsRawArguments, - }); - return { - success: result.status.success, - code: result.status.code, - signal: result.status.signal, - get stdout() { - if (result.stdout == null) { - throw new TypeError("stdout is not piped"); - } - return result.stdout; - }, - get stderr() { - if (result.stderr == null) { - throw new TypeError("stderr is not piped"); - } - return result.stderr; - }, + return spawn(this.#command, this.#options); + } + + outputSync() { + if (this.#options?.stdin === "piped") { + throw new TypeError( + "Piped stdin is not supported for this function, use 'Deno.Command.spawn()' instead", + ); + } + return spawnSync(this.#command, this.#options); + } + + spawn() { + const options = { + ...(this.#options ?? {}), + stdout: this.#options?.stdout ?? "inherit", + stderr: this.#options?.stderr ?? "inherit", + stdin: this.#options?.stdin ?? "inherit", }; - }; + return spawnChild(this.#command, options); + } } -function createCommand(spawn, spawnSync, spawnChild) { - return class Command { - #command; - #options; - - constructor(command, options) { - this.#command = command; - this.#options = options; - } - - output() { - if (this.#options?.stdin === "piped") { - throw new TypeError( - "Piped stdin is not supported for this function, use 'Deno.Command.spawn()' instead", - ); - } - return spawn(this.#command, this.#options); - } - - outputSync() { - if (this.#options?.stdin === "piped") { - throw new TypeError( - "Piped stdin is not supported for this function, use 'Deno.Command.spawn()' instead", - ); - } - return spawnSync(this.#command, this.#options); - } - - spawn() { - const options = { - ...(this.#options ?? {}), - stdout: this.#options?.stdout ?? "inherit", - stderr: this.#options?.stderr ?? "inherit", - stdin: this.#options?.stdin ?? "inherit", - }; - return spawnChild(this.#command, options); - } - }; -} - -const ChildProcess = Child; - -export { - Child, - ChildProcess, - createCommand, - createSpawn, - createSpawnChild, - createSpawnSync, -}; +export { ChildProcess, Command }; diff --git a/runtime/js/90_deno_ns.js b/runtime/js/90_deno_ns.js index fe59ea1a79..7b9d8e6e60 100644 --- a/runtime/js/90_deno_ns.js +++ b/runtime/js/90_deno_ns.js @@ -152,6 +152,9 @@ const denoNs = { consoleSize: tty.consoleSize, gid: os.gid, uid: os.uid, + Command: spawn.Command, + // TODO(bartlomieju): why is this exported? + ChildProcess: spawn.ChildProcess, }; const denoNsUnstable = { @@ -171,9 +174,6 @@ const denoNsUnstable = { flockSync: fs.flockSync, funlock: fs.funlock, funlockSync: fs.funlockSync, - Child: spawn.Child, - ChildProcess: spawn.ChildProcess, - Command: spawn.Command, upgradeHttp: http.upgradeHttp, upgradeHttpRaw: flash.upgradeHttpRaw, }; diff --git a/runtime/js/99_main.js b/runtime/js/99_main.js index a4301ed3a4..cfddb143d9 100644 --- a/runtime/js/99_main.js +++ b/runtime/js/99_main.js @@ -62,7 +62,6 @@ import { errors } from "internal:runtime/js/01_errors.js"; import * as webidl from "internal:deno_webidl/00_webidl.js"; import DOMException from "internal:deno_web/01_dom_exception.js"; import * as flash from "internal:deno_flash/01_http.js"; -import * as spawn from "internal:runtime/js/40_spawn.js"; import { mainRuntimeGlobalProperties, setLanguage, @@ -466,15 +465,6 @@ function bootstrapMainRuntime(runtimeOptions) { // a snapshot ObjectAssign(internals, { nodeUnstable: { - Command: spawn.createCommand( - spawn.createSpawn(ops.op_node_unstable_spawn_child), - spawn.createSpawnSync( - ops.op_node_unstable_spawn_sync, - ), - spawn.createSpawnChild( - ops.op_node_unstable_spawn_child, - ), - ), serve: flash.createServe(ops.op_node_unstable_flash_serve), upgradeHttpRaw: flash.upgradeHttpRaw, listenDatagram: net.createListenDatagram( @@ -513,11 +503,6 @@ function bootstrapMainRuntime(runtimeOptions) { // the op function that needs to be passed will be invalidated by creating // a snapshot ObjectAssign(finalDenoNs, { - Command: spawn.createCommand( - spawn.createSpawn(ops.op_spawn_child), - spawn.createSpawnSync(ops.op_spawn_sync), - spawn.createSpawnChild(ops.op_spawn_child), - ), serve: flash.createServe(ops.op_flash_serve), listenDatagram: net.createListenDatagram( ops.op_net_listen_udp, @@ -611,15 +596,6 @@ function bootstrapWorkerRuntime( // a snapshot ObjectAssign(internals, { nodeUnstable: { - Command: spawn.createCommand( - spawn.createSpawn(ops.op_node_unstable_spawn_child), - spawn.createSpawnSync( - ops.op_node_unstable_spawn_sync, - ), - spawn.createSpawnChild( - ops.op_node_unstable_spawn_child, - ), - ), serve: flash.createServe(ops.op_node_unstable_flash_serve), upgradeHttpRaw: flash.upgradeHttpRaw, listenDatagram: net.createListenDatagram( @@ -650,11 +626,6 @@ function bootstrapWorkerRuntime( // the op function that needs to be passed will be invalidated by creating // a snapshot ObjectAssign(finalDenoNs, { - Command: spawn.createCommand( - spawn.createSpawn(ops.op_spawn_child), - spawn.createSpawnSync(ops.op_spawn_sync), - spawn.createSpawnChild(ops.op_spawn_child), - ), serve: flash.createServe(ops.op_flash_serve), listenDatagram: net.createListenDatagram( ops.op_net_listen_udp, diff --git a/runtime/ops/spawn.rs b/runtime/ops/spawn.rs index e5454371e2..089a53c238 100644 --- a/runtime/ops/spawn.rs +++ b/runtime/ops/spawn.rs @@ -31,10 +31,8 @@ pub fn init() -> Extension { Extension::builder("deno_spawn") .ops(vec![ op_spawn_child::decl(), - op_node_unstable_spawn_child::decl(), op_spawn_wait::decl(), op_spawn_sync::decl(), - op_node_unstable_spawn_sync::decl(), ]) .build() } @@ -125,75 +123,11 @@ pub struct SpawnOutput { stderr: Option, } -fn node_unstable_create_command( - state: &mut OpState, - args: SpawnArgs, - api_name: &str, -) -> Result { - state - .borrow_mut::() - .check_run(&args.cmd, api_name)?; - - let mut command = std::process::Command::new(args.cmd); - - #[cfg(windows)] - if args.windows_raw_arguments { - for arg in args.args.iter() { - command.raw_arg(arg); - } - } else { - command.args(args.args); - } - - #[cfg(not(windows))] - command.args(args.args); - - if let Some(cwd) = args.cwd { - command.current_dir(cwd); - } - - if args.clear_env { - command.env_clear(); - } - command.envs(args.env); - - #[cfg(unix)] - if let Some(gid) = args.gid { - command.gid(gid); - } - #[cfg(unix)] - if let Some(uid) = args.uid { - command.uid(uid); - } - #[cfg(unix)] - // TODO(bartlomieju): - #[allow(clippy::undocumented_unsafe_blocks)] - unsafe { - command.pre_exec(|| { - libc::setgroups(0, std::ptr::null()); - Ok(()) - }); - } - - command.stdin(args.stdio.stdin.as_stdio()); - command.stdout(match args.stdio.stdout { - Stdio::Inherit => StdioOrRid::Rid(1).as_stdio(state)?, - value => value.as_stdio(), - }); - command.stderr(match args.stdio.stderr { - Stdio::Inherit => StdioOrRid::Rid(2).as_stdio(state)?, - value => value.as_stdio(), - }); - - Ok(command) -} - fn create_command( state: &mut OpState, args: SpawnArgs, api_name: &str, ) -> Result { - super::check_unstable(state, "Deno.Command"); state .borrow_mut::() .check_run(&args.cmd, api_name)?; @@ -223,12 +157,10 @@ fn create_command( #[cfg(unix)] if let Some(gid) = args.gid { - super::check_unstable(state, "Deno.CommandOptions.gid"); command.gid(gid); } #[cfg(unix)] if let Some(uid) = args.uid { - super::check_unstable(state, "Deno.CommandOptions.uid"); command.uid(uid); } #[cfg(unix)] @@ -313,16 +245,6 @@ fn op_spawn_child( spawn_child(state, command) } -#[op] -fn op_node_unstable_spawn_child( - state: &mut OpState, - args: SpawnArgs, - api_name: String, -) -> Result { - let command = node_unstable_create_command(state, args, &api_name)?; - spawn_child(state, command) -} - #[op] async fn op_spawn_wait( state: Rc>, @@ -365,29 +287,3 @@ fn op_spawn_sync( }, }) } - -#[op] -fn op_node_unstable_spawn_sync( - state: &mut OpState, - args: SpawnArgs, -) -> Result { - let stdout = matches!(args.stdio.stdout, Stdio::Piped); - let stderr = matches!(args.stdio.stderr, Stdio::Piped); - let output = - node_unstable_create_command(state, args, "Deno.Command().outputSync()")? - .output()?; - - Ok(SpawnOutput { - status: output.status.try_into()?, - stdout: if stdout { - Some(output.stdout.into()) - } else { - None - }, - stderr: if stderr { - Some(output.stderr.into()) - } else { - None - }, - }) -}