summaryrefslogtreecommitdiff
path: root/packages/create-astro/src/shell.ts
diff options
context:
space:
mode:
authorGravatar Emanuele Stoppa <my.burning@gmail.com> 2023-08-15 09:24:06 +0100
committerGravatar Emanuele Stoppa <my.burning@gmail.com> 2023-08-15 09:24:06 +0100
commit7530d5689db67eb77d2dce0db0e13d25b3d13063 (patch)
tree0f33f492b25ace9dd7ca2cfc5de4fec311f9be14 /packages/create-astro/src/shell.ts
parent68efd4a8b29f248397667801465b3152dc98e9a7 (diff)
parentc19987df0be3520cf774476cea270c03edd08354 (diff)
downloadastro-7530d5689db67eb77d2dce0db0e13d25b3d13063.tar.gz
astro-7530d5689db67eb77d2dce0db0e13d25b3d13063.tar.zst
astro-7530d5689db67eb77d2dce0db0e13d25b3d13063.zip
Merge remote-tracking branch 'origin/main' into next
Diffstat (limited to 'packages/create-astro/src/shell.ts')
-rw-r--r--packages/create-astro/src/shell.ts49
1 files changed, 49 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..d2d7ef033
--- /dev/null
+++ b/packages/create-astro/src/shell.ts
@@ -0,0 +1,49 @@
+// This is an extremely simplified version of [`execa`](https://github.com/sindresorhus/execa)
+// intended to keep our dependency size down
+import type { 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';
+import { setTimeout as sleep } from 'node:timers/promises';
+
+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> {
+ const controller = opts.timeout ? new AbortController() : undefined;
+ const child = spawn(command, flags, {
+ cwd: opts.cwd,
+ shell: true,
+ stdio: opts.stdio,
+ signal: controller?.signal,
+ });
+ const stdout = await text(child.stdout);
+ const stderr = await text(child.stderr);
+ if (opts.timeout) {
+ sleep(opts.timeout).then(() => {
+ controller!.abort();
+ throw { stdout, stderr, exitCode: 1 };
+ });
+ }
+ await new Promise((resolve) => child.on('exit', resolve));
+ const { exitCode } = child;
+ if (exitCode !== 0) {
+ throw { stdout, stderr, exitCode };
+ }
+ return { stdout, stderr, exitCode };
+}