diff options
Diffstat (limited to 'packages/create-astro/src/shell.ts')
-rw-r--r-- | packages/create-astro/src/shell.ts | 51 |
1 files changed, 51 insertions, 0 deletions
diff --git a/packages/create-astro/src/shell.ts b/packages/create-astro/src/shell.ts new file mode 100644 index 000000000..7c3e22622 --- /dev/null +++ b/packages/create-astro/src/shell.ts @@ -0,0 +1,51 @@ +// This is an extremely simplified version of [`execa`](https://github.com/sindresorhus/execa) +// intended to keep our dependency size down +import type { ChildProcess, StdioOptions } from 'node:child_process'; +import type { Readable } from 'node:stream'; + +import { spawn } from 'node:child_process'; +import { text as textFromStream } from 'node:stream/consumers'; + +export interface ExecaOptions { + cwd?: string | URL; + stdio?: StdioOptions; + timeout?: number; +} +export interface Output { + stdout: string; + stderr: string; + exitCode: number; +} +const text = (stream: NodeJS.ReadableStream | Readable | null) => + stream ? textFromStream(stream).then((t) => t.trimEnd()) : ''; + +export async function shell( + command: string, + flags: string[], + opts: ExecaOptions = {}, +): Promise<Output> { + let child: ChildProcess; + let stdout = ''; + let stderr = ''; + try { + child = spawn(command, flags, { + cwd: opts.cwd, + shell: true, + stdio: opts.stdio, + timeout: opts.timeout, + }); + const done = new Promise((resolve) => child.on('close', resolve)); + [stdout, stderr] = await Promise.all([text(child.stdout), text(child.stderr)]); + await done; + } catch { + throw { stdout, stderr, exitCode: 1 }; + } + const { exitCode } = child; + if (exitCode === null) { + throw new Error('Timeout'); + } + if (exitCode !== 0) { + throw new Error(stderr); + } + return { stdout, stderr, exitCode }; +} |