1
0
Fork 0
mirror of https://github.com/denoland/deno.git synced 2024-12-24 08:09:08 -05:00

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.
This commit is contained in:
Bartek Iwańczuk 2023-02-13 19:25:00 +01:00 committed by GitHub
parent 9e3d433249
commit f917d2e2c1
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 318 additions and 475 deletions

View file

@ -29,15 +29,6 @@ const UNSTABLE_DENO_PROPS: &[&str] = &[
"removeSignalListener",
"shutdown",
"umask",
"Child",
"ChildProcess",
"ChildStatus",
"SpawnOutput",
"command",
"Command",
"CommandOptions",
"CommandStatus",
"CommandOutput",
"serve",
"ServeInit",
"ServeTlsInit",

View file

@ -3958,6 +3958,218 @@ declare namespace Deno {
*/
export function run<T extends RunOptions = RunOptions>(opt: T): Process<T>;
/** 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<CommandOutput>;
/**
* 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<Uint8Array>;
get stdout(): ReadableStream<Uint8Array>;
get stderr(): ReadableStream<Uint8Array>;
readonly pid: number;
/** Get the status of the child. */
readonly status: Promise<CommandStatus>;
/** Waits for the child to exit completely, returning all its output and
* status. */
output(): Promise<CommandOutput>;
/** 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<string, string>;
/**
* Sets the child processs 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 */

View file

@ -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<CommandOutput>;
/**
* 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<Uint8Array>;
get stdout(): ReadableStream<Uint8Array>;
get stderr(): ReadableStream<Uint8Array>;
readonly pid: number;
/** Get the status of the child. */
readonly status: Promise<CommandStatus>;
/** Waits for the child to exit completely, returning all its output and
* status. */
output(): Promise<CommandOutput>;
/** 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<string, string>;
/**
* Sets the child processs 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.

View file

@ -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 };

View file

@ -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,
};

View file

@ -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,

View file

@ -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<ZeroCopyBuf>,
}
fn node_unstable_create_command(
state: &mut OpState,
args: SpawnArgs,
api_name: &str,
) -> Result<std::process::Command, AnyError> {
state
.borrow_mut::<PermissionsContainer>()
.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<std::process::Command, AnyError> {
super::check_unstable(state, "Deno.Command");
state
.borrow_mut::<PermissionsContainer>()
.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<Child, AnyError> {
let command = node_unstable_create_command(state, args, &api_name)?;
spawn_child(state, command)
}
#[op]
async fn op_spawn_wait(
state: Rc<RefCell<OpState>>,
@ -365,29 +287,3 @@ fn op_spawn_sync(
},
})
}
#[op]
fn op_node_unstable_spawn_sync(
state: &mut OpState,
args: SpawnArgs,
) -> Result<SpawnOutput, AnyError> {
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
},
})
}