1 | import { exec as cpExec, spawn as cpSpawn } from "child_process";
|
2 | import { lstatSync, readdirSync } from "fs";
|
3 | import { lstat, readdir } from "fs/promises";
|
4 | import { join } from "path";
|
5 | import { pipeline } from "stream";
|
6 | import { promisify } from "util";
|
7 |
|
8 | const internalExec = promisify(cpExec);
|
9 | const internalPipeline = promisify(pipeline);
|
10 |
|
11 | export { join as pathJoin };
|
12 |
|
13 |
|
14 |
|
15 |
|
16 |
|
17 |
|
18 |
|
19 | export async function exec(command, opts = {}) {
|
20 | try {
|
21 | const promise = internalExec(command, { encoding: "utf8", ...opts });
|
22 | const { stdout, stderr } = await promise;
|
23 |
|
24 | return {
|
25 | stdout,
|
26 | stderr,
|
27 | exitCode: promise.child.exitCode ?? 0,
|
28 | };
|
29 | } catch (e) {
|
30 | return {
|
31 | stdout: e.stdout ?? "",
|
32 | stderr: e.stderr ?? "",
|
33 | exitCode: e.code ?? 1,
|
34 | };
|
35 | }
|
36 | }
|
37 |
|
38 |
|
39 |
|
40 |
|
41 |
|
42 |
|
43 |
|
44 | export function spawn(command, args, opts = {}) {
|
45 | return new Promise((resolve, reject) => {
|
46 | const sp = cpSpawn(command, args, { stdio: "inherit", ...opts });
|
47 |
|
48 | sp.once("error", reject);
|
49 | sp.once("exit", (code) => {
|
50 | resolve({ exitCode: code ?? 0 });
|
51 | });
|
52 | });
|
53 | }
|
54 |
|
55 |
|
56 |
|
57 |
|
58 |
|
59 |
|
60 | export async function streamToBuffer(stream) {
|
61 | const buffers = [];
|
62 | await internalPipeline(stream, async function* (transform) {
|
63 | for await (const chunk of transform) {
|
64 | buffers.push(chunk);
|
65 | yield chunk;
|
66 | }
|
67 | });
|
68 |
|
69 | return Buffer.concat(buffers);
|
70 | }
|
71 |
|
72 |
|
73 |
|
74 |
|
75 |
|
76 |
|
77 | export async function processDirectoryRecursive(
|
78 | dir,
|
79 | cb,
|
80 | opts = {
|
81 | skipDotFiles: true,
|
82 | skipNodeModules: true,
|
83 | },
|
84 | ) {
|
85 | for (const file of await readdir(dir, { encoding: "utf8" })) {
|
86 | if (opts.skipNodeModules && file === "node_modules") {
|
87 | continue;
|
88 | }
|
89 | if (opts.skipDotFiles && file[0] === ".") {
|
90 | continue;
|
91 | }
|
92 |
|
93 | const newPath = join(dir, file);
|
94 | const stat = await lstat(newPath);
|
95 | if (stat.isDirectory()) {
|
96 | await processDirectoryRecursive(newPath, cb, opts);
|
97 | } else if (stat.isFile()) {
|
98 | await Promise.resolve(cb(newPath));
|
99 | }
|
100 | }
|
101 | }
|
102 |
|
103 |
|
104 |
|
105 |
|
106 |
|
107 |
|
108 |
|
109 |
|
110 |
|
111 |
|
112 | export function processDirectoryRecursiveSync(
|
113 | dir,
|
114 | cb,
|
115 | opts = {
|
116 | skipDotFiles: true,
|
117 | skipNodeModules: true,
|
118 | },
|
119 | ) {
|
120 | for (const file of readdirSync(dir, { encoding: "utf8" })) {
|
121 | if (opts.skipNodeModules && file === "node_modules") {
|
122 | continue;
|
123 | }
|
124 | if (opts.skipDotFiles && file[0] === ".") {
|
125 | continue;
|
126 | }
|
127 |
|
128 | const newPath = join(dir, file);
|
129 | const stat = lstatSync(newPath);
|
130 | if (stat.isDirectory()) {
|
131 | processDirectoryRecursiveSync(newPath, cb, opts);
|
132 | } else if (stat.isFile()) {
|
133 | cb(newPath);
|
134 | }
|
135 | }
|
136 | }
|