@gjsify/child_process 0.3.12 → 0.3.14

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/lib/esm/index.js +354 -323
  2. package/package.json +8 -8
package/lib/esm/index.js CHANGED
@@ -3,341 +3,372 @@ import GLib from "@girs/glib-2.0";
3
3
  import { EventEmitter } from "node:events";
4
4
  import { Buffer } from "node:buffer";
5
5
  import { Readable } from "node:stream";
6
- import { gbytesToUint8Array, deferEmit, ensureMainLoop } from "@gjsify/utils";
7
- class GioInputStreamReadable extends Readable {
8
- _stream;
9
- _cancellable = new Gio.Cancellable();
10
- constructor(stream) {
11
- super();
12
- this._stream = stream;
13
- }
14
- _read(size) {
15
- this._stream.read_bytes_async(
16
- Math.max(size, 4096),
17
- GLib.PRIORITY_DEFAULT,
18
- this._cancellable,
19
- (_source, result) => {
20
- try {
21
- const gbytes = this._stream.read_bytes_finish(result);
22
- const data = gbytes.get_data();
23
- if (!data || data.length === 0) {
24
- this.push(null);
25
- } else {
26
- this.push(Buffer.from(data));
27
- }
28
- } catch (err) {
29
- if (!this._cancellable.is_cancelled()) {
30
- this.destroy(err);
31
- }
32
- }
33
- }
34
- );
35
- }
36
- _destroy(error, callback) {
37
- this._cancellable.cancel();
38
- callback(error);
39
- }
40
- }
41
- const _activeProcesses = /* @__PURE__ */ new Set();
42
- class ChildProcess extends EventEmitter {
43
- pid;
44
- exitCode = null;
45
- signalCode = null;
46
- killed = false;
47
- connected = false;
48
- stdin = null;
49
- stdout = null;
50
- stderr = null;
51
- _subprocess = null;
52
- /** @internal Set the underlying Gio.Subprocess and extract PID. */
53
- _setSubprocess(proc) {
54
- this._subprocess = proc;
55
- const pid = proc.get_identifier();
56
- if (pid) this.pid = parseInt(pid, 10);
57
- }
58
- /** Send a signal to the child process. */
59
- kill(signal) {
60
- if (!this._subprocess) return false;
61
- try {
62
- if (signal === "SIGKILL" || signal === 9) {
63
- this._subprocess.force_exit();
64
- } else {
65
- this._subprocess.send_signal(typeof signal === "number" ? signal : 15);
66
- }
67
- this.killed = true;
68
- return true;
69
- } catch {
70
- return false;
71
- }
72
- }
73
- ref() {
74
- return this;
75
- }
76
- unref() {
77
- return this;
78
- }
79
- }
6
+ import { deferEmit, ensureMainLoop, gbytesToUint8Array } from "@gjsify/utils";
7
+
8
+ //#region src/index.ts
9
+ var GioInputStreamReadable = class extends Readable {
10
+ _stream;
11
+ _cancellable = new Gio.Cancellable();
12
+ constructor(stream) {
13
+ super();
14
+ this._stream = stream;
15
+ }
16
+ _read(size) {
17
+ this._stream.read_bytes_async(Math.max(size, 4096), GLib.PRIORITY_DEFAULT, this._cancellable, (_source, result) => {
18
+ try {
19
+ const gbytes = this._stream.read_bytes_finish(result);
20
+ const data = gbytes.get_data();
21
+ if (!data || data.length === 0) {
22
+ this.push(null);
23
+ } else {
24
+ this.push(Buffer.from(data));
25
+ }
26
+ } catch (err) {
27
+ if (!this._cancellable.is_cancelled()) {
28
+ this.destroy(err);
29
+ }
30
+ }
31
+ });
32
+ }
33
+ _destroy(error, callback) {
34
+ this._cancellable.cancel();
35
+ callback(error);
36
+ }
37
+ };
38
+ const _activeProcesses = new Set();
39
+ /**
40
+ * ChildProcess — EventEmitter wrapping Gio.Subprocess.
41
+ */
42
+ var ChildProcess = class extends EventEmitter {
43
+ pid;
44
+ exitCode = null;
45
+ signalCode = null;
46
+ killed = false;
47
+ connected = false;
48
+ stdin = null;
49
+ stdout = null;
50
+ stderr = null;
51
+ _subprocess = null;
52
+ /** @internal Set the underlying Gio.Subprocess and extract PID. */
53
+ _setSubprocess(proc) {
54
+ this._subprocess = proc;
55
+ const pid = proc.get_identifier();
56
+ if (pid) this.pid = parseInt(pid, 10);
57
+ }
58
+ /** Send a signal to the child process. */
59
+ kill(signal) {
60
+ if (!this._subprocess) return false;
61
+ try {
62
+ if (signal === "SIGKILL" || signal === 9) {
63
+ this._subprocess.force_exit();
64
+ } else {
65
+ this._subprocess.send_signal(typeof signal === "number" ? signal : 15);
66
+ }
67
+ this.killed = true;
68
+ return true;
69
+ } catch {
70
+ return false;
71
+ }
72
+ }
73
+ ref() {
74
+ return this;
75
+ }
76
+ unref() {
77
+ return this;
78
+ }
79
+ };
80
80
  function _spawnSubprocess(argv, flags, options) {
81
- const launcher = new Gio.SubprocessLauncher({ flags });
82
- if (options?.cwd) {
83
- launcher.set_cwd(options.cwd);
84
- }
85
- if (options?.env) {
86
- for (const [key, value] of Object.entries(options.env)) {
87
- launcher.setenv(key, value, true);
88
- }
89
- }
90
- return launcher.spawnv(argv);
81
+ const launcher = new Gio.SubprocessLauncher({ flags });
82
+ if (options?.cwd) {
83
+ launcher.set_cwd(options.cwd);
84
+ }
85
+ if (options?.env) {
86
+ for (const [key, value] of Object.entries(options.env)) {
87
+ launcher.setenv(key, value, true);
88
+ }
89
+ }
90
+ return launcher.spawnv(argv);
91
91
  }
92
92
  function execSync(command, options) {
93
- const encoding = options?.encoding;
94
- const input = options?.input;
95
- const flags = Gio.SubprocessFlags.STDOUT_PIPE | Gio.SubprocessFlags.STDERR_PIPE | (input ? Gio.SubprocessFlags.STDIN_PIPE : Gio.SubprocessFlags.NONE);
96
- const shell = typeof options?.shell === "string" ? options.shell : "/bin/sh";
97
- const proc = _spawnSubprocess([shell, "-c", command], flags, options);
98
- const stdinBytes = input ? new GLib.Bytes(typeof input === "string" ? new TextEncoder().encode(input) : input) : null;
99
- const [, stdoutBytes, stderrBytes] = proc.communicate(stdinBytes, null);
100
- const status = proc.get_exit_status();
101
- if (status !== 0) {
102
- const stderrStr = stderrBytes ? new TextDecoder().decode(gbytesToUint8Array(stderrBytes)) : "";
103
- const error = new Error(`Command failed: ${command}
104
- ${stderrStr}`);
105
- error.status = status;
106
- error.stderr = stderrStr;
107
- error.stdout = stdoutBytes ? new TextDecoder().decode(gbytesToUint8Array(stdoutBytes)) : "";
108
- throw error;
109
- }
110
- if (!stdoutBytes) return encoding && encoding !== "buffer" ? "" : Buffer.alloc(0);
111
- const data = gbytesToUint8Array(stdoutBytes);
112
- if (encoding && encoding !== "buffer") {
113
- return new TextDecoder().decode(data);
114
- }
115
- return Buffer.from(data);
93
+ const encoding = options?.encoding;
94
+ const input = options?.input;
95
+ const flags = Gio.SubprocessFlags.STDOUT_PIPE | Gio.SubprocessFlags.STDERR_PIPE | (input ? Gio.SubprocessFlags.STDIN_PIPE : Gio.SubprocessFlags.NONE);
96
+ const shell = typeof options?.shell === "string" ? options.shell : "/bin/sh";
97
+ const proc = _spawnSubprocess([
98
+ shell,
99
+ "-c",
100
+ command
101
+ ], flags, options);
102
+ const stdinBytes = input ? new GLib.Bytes(typeof input === "string" ? new TextEncoder().encode(input) : input) : null;
103
+ const [, stdoutBytes, stderrBytes] = proc.communicate(stdinBytes, null);
104
+ const status = proc.get_exit_status();
105
+ if (status !== 0) {
106
+ const stderrStr = stderrBytes ? new TextDecoder().decode(gbytesToUint8Array(stderrBytes)) : "";
107
+ const error = new Error(`Command failed: ${command}\n${stderrStr}`);
108
+ error.status = status;
109
+ error.stderr = stderrStr;
110
+ error.stdout = stdoutBytes ? new TextDecoder().decode(gbytesToUint8Array(stdoutBytes)) : "";
111
+ throw error;
112
+ }
113
+ if (!stdoutBytes) return encoding && encoding !== "buffer" ? "" : Buffer.alloc(0);
114
+ const data = gbytesToUint8Array(stdoutBytes);
115
+ if (encoding && encoding !== "buffer") {
116
+ return new TextDecoder().decode(data);
117
+ }
118
+ return Buffer.from(data);
116
119
  }
120
+ /**
121
+ * Execute a command in a shell (async with callback).
122
+ */
117
123
  function _exec(command, options, callback) {
118
- if (typeof options === "function") {
119
- callback = options;
120
- options = {};
121
- }
122
- const opts = options || {};
123
- const child = new ChildProcess();
124
- const shell = typeof opts.shell === "string" ? opts.shell : "/bin/sh";
125
- const flags = Gio.SubprocessFlags.STDOUT_PIPE | Gio.SubprocessFlags.STDERR_PIPE;
126
- try {
127
- const proc = _spawnSubprocess([shell, "-c", command], flags, opts);
128
- child._setSubprocess(proc);
129
- ensureMainLoop();
130
- proc.communicate_utf8_async(null, null, (_source, result) => {
131
- try {
132
- const [, stdout, stderr] = proc.communicate_utf8_finish(result);
133
- const exitStatus = proc.get_exit_status();
134
- child.exitCode = exitStatus;
135
- if (exitStatus !== 0) {
136
- const error = new Error(`Command failed: ${command}`);
137
- error.code = exitStatus;
138
- error.killed = child.killed;
139
- error.stdout = stdout || "";
140
- error.stderr = stderr || "";
141
- if (callback) callback(error, stdout || "", stderr || "");
142
- } else {
143
- if (callback) callback(null, stdout || "", stderr || "");
144
- }
145
- child.emit("close", exitStatus, null);
146
- child.emit("exit", exitStatus, null);
147
- } catch (err) {
148
- const error = err instanceof Error ? err : new Error(String(err));
149
- if (callback) callback(error, "", "");
150
- child.emit("error", error);
151
- }
152
- });
153
- } catch (err) {
154
- const error = err instanceof Error ? err : new Error(String(err));
155
- setTimeout(() => {
156
- if (callback) callback(error, "", "");
157
- child.emit("error", error);
158
- }, 0);
159
- }
160
- return child;
124
+ if (typeof options === "function") {
125
+ callback = options;
126
+ options = {};
127
+ }
128
+ const opts = options || {};
129
+ const child = new ChildProcess();
130
+ const shell = typeof opts.shell === "string" ? opts.shell : "/bin/sh";
131
+ const flags = Gio.SubprocessFlags.STDOUT_PIPE | Gio.SubprocessFlags.STDERR_PIPE;
132
+ try {
133
+ const proc = _spawnSubprocess([
134
+ shell,
135
+ "-c",
136
+ command
137
+ ], flags, opts);
138
+ child._setSubprocess(proc);
139
+ ensureMainLoop();
140
+ proc.communicate_utf8_async(null, null, (_source, result) => {
141
+ try {
142
+ const [, stdout, stderr] = proc.communicate_utf8_finish(result);
143
+ const exitStatus = proc.get_exit_status();
144
+ child.exitCode = exitStatus;
145
+ if (exitStatus !== 0) {
146
+ const error = new Error(`Command failed: ${command}`);
147
+ error.code = exitStatus;
148
+ error.killed = child.killed;
149
+ error.stdout = stdout || "";
150
+ error.stderr = stderr || "";
151
+ if (callback) callback(error, stdout || "", stderr || "");
152
+ } else {
153
+ if (callback) callback(null, stdout || "", stderr || "");
154
+ }
155
+ child.emit("close", exitStatus, null);
156
+ child.emit("exit", exitStatus, null);
157
+ } catch (err) {
158
+ const error = err instanceof Error ? err : new Error(String(err));
159
+ if (callback) callback(error, "", "");
160
+ child.emit("error", error);
161
+ }
162
+ });
163
+ } catch (err) {
164
+ const error = err instanceof Error ? err : new Error(String(err));
165
+ setTimeout(() => {
166
+ if (callback) callback(error, "", "");
167
+ child.emit("error", error);
168
+ }, 0);
169
+ }
170
+ return child;
161
171
  }
172
+ /**
173
+ * Execute a file directly without shell (async).
174
+ */
162
175
  function execFile(file, args, options, callback) {
163
- let _args = [];
164
- let _opts = {};
165
- let _callback;
166
- if (typeof args === "function") {
167
- _callback = args;
168
- } else if (Array.isArray(args)) {
169
- _args = args;
170
- if (typeof options === "function") {
171
- _callback = options;
172
- } else {
173
- _opts = options || {};
174
- _callback = callback;
175
- }
176
- }
177
- const child = new ChildProcess();
178
- const flags = Gio.SubprocessFlags.STDOUT_PIPE | Gio.SubprocessFlags.STDERR_PIPE;
179
- try {
180
- const proc = _spawnSubprocess([file, ..._args], flags, _opts);
181
- child._setSubprocess(proc);
182
- ensureMainLoop();
183
- proc.communicate_utf8_async(null, null, (_source, result) => {
184
- try {
185
- const [, stdout, stderr] = proc.communicate_utf8_finish(result);
186
- const exitStatus = proc.get_exit_status();
187
- child.exitCode = exitStatus;
188
- if (exitStatus !== 0) {
189
- const error = new Error(`Command failed: ${file}`);
190
- error.code = exitStatus;
191
- error.stdout = stdout || "";
192
- error.stderr = stderr || "";
193
- if (_callback) _callback(error, stdout || "", stderr || "");
194
- } else {
195
- if (_callback) _callback(null, stdout || "", stderr || "");
196
- }
197
- child.emit("close", exitStatus, null);
198
- child.emit("exit", exitStatus, null);
199
- } catch (err) {
200
- const error = err instanceof Error ? err : new Error(String(err));
201
- if (_callback) _callback(error, "", "");
202
- child.emit("error", error);
203
- }
204
- });
205
- } catch (err) {
206
- const error = err instanceof Error ? err : new Error(String(err));
207
- setTimeout(() => {
208
- if (_callback) _callback(error, "", "");
209
- child.emit("error", error);
210
- }, 0);
211
- }
212
- return child;
176
+ let _args = [];
177
+ let _opts = {};
178
+ let _callback;
179
+ if (typeof args === "function") {
180
+ _callback = args;
181
+ } else if (Array.isArray(args)) {
182
+ _args = args;
183
+ if (typeof options === "function") {
184
+ _callback = options;
185
+ } else {
186
+ _opts = options || {};
187
+ _callback = callback;
188
+ }
189
+ }
190
+ const child = new ChildProcess();
191
+ const flags = Gio.SubprocessFlags.STDOUT_PIPE | Gio.SubprocessFlags.STDERR_PIPE;
192
+ try {
193
+ const proc = _spawnSubprocess([file, ..._args], flags, _opts);
194
+ child._setSubprocess(proc);
195
+ ensureMainLoop();
196
+ proc.communicate_utf8_async(null, null, (_source, result) => {
197
+ try {
198
+ const [, stdout, stderr] = proc.communicate_utf8_finish(result);
199
+ const exitStatus = proc.get_exit_status();
200
+ child.exitCode = exitStatus;
201
+ if (exitStatus !== 0) {
202
+ const error = new Error(`Command failed: ${file}`);
203
+ error.code = exitStatus;
204
+ error.stdout = stdout || "";
205
+ error.stderr = stderr || "";
206
+ if (_callback) _callback(error, stdout || "", stderr || "");
207
+ } else {
208
+ if (_callback) _callback(null, stdout || "", stderr || "");
209
+ }
210
+ child.emit("close", exitStatus, null);
211
+ child.emit("exit", exitStatus, null);
212
+ } catch (err) {
213
+ const error = err instanceof Error ? err : new Error(String(err));
214
+ if (_callback) _callback(error, "", "");
215
+ child.emit("error", error);
216
+ }
217
+ });
218
+ } catch (err) {
219
+ const error = err instanceof Error ? err : new Error(String(err));
220
+ setTimeout(() => {
221
+ if (_callback) _callback(error, "", "");
222
+ child.emit("error", error);
223
+ }, 0);
224
+ }
225
+ return child;
213
226
  }
227
+ /**
228
+ * Execute a file directly without shell (sync).
229
+ */
214
230
  function execFileSync(file, args, options) {
215
- const _args = args || [];
216
- const encoding = options?.encoding;
217
- const input = options?.input;
218
- const flags = Gio.SubprocessFlags.STDOUT_PIPE | Gio.SubprocessFlags.STDERR_PIPE | (input ? Gio.SubprocessFlags.STDIN_PIPE : Gio.SubprocessFlags.NONE);
219
- const proc = _spawnSubprocess([file, ..._args], flags, options);
220
- const stdinBytes = input ? new GLib.Bytes(typeof input === "string" ? new TextEncoder().encode(input) : input) : null;
221
- const [, stdoutBytes, stderrBytes] = proc.communicate(stdinBytes, null);
222
- const status = proc.get_exit_status();
223
- if (status !== 0) {
224
- const stderrStr = stderrBytes ? new TextDecoder().decode(gbytesToUint8Array(stderrBytes)) : "";
225
- const error = new Error(`Command failed: ${file} ${_args.join(" ")}`);
226
- error.status = status;
227
- error.stderr = stderrStr;
228
- throw error;
229
- }
230
- if (!stdoutBytes) return encoding && encoding !== "buffer" ? "" : Buffer.alloc(0);
231
- const data = gbytesToUint8Array(stdoutBytes);
232
- if (encoding && encoding !== "buffer") {
233
- return new TextDecoder().decode(data);
234
- }
235
- return Buffer.from(data);
231
+ const _args = args || [];
232
+ const encoding = options?.encoding;
233
+ const input = options?.input;
234
+ const flags = Gio.SubprocessFlags.STDOUT_PIPE | Gio.SubprocessFlags.STDERR_PIPE | (input ? Gio.SubprocessFlags.STDIN_PIPE : Gio.SubprocessFlags.NONE);
235
+ const proc = _spawnSubprocess([file, ..._args], flags, options);
236
+ const stdinBytes = input ? new GLib.Bytes(typeof input === "string" ? new TextEncoder().encode(input) : input) : null;
237
+ const [, stdoutBytes, stderrBytes] = proc.communicate(stdinBytes, null);
238
+ const status = proc.get_exit_status();
239
+ if (status !== 0) {
240
+ const stderrStr = stderrBytes ? new TextDecoder().decode(gbytesToUint8Array(stderrBytes)) : "";
241
+ const error = new Error(`Command failed: ${file} ${_args.join(" ")}`);
242
+ error.status = status;
243
+ error.stderr = stderrStr;
244
+ throw error;
245
+ }
246
+ if (!stdoutBytes) return encoding && encoding !== "buffer" ? "" : Buffer.alloc(0);
247
+ const data = gbytesToUint8Array(stdoutBytes);
248
+ if (encoding && encoding !== "buffer") {
249
+ return new TextDecoder().decode(data);
250
+ }
251
+ return Buffer.from(data);
236
252
  }
253
+ /**
254
+ * Spawn a new process (async, with event-based API).
255
+ */
237
256
  function spawn(command, args, options) {
238
- const _args = args || [];
239
- const child = new ChildProcess();
240
- const useShell = options?.shell;
241
- let argv;
242
- if (useShell) {
243
- const shell = typeof useShell === "string" ? useShell : "/bin/sh";
244
- const fullCmd = [command, ..._args].join(" ");
245
- argv = [shell, "-c", fullCmd];
246
- } else {
247
- argv = [command, ..._args];
248
- }
249
- const flags = Gio.SubprocessFlags.STDOUT_PIPE | Gio.SubprocessFlags.STDERR_PIPE | Gio.SubprocessFlags.STDIN_PIPE;
250
- try {
251
- const proc = _spawnSubprocess(argv, flags, options);
252
- child._setSubprocess(proc);
253
- _activeProcesses.add(child);
254
- const stdoutPipe = proc.get_stdout_pipe();
255
- if (stdoutPipe) child.stdout = new GioInputStreamReadable(stdoutPipe);
256
- const stderrPipe = proc.get_stderr_pipe();
257
- if (stderrPipe) child.stderr = new GioInputStreamReadable(stderrPipe);
258
- ensureMainLoop();
259
- proc.wait_async(null, (_source, result) => {
260
- try {
261
- proc.wait_finish(result);
262
- const exitStatus = proc.get_if_exited() ? proc.get_exit_status() : null;
263
- const signal = proc.get_if_signaled() ? "SIGTERM" : null;
264
- child.exitCode = exitStatus;
265
- child.signalCode = signal;
266
- child.emit("exit", exitStatus, signal);
267
- child.emit("close", exitStatus, signal);
268
- } catch (err) {
269
- child.emit("error", err instanceof Error ? err : new Error(String(err)));
270
- }
271
- _activeProcesses.delete(child);
272
- });
273
- deferEmit(child, "spawn");
274
- } catch (err) {
275
- deferEmit(child, "error", err instanceof Error ? err : new Error(String(err)));
276
- }
277
- return child;
257
+ const _args = args || [];
258
+ const child = new ChildProcess();
259
+ const useShell = options?.shell;
260
+ let argv;
261
+ if (useShell) {
262
+ const shell = typeof useShell === "string" ? useShell : "/bin/sh";
263
+ const fullCmd = [command, ..._args].join(" ");
264
+ argv = [
265
+ shell,
266
+ "-c",
267
+ fullCmd
268
+ ];
269
+ } else {
270
+ argv = [command, ..._args];
271
+ }
272
+ const flags = Gio.SubprocessFlags.STDOUT_PIPE | Gio.SubprocessFlags.STDERR_PIPE | Gio.SubprocessFlags.STDIN_PIPE;
273
+ try {
274
+ const proc = _spawnSubprocess(argv, flags, options);
275
+ child._setSubprocess(proc);
276
+ _activeProcesses.add(child);
277
+ const stdoutPipe = proc.get_stdout_pipe();
278
+ if (stdoutPipe) child.stdout = new GioInputStreamReadable(stdoutPipe);
279
+ const stderrPipe = proc.get_stderr_pipe();
280
+ if (stderrPipe) child.stderr = new GioInputStreamReadable(stderrPipe);
281
+ ensureMainLoop();
282
+ proc.wait_async(null, (_source, result) => {
283
+ try {
284
+ proc.wait_finish(result);
285
+ const exitStatus = proc.get_if_exited() ? proc.get_exit_status() : null;
286
+ const signal = proc.get_if_signaled() ? "SIGTERM" : null;
287
+ child.exitCode = exitStatus;
288
+ child.signalCode = signal;
289
+ child.emit("exit", exitStatus, signal);
290
+ child.emit("close", exitStatus, signal);
291
+ } catch (err) {
292
+ child.emit("error", err instanceof Error ? err : new Error(String(err)));
293
+ }
294
+ _activeProcesses.delete(child);
295
+ });
296
+ deferEmit(child, "spawn");
297
+ } catch (err) {
298
+ deferEmit(child, "error", err instanceof Error ? err : new Error(String(err)));
299
+ }
300
+ return child;
278
301
  }
302
+ /**
303
+ * Spawn a new process (sync).
304
+ */
279
305
  function spawnSync(command, args, options) {
280
- const _args = args || [];
281
- const useShell = options?.shell;
282
- const input = options?.input;
283
- let argv;
284
- if (useShell) {
285
- const shell = typeof useShell === "string" ? useShell : "/bin/sh";
286
- const fullCmd = [command, ..._args].join(" ");
287
- argv = [shell, "-c", fullCmd];
288
- } else {
289
- argv = [command, ..._args];
290
- }
291
- const flags = Gio.SubprocessFlags.STDOUT_PIPE | Gio.SubprocessFlags.STDERR_PIPE | (input ? Gio.SubprocessFlags.STDIN_PIPE : Gio.SubprocessFlags.NONE);
292
- try {
293
- const proc = _spawnSubprocess(argv, flags, options);
294
- const pid = proc.get_identifier();
295
- const stdinBytes = input ? new GLib.Bytes(typeof input === "string" ? new TextEncoder().encode(input) : input) : null;
296
- const [, stdoutBytes, stderrBytes] = proc.communicate(stdinBytes, null);
297
- const stdoutBuf = stdoutBytes ? Buffer.from(gbytesToUint8Array(stdoutBytes)) : Buffer.alloc(0);
298
- const stderrBuf = stderrBytes ? Buffer.from(gbytesToUint8Array(stderrBytes)) : Buffer.alloc(0);
299
- const encoding = options?.encoding;
300
- const stdoutData = encoding && encoding !== "buffer" ? new TextDecoder().decode(stdoutBuf) : stdoutBuf;
301
- const stderrData = encoding && encoding !== "buffer" ? new TextDecoder().decode(stderrBuf) : stderrBuf;
302
- const status = proc.get_if_exited() ? proc.get_exit_status() : null;
303
- const signal = proc.get_if_signaled() ? "SIGTERM" : null;
304
- return {
305
- pid: pid ? parseInt(pid, 10) : 0,
306
- output: [null, stdoutData, stderrData],
307
- stdout: stdoutData,
308
- stderr: stderrData,
309
- status,
310
- signal
311
- };
312
- } catch (err) {
313
- const empty = options?.encoding && options.encoding !== "buffer" ? "" : Buffer.alloc(0);
314
- return {
315
- pid: 0,
316
- output: [null, empty, empty],
317
- stdout: empty,
318
- stderr: empty,
319
- status: null,
320
- signal: null,
321
- error: err instanceof Error ? err : new Error(String(err))
322
- };
323
- }
306
+ const _args = args || [];
307
+ const useShell = options?.shell;
308
+ const input = options?.input;
309
+ let argv;
310
+ if (useShell) {
311
+ const shell = typeof useShell === "string" ? useShell : "/bin/sh";
312
+ const fullCmd = [command, ..._args].join(" ");
313
+ argv = [
314
+ shell,
315
+ "-c",
316
+ fullCmd
317
+ ];
318
+ } else {
319
+ argv = [command, ..._args];
320
+ }
321
+ const flags = Gio.SubprocessFlags.STDOUT_PIPE | Gio.SubprocessFlags.STDERR_PIPE | (input ? Gio.SubprocessFlags.STDIN_PIPE : Gio.SubprocessFlags.NONE);
322
+ try {
323
+ const proc = _spawnSubprocess(argv, flags, options);
324
+ const pid = proc.get_identifier();
325
+ const stdinBytes = input ? new GLib.Bytes(typeof input === "string" ? new TextEncoder().encode(input) : input) : null;
326
+ const [, stdoutBytes, stderrBytes] = proc.communicate(stdinBytes, null);
327
+ const stdoutBuf = stdoutBytes ? Buffer.from(gbytesToUint8Array(stdoutBytes)) : Buffer.alloc(0);
328
+ const stderrBuf = stderrBytes ? Buffer.from(gbytesToUint8Array(stderrBytes)) : Buffer.alloc(0);
329
+ const encoding = options?.encoding;
330
+ const stdoutData = encoding && encoding !== "buffer" ? new TextDecoder().decode(stdoutBuf) : stdoutBuf;
331
+ const stderrData = encoding && encoding !== "buffer" ? new TextDecoder().decode(stderrBuf) : stderrBuf;
332
+ const status = proc.get_if_exited() ? proc.get_exit_status() : null;
333
+ const signal = proc.get_if_signaled() ? "SIGTERM" : null;
334
+ return {
335
+ pid: pid ? parseInt(pid, 10) : 0,
336
+ output: [
337
+ null,
338
+ stdoutData,
339
+ stderrData
340
+ ],
341
+ stdout: stdoutData,
342
+ stderr: stderrData,
343
+ status,
344
+ signal
345
+ };
346
+ } catch (err) {
347
+ const empty = options?.encoding && options.encoding !== "buffer" ? "" : Buffer.alloc(0);
348
+ return {
349
+ pid: 0,
350
+ output: [
351
+ null,
352
+ empty,
353
+ empty
354
+ ],
355
+ stdout: empty,
356
+ stderr: empty,
357
+ status: null,
358
+ signal: null,
359
+ error: err instanceof Error ? err : new Error(String(err))
360
+ };
361
+ }
324
362
  }
325
- var index_default = {
326
- ChildProcess,
327
- exec: _exec,
328
- execSync,
329
- execFile,
330
- execFileSync,
331
- spawn,
332
- spawnSync
333
- };
334
- export {
335
- ChildProcess,
336
- index_default as default,
337
- _exec as exec,
338
- execFile,
339
- execFileSync,
340
- execSync,
341
- spawn,
342
- spawnSync
363
+ var src_default = {
364
+ ChildProcess,
365
+ exec: _exec,
366
+ execSync,
367
+ execFile,
368
+ execFileSync,
369
+ spawn,
370
+ spawnSync
343
371
  };
372
+
373
+ //#endregion
374
+ export { ChildProcess, src_default as default, _exec as exec, execFile, execFileSync, execSync, spawn, spawnSync };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gjsify/child_process",
3
- "version": "0.3.12",
3
+ "version": "0.3.14",
4
4
  "description": "Node.js child_process module for Gjs",
5
5
  "type": "module",
6
6
  "module": "lib/esm/index.js",
@@ -30,16 +30,16 @@
30
30
  "child_process"
31
31
  ],
32
32
  "devDependencies": {
33
- "@gjsify/cli": "^0.3.12",
34
- "@gjsify/unit": "^0.3.12",
33
+ "@gjsify/cli": "^0.3.14",
34
+ "@gjsify/unit": "^0.3.14",
35
35
  "@types/node": "^25.6.0",
36
36
  "typescript": "^6.0.3"
37
37
  },
38
38
  "dependencies": {
39
- "@girs/gio-2.0": "^2.88.0-4.0.0-rc.9",
40
- "@girs/glib-2.0": "^2.88.0-4.0.0-rc.9",
41
- "@gjsify/buffer": "^0.3.12",
42
- "@gjsify/events": "^0.3.12",
43
- "@gjsify/utils": "^0.3.12"
39
+ "@girs/gio-2.0": "2.88.0-4.0.0-rc.9",
40
+ "@girs/glib-2.0": "2.88.0-4.0.0-rc.9",
41
+ "@gjsify/buffer": "^0.3.14",
42
+ "@gjsify/events": "^0.3.14",
43
+ "@gjsify/utils": "^0.3.14"
44
44
  }
45
45
  }