mirror of
https://github.com/denoland/deno.git
synced 2025-01-11 16:42:21 -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:
parent
9e3d433249
commit
f917d2e2c1
7 changed files with 318 additions and 475 deletions
|
@ -29,15 +29,6 @@ const UNSTABLE_DENO_PROPS: &[&str] = &[
|
||||||
"removeSignalListener",
|
"removeSignalListener",
|
||||||
"shutdown",
|
"shutdown",
|
||||||
"umask",
|
"umask",
|
||||||
"Child",
|
|
||||||
"ChildProcess",
|
|
||||||
"ChildStatus",
|
|
||||||
"SpawnOutput",
|
|
||||||
"command",
|
|
||||||
"Command",
|
|
||||||
"CommandOptions",
|
|
||||||
"CommandStatus",
|
|
||||||
"CommandOutput",
|
|
||||||
"serve",
|
"serve",
|
||||||
"ServeInit",
|
"ServeInit",
|
||||||
"ServeTlsInit",
|
"ServeTlsInit",
|
||||||
|
|
212
cli/tsc/dts/lib.deno.ns.d.ts
vendored
212
cli/tsc/dts/lib.deno.ns.d.ts
vendored
|
@ -3958,6 +3958,218 @@ declare namespace Deno {
|
||||||
*/
|
*/
|
||||||
export function run<T extends RunOptions = RunOptions>(opt: T): Process<T>;
|
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 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}.
|
/** Option which can be specified when performing {@linkcode Deno.inspect}.
|
||||||
*
|
*
|
||||||
* @category Console and Debugging */
|
* @category Console and Debugging */
|
||||||
|
|
218
cli/tsc/dts/lib.deno.unstable.d.ts
vendored
218
cli/tsc/dts/lib.deno.unstable.d.ts
vendored
|
@ -1407,224 +1407,6 @@ declare namespace Deno {
|
||||||
*/
|
*/
|
||||||
export function upgradeHttpRaw(request: Request): [Deno.Conn, Uint8Array];
|
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 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.
|
/** **UNSTABLE**: New API, yet to be vetted.
|
||||||
*
|
*
|
||||||
* Returns the Operating System uptime in number of seconds.
|
* Returns the Operating System uptime in number of seconds.
|
||||||
|
|
|
@ -55,16 +55,19 @@ function spawnChildInner(opFn, command, apiName, {
|
||||||
stderr,
|
stderr,
|
||||||
windowsRawArguments,
|
windowsRawArguments,
|
||||||
}, apiName);
|
}, apiName);
|
||||||
return new Child(illegalConstructorKey, {
|
return new ChildProcess(illegalConstructorKey, {
|
||||||
...child,
|
...child,
|
||||||
signal,
|
signal,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function createSpawnChild(opFn) {
|
function spawnChild(command, options = {}) {
|
||||||
return function spawnChild(command, options = {}) {
|
return spawnChildInner(
|
||||||
return spawnChildInner(opFn, command, "Deno.Command().spawn()", options);
|
ops.op_spawn_child,
|
||||||
};
|
command,
|
||||||
|
"Deno.Command().spawn()",
|
||||||
|
options,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function collectOutput(readableStream) {
|
function collectOutput(readableStream) {
|
||||||
|
@ -77,7 +80,7 @@ function collectOutput(readableStream) {
|
||||||
return readableStreamCollectIntoUint8Array(readableStream);
|
return readableStreamCollectIntoUint8Array(readableStream);
|
||||||
}
|
}
|
||||||
|
|
||||||
class Child {
|
class ChildProcess {
|
||||||
#rid;
|
#rid;
|
||||||
#waitPromiseId;
|
#waitPromiseId;
|
||||||
#unrefed = false;
|
#unrefed = false;
|
||||||
|
@ -95,7 +98,6 @@ class Child {
|
||||||
return this.#stdin;
|
return this.#stdin;
|
||||||
}
|
}
|
||||||
|
|
||||||
#stdoutPromiseId;
|
|
||||||
#stdoutRid;
|
#stdoutRid;
|
||||||
#stdout = null;
|
#stdout = null;
|
||||||
get stdout() {
|
get stdout() {
|
||||||
|
@ -105,7 +107,6 @@ class Child {
|
||||||
return this.#stdout;
|
return this.#stdout;
|
||||||
}
|
}
|
||||||
|
|
||||||
#stderrPromiseId;
|
|
||||||
#stderrRid;
|
#stderrRid;
|
||||||
#stderr = null;
|
#stderr = null;
|
||||||
get stderr() {
|
get stderr() {
|
||||||
|
@ -220,116 +221,106 @@ class Child {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function createSpawn(opFn) {
|
function spawn(command, options) {
|
||||||
return function spawn(command, options) {
|
if (options?.stdin === "piped") {
|
||||||
if (options?.stdin === "piped") {
|
throw new TypeError(
|
||||||
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",
|
);
|
||||||
);
|
}
|
||||||
}
|
return spawnChildInner(
|
||||||
return spawnChildInner(opFn, command, "Deno.Command().output()", options)
|
ops.op_spawn_child,
|
||||||
.output();
|
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) {
|
class Command {
|
||||||
return function spawnSync(command, {
|
#command;
|
||||||
args = [],
|
#options;
|
||||||
cwd = undefined,
|
|
||||||
clearEnv = false,
|
constructor(command, options) {
|
||||||
env = {},
|
this.#command = command;
|
||||||
uid = undefined,
|
this.#options = options;
|
||||||
gid = undefined,
|
}
|
||||||
stdin = "null",
|
|
||||||
stdout = "piped",
|
output() {
|
||||||
stderr = "piped",
|
if (this.#options?.stdin === "piped") {
|
||||||
windowsRawArguments = false,
|
|
||||||
} = {}) {
|
|
||||||
if (stdin === "piped") {
|
|
||||||
throw new TypeError(
|
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({
|
return spawn(this.#command, this.#options);
|
||||||
cmd: pathFromURL(command),
|
}
|
||||||
args: ArrayPrototypeMap(args, String),
|
|
||||||
cwd: pathFromURL(cwd),
|
outputSync() {
|
||||||
clearEnv,
|
if (this.#options?.stdin === "piped") {
|
||||||
env: ObjectEntries(env),
|
throw new TypeError(
|
||||||
uid,
|
"Piped stdin is not supported for this function, use 'Deno.Command.spawn()' instead",
|
||||||
gid,
|
);
|
||||||
stdin,
|
}
|
||||||
stdout,
|
return spawnSync(this.#command, this.#options);
|
||||||
stderr,
|
}
|
||||||
windowsRawArguments,
|
|
||||||
});
|
spawn() {
|
||||||
return {
|
const options = {
|
||||||
success: result.status.success,
|
...(this.#options ?? {}),
|
||||||
code: result.status.code,
|
stdout: this.#options?.stdout ?? "inherit",
|
||||||
signal: result.status.signal,
|
stderr: this.#options?.stderr ?? "inherit",
|
||||||
get stdout() {
|
stdin: this.#options?.stdin ?? "inherit",
|
||||||
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 spawnChild(this.#command, options);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function createCommand(spawn, spawnSync, spawnChild) {
|
export { ChildProcess, Command };
|
||||||
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,
|
|
||||||
};
|
|
||||||
|
|
|
@ -152,6 +152,9 @@ const denoNs = {
|
||||||
consoleSize: tty.consoleSize,
|
consoleSize: tty.consoleSize,
|
||||||
gid: os.gid,
|
gid: os.gid,
|
||||||
uid: os.uid,
|
uid: os.uid,
|
||||||
|
Command: spawn.Command,
|
||||||
|
// TODO(bartlomieju): why is this exported?
|
||||||
|
ChildProcess: spawn.ChildProcess,
|
||||||
};
|
};
|
||||||
|
|
||||||
const denoNsUnstable = {
|
const denoNsUnstable = {
|
||||||
|
@ -171,9 +174,6 @@ const denoNsUnstable = {
|
||||||
flockSync: fs.flockSync,
|
flockSync: fs.flockSync,
|
||||||
funlock: fs.funlock,
|
funlock: fs.funlock,
|
||||||
funlockSync: fs.funlockSync,
|
funlockSync: fs.funlockSync,
|
||||||
Child: spawn.Child,
|
|
||||||
ChildProcess: spawn.ChildProcess,
|
|
||||||
Command: spawn.Command,
|
|
||||||
upgradeHttp: http.upgradeHttp,
|
upgradeHttp: http.upgradeHttp,
|
||||||
upgradeHttpRaw: flash.upgradeHttpRaw,
|
upgradeHttpRaw: flash.upgradeHttpRaw,
|
||||||
};
|
};
|
||||||
|
|
|
@ -62,7 +62,6 @@ import { errors } from "internal:runtime/js/01_errors.js";
|
||||||
import * as webidl from "internal:deno_webidl/00_webidl.js";
|
import * as webidl from "internal:deno_webidl/00_webidl.js";
|
||||||
import DOMException from "internal:deno_web/01_dom_exception.js";
|
import DOMException from "internal:deno_web/01_dom_exception.js";
|
||||||
import * as flash from "internal:deno_flash/01_http.js";
|
import * as flash from "internal:deno_flash/01_http.js";
|
||||||
import * as spawn from "internal:runtime/js/40_spawn.js";
|
|
||||||
import {
|
import {
|
||||||
mainRuntimeGlobalProperties,
|
mainRuntimeGlobalProperties,
|
||||||
setLanguage,
|
setLanguage,
|
||||||
|
@ -466,15 +465,6 @@ function bootstrapMainRuntime(runtimeOptions) {
|
||||||
// a snapshot
|
// a snapshot
|
||||||
ObjectAssign(internals, {
|
ObjectAssign(internals, {
|
||||||
nodeUnstable: {
|
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),
|
serve: flash.createServe(ops.op_node_unstable_flash_serve),
|
||||||
upgradeHttpRaw: flash.upgradeHttpRaw,
|
upgradeHttpRaw: flash.upgradeHttpRaw,
|
||||||
listenDatagram: net.createListenDatagram(
|
listenDatagram: net.createListenDatagram(
|
||||||
|
@ -513,11 +503,6 @@ function bootstrapMainRuntime(runtimeOptions) {
|
||||||
// the op function that needs to be passed will be invalidated by creating
|
// the op function that needs to be passed will be invalidated by creating
|
||||||
// a snapshot
|
// a snapshot
|
||||||
ObjectAssign(finalDenoNs, {
|
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),
|
serve: flash.createServe(ops.op_flash_serve),
|
||||||
listenDatagram: net.createListenDatagram(
|
listenDatagram: net.createListenDatagram(
|
||||||
ops.op_net_listen_udp,
|
ops.op_net_listen_udp,
|
||||||
|
@ -611,15 +596,6 @@ function bootstrapWorkerRuntime(
|
||||||
// a snapshot
|
// a snapshot
|
||||||
ObjectAssign(internals, {
|
ObjectAssign(internals, {
|
||||||
nodeUnstable: {
|
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),
|
serve: flash.createServe(ops.op_node_unstable_flash_serve),
|
||||||
upgradeHttpRaw: flash.upgradeHttpRaw,
|
upgradeHttpRaw: flash.upgradeHttpRaw,
|
||||||
listenDatagram: net.createListenDatagram(
|
listenDatagram: net.createListenDatagram(
|
||||||
|
@ -650,11 +626,6 @@ function bootstrapWorkerRuntime(
|
||||||
// the op function that needs to be passed will be invalidated by creating
|
// the op function that needs to be passed will be invalidated by creating
|
||||||
// a snapshot
|
// a snapshot
|
||||||
ObjectAssign(finalDenoNs, {
|
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),
|
serve: flash.createServe(ops.op_flash_serve),
|
||||||
listenDatagram: net.createListenDatagram(
|
listenDatagram: net.createListenDatagram(
|
||||||
ops.op_net_listen_udp,
|
ops.op_net_listen_udp,
|
||||||
|
|
|
@ -31,10 +31,8 @@ pub fn init() -> Extension {
|
||||||
Extension::builder("deno_spawn")
|
Extension::builder("deno_spawn")
|
||||||
.ops(vec![
|
.ops(vec![
|
||||||
op_spawn_child::decl(),
|
op_spawn_child::decl(),
|
||||||
op_node_unstable_spawn_child::decl(),
|
|
||||||
op_spawn_wait::decl(),
|
op_spawn_wait::decl(),
|
||||||
op_spawn_sync::decl(),
|
op_spawn_sync::decl(),
|
||||||
op_node_unstable_spawn_sync::decl(),
|
|
||||||
])
|
])
|
||||||
.build()
|
.build()
|
||||||
}
|
}
|
||||||
|
@ -125,75 +123,11 @@ pub struct SpawnOutput {
|
||||||
stderr: Option<ZeroCopyBuf>,
|
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(
|
fn create_command(
|
||||||
state: &mut OpState,
|
state: &mut OpState,
|
||||||
args: SpawnArgs,
|
args: SpawnArgs,
|
||||||
api_name: &str,
|
api_name: &str,
|
||||||
) -> Result<std::process::Command, AnyError> {
|
) -> Result<std::process::Command, AnyError> {
|
||||||
super::check_unstable(state, "Deno.Command");
|
|
||||||
state
|
state
|
||||||
.borrow_mut::<PermissionsContainer>()
|
.borrow_mut::<PermissionsContainer>()
|
||||||
.check_run(&args.cmd, api_name)?;
|
.check_run(&args.cmd, api_name)?;
|
||||||
|
@ -223,12 +157,10 @@ fn create_command(
|
||||||
|
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
if let Some(gid) = args.gid {
|
if let Some(gid) = args.gid {
|
||||||
super::check_unstable(state, "Deno.CommandOptions.gid");
|
|
||||||
command.gid(gid);
|
command.gid(gid);
|
||||||
}
|
}
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
if let Some(uid) = args.uid {
|
if let Some(uid) = args.uid {
|
||||||
super::check_unstable(state, "Deno.CommandOptions.uid");
|
|
||||||
command.uid(uid);
|
command.uid(uid);
|
||||||
}
|
}
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
|
@ -313,16 +245,6 @@ fn op_spawn_child(
|
||||||
spawn_child(state, command)
|
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]
|
#[op]
|
||||||
async fn op_spawn_wait(
|
async fn op_spawn_wait(
|
||||||
state: Rc<RefCell<OpState>>,
|
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
|
|
||||||
},
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
Loading…
Reference in a new issue