summaryrefslogtreecommitdiff
path: root/runtime/js/40_spawn.js
diff options
context:
space:
mode:
Diffstat (limited to 'runtime/js/40_spawn.js')
-rw-r--r--runtime/js/40_spawn.js584
1 files changed, 293 insertions, 291 deletions
diff --git a/runtime/js/40_spawn.js b/runtime/js/40_spawn.js
index ecbab52ad..dfccec5d7 100644
--- a/runtime/js/40_spawn.js
+++ b/runtime/js/40_spawn.js
@@ -1,333 +1,335 @@
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
-"use strict";
-
-((window) => {
- const core = window.Deno.core;
- const ops = core.ops;
- const { pathFromURL } = window.__bootstrap.util;
- const { illegalConstructorKey } = window.__bootstrap.webUtil;
- const { add, remove } = window.__bootstrap.abortSignal;
- const {
- ArrayPrototypeMap,
- ObjectEntries,
- ObjectPrototypeIsPrototypeOf,
- String,
- TypeError,
- PromisePrototypeThen,
- SafePromiseAll,
- SymbolFor,
- } = window.__bootstrap.primordials;
- const {
- readableStreamCollectIntoUint8Array,
- readableStreamForRidUnrefable,
- readableStreamForRidUnrefableRef,
- readableStreamForRidUnrefableUnref,
- ReadableStreamPrototype,
- writableStreamForRid,
- } = window.__bootstrap.streams;
-
- const promiseIdSymbol = SymbolFor("Deno.core.internalPromiseId");
-
- function spawnChildInner(opFn, command, apiName, {
- args = [],
- cwd = undefined,
- clearEnv = false,
- env = {},
- uid = undefined,
- gid = undefined,
- stdin = "null",
- stdout = "piped",
- stderr = "piped",
- signal = undefined,
- windowsRawArguments = false,
- } = {}) {
- const child = opFn({
- cmd: pathFromURL(command),
- args: ArrayPrototypeMap(args, String),
- cwd: pathFromURL(cwd),
- clearEnv,
- env: ObjectEntries(env),
- uid,
- gid,
- stdin,
- stdout,
- stderr,
- windowsRawArguments,
- }, apiName);
- return new Child(illegalConstructorKey, {
- ...child,
- signal,
- });
- }
- function createSpawnChild(opFn) {
- return function spawnChild(command, options = {}) {
- return spawnChildInner(opFn, command, "Deno.Command().spawn()", options);
- };
+const core = globalThis.Deno.core;
+const ops = core.ops;
+const primordials = globalThis.__bootstrap.primordials;
+import { pathFromURL } from "internal:runtime/js/06_util.js";
+import { add, remove } from "internal:ext/web/03_abort_signal.js";
+const {
+ ArrayPrototypeMap,
+ ObjectEntries,
+ ObjectPrototypeIsPrototypeOf,
+ String,
+ TypeError,
+ PromisePrototypeThen,
+ SafePromiseAll,
+ SymbolFor,
+ Symbol,
+} = primordials;
+import {
+ readableStreamCollectIntoUint8Array,
+ readableStreamForRidUnrefable,
+ readableStreamForRidUnrefableRef,
+ readableStreamForRidUnrefableUnref,
+ ReadableStreamPrototype,
+ writableStreamForRid,
+} from "internal:ext/web/06_streams.js";
+
+const illegalConstructorKey = Symbol("illegalConstructorKey");
+
+const promiseIdSymbol = SymbolFor("Deno.core.internalPromiseId");
+
+function spawnChildInner(opFn, command, apiName, {
+ args = [],
+ cwd = undefined,
+ clearEnv = false,
+ env = {},
+ uid = undefined,
+ gid = undefined,
+ stdin = "null",
+ stdout = "piped",
+ stderr = "piped",
+ signal = undefined,
+ windowsRawArguments = false,
+} = {}) {
+ const child = opFn({
+ cmd: pathFromURL(command),
+ args: ArrayPrototypeMap(args, String),
+ cwd: pathFromURL(cwd),
+ clearEnv,
+ env: ObjectEntries(env),
+ uid,
+ gid,
+ stdin,
+ stdout,
+ stderr,
+ windowsRawArguments,
+ }, apiName);
+ return new Child(illegalConstructorKey, {
+ ...child,
+ signal,
+ });
+}
+
+function createSpawnChild(opFn) {
+ return function spawnChild(command, options = {}) {
+ return spawnChildInner(opFn, command, "Deno.Command().spawn()", options);
+ };
+}
+
+function collectOutput(readableStream) {
+ if (
+ !(ObjectPrototypeIsPrototypeOf(ReadableStreamPrototype, readableStream))
+ ) {
+ return null;
}
- function collectOutput(readableStream) {
- if (
- !(ObjectPrototypeIsPrototypeOf(ReadableStreamPrototype, readableStream))
- ) {
- return null;
- }
+ return readableStreamCollectIntoUint8Array(readableStream);
+}
- return readableStreamCollectIntoUint8Array(readableStream);
- }
+class Child {
+ #rid;
+ #waitPromiseId;
+ #unrefed = false;
- class Child {
- #rid;
- #waitPromiseId;
- #unrefed = false;
+ #pid;
+ get pid() {
+ return this.#pid;
+ }
- #pid;
- get pid() {
- return this.#pid;
+ #stdin = null;
+ get stdin() {
+ if (this.#stdin == null) {
+ throw new TypeError("stdin is not piped");
}
+ return this.#stdin;
+ }
- #stdin = null;
- get stdin() {
- if (this.#stdin == null) {
- throw new TypeError("stdin is not piped");
- }
- return this.#stdin;
+ #stdoutPromiseId;
+ #stdoutRid;
+ #stdout = null;
+ get stdout() {
+ if (this.#stdout == null) {
+ throw new TypeError("stdout is not piped");
}
+ return this.#stdout;
+ }
- #stdoutPromiseId;
- #stdoutRid;
- #stdout = null;
- get stdout() {
- if (this.#stdout == null) {
- throw new TypeError("stdout is not piped");
- }
- return this.#stdout;
+ #stderrPromiseId;
+ #stderrRid;
+ #stderr = null;
+ get stderr() {
+ if (this.#stderr == null) {
+ throw new TypeError("stderr is not piped");
}
+ return this.#stderr;
+ }
- #stderrPromiseId;
- #stderrRid;
- #stderr = null;
- get stderr() {
- if (this.#stderr == null) {
- throw new TypeError("stderr is not piped");
- }
- return this.#stderr;
+ constructor(key = null, {
+ signal,
+ rid,
+ pid,
+ stdinRid,
+ stdoutRid,
+ stderrRid,
+ } = null) {
+ if (key !== illegalConstructorKey) {
+ throw new TypeError("Illegal constructor.");
}
- constructor(key = null, {
- signal,
- rid,
- pid,
- stdinRid,
- stdoutRid,
- stderrRid,
- } = null) {
- if (key !== illegalConstructorKey) {
- throw new TypeError("Illegal constructor.");
- }
+ this.#rid = rid;
+ this.#pid = pid;
- this.#rid = rid;
- this.#pid = pid;
+ if (stdinRid !== null) {
+ this.#stdin = writableStreamForRid(stdinRid);
+ }
- if (stdinRid !== null) {
- this.#stdin = writableStreamForRid(stdinRid);
- }
+ if (stdoutRid !== null) {
+ this.#stdoutRid = stdoutRid;
+ this.#stdout = readableStreamForRidUnrefable(stdoutRid);
+ }
- if (stdoutRid !== null) {
- this.#stdoutRid = stdoutRid;
- this.#stdout = readableStreamForRidUnrefable(stdoutRid);
- }
+ if (stderrRid !== null) {
+ this.#stderrRid = stderrRid;
+ this.#stderr = readableStreamForRidUnrefable(stderrRid);
+ }
- if (stderrRid !== null) {
- this.#stderrRid = stderrRid;
- this.#stderr = readableStreamForRidUnrefable(stderrRid);
- }
+ const onAbort = () => this.kill("SIGTERM");
+ signal?.[add](onAbort);
- const onAbort = () => this.kill("SIGTERM");
- signal?.[add](onAbort);
+ const waitPromise = core.opAsync("op_spawn_wait", this.#rid);
+ this.#waitPromiseId = waitPromise[promiseIdSymbol];
+ this.#status = PromisePrototypeThen(waitPromise, (res) => {
+ this.#rid = null;
+ signal?.[remove](onAbort);
+ return res;
+ });
+ }
- const waitPromise = core.opAsync("op_spawn_wait", this.#rid);
- this.#waitPromiseId = waitPromise[promiseIdSymbol];
- this.#status = PromisePrototypeThen(waitPromise, (res) => {
- this.#rid = null;
- signal?.[remove](onAbort);
- return res;
- });
- }
+ #status;
+ get status() {
+ return this.#status;
+ }
- #status;
- get status() {
- return this.#status;
+ async output() {
+ if (this.#stdout?.locked) {
+ throw new TypeError(
+ "Can't collect output because stdout is locked",
+ );
+ }
+ if (this.#stderr?.locked) {
+ throw new TypeError(
+ "Can't collect output because stderr is locked",
+ );
}
- async output() {
- if (this.#stdout?.locked) {
- throw new TypeError(
- "Can't collect output because stdout is locked",
- );
- }
- if (this.#stderr?.locked) {
- throw new TypeError(
- "Can't collect output because stderr is locked",
- );
- }
+ const { 0: status, 1: stdout, 2: stderr } = await SafePromiseAll([
+ this.#status,
+ collectOutput(this.#stdout),
+ collectOutput(this.#stderr),
+ ]);
+
+ return {
+ success: status.success,
+ code: status.code,
+ signal: status.signal,
+ get stdout() {
+ if (stdout == null) {
+ throw new TypeError("stdout is not piped");
+ }
+ return stdout;
+ },
+ get stderr() {
+ if (stderr == null) {
+ throw new TypeError("stderr is not piped");
+ }
+ return stderr;
+ },
+ };
+ }
- const { 0: status, 1: stdout, 2: stderr } = await SafePromiseAll([
- this.#status,
- collectOutput(this.#stdout),
- collectOutput(this.#stderr),
- ]);
-
- return {
- success: status.success,
- code: status.code,
- signal: status.signal,
- get stdout() {
- if (stdout == null) {
- throw new TypeError("stdout is not piped");
- }
- return stdout;
- },
- get stderr() {
- if (stderr == null) {
- throw new TypeError("stderr is not piped");
- }
- return stderr;
- },
- };
+ kill(signo = "SIGTERM") {
+ if (this.#rid === null) {
+ throw new TypeError("Child process has already terminated.");
}
+ ops.op_kill(this.#pid, signo, "Deno.Child.kill()");
+ }
- kill(signo = "SIGTERM") {
- if (this.#rid === null) {
- throw new TypeError("Child process has already terminated.");
- }
- ops.op_kill(this.#pid, signo, "Deno.Child.kill()");
+ ref() {
+ this.#unrefed = false;
+ core.refOp(this.#waitPromiseId);
+ if (this.#stdout) readableStreamForRidUnrefableRef(this.#stdout);
+ if (this.#stderr) readableStreamForRidUnrefableRef(this.#stderr);
+ }
+
+ unref() {
+ this.#unrefed = true;
+ core.unrefOp(this.#waitPromiseId);
+ if (this.#stdout) readableStreamForRidUnrefableUnref(this.#stdout);
+ if (this.#stderr) readableStreamForRidUnrefableUnref(this.#stderr);
+ }
+}
+
+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();
+ };
+}
- ref() {
- this.#unrefed = false;
- core.refOp(this.#waitPromiseId);
- if (this.#stdout) readableStreamForRidUnrefableRef(this.#stdout);
- if (this.#stderr) readableStreamForRidUnrefableRef(this.#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") {
+ throw new TypeError(
+ "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;
+ },
+ };
+ };
+}
+
+function createCommand(spawn, spawnSync, spawnChild) {
+ return class Command {
+ #command;
+ #options;
- unref() {
- this.#unrefed = true;
- core.unrefOp(this.#waitPromiseId);
- if (this.#stdout) readableStreamForRidUnrefableUnref(this.#stdout);
- if (this.#stderr) readableStreamForRidUnrefableUnref(this.#stderr);
+ constructor(command, options) {
+ this.#command = command;
+ this.#options = options;
}
- }
- function createSpawn(opFn) {
- return function spawn(command, options) {
- if (options?.stdin === "piped") {
+ 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",
);
}
- return spawnChildInner(opFn, command, "Deno.Command().output()", options)
- .output();
- };
- }
+ return spawn(this.#command, this.#options);
+ }
- 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") {
+ outputSync() {
+ 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;
- },
- };
- };
- }
-
- 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);
- }
- };
- }
+ return spawnSync(this.#command, this.#options);
+ }
- window.__bootstrap.spawn = {
- Child,
- ChildProcess: Child,
- createCommand,
- createSpawn,
- createSpawnChild,
- createSpawnSync,
+ 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);
+ }
};
-})(this);
+}
+
+const ChildProcess = Child;
+
+export {
+ Child,
+ ChildProcess,
+ createCommand,
+ createSpawn,
+ createSpawnChild,
+ createSpawnSync,
+};