-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathdeno.ts
132 lines (119 loc) Β· 3.6 KB
/
deno.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
// Bazx implementation for Deno.
/// <reference path="./deno.d.ts" />
export * from './mod.ts'
import type { BazxExec, BazxOptions } from './mod.ts';
import { createBazx } from './mod.ts';
function streamCopyToStream(reader: Deno.Reader & Deno.Closer) {
const buffer = new Uint8Array(16_640);
return new ReadableStream<Uint8Array>({
async pull(controller) {
let read;
try {
while (controller.desiredSize! > 0) {
if ((read = await reader.read(buffer.subarray(0, Math.min(buffer.byteLength, controller.desiredSize ?? Number.MAX_VALUE)))) === null) {
reader.close();
controller.close();
return;
}
controller.enqueue(buffer.slice(0, read));
}
} catch (err) {
if (!(err instanceof Deno.errors.BadResource))
controller.error(err);
else
controller.close();
}
},
cancel() {
reader.close();
}
}, new ByteLengthQueuingStrategy({
highWaterMark: 16640
}));
}
async function pipeReadableStream2Writer(
readable: ReadableStream<Uint8Array>,
writer: Deno.Writer & Deno.Closer
) {
const reader = readable.getReader();
try {
let read: ReadableStreamReadResult<Uint8Array>;
while (!(read = await reader.read()).done)
if (!await writer.write(read.value!))
break;
await reader.cancel();
} catch (err) {
if (err instanceof Deno.errors.BrokenPipe)
await reader.releaseLock();
else
await reader.cancel(err);
} finally {
try {
writer.close();
} catch (ignored) { }
}
}
export const exec: BazxExec = async function exec(cmd, {
cwd,
env,
stdin,
stdout,
stderr,
signal
} = {}) {
const process = Deno.run({
cmd,
cwd,
env,
stdin: stdin ? 'piped' : 'null',
stdout: stdout ? 'piped' : 'null',
stderr: stderr ? 'piped' : 'null',
});
signal?.addEventListener('abort', () => process.kill?.(9), { once: true });
try {
const [{ code, signal: exitSignal }] = await Promise.all([
process.status(),
stdin && pipeReadableStream2Writer(stdin, process.stdin!),
stdout && streamCopyToStream(process.stdout!).pipeTo(stdout),
stderr && streamCopyToStream(process.stderr!).pipeTo(stderr),
]);
return { code, signal: exitSignal };
} finally {
process.close();
}
}
export const options: BazxOptions = {
highWaterMark: 16640,
noColors: Deno.noColor,
log: chunk => Deno.stdout.writeSync(chunk)
};
export const $ = createBazx(exec, options);
export default $;
Deno.test({
name: 'everything works',
async fn() {
// @ts-ignore
const assert: (expr: unknown, msg: string) => asserts expr = (await import("https://deno.land/std/testing/asserts.ts")).assert;
// @ts-ignore
const { fail, assertEquals } = await import("https://deno.land/std/testing/asserts.ts");
const cmd = $`bash -c ${'echo Hello world! $(env | grep WTF) $(pwd)'}`
.cwd('/bin')
.pipe(new TransformStream({
start(controller) {
controller.enqueue(new TextEncoder().encode('Someone said: '));
}
}))
.env('WTF', 'it works')
.pipe($`sh -c ${'cat - $(realpath $(env | grep WTF))'}`)
.env('WTF', 'not_found')
.cwd('/');
try {
await cmd.text();
fail("Should have thrown since cat should have failed");
} catch (err) {
assertEquals(`Command ${cmd.command} exited with code 1`, err.message);
assert(err.response instanceof Response, "err.response is defined and is an instance of Response");
assertEquals('Someone said: Hello world! WTF=it works /bin\n', await err.response.text());
}
}
});