forked from yukino-org/kazahana-v3
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathspawn.ts
102 lines (83 loc) · 2.51 KB
/
spawn.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
import { StdioOptions } from "child_process";
import { spawn as crossSpawn } from "cross-spawn";
export class SpawnResult {
constructor(
public readonly command: string,
public readonly code: number | null,
public readonly stdout: string,
public readonly stderr: string
) { }
}
export class SpawnError extends Error {
constructor(
public readonly result: SpawnResult,
public readonly err?: Error
) {
super();
if (err) {
Object.assign(this, err);
}
this.message = `Spawn failed with code ${result.code}\nCommand: ${result.command || "-"
}\nOutput: ${result.stdout || "-"}\nError: ${err || "-"}`;
}
}
export interface SpawnOptions {
cwd: string;
stdio?: StdioOptions;
env?: Record<string, string | undefined>;
}
export const spawn = async (
cmd: string,
args: string[],
{ cwd, stdio, env }: SpawnOptions
) =>
new Promise<SpawnResult>(async (resolve, reject) => {
if (!env) {
env = { ...process.env };
}
if (isVerbose()) {
stdio = "inherit";
env.verbose = "true";
}
const cp = crossSpawn(cmd, args, {
stdio,
env,
cwd,
});
let stdout = "";
let stderr = "";
const getResult = (code: number | null) =>
new SpawnResult(cp.spawnargs.join(" "), code, stdout, stderr);
const getError = (code: number | null, err?: Error) =>
new SpawnError(getResult(code), err);
cp.stdout?.on("data", (data) => {
stdout += data.toString();
});
cp.stdout?.on("data", (data) => {
stderr += data.toString();
});
cp.once("close", (code) => {
if (code === 0) {
resolve(getResult(code));
} else {
reject(getError(code));
}
});
});
export const defaultArgs = {
verbose: ["--verbose", "-v"],
force: ["--force", "-f"],
};
export const getArgsInfo = () => ({
args: getArgs(),
verbose: isVerbose(),
force: isForce(),
});
export const isVerbose = () =>
process.env.verbose === "true" || process.argv.slice(2).some((x) => defaultArgs.verbose.includes(x));
export const isForce = () =>
process.argv.slice(2).some((x) => defaultArgs.force.includes(x));
export const getArgs = () =>
process.argv
.slice(2)
.filter((x) => !Object.values(defaultArgs).flat().includes(x));