@gjsify/child_process 0.21.0 → 0.23.0
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.
- package/README.md +102 -1
- package/lib/esm/_virtual/_rolldown/runtime.js +1 -1
- package/lib/esm/communicate.js +1 -0
- package/lib/esm/index.js +1 -1
- package/lib/esm/platform/darwin.js +1 -0
- package/lib/esm/platform/index.js +1 -0
- package/lib/esm/platform/linux.js +1 -0
- package/lib/esm/platform/posix.js +1 -0
- package/lib/esm/platform/win32.js +1 -0
- package/lib/types/communicate.d.ts +25 -0
- package/lib/types/index.d.ts +25 -8
- package/lib/types/platform/darwin.d.ts +10 -0
- package/lib/types/platform/index.d.ts +42 -0
- package/lib/types/platform/linux.d.ts +9 -0
- package/lib/types/platform/posix.d.ts +57 -0
- package/lib/types/platform/win32.d.ts +55 -0
- package/package.json +7 -7
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @gjsify/child_process
|
|
2
2
|
|
|
3
|
-
GJS implementation of the Node.js `child_process` module using Gio.Subprocess. Supports exec, execSync, spawn, and spawnSync.
|
|
3
|
+
GJS implementation of the Node.js `child_process` module using Gio.Subprocess. Supports exec, execSync, execFile, execFileSync, spawn, and spawnSync.
|
|
4
4
|
|
|
5
5
|
Part of the [gjsify](https://github.com/gjsify/gjsify) project — Node.js and Web APIs for GJS (GNOME JavaScript).
|
|
6
6
|
|
|
@@ -23,6 +23,107 @@ const output = execSync('echo hello').toString();
|
|
|
23
23
|
const child = spawn('ls', ['-la']);
|
|
24
24
|
```
|
|
25
25
|
|
|
26
|
+
## Platform support
|
|
27
|
+
|
|
28
|
+
Process spawning goes through `Gio.Subprocess`, which works on every platform
|
|
29
|
+
GIO runs on. The parts of Node's API that are inherently platform-specific are
|
|
30
|
+
resolved in `src/platform/` (`linux.ts` / `darwin.ts` / `win32.ts` behind an
|
|
31
|
+
`index.ts`, mirroring `@gjsify/os`). Detection is capability-based — the
|
|
32
|
+
filesystem is probed for what is actually there — so an unrecognised POSIX host
|
|
33
|
+
degrades to the generic POSIX answers rather than to a wrong one.
|
|
34
|
+
|
|
35
|
+
| Feature | Linux / Android | macOS | Windows |
|
|
36
|
+
|---|---|---|---|
|
|
37
|
+
| `shell: true` | `/bin/sh -c` (`/system/bin/sh` on Bionic) | `/bin/sh -c` | `%ComSpec%` (default `cmd.exe`) with `/d /s /c "<cmd>"`, matching Node |
|
|
38
|
+
| `shell: '<path>'` | that shell, `-c` | that shell, `-c` | that shell; `-c` unless it is `cmd`/`cmd.exe` |
|
|
39
|
+
| `timeout` (`spawnSync`) | ✅ in-process GLib timer | ✅ same | ✅ same |
|
|
40
|
+
| `timeout` / `signal` (`spawn`, `exec`, `execFile`) | ✅ | ✅ | ⚠️ kill degrades to `force_exit()` (see *Signals*) |
|
|
41
|
+
| `argv0` | ✅ via `bash -c 'exec -a "$0" "$@"'` | ✅ same | ❌ throws `ERR_UNSUPPORTED_OPERATION` |
|
|
42
|
+
| `detached` | ✅ via `setsid(1)` from `PATH` | ⚠️ no `setsid(1)` on stock macOS | ⚠️ no equivalent |
|
|
43
|
+
| `stdio` `pipe`/`inherit`/`ignore` | ✅ | ✅ | ✅ |
|
|
44
|
+
| `uid` / `gid` | accepted, no-op | accepted, no-op | accepted, no-op |
|
|
45
|
+
| `windowsHide` / `windowsVerbatimArguments` | accepted, no-op | accepted, no-op | accepted, no-op |
|
|
46
|
+
|
|
47
|
+
### Timeouts need no external binary
|
|
48
|
+
|
|
49
|
+
`options.timeout` on `spawnSync` used to be delegated to the GNU coreutils
|
|
50
|
+
`timeout(1)` binary, because `Gio.Subprocess.communicate()` blocks the calling
|
|
51
|
+
thread and never iterates a GLib main context — so a timer armed around it could
|
|
52
|
+
never fire.
|
|
53
|
+
|
|
54
|
+
It is now enforced in-process: `communicate_async()` is driven on a **private**
|
|
55
|
+
`GLib.MainContext` pushed as thread-default, with the deadline as a
|
|
56
|
+
`GLib.timeout_source_new()` attached to that same context. Iterating a private
|
|
57
|
+
context dispatches only our own sources, so no application timer, GTK event or
|
|
58
|
+
unrelated GIO callback can run — the re-entrancy profile is identical to the
|
|
59
|
+
blocking `communicate()` it replaces.
|
|
60
|
+
|
|
61
|
+
Besides removing the GNU-userland dependency (macOS ships `timeout` only as
|
|
62
|
+
Homebrew's `gtimeout`; Windows not at all), this reports the **real child pid**
|
|
63
|
+
in `result.pid` and the **real termination signal** in `result.signal`, both of
|
|
64
|
+
which the wrapper process used to mask.
|
|
65
|
+
|
|
66
|
+
`options.timeout` is **not** implemented for `execSync` / `execFileSync` on any
|
|
67
|
+
platform — it is accepted and ignored, as it was before.
|
|
68
|
+
|
|
69
|
+
### `detached`
|
|
70
|
+
|
|
71
|
+
Node implements `detached` as `setsid(2)` in the child on POSIX and
|
|
72
|
+
`DETACHED_PROCESS` / `CREATE_NEW_PROCESS_GROUP` on Windows. Neither is reachable
|
|
73
|
+
from GJS: `g_subprocess_launcher_set_child_setup()` is `(skip)`-annotated in the
|
|
74
|
+
GIR (it takes a raw C function pointer), `GSubprocess` never sets
|
|
75
|
+
`G_SPAWN_FILE_AND_ARGV_ZERO`, and `Gio.SubprocessLauncher` exposes no
|
|
76
|
+
`CreateProcess` creation flags.
|
|
77
|
+
|
|
78
|
+
The POSIX path therefore prepends the `setsid(1)` binary, resolved from `PATH`
|
|
79
|
+
(not hard-coded to `/usr/bin/setsid`, so Alpine/Nix layouts work).
|
|
80
|
+
|
|
81
|
+
**Degraded contract where no `setsid(1)` exists** (stock macOS, Windows): the
|
|
82
|
+
child is spawned normally and still outlives the parent — GIO sets no
|
|
83
|
+
`PR_SET_PDEATHSIG` equivalent and does not place children in a job object — but
|
|
84
|
+
it is **not** promoted to a session/process-group leader, so terminal-generated
|
|
85
|
+
signals (Ctrl-C `SIGINT`, `SIGHUP` on terminal close; a console Ctrl-C event on
|
|
86
|
+
Windows) still reach it. Installing `setsid` on macOS (`brew install util-linux`,
|
|
87
|
+
then put it on `PATH`) restores the full contract.
|
|
88
|
+
|
|
89
|
+
### `argv0`
|
|
90
|
+
|
|
91
|
+
Because the launcher's child-setup hook is not introspectable, `argv0` is
|
|
92
|
+
implemented by wrapping the spawn in a shell's `exec -a "$0" "$@"`, which issues
|
|
93
|
+
exactly the `execve()` Node's `posix_spawn` path does.
|
|
94
|
+
|
|
95
|
+
`exec -a` is a bash/ksh/zsh extension, **not** POSIX `sh` — on Debian/Ubuntu
|
|
96
|
+
`/bin/sh` is `dash` and has no `exec -a`. The shell for this wrapper is
|
|
97
|
+
therefore resolved as `bash` → `zsh` → the platform default shell, so the option
|
|
98
|
+
behaves correctly on dash-based distributions too.
|
|
99
|
+
|
|
100
|
+
On Windows there is no mechanism at all (no `exec -a` in `cmd.exe`, and GLib's
|
|
101
|
+
`protect_argv()` builds `lpCommandLine` from `argv[0]`), so `argv0` **throws**
|
|
102
|
+
an `Error` with `code: 'ERR_UNSUPPORTED_OPERATION'` rather than silently running
|
|
103
|
+
the child under the wrong name.
|
|
104
|
+
|
|
105
|
+
### Signals
|
|
106
|
+
|
|
107
|
+
`child.kill(signal)` and the `killSignal` used by `timeout` / `AbortSignal`
|
|
108
|
+
accept a name or a number. Names are translated through a **per-platform** table
|
|
109
|
+
because the numeric values genuinely differ: `SIGUSR1` is `10` on Linux but `30`
|
|
110
|
+
on macOS, `SIGSTOP` is `19` on Linux but `17` on macOS. Sending a Linux number
|
|
111
|
+
on macOS would deliver a completely different signal.
|
|
112
|
+
|
|
113
|
+
`SIGKILL` always routes through `Gio.Subprocess.force_exit()`. On Windows
|
|
114
|
+
`g_subprocess_send_signal()` is a documented no-op, so **every** signal routes
|
|
115
|
+
through `force_exit()` (`TerminateProcess`) — matching how Node maps
|
|
116
|
+
`SIGTERM`/`SIGKILL`/`SIGINT` there, but meaning a Windows child cannot be sent a
|
|
117
|
+
graceful, catchable signal.
|
|
118
|
+
|
|
119
|
+
### `windowsVerbatimArguments`
|
|
120
|
+
|
|
121
|
+
Node forces this on for the `cmd.exe` shell path so libuv does not re-quote the
|
|
122
|
+
already-quoted command string. GLib always builds the Windows command line
|
|
123
|
+
itself via `protect_argv()` and offers no opt-out, so the option is accepted and
|
|
124
|
+
ignored. A shell command containing embedded double quotes may therefore be
|
|
125
|
+
quoted differently under GJS than under Node on Windows.
|
|
126
|
+
|
|
26
127
|
## License
|
|
27
128
|
|
|
28
129
|
MIT
|
|
@@ -1 +1 @@
|
|
|
1
|
-
var e=Object.defineProperty,__name=(t,n)=>e(t,`name`,{value:n,configurable:!0});export{__name};
|
|
1
|
+
var e=Object.defineProperty,__name=(t,n)=>e(t,`name`,{value:n,configurable:!0}),__exportAll=(t,n)=>{let r={};for(var i in t)e(r,i,{get:t[i],enumerable:!0});return n||e(r,Symbol.toStringTag,{value:`Module`}),r};export{__exportAll,__name};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import"./_virtual/_rolldown/runtime.js";import e from"@girs/glib-2.0";function communicateWithTimeout(t,n,r,i){let a={stdout:null,stderr:null,timedOut:!1,error:null},o=e.MainContext.new(),s=null,c=!1;o.push_thread_default();try{for(t.communicate_async(n,null,(e,n)=>{try{let e=t.communicate_finish(n);a.stdout=e[1]??null,a.stderr=e[2]??null}catch(e){a.error=e}c=!0}),s=e.timeout_source_new(r),s.set_callback(()=>(a.timedOut=!0,i(),e.SOURCE_REMOVE)),s.attach(o);!c;)o.iteration(!0)}finally{s!==null&&s.destroy(),o.pop_thread_default()}return a}export{communicateWithTimeout};
|
package/lib/esm/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import"./_virtual/_rolldown/runtime.js";import e from"@girs/gio-2.0";import t from"@girs/glib-2.0";import{EventEmitter as n}from"node:events";import{Buffer as r}from"node:buffer";import{Readable as i,Writable as a}from"node:stream";import{fileURLToPath as o}from"node:url";import{deferEmit as s,ensureMainLoop as c,gbytesToUint8Array as l}from"@gjsify/utils";var GioInputStreamReadable=class extends i{_stream;_cancellable=new e.Cancellable;constructor(e){super(),this._stream=e}_read(e){this._stream.read_bytes_async(Math.max(e,4096),t.PRIORITY_DEFAULT,this._cancellable,(e,t)=>{try{let e=this._stream.read_bytes_finish(t).get_data();!e||e.length===0?this.push(null):this.push(r.from(e))}catch(e){this._cancellable.is_cancelled()||this.destroy(e)}})}_destroy(e,t){this._cancellable.cancel(),t(e)}},GioOutputStreamWritable=class extends a{_stream;_cancellable=new e.Cancellable;_closed=!1;constructor(e){super(),this._stream=e}_write(e,n,i){if(this._closed){i(Error(`write after end`));return}let a=typeof e==`string`?r.from(e):e instanceof Uint8Array?e:r.from(e);this._stream.write_bytes_async(new t.Bytes(a),t.PRIORITY_DEFAULT,this._cancellable,(e,t)=>{try{this._stream.write_bytes_finish(t),i()}catch(e){this._cancellable.is_cancelled()?i():i(e)}})}_final(e){if(this._closed){e();return}this._closed=!0;try{this._stream.close(null)}catch{}e()}_destroy(e,t){if(this._cancellable.cancel(),!this._closed){this._closed=!0;try{this._stream.close(null)}catch{}}t(e)}};function _gioErrorToNodeError(e,n,r){let i=e??Error(`Unknown spawn error`),a=i,o=i.code,s=i.matches,c=!1;if(typeof s==`function`)try{c=s.call(i,t.SpawnError,t.SpawnError.NOENT)===!0}catch{}if(!c&&o===t.SpawnError.NOENT&&(c=!0),!c&&typeof i.message==`string`&&/No such file or directory|ENOENT|Failed to execute|nicht gefunden|nicht ausgeführt/i.test(i.message)&&(c=!0),c){let e=Error(`spawn ${n} ENOENT`);return e.code=`ENOENT`,e.errno=-2,e.syscall=`spawn ${n}`,e.path=n,e.spawnargs=r.slice(),e}if(i instanceof Error)return a;let l=i,u=typeof l.message==`string`?l.message:String(i),d=Error(u);return(typeof o==`number`||typeof o==`string`)&&(d.code=o),d}const u=new Set;var ChildProcess=class extends n{pid;exitCode=null;signalCode=null;killed=!1;connected=!1;stdin=null;stdout=null;stderr=null;get stdio(){return[this.stdin,this.stdout,this.stderr]}_subprocess=null;_setSubprocess(e,t){this._subprocess=e,t>0&&(this.pid=t)}kill(e){if(!this._subprocess)return!1;try{let t=e??`SIGTERM`;return t===`SIGKILL`||t===9?this._subprocess.force_exit():typeof t==`number`?this._subprocess.send_signal(t):this._subprocess.send_signal({SIGHUP:1,SIGINT:2,SIGQUIT:3,SIGABRT:6,SIGKILL:9,SIGUSR1:10,SIGUSR2:12,SIGTERM:15}[t]??15),this.killed=!0,!0}catch{return!1}}ref(){return this}unref(){return this}};function _normalizeCwd(e){if(e!=null){if(typeof e==`string`)return e;if(typeof e==`object`&&e&&typeof e.href==`string`&&typeof e.protocol==`string`){let t=e;if(t.protocol!==`file:`)throw TypeError(`The URL must be of scheme file:; received '${t.protocol}' for 'options.cwd'`);return o(t)}return e instanceof Uint8Array?new TextDecoder().decode(e):String(e)}}function _encodeEnvValue(e){if(e!==void 0)return`${e}`}function _spawnSubprocess(t,n,r){let i=new e.SubprocessLauncher({flags:n}),a=_normalizeCwd(r?.cwd);if(a!==void 0&&i.set_cwd(a),r?.env){let e=r.env;i.set_environ([]);let t=new Set;for(let n in e){if(t.has(n))continue;t.add(n);let r=_encodeEnvValue(e[n]);r!==void 0&&i.setenv(n,r,!0)}}let o=t;if(r?.argv0!==void 0&&r.argv0!==null){if(typeof r.argv0!=`string`)throw TypeError(`The "options.argv0" property must be of type string. Received type ${typeof r.argv0}`);o=[`/bin/sh`,`-c`,`exec -a "$0" "$@"`,r.argv0,...t]}r?.detached===!0&&(o=[`/usr/bin/setsid`,...o]);let s=i.spawnv(o);return{proc:s,pid:_capturePidAtSpawn(s)}}function _capturePidAtSpawn(e){let t=e.get_identifier();if(t){let e=parseInt(t,10);if(e>0)return e}return 0}function execSync(n,i){let a=i?.encoding,o=i?.input,s=e.SubprocessFlags.STDOUT_PIPE|e.SubprocessFlags.STDERR_PIPE|(o?e.SubprocessFlags.STDIN_PIPE:e.SubprocessFlags.NONE),c=typeof i?.shell==`string`?i.shell:`/bin/sh`,u;try{({proc:u}=_spawnSubprocess([c,`-c`,n],s,i))}catch(e){throw _gioErrorToNodeError(e,c,[`-c`,n])}let d=o?new t.Bytes(typeof o==`string`?new TextEncoder().encode(o):o):null,[,f,p]=u.communicate(d,null),m=u.get_exit_status();if(m!==0){let e=p?new TextDecoder().decode(l(p)):``,t=f?new TextDecoder().decode(l(f)):``,i=Error(`Command failed: ${n}\n${e}`);throw i.status=m,a===`buffer`||a===null?(i.stderr=p?r.from(l(p)):r.alloc(0),i.stdout=f?r.from(l(f)):r.alloc(0)):(i.stderr=e,i.stdout=t),i}if(!f)return a===`buffer`||a==null?r.alloc(0):``;let h=l(f);if(a===`buffer`||a==null)return r.from(h);let g=r.isEncoding(a)?a:`utf8`;return r.from(h).toString(g)}function _decodeExecOutput(e,t){let n=e??new Uint8Array;if(t===`buffer`||t===null)return r.from(n);let i=t&&r.isEncoding(t)?t:`utf8`;return r.from(n).toString(i)}function _normalizeKillSignal(e){return e??`SIGTERM`}function _exec(t,n,r){typeof n==`function`&&(r=n,n={});let i=n||{},a=new ChildProcess,o=typeof i.shell==`string`?i.shell:`/bin/sh`,s=e.SubprocessFlags.STDOUT_PIPE|e.SubprocessFlags.STDERR_PIPE,c=i.maxBuffer??1024*1024,l=i.timeout&&i.timeout>0?i.timeout:0,u=_normalizeKillSignal(i.killSignal),d=i.signal;return _execImpl(a,[o,`-c`,t],s,i,{cmd:t,encoding:i.encoding,maxBuffer:c,timeoutMs:l,killSignal:u,abortSignal:d,callback:r})}function _execImpl(e,t,n,r,i){let a=null,o=!1,s=null,d=null,armTimeout=t=>{i.timeoutMs&&(a=setTimeout(()=>{o=!0;try{t.send_signal(typeof i.killSignal==`number`?i.killSignal:15)}catch{}e.killed=!0},i.timeoutMs))},disarmTimeout=()=>{a!==null&&(clearTimeout(a),a=null)},armAbort=t=>{if(!i.abortSignal)return;let fire=()=>{s=Error(`The operation was aborted`),s.name=`AbortError`;try{t.send_signal(typeof i.killSignal==`number`?i.killSignal:15)}catch{}e.killed=!0};if(i.abortSignal.aborted){queueMicrotask(fire);return}d=fire,i.abortSignal.addEventListener(`abort`,d,{once:!0})},disarmAbort=()=>{i.abortSignal&&d&&(i.abortSignal.removeEventListener(`abort`,d),d=null)};try{let{proc:a,pid:d}=_spawnSubprocess(t,n,r);e._setSubprocess(a,d),u.add(e),c(),armTimeout(a),armAbort(a),a.communicate_async(null,null,(t,n)=>{disarmTimeout(),disarmAbort(),u.delete(e);try{let[,t,r]=a.communicate_finish(n),c=t?l(t):null,u=r?l(r):null,d=null;i.maxBuffer!==1/0&&c&&c.length>i.maxBuffer&&(c=c.subarray(0,i.maxBuffer),d=RangeError(`stdout maxBuffer length exceeded`),d.code=`ERR_CHILD_PROCESS_STDIO_MAXBUFFER`),!d&&i.maxBuffer!==1/0&&u&&u.length>i.maxBuffer&&(u=u.subarray(0,i.maxBuffer),d=RangeError(`stderr maxBuffer length exceeded`),d.code=`ERR_CHILD_PROCESS_STDIO_MAXBUFFER`);let f=_decodeExecOutput(c,i.encoding),p=_decodeExecOutput(u,i.encoding),m=a.get_if_exited()?a.get_exit_status():null,h=a.get_if_signaled()?typeof i.killSignal==`string`?i.killSignal:`SIGTERM`:null;e.exitCode=m,e.signalCode=h;let g=null;if(s)g=s,g.killed=!0,g.signal=h,g.stdout=f,g.stderr=p,g.cmd=i.cmd;else if(d)g=d,g.killed=e.killed,g.signal=h,g.stdout=f,g.stderr=p,g.cmd=i.cmd;else if(o)g=Error(`Command failed: ${i.cmd}`),g.killed=!0,g.code=null,g.signal=typeof i.killSignal==`string`?i.killSignal:`SIGTERM`,g.stdout=f,g.stderr=p,g.cmd=i.cmd;else if(m!==0&&m!==null){let t=typeof p==`string`?p:p.toString();g=Error(`Command failed: ${i.cmd}\n${t}`),g.code=m,g.killed=e.killed,g.signal=h,g.stdout=f,g.stderr=p,g.cmd=i.cmd}else h&&(g=Error(`Command failed: ${i.cmd}`),g.killed=!0,g.signal=h,g.code=null,g.stdout=f,g.stderr=p,g.cmd=i.cmd);i.callback&&i.callback(g,f,p),e.emit(`exit`,m,h),e.emit(`close`,m,h)}catch(t){let n=t instanceof Error?t:Error(String(t));i.callback&&i.callback(n,``,``),e.emit(`error`,n)}}),queueMicrotask(()=>e.emit(`spawn`))}catch(n){disarmTimeout(),disarmAbort();let r=_gioErrorToNodeError(n,t[0]??``,t.slice(1));setTimeout(()=>{i.callback&&i.callback(r,``,``),e.emit(`error`,r)},0)}return e}function execFile(t,n,r,i){let a=[],o={},s;typeof n==`function`?s=n:Array.isArray(n)?(a=n,typeof r==`function`?s=r:(o=r||{},s=i)):n&&typeof n==`object`&&(o=n,s=typeof r==`function`?r:i);let c=new ChildProcess,l=e.SubprocessFlags.STDOUT_PIPE|e.SubprocessFlags.STDERR_PIPE,u=o.maxBuffer??1024*1024,d=o.timeout&&o.timeout>0?o.timeout:0,f=_normalizeKillSignal(o.killSignal);return _execImpl(c,[t,...a],l,o,{cmd:t,encoding:o.encoding,maxBuffer:u,timeoutMs:d,killSignal:f,abortSignal:o.signal,callback:s})}function execFileSync(n,i,a){let o=[],s;Array.isArray(i)?(o=i,s=a):i&&typeof i==`object`&&(s=i);let c=s?.encoding,u=s?.input,d=e.SubprocessFlags.STDOUT_PIPE|e.SubprocessFlags.STDERR_PIPE|(u?e.SubprocessFlags.STDIN_PIPE:e.SubprocessFlags.NONE),f;try{({proc:f}=_spawnSubprocess([n,...o],d,s))}catch(e){throw _gioErrorToNodeError(e,n,o)}let p=u?new t.Bytes(typeof u==`string`?new TextEncoder().encode(u):u):null,[,m,h]=f.communicate(p,null),g=f.get_exit_status();if(g!==0){let e=h?new TextDecoder().decode(l(h)):``,t=m?new TextDecoder().decode(l(m)):``,i=Error(`Command failed: ${n} ${o.join(` `)}`);throw i.status=g,c===`buffer`||c===null?(i.stderr=h?r.from(l(h)):r.alloc(0),i.stdout=m?r.from(l(m)):r.alloc(0)):(i.stderr=e,i.stdout=t),i}if(!m)return c===`buffer`||c==null?r.alloc(0):``;let _=l(m);if(c===`buffer`||c==null)return r.from(_);let v=r.isEncoding(c)?c:`utf8`;return r.from(_).toString(v)}function spawn(t,n,r){let i,a;if(Array.isArray(n))i=n,a=r;else if(n!=null){if(typeof n!=`object`)throw TypeError(`The "args" argument must be of type object. Received type ${typeof n}`);i=void 0,a=n}else i=void 0,a=n;if(a!=null&&typeof a!=`object`)throw TypeError(`The "options" argument must be of type object. Received type ${typeof a}`);if(a?.argv0!==void 0&&a.argv0!==null&&typeof a.argv0!=`string`)throw TypeError(`The "options.argv0" property must be of type string. Received type ${typeof a.argv0}`);a?.cwd!==void 0&&_normalizeCwd(a.cwd);let o=i||[],l=new ChildProcess,d=a?.shell,f;f=d?[typeof d==`string`?d:`/bin/sh`,`-c`,[t,...o].join(` `)]:[t,...o];let p=a?.stdio,m=Array.isArray(p)?[typeof p[0]==`string`?p[0]:`pipe`,typeof p[1]==`string`?p[1]:`pipe`,typeof p[2]==`string`?p[2]:`pipe`]:typeof p==`string`?[p,p,p]:[`pipe`,`pipe`,`pipe`],h=e.SubprocessFlags.NONE;m[0]===`pipe`?h|=e.SubprocessFlags.STDIN_PIPE:m[0]===`inherit`&&(h|=e.SubprocessFlags.STDIN_INHERIT),m[1]===`pipe`&&(h|=e.SubprocessFlags.STDOUT_PIPE),m[1]===`ignore`&&(h|=e.SubprocessFlags.STDOUT_SILENCE),m[2]===`pipe`&&(h|=e.SubprocessFlags.STDERR_PIPE),m[2]===`ignore`&&(h|=e.SubprocessFlags.STDERR_SILENCE);try{let{proc:e,pid:t}=_spawnSubprocess(f,h,a);if(l._setSubprocess(e,t),u.add(l),m[0]===`pipe`){let t=e.get_stdin_pipe();t&&(l.stdin=new GioOutputStreamWritable(t))}let n=e.get_stdout_pipe();n&&(l.stdout=new GioInputStreamReadable(n));let r=e.get_stderr_pipe();r&&(l.stderr=new GioInputStreamReadable(r));let i=a?.signal,o=null,emitAbortError=()=>{let e=a?.killSignal??`SIGTERM`;l.kill(e);let t=Error(`The operation was aborted`);t.name=`AbortError`,l.emit(`error`,t)};i&&(i.aborted?queueMicrotask(emitAbortError):(o=emitAbortError,i.addEventListener(`abort`,o,{once:!0})));let s=null;if(a?.timeout&&a.timeout>0){let e=a.killSignal??`SIGTERM`;s=setTimeout(()=>{l.kill(e),s=null},a.timeout)}c(),e.wait_async(null,(t,n)=>{try{e.wait_finish(n);let t=e.get_if_exited()?e.get_exit_status():null,r=null;if(e.get_if_signaled()){let e=a?.killSignal;r=typeof e==`string`?e:`SIGTERM`}l.exitCode=t,l.signalCode=r,s!==null&&(clearTimeout(s),s=null),i&&o&&i.removeEventListener(`abort`,o),l.stdin&&!l.stdin.destroyed&&l.stdin.destroy(),l.emit(`exit`,t,r),l.emit(`close`,t,r)}catch(e){l.emit(`error`,e instanceof Error?e:Error(String(e)))}u.delete(l)}),queueMicrotask(()=>l.emit(`spawn`))}catch(e){s(l,`error`,_gioErrorToNodeError(e,d?t:f[0]??``,d?o:f.slice(1)))}return l}function spawnSync(n,i,a){let o,s;if(Array.isArray(i))o=i,s=a;else if(i!=null){if(typeof i!=`object`)throw TypeError(`The "args" argument must be of type object. Received type ${typeof i}`);o=void 0,s=i}else o=void 0,s=i;if(s!=null&&typeof s!=`object`)throw TypeError(`The "options" argument must be of type object. Received type ${typeof s}`);if(s?.argv0!==void 0&&s.argv0!==null&&typeof s.argv0!=`string`)throw TypeError(`The "options.argv0" property must be of type string. Received type ${typeof s.argv0}`);s?.cwd!==void 0&&_normalizeCwd(s.cwd);let c=o||[],u=s?.shell,d=s?.input,f;f=u?[typeof u==`string`?u:`/bin/sh`,`-c`,[n,...c].join(` `)]:[n,...c];let p=!1;if(s?.timeout&&s.timeout>0){let e=s.timeout/1e3,t=s.killSignal;f=[`/usr/bin/timeout`,`-s`,typeof t==`string`?t.replace(/^SIG/,``):`TERM`,String(e),...f],p=!0}let m=e.SubprocessFlags.STDOUT_PIPE|e.SubprocessFlags.STDERR_PIPE|(d?e.SubprocessFlags.STDIN_PIPE:e.SubprocessFlags.NONE),h=d;if(h!=null&&typeof h!=`string`&&!(h instanceof Uint8Array)&&!(h instanceof ArrayBuffer)&&!ArrayBuffer.isView(h))throw TypeError(`The "input" property must be of type string, Buffer, TypedArray, or DataView. Received type ${typeof h}`);let g=s?.encoding,_=g===`buffer`||g==null?r.alloc(0):``,v,y=0;try{({proc:v,pid:y}=_spawnSubprocess(f,m,s))}catch(e){let t=u?n:f[0]??``,r=u?c:f.slice(1);return{pid:0,output:[null,_,_],stdout:_,stderr:_,status:null,signal:null,error:_gioErrorToNodeError(e,t,r)}}let b=d?new t.Bytes(typeof d==`string`?new TextEncoder().encode(d):d):null,x,S,C=null;try{let e=v.communicate(b,null);x=e[1]??null,S=e[2]??null}catch(e){C=e instanceof Error?e:Error(String(e)),x=null,S=null}let w=x?r.from(l(x)):r.alloc(0),T=S?r.from(l(S)):r.alloc(0),decode=e=>{if(g===`buffer`||g==null)return e;let t=r.isEncoding(g)?g:`utf8`;return e.toString(t)},E=decode(w),D=decode(T),O=v.get_if_exited()?v.get_exit_status():null,k=null;if(v.get_if_signaled()){let e=s?.killSignal;k=typeof e==`string`?e:`SIGTERM`}let A=!1;p&&(O===124||O===137)&&(A=!0,k=typeof s?.killSignal==`string`?s.killSignal:`SIGTERM`);let j={pid:y,output:[null,E,D],stdout:E,stderr:D,status:A?null:O,signal:k};if(A){let e=Error(`Command failed: ${f.join(` `)}\n${typeof D==`string`?D:D.toString()}`);e.code=`ETIMEDOUT`,e.killed=!0,e.signal=k,j.error=e}else C&&(j.error=C);return j}var d={ChildProcess,exec:_exec,execSync,execFile,execFileSync,spawn,spawnSync};export{ChildProcess,d as default,_exec as exec,execFile,execFileSync,execSync,spawn,spawnSync};
|
|
1
|
+
import"./_virtual/_rolldown/runtime.js";import{communicateWithTimeout as e}from"./communicate.js";import{applyArgv0 as t,detachedPrefix as n,killProcess as r,shellArgv as i}from"./platform/index.js";import a from"@girs/glib-2.0";import o from"@girs/gio-2.0";import{EventEmitter as s}from"node:events";import{Buffer as c}from"node:buffer";import{Readable as l,Writable as u}from"node:stream";import{fileURLToPath as d}from"node:url";import{deferEmit as f,ensureMainLoop as p,gbytesToUint8Array as m}from"@gjsify/utils";var GioInputStreamReadable=class extends l{_stream;_cancellable=new o.Cancellable;constructor(e){super(),this._stream=e}_read(e){this._stream.read_bytes_async(Math.max(e,4096),a.PRIORITY_DEFAULT,this._cancellable,(e,t)=>{try{let e=this._stream.read_bytes_finish(t).get_data();!e||e.length===0?this.push(null):this.push(c.from(e))}catch(e){this._cancellable.is_cancelled()||this.destroy(e)}})}_destroy(e,t){this._cancellable.cancel(),t(e)}},GioOutputStreamWritable=class extends u{_stream;_cancellable=new o.Cancellable;_closed=!1;constructor(e){super(),this._stream=e}_write(e,t,n){if(this._closed){n(Error(`write after end`));return}let r=typeof e==`string`?c.from(e):e instanceof Uint8Array?e:c.from(e);this._stream.write_bytes_async(new a.Bytes(r),a.PRIORITY_DEFAULT,this._cancellable,(e,t)=>{try{this._stream.write_bytes_finish(t),n()}catch(e){this._cancellable.is_cancelled()?n():n(e)}})}_final(e){if(this._closed){e();return}this._closed=!0;try{this._stream.close(null)}catch{}e()}_destroy(e,t){if(this._cancellable.cancel(),!this._closed){this._closed=!0;try{this._stream.close(null)}catch{}}t(e)}};function _gioErrorToNodeError(e,t,n){let r=e??Error(`Unknown spawn error`),i=r,o=r.code,s=r.matches,c=!1;if(typeof s==`function`)try{c=s.call(r,a.SpawnError,a.SpawnError.NOENT)===!0}catch{}if(!c&&o===a.SpawnError.NOENT&&(c=!0),!c&&typeof r.message==`string`&&/No such file or directory|ENOENT|Failed to execute|nicht gefunden|nicht ausgeführt/i.test(r.message)&&(c=!0),c){let e=Error(`spawn ${t} ENOENT`);return e.code=`ENOENT`,e.errno=-2,e.syscall=`spawn ${t}`,e.path=t,e.spawnargs=n.slice(),e}if(r instanceof Error)return i;let l=r,u=typeof l.message==`string`?l.message:String(r),d=Error(u);return(typeof o==`number`||typeof o==`string`)&&(d.code=o),d}const h=new Set;var ChildProcess=class extends s{pid;exitCode=null;signalCode=null;killed=!1;connected=!1;stdin=null;stdout=null;stderr=null;get stdio(){return[this.stdin,this.stdout,this.stderr]}_subprocess=null;_setSubprocess(e,t){this._subprocess=e,t>0&&(this.pid=t)}kill(e){if(!this._subprocess)return!1;try{return r(this._subprocess,e??`SIGTERM`),this.killed=!0,!0}catch{return!1}}ref(){return this}unref(){return this}};function _normalizeCwd(e){if(e!=null){if(typeof e==`string`)return e;if(typeof e==`object`&&e&&typeof e.href==`string`&&typeof e.protocol==`string`){let t=e;if(t.protocol!==`file:`)throw TypeError(`The URL must be of scheme file:; received '${t.protocol}' for 'options.cwd'`);return d(t)}return e instanceof Uint8Array?new TextDecoder().decode(e):String(e)}}function _encodeEnvValue(e){if(e!==void 0)return`${e}`}function _spawnSubprocess(e,r,i){let a=new o.SubprocessLauncher({flags:r}),s=_normalizeCwd(i?.cwd);if(s!==void 0&&a.set_cwd(s),i?.env){let e=i.env;a.set_environ([]);let t=new Set;for(let n in e){if(t.has(n))continue;t.add(n);let r=_encodeEnvValue(e[n]);r!==void 0&&a.setenv(n,r,!0)}}let c=e;if(i?.argv0!==void 0&&i.argv0!==null){if(typeof i.argv0!=`string`)throw TypeError(`The "options.argv0" property must be of type string. Received type ${typeof i.argv0}`);c=t(i.argv0,e)}if(i?.detached===!0){let e=n();e!==null&&(c=[...e,...c])}let l=a.spawnv(c);return{proc:l,pid:_capturePidAtSpawn(l)}}function _capturePidAtSpawn(e){let t=e.get_identifier();if(t){let e=parseInt(t,10);if(e>0)return e}return 0}function _communicateSync(t,n,i,a){if(i<=0){let e=t.communicate(n,null);return{stdout:e[1]??null,stderr:e[2]??null,timedOut:!1}}let o=e(t,n,i,()=>{r(t,a??`SIGTERM`)});if(o.error)throw o.error;return{stdout:o.stdout,stderr:o.stderr,timedOut:o.timedOut}}function _syncTimeoutError(e,t,n,r,i){let a=t?m(t):new Uint8Array,o=n?m(n):new Uint8Array,s=new TextDecoder().decode(o),l=Error(`Command failed: ${e}\n${s}`);return l.code=`ETIMEDOUT`,l.killed=!0,l.signal=typeof i==`string`?i:`SIGTERM`,l.status=null,r===`buffer`||r===null?(l.stdout=c.from(a),l.stderr=c.from(o)):(l.stdout=new TextDecoder().decode(a),l.stderr=s),l}function execSync(e,t){let n=t?.encoding,r=t?.input,s=o.SubprocessFlags.STDOUT_PIPE|o.SubprocessFlags.STDERR_PIPE|(r?o.SubprocessFlags.STDIN_PIPE:o.SubprocessFlags.NONE),l=i(e,t?.shell),u;try{({proc:u}=_spawnSubprocess(l,s,t))}catch(e){throw _gioErrorToNodeError(e,l[0],l.slice(1))}let d=r?new a.Bytes(typeof r==`string`?new TextEncoder().encode(r):r):null,f=t?.timeout&&t.timeout>0?t.timeout:0,{stdout:p,stderr:h,timedOut:g}=_communicateSync(u,d,f,t?.killSignal);if(g)throw _syncTimeoutError(e,p,h,n,t?.killSignal);let _=u.get_exit_status();if(_!==0){let t=h?new TextDecoder().decode(m(h)):``,r=p?new TextDecoder().decode(m(p)):``,i=Error(`Command failed: ${e}\n${t}`);throw i.status=_,n===`buffer`||n===null?(i.stderr=h?c.from(m(h)):c.alloc(0),i.stdout=p?c.from(m(p)):c.alloc(0)):(i.stderr=t,i.stdout=r),i}if(!p)return n===`buffer`||n==null?c.alloc(0):``;let v=m(p);if(n===`buffer`||n==null)return c.from(v);let y=c.isEncoding(n)?n:`utf8`;return c.from(v).toString(y)}function _decodeExecOutput(e,t){let n=e??new Uint8Array;if(t===`buffer`||t===null)return c.from(n);let r=t&&c.isEncoding(t)?t:`utf8`;return c.from(n).toString(r)}function _normalizeKillSignal(e){return e??`SIGTERM`}function _exec(e,t,n){typeof t==`function`&&(n=t,t={});let r=t||{},a=new ChildProcess,s=o.SubprocessFlags.STDOUT_PIPE|o.SubprocessFlags.STDERR_PIPE,c=r.maxBuffer??1024*1024,l=r.timeout&&r.timeout>0?r.timeout:0,u=_normalizeKillSignal(r.killSignal),d=r.signal;return _execImpl(a,i(e,r.shell),s,r,{cmd:e,encoding:r.encoding,maxBuffer:c,timeoutMs:l,killSignal:u,abortSignal:d,callback:n})}function _absorbExecError(){}function _execImpl(e,t,n,i,a){e.on(`error`,_absorbExecError);let o=null,s=!1,c=null,l=null,armTimeout=t=>{a.timeoutMs&&(o=setTimeout(()=>{s=!0;try{r(t,a.killSignal)}catch{}e.killed=!0},a.timeoutMs))},disarmTimeout=()=>{o!==null&&(clearTimeout(o),o=null)},armAbort=t=>{if(!a.abortSignal)return;let fire=()=>{c=Error(`The operation was aborted`),c.name=`AbortError`;try{r(t,a.killSignal)}catch{}e.killed=!0};if(a.abortSignal.aborted){queueMicrotask(fire);return}l=fire,a.abortSignal.addEventListener(`abort`,l,{once:!0})},disarmAbort=()=>{a.abortSignal&&l&&(a.abortSignal.removeEventListener(`abort`,l),l=null)};try{let{proc:r,pid:o}=_spawnSubprocess(t,n,i);e._setSubprocess(r,o),h.add(e),p(),armTimeout(r),armAbort(r),r.communicate_async(null,null,(t,n)=>{disarmTimeout(),disarmAbort(),h.delete(e);try{let[,t,i]=r.communicate_finish(n),o=t?m(t):null,l=i?m(i):null,u=null;a.maxBuffer!==1/0&&o&&o.length>a.maxBuffer&&(o=o.subarray(0,a.maxBuffer),u=RangeError(`stdout maxBuffer length exceeded`),u.code=`ERR_CHILD_PROCESS_STDIO_MAXBUFFER`),!u&&a.maxBuffer!==1/0&&l&&l.length>a.maxBuffer&&(l=l.subarray(0,a.maxBuffer),u=RangeError(`stderr maxBuffer length exceeded`),u.code=`ERR_CHILD_PROCESS_STDIO_MAXBUFFER`);let d=_decodeExecOutput(o,a.encoding),f=_decodeExecOutput(l,a.encoding),p=r.get_if_exited()?r.get_exit_status():null,h=r.get_if_signaled()?typeof a.killSignal==`string`?a.killSignal:`SIGTERM`:null;e.exitCode=p,e.signalCode=h;let g=null;if(c)g=c,g.killed=!0,g.signal=h,g.stdout=d,g.stderr=f,g.cmd=a.cmd;else if(u)g=u,g.killed=e.killed,g.signal=h,g.stdout=d,g.stderr=f,g.cmd=a.cmd;else if(s)g=Error(`Command failed: ${a.cmd}`),g.killed=!0,g.code=null,g.signal=typeof a.killSignal==`string`?a.killSignal:`SIGTERM`,g.stdout=d,g.stderr=f,g.cmd=a.cmd;else if(p!==0&&p!==null){let t=typeof f==`string`?f:f.toString();g=Error(`Command failed: ${a.cmd}\n${t}`),g.code=p,g.killed=e.killed,g.signal=h,g.stdout=d,g.stderr=f,g.cmd=a.cmd}else h&&(g=Error(`Command failed: ${a.cmd}`),g.killed=!0,g.signal=h,g.code=null,g.stdout=d,g.stderr=f,g.cmd=a.cmd);a.callback&&a.callback(g,d,f),e.emit(`exit`,p,h),e.emit(`close`,p,h)}catch(t){let n=t instanceof Error?t:Error(String(t));a.callback&&a.callback(n,``,``),e.emit(`error`,n)}}),queueMicrotask(()=>e.emit(`spawn`))}catch(n){disarmTimeout(),disarmAbort();let r=_gioErrorToNodeError(n,t[0]??``,t.slice(1));setTimeout(()=>{a.callback&&a.callback(r,``,``),e.emit(`error`,r)},0)}return e}function execFile(e,t,n,r){let i=[],a={},s;typeof t==`function`?s=t:Array.isArray(t)?(i=t,typeof n==`function`?s=n:(a=n||{},s=r)):t&&typeof t==`object`&&(a=t,s=typeof n==`function`?n:r);let c=new ChildProcess,l=o.SubprocessFlags.STDOUT_PIPE|o.SubprocessFlags.STDERR_PIPE,u=a.maxBuffer??1024*1024,d=a.timeout&&a.timeout>0?a.timeout:0,f=_normalizeKillSignal(a.killSignal);return _execImpl(c,[e,...i],l,a,{cmd:e,encoding:a.encoding,maxBuffer:u,timeoutMs:d,killSignal:f,abortSignal:a.signal,callback:s})}function execFileSync(e,t,n){let r=[],i;Array.isArray(t)?(r=t,i=n):t&&typeof t==`object`&&(i=t);let s=i?.encoding,l=i?.input,u=o.SubprocessFlags.STDOUT_PIPE|o.SubprocessFlags.STDERR_PIPE|(l?o.SubprocessFlags.STDIN_PIPE:o.SubprocessFlags.NONE),d;try{({proc:d}=_spawnSubprocess([e,...r],u,i))}catch(t){throw _gioErrorToNodeError(t,e,r)}let f=l?new a.Bytes(typeof l==`string`?new TextEncoder().encode(l):l):null,p=i?.timeout&&i.timeout>0?i.timeout:0,{stdout:h,stderr:g,timedOut:_}=_communicateSync(d,f,p,i?.killSignal);if(_)throw _syncTimeoutError(`${e} ${r.join(` `)}`.trim(),h,g,s,i?.killSignal);let v=d.get_exit_status();if(v!==0){let t=g?new TextDecoder().decode(m(g)):``,n=h?new TextDecoder().decode(m(h)):``,i=Error(`Command failed: ${e} ${r.join(` `)}`);throw i.status=v,s===`buffer`||s===null?(i.stderr=g?c.from(m(g)):c.alloc(0),i.stdout=h?c.from(m(h)):c.alloc(0)):(i.stderr=t,i.stdout=n),i}if(!h)return s===`buffer`||s==null?c.alloc(0):``;let y=m(h);if(s===`buffer`||s==null)return c.from(y);let b=c.isEncoding(s)?s:`utf8`;return c.from(y).toString(b)}function spawn(e,t,n){let r,a;if(Array.isArray(t))r=t,a=n;else if(t!=null){if(typeof t!=`object`)throw TypeError(`The "args" argument must be of type object. Received type ${typeof t}`);r=void 0,a=t}else r=void 0,a=t;if(a!=null&&typeof a!=`object`)throw TypeError(`The "options" argument must be of type object. Received type ${typeof a}`);if(a?.argv0!==void 0&&a.argv0!==null&&typeof a.argv0!=`string`)throw TypeError(`The "options.argv0" property must be of type string. Received type ${typeof a.argv0}`);a?.cwd!==void 0&&_normalizeCwd(a.cwd);let s=r||[],c=new ChildProcess,l=a?.shell,u;u=l?i([e,...s].join(` `),l):[e,...s];let d=a?.stdio,m=Array.isArray(d)?[typeof d[0]==`string`?d[0]:`pipe`,typeof d[1]==`string`?d[1]:`pipe`,typeof d[2]==`string`?d[2]:`pipe`]:typeof d==`string`?[d,d,d]:[`pipe`,`pipe`,`pipe`],g=o.SubprocessFlags.NONE;m[0]===`pipe`?g|=o.SubprocessFlags.STDIN_PIPE:m[0]===`inherit`&&(g|=o.SubprocessFlags.STDIN_INHERIT),m[1]===`pipe`&&(g|=o.SubprocessFlags.STDOUT_PIPE),m[1]===`ignore`&&(g|=o.SubprocessFlags.STDOUT_SILENCE),m[2]===`pipe`&&(g|=o.SubprocessFlags.STDERR_PIPE),m[2]===`ignore`&&(g|=o.SubprocessFlags.STDERR_SILENCE);try{let{proc:e,pid:t}=_spawnSubprocess(u,g,a);if(c._setSubprocess(e,t),h.add(c),m[0]===`pipe`){let t=e.get_stdin_pipe();t&&(c.stdin=new GioOutputStreamWritable(t))}let n=e.get_stdout_pipe();n&&(c.stdout=new GioInputStreamReadable(n));let r=e.get_stderr_pipe();r&&(c.stderr=new GioInputStreamReadable(r));let i=a?.signal,o=null,emitAbortError=()=>{let e=a?.killSignal??`SIGTERM`;c.kill(e);let t=Error(`The operation was aborted`);t.name=`AbortError`,c.emit(`error`,t)};i&&(i.aborted?queueMicrotask(emitAbortError):(o=emitAbortError,i.addEventListener(`abort`,o,{once:!0})));let s=null;if(a?.timeout&&a.timeout>0){let e=a.killSignal??`SIGTERM`;s=setTimeout(()=>{c.kill(e),s=null},a.timeout)}p(),e.wait_async(null,(t,n)=>{try{e.wait_finish(n);let t=e.get_if_exited()?e.get_exit_status():null,r=null;if(e.get_if_signaled()){let e=a?.killSignal;r=typeof e==`string`?e:`SIGTERM`}c.exitCode=t,c.signalCode=r,s!==null&&(clearTimeout(s),s=null),i&&o&&i.removeEventListener(`abort`,o),c.stdin&&!c.stdin.destroyed&&c.stdin.destroy(),c.emit(`exit`,t,r),c.emit(`close`,t,r)}catch(e){c.emit(`error`,e instanceof Error?e:Error(String(e)))}h.delete(c)}),queueMicrotask(()=>c.emit(`spawn`))}catch(t){f(c,`error`,_gioErrorToNodeError(t,l?e:u[0]??``,l?s:u.slice(1)))}return c}function spawnSync(t,n,s){let l,u;if(Array.isArray(n))l=n,u=s;else if(n!=null){if(typeof n!=`object`)throw TypeError(`The "args" argument must be of type object. Received type ${typeof n}`);l=void 0,u=n}else l=void 0,u=n;if(u!=null&&typeof u!=`object`)throw TypeError(`The "options" argument must be of type object. Received type ${typeof u}`);if(u?.argv0!==void 0&&u.argv0!==null&&typeof u.argv0!=`string`)throw TypeError(`The "options.argv0" property must be of type string. Received type ${typeof u.argv0}`);u?.cwd!==void 0&&_normalizeCwd(u.cwd);let d=l||[],f=u?.shell,p=u?.input,h;h=f?i([t,...d].join(` `),f):[t,...d];let g=u?.timeout&&u.timeout>0?u.timeout:0,_=o.SubprocessFlags.STDOUT_PIPE|o.SubprocessFlags.STDERR_PIPE|(p?o.SubprocessFlags.STDIN_PIPE:o.SubprocessFlags.NONE),v=p;if(v!=null&&typeof v!=`string`&&!(v instanceof Uint8Array)&&!(v instanceof ArrayBuffer)&&!ArrayBuffer.isView(v))throw TypeError(`The "input" property must be of type string, Buffer, TypedArray, or DataView. Received type ${typeof v}`);let y=u?.encoding,b=y===`buffer`||y==null?c.alloc(0):``,x,S=0;try{({proc:x,pid:S}=_spawnSubprocess(h,_,u))}catch(e){let n=f?t:h[0]??``,r=f?d:h.slice(1);return{pid:0,output:[null,b,b],stdout:b,stderr:b,status:null,signal:null,error:_gioErrorToNodeError(e,n,r)}}let C=p?new a.Bytes(typeof p==`string`?new TextEncoder().encode(p):p):null,w,T,E=null,D=!1;try{if(g>0){let t=e(x,C,g,()=>{r(x,u?.killSignal??`SIGTERM`)});if(D=t.timedOut,t.error)throw t.error;w=t.stdout,T=t.stderr}else{let e=x.communicate(C,null);w=e[1]??null,T=e[2]??null}}catch(e){E=e instanceof Error?e:Error(String(e)),w=null,T=null}let O=w?c.from(m(w)):c.alloc(0),k=T?c.from(m(T)):c.alloc(0),decode=e=>{if(y===`buffer`||y==null)return e;let t=c.isEncoding(y)?y:`utf8`;return e.toString(t)},A=decode(O),j=decode(k),M=x.get_if_exited()?x.get_exit_status():null,N=null;if(x.get_if_signaled()){let e=u?.killSignal;N=typeof e==`string`?e:`SIGTERM`}D&&(N=typeof u?.killSignal==`string`?u.killSignal:`SIGTERM`);let P={pid:S,output:[null,A,j],stdout:A,stderr:j,status:D?null:M,signal:N};if(D){let e=Error(`Command failed: ${h.join(` `)}\n${typeof j==`string`?j:j.toString()}`);e.code=`ETIMEDOUT`,e.killed=!0,e.signal=N,P.error=e}else E&&(P.error=E);return P}var g={ChildProcess,exec:_exec,execSync,execFile,execFileSync,spawn,spawnSync};export{ChildProcess,g as default,_exec as exec,execFile,execFileSync,execSync,spawn,spawnSync};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{__exportAll as e}from"../_virtual/_rolldown/runtime.js";import{COMMON_SIGNALS as t,applyArgv0 as n,defaultShell as r,detachedPrefix as i,killProcess as a,shellArgv as o}from"./posix.js";var s=e({SIGNALS:()=>c,applyArgv0:()=>n,defaultShell:()=>r,detachedPrefix:()=>i,killProcess:()=>killProcess,shellArgv:()=>o});const c=Object.freeze({...t,SIGEMT:7,SIGBUS:10,SIGSYS:12,SIGURG:16,SIGSTOP:17,SIGTSTP:18,SIGCONT:19,SIGCHLD:20,SIGTTIN:21,SIGTTOU:22,SIGIO:23,SIGUSR1:30,SIGUSR2:31});function killProcess(e,t){a(e,t,c)}export{c as SIGNALS,n as applyArgv0,s as darwin_exports,r as defaultShell,i as detachedPrefix,killProcess,o as shellArgv};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import"../_virtual/_rolldown/runtime.js";import{COMMON_SIGNALS as e,applyArgv0 as t,defaultShell as n,detachedPrefix as r,killProcess as i,shellArgv as a}from"./posix.js";import{darwin_exports as o}from"./darwin.js";import{linux_exports as s}from"./linux.js";import{win32_exports as c}from"./win32.js";import l from"@girs/glib-2.0";const u={defaultShell:n,shellArgv:a,detachedPrefix:r,applyArgv0:t,killProcess:(t,n)=>i(t,n,e),SIGNALS:e};let d=null;function detectPlatform(){return d===null&&(d=l.get_current_dir().startsWith(`/`)?l.file_test(`/proc/self/status`,l.FileTest.EXISTS)?!l.file_test(`/bin/sh`,l.FileTest.IS_EXECUTABLE)&&l.file_test(`/system/bin/sh`,l.FileTest.IS_EXECUTABLE)?`android`:`linux`:l.file_test(`/System/Library/CoreServices/SystemVersion.plist`,l.FileTest.EXISTS)?`darwin`:`posix`:`win32`),d}function ops(){switch(detectPlatform()){case`win32`:return c;case`darwin`:return o;case`linux`:case`android`:return s;default:return u}}function defaultShell(){return ops().defaultShell()}function shellArgv(e,t){return ops().shellArgv(e,t)}function detachedPrefix(){return ops().detachedPrefix()}function applyArgv0(e,t){return ops().applyArgv0(e,t)}function killProcess(e,t){ops().killProcess(e,t)}function signalNumbers(){return ops().SIGNALS}function signalNumber(e){if(typeof e==`number`)return e;let t=signalNumbers();return typeof e==`string`&&t[e]!==void 0?t[e]:t.SIGTERM??15}export{applyArgv0,defaultShell,detachedPrefix,detectPlatform,killProcess,shellArgv,signalNumber,signalNumbers};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{__exportAll as e}from"../_virtual/_rolldown/runtime.js";import{COMMON_SIGNALS as t,applyArgv0 as n,defaultShell as r,detachedPrefix as i,killProcess as a,shellArgv as o}from"./posix.js";var s=e({SIGNALS:()=>c,applyArgv0:()=>n,defaultShell:()=>r,detachedPrefix:()=>i,killProcess:()=>killProcess,shellArgv:()=>o});const c=Object.freeze({...t,SIGBUS:7,SIGUSR1:10,SIGUSR2:12,SIGCHLD:17,SIGCONT:18,SIGSTOP:19,SIGTSTP:20,SIGTTIN:21,SIGTTOU:22,SIGURG:23,SIGIO:29,SIGPOLL:29,SIGPWR:30,SIGSYS:31});function killProcess(e,t){a(e,t,c)}export{c as SIGNALS,n as applyArgv0,r as defaultShell,i as detachedPrefix,killProcess,s as linux_exports,o as shellArgv};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import"../_virtual/_rolldown/runtime.js";import e from"@girs/glib-2.0";const t=Object.freeze({SIGHUP:1,SIGINT:2,SIGQUIT:3,SIGILL:4,SIGTRAP:5,SIGABRT:6,SIGIOT:6,SIGFPE:8,SIGKILL:9,SIGSEGV:11,SIGPIPE:13,SIGALRM:14,SIGTERM:15,SIGXCPU:24,SIGXFSZ:25,SIGVTALRM:26,SIGPROF:27,SIGWINCH:28});let n=null;function defaultShell(){return n===null&&(n=!e.file_test(`/bin/sh`,e.FileTest.IS_EXECUTABLE)&&e.file_test(`/system/bin/sh`,e.FileTest.IS_EXECUTABLE)?`/system/bin/sh`:`/bin/sh`),n}function shellArgv(e,t){return[typeof t==`string`&&t.length>0?t:defaultShell(),`-c`,e]}let r;function argv0Shell(){return r===void 0&&(r=e.find_program_in_path(`bash`)??e.find_program_in_path(`zsh`)),r??defaultShell()}function applyArgv0(e,t){return[argv0Shell(),`-c`,`exec -a "$0" "$@"`,e,...t]}let i;function detachedPrefix(){return i===void 0&&(i=e.find_program_in_path(`setsid`)),i===null?null:[i]}function killProcess(e,t,n){let r=t??`SIGTERM`;if(r===`SIGKILL`||r===9){e.force_exit();return}let i=typeof r==`number`?r:n[r]??n.SIGTERM;e.send_signal(i)}export{t as COMMON_SIGNALS,applyArgv0,defaultShell,detachedPrefix,killProcess,shellArgv};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{__exportAll as e}from"../_virtual/_rolldown/runtime.js";import t from"@girs/glib-2.0";var n=e({SIGNALS:()=>i,applyArgv0:()=>applyArgv0,defaultShell:()=>defaultShell,detachedPrefix:()=>detachedPrefix,killProcess:()=>killProcess,shellArgv:()=>shellArgv});const r=/^(?:.*\\)?cmd(?:\.exe)?$/i;function defaultShell(){return t.getenv(`ComSpec`)||`cmd.exe`}function shellArgv(e,t){let n=typeof t==`string`&&t.length>0?t:defaultShell();return r.test(n)?[n,`/d`,`/s`,`/c`,`"${e}"`]:[n,`-c`,e]}function detachedPrefix(){return null}function applyArgv0(e,t){let n=Error(`options.argv0 (${e}) is not supported on Windows: GSubprocess cannot decouple the executable path from the child's argv[0]`);throw n.code=`ERR_UNSUPPORTED_OPERATION`,n}function killProcess(e,t){e.force_exit()}const i=Object.freeze({SIGINT:2,SIGKILL:9,SIGTERM:15});export{i as SIGNALS,applyArgv0,defaultShell,detachedPrefix,killProcess,shellArgv,n as win32_exports};
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import GLib from '@girs/glib-2.0';
|
|
2
|
+
import type Gio from '@girs/gio-2.0';
|
|
3
|
+
export interface CommunicateResult {
|
|
4
|
+
stdout: GLib.Bytes | null;
|
|
5
|
+
stderr: GLib.Bytes | null;
|
|
6
|
+
/** `true` when the deadline elapsed and `onTimeout` was invoked. */
|
|
7
|
+
timedOut: boolean;
|
|
8
|
+
/** Error thrown by `communicate_finish()`, if any. */
|
|
9
|
+
error: unknown;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Run `proc.communicate()` semantics with a wall-clock deadline.
|
|
13
|
+
*
|
|
14
|
+
* Returns once the child's stdio has been fully drained and the child reaped —
|
|
15
|
+
* exactly like the blocking `communicate()`. When `timeoutMs` elapses first,
|
|
16
|
+
* `onTimeout` is invoked (the caller kills the child there) and the loop keeps
|
|
17
|
+
* running until the now-dying child closes its pipes, so the partial output is
|
|
18
|
+
* still returned. `timedOut` records that the deadline was hit.
|
|
19
|
+
*
|
|
20
|
+
* @param proc the spawned subprocess
|
|
21
|
+
* @param stdinBytes data to write to the child's stdin, or `null`
|
|
22
|
+
* @param timeoutMs deadline in milliseconds (must be > 0)
|
|
23
|
+
* @param onTimeout invoked on the deadline; expected to kill `proc`
|
|
24
|
+
*/
|
|
25
|
+
export declare function communicateWithTimeout(proc: Gio.Subprocess, stdinBytes: GLib.Bytes | null, timeoutMs: number, onTimeout: () => void): CommunicateResult;
|
package/lib/types/index.d.ts
CHANGED
|
@@ -3,7 +3,8 @@ import { EventEmitter } from 'node:events';
|
|
|
3
3
|
import { Buffer } from 'node:buffer';
|
|
4
4
|
import { Readable, Writable } from 'node:stream';
|
|
5
5
|
interface ExecError extends Error {
|
|
6
|
-
|
|
6
|
+
/** `null` when the child was signalled (timeout kill) — matches Node. */
|
|
7
|
+
status?: number | null;
|
|
7
8
|
code?: number | string;
|
|
8
9
|
errno?: number;
|
|
9
10
|
syscall?: string;
|
|
@@ -60,19 +61,35 @@ export interface SpawnOptions {
|
|
|
60
61
|
uid?: number;
|
|
61
62
|
gid?: number;
|
|
62
63
|
/**
|
|
63
|
-
* Override what the child process sees as `argv[0]`.
|
|
64
|
-
*
|
|
65
|
-
* `Gio.SubprocessLauncher` does not expose `set_child_setup` to GIR
|
|
64
|
+
* Override what the child process sees as `argv[0]`.
|
|
65
|
+
*
|
|
66
|
+
* `Gio.SubprocessLauncher` does not expose `set_child_setup` to GIR, so on
|
|
67
|
+
* POSIX this is implemented by wrapping the spawn through a shell's
|
|
68
|
+
* `exec -a "$0" "$@"`. Not expressible on Windows — throws there
|
|
69
|
+
* (`ERR_UNSUPPORTED_OPERATION`).
|
|
66
70
|
*/
|
|
67
71
|
argv0?: string;
|
|
68
72
|
/**
|
|
69
|
-
* Spawn the child as the leader of a new process group
|
|
70
|
-
*
|
|
73
|
+
* Spawn the child as the leader of a new session/process group so it
|
|
74
|
+
* survives the parent exiting.
|
|
75
|
+
*
|
|
76
|
+
* POSIX: uses `setsid(1)` resolved from PATH. When no `setsid` binary
|
|
77
|
+
* exists (stock macOS, Windows) the child is still spawned and still
|
|
78
|
+
* outlives the parent, but is not promoted to a session leader — see the
|
|
79
|
+
* package README for the exact per-platform contract.
|
|
71
80
|
*/
|
|
72
81
|
detached?: boolean;
|
|
73
|
-
/**
|
|
82
|
+
/**
|
|
83
|
+
* Accepted and ignored on every platform: `Gio.SubprocessLauncher` exposes
|
|
84
|
+
* no `CreateProcess` creation flags, so the console-window suppression
|
|
85
|
+
* Node performs on Windows is unreachable from GIR.
|
|
86
|
+
*/
|
|
74
87
|
windowsHide?: boolean;
|
|
75
|
-
/**
|
|
88
|
+
/**
|
|
89
|
+
* Accepted and ignored on every platform: GLib always builds the Windows
|
|
90
|
+
* command line itself (`protect_argv()`), so its argument quoting cannot
|
|
91
|
+
* be bypassed the way libuv's can.
|
|
92
|
+
*/
|
|
76
93
|
windowsVerbatimArguments?: boolean;
|
|
77
94
|
/**
|
|
78
95
|
* Allows aborting the child process via an `AbortController`. When the
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type Gio from '@girs/gio-2.0';
|
|
2
|
+
export { applyArgv0, defaultShell, detachedPrefix, shellArgv } from './posix.js';
|
|
3
|
+
/**
|
|
4
|
+
* macOS / BSD signal numbers (`/usr/include/sys/signal.h`). Note how far these
|
|
5
|
+
* drift from Linux: `SIGUSR1` is 30 here but 10 on Linux, `SIGSTOP` is 17 here
|
|
6
|
+
* but 19 on Linux. Sending the Linux number on macOS would deliver a
|
|
7
|
+
* completely different signal, which is why the table is per-platform.
|
|
8
|
+
*/
|
|
9
|
+
export declare const SIGNALS: Readonly<Record<string, number>>;
|
|
10
|
+
export declare function killProcess(proc: Gio.Subprocess, signal: string | number | undefined): void;
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import type Gio from '@girs/gio-2.0';
|
|
2
|
+
export type Platform = 'linux' | 'android' | 'darwin' | 'win32' | 'posix';
|
|
3
|
+
/**
|
|
4
|
+
* Detect the host platform once, from filesystem facts:
|
|
5
|
+
*
|
|
6
|
+
* - Windows — GLib returns native paths, so `g_get_current_dir()` is
|
|
7
|
+
* drive-rooted (`C:\…`) instead of `/`-rooted. This is the same probe
|
|
8
|
+
* `@gjsify/utils`' `getPathSeparator()` uses.
|
|
9
|
+
* - Linux — `/proc/self/status` exists (procfs is Linux-only; the kernel
|
|
10
|
+
* mounts it on every mainstream distribution and inside Flatpak/containers).
|
|
11
|
+
* - Android — a Linux kernel with a Bionic userland: no `/bin/sh`, but
|
|
12
|
+
* `/system/bin/sh`. Node reports this as `process.platform === 'android'`
|
|
13
|
+
* and picks a different default shell for it.
|
|
14
|
+
* - macOS — no procfs, but the system version plist is always present.
|
|
15
|
+
* - anything else — generic POSIX.
|
|
16
|
+
*/
|
|
17
|
+
export declare function detectPlatform(): Platform;
|
|
18
|
+
/** Node's default shell for `shell: true` on this platform. */
|
|
19
|
+
export declare function defaultShell(): string;
|
|
20
|
+
/**
|
|
21
|
+
* Full argv for a shell-mediated spawn — `[<shell>, ...switches, <command>]`.
|
|
22
|
+
* `shell` is the caller's `options.shell` (`true` → platform default, a string
|
|
23
|
+
* → that shell verbatim).
|
|
24
|
+
*/
|
|
25
|
+
export declare function shellArgv(command: string, shell: string | boolean | undefined): string[];
|
|
26
|
+
/**
|
|
27
|
+
* argv prefix implementing `detached: true`, or `null` when the platform has no
|
|
28
|
+
* reachable mechanism (see each platform module for the degraded contract).
|
|
29
|
+
*/
|
|
30
|
+
export declare function detachedPrefix(): string[] | null;
|
|
31
|
+
/** Rewrite argv so the child sees `argv0` as `argv[0]`. Throws on Windows. */
|
|
32
|
+
export declare function applyArgv0(argv0: string, argv: string[]): string[];
|
|
33
|
+
/** Deliver a signal (name or number) to a live `Gio.Subprocess`. */
|
|
34
|
+
export declare function killProcess(proc: Gio.Subprocess, signal: string | number | undefined): void;
|
|
35
|
+
/** This platform's signal-name → number table. */
|
|
36
|
+
export declare function signalNumbers(): Readonly<Record<string, number>>;
|
|
37
|
+
/**
|
|
38
|
+
* Resolve a signal name/number to this platform's numeric value, falling back
|
|
39
|
+
* to `SIGTERM` for unknown names — the same lenient behaviour Gio's own kill
|
|
40
|
+
* paths use.
|
|
41
|
+
*/
|
|
42
|
+
export declare function signalNumber(signal: string | number | undefined): number;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type Gio from '@girs/gio-2.0';
|
|
2
|
+
export { applyArgv0, defaultShell, detachedPrefix, shellArgv } from './posix.js';
|
|
3
|
+
/**
|
|
4
|
+
* Linux signal numbers (`signal(7)`, `asm-generic/signal.h`). Differs from BSD /
|
|
5
|
+
* macOS for `SIGBUS`, `SIGUSR1`, `SIGUSR2`, `SIGCHLD`, `SIGCONT`, `SIGSTOP`,
|
|
6
|
+
* `SIGTSTP`, `SIGURG`, `SIGIO` and `SIGSYS` — see `darwin.ts`.
|
|
7
|
+
*/
|
|
8
|
+
export declare const SIGNALS: Readonly<Record<string, number>>;
|
|
9
|
+
export declare function killProcess(proc: Gio.Subprocess, signal: string | number | undefined): void;
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import type Gio from '@girs/gio-2.0';
|
|
2
|
+
/**
|
|
3
|
+
* Signal numbers that are identical across every POSIX platform we target
|
|
4
|
+
* (Linux, macOS/BSD). The ones that DIFFER — `SIGUSR1`, `SIGUSR2`, `SIGCHLD`,
|
|
5
|
+
* `SIGCONT`, `SIGSTOP`, `SIGBUS`, … — live in `linux.ts` / `darwin.ts`, which
|
|
6
|
+
* spread this table and then override.
|
|
7
|
+
*/
|
|
8
|
+
export declare const COMMON_SIGNALS: Readonly<Record<string, number>>;
|
|
9
|
+
/**
|
|
10
|
+
* Node's default shell for `shell: true` on POSIX.
|
|
11
|
+
*
|
|
12
|
+
* `refs/node/lib/child_process.js` picks `/system/bin/sh` when
|
|
13
|
+
* `process.platform === 'android'` and `/bin/sh` otherwise. We probe for the
|
|
14
|
+
* binaries instead of the platform string: an Android/Bionic userland has no
|
|
15
|
+
* `/bin/sh`, so the probe reproduces Node's choice without needing to know
|
|
16
|
+
* which libc we are on. Cached — the answer cannot change within a process.
|
|
17
|
+
*/
|
|
18
|
+
export declare function defaultShell(): string;
|
|
19
|
+
/**
|
|
20
|
+
* Build the full argv for a `shell: true` / `shell: '<path>'` spawn.
|
|
21
|
+
* Mirrors Node's POSIX branch verbatim: `<shell> -c <command>`.
|
|
22
|
+
*/
|
|
23
|
+
export declare function shellArgv(command: string, shell: string | boolean | undefined): string[];
|
|
24
|
+
/**
|
|
25
|
+
* Rewrite argv so the child sees `argv0` as its `argv[0]`.
|
|
26
|
+
*
|
|
27
|
+
* `Gio.SubprocessLauncher` does not expose `g_subprocess_launcher_set_child_setup()`
|
|
28
|
+
* to GObject-Introspection (it is `(skip)`-annotated because it takes a raw C
|
|
29
|
+
* function pointer), and `GSubprocess` never sets `G_SPAWN_FILE_AND_ARGV_ZERO`,
|
|
30
|
+
* so there is no way to reach `execve()`'s argv[0] from JS. The shell's
|
|
31
|
+
* `exec -a "$0" "$@"` performs exactly the same syscall, at the cost of one
|
|
32
|
+
* extra short-lived process.
|
|
33
|
+
*/
|
|
34
|
+
export declare function applyArgv0(argv0: string, argv: string[]): string[];
|
|
35
|
+
/**
|
|
36
|
+
* argv prefix that promotes the child to a new session / process-group leader
|
|
37
|
+
* (Node's `detached: true`), or `null` when no such helper exists here.
|
|
38
|
+
*
|
|
39
|
+
* `setsid(2)` itself is unreachable from JS for the same introspection reason
|
|
40
|
+
* as `argv0` above, so we shell out to `setsid(1)` (util-linux). It is resolved
|
|
41
|
+
* from PATH rather than hard-coded to `/usr/bin/setsid` so distributions that
|
|
42
|
+
* install it elsewhere (Nix, Alpine, `/bin/setsid`) keep working.
|
|
43
|
+
*
|
|
44
|
+
* macOS ships no `setsid(1)`, so this returns `null` there unless the user
|
|
45
|
+
* installed one (e.g. Homebrew `util-linux`). See `darwin.ts` for the exact
|
|
46
|
+
* degraded contract.
|
|
47
|
+
*/
|
|
48
|
+
export declare function detachedPrefix(): string[] | null;
|
|
49
|
+
/**
|
|
50
|
+
* Deliver `signal` to a running `Gio.Subprocess`.
|
|
51
|
+
*
|
|
52
|
+
* `SIGKILL` routes through `force_exit()` (Gio's dedicated kernel-level path);
|
|
53
|
+
* everything else is translated through the platform's signal table and sent
|
|
54
|
+
* via `send_signal()`. Unknown names fall back to `SIGTERM`, which is what
|
|
55
|
+
* Gio's own kill paths use.
|
|
56
|
+
*/
|
|
57
|
+
export declare function killProcess(proc: Gio.Subprocess, signal: string | number | undefined, signals: Readonly<Record<string, number>>): void;
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import type Gio from '@girs/gio-2.0';
|
|
2
|
+
/**
|
|
3
|
+
* Node's default shell on Windows: `process.env.comspec || 'cmd.exe'`.
|
|
4
|
+
* `g_getenv()` maps onto `GetEnvironmentVariable()`, which is case-insensitive,
|
|
5
|
+
* so a single lookup covers `ComSpec` / `COMSPEC` / `comspec`.
|
|
6
|
+
*/
|
|
7
|
+
export declare function defaultShell(): string;
|
|
8
|
+
/**
|
|
9
|
+
* Build the full argv for a `shell: true` / `shell: '<path>'` spawn.
|
|
10
|
+
*
|
|
11
|
+
* Mirrors Node's win32 branch: `cmd.exe` gets `/d /s /c "<command>"` (the extra
|
|
12
|
+
* quoting is what makes `cmd` treat the whole string as one command), any other
|
|
13
|
+
* shell gets the POSIX `-c <command>` form.
|
|
14
|
+
*
|
|
15
|
+
* Node additionally forces `windowsVerbatimArguments = true` for the `cmd` case
|
|
16
|
+
* so libuv does not re-quote the already-quoted string. GLib has no equivalent
|
|
17
|
+
* opt-out — `g_spawn_*` always runs argv through its own `protect_argv()` — so
|
|
18
|
+
* a command containing embedded double quotes may be quoted differently than
|
|
19
|
+
* under Node. See `windowsVerbatimArguments` in the package README.
|
|
20
|
+
*/
|
|
21
|
+
export declare function shellArgv(command: string, shell: string | boolean | undefined): string[];
|
|
22
|
+
/**
|
|
23
|
+
* Windows has no sessions/process groups in the POSIX sense; Node implements
|
|
24
|
+
* `detached` with `DETACHED_PROCESS` / `CREATE_NEW_PROCESS_GROUP` flags passed
|
|
25
|
+
* to `CreateProcess()`. `Gio.SubprocessLauncher` exposes no way to set
|
|
26
|
+
* `CreateProcess` creation flags, so there is nothing to prepend.
|
|
27
|
+
*
|
|
28
|
+
* DEGRADED CONTRACT: `detached: true` is accepted and the child is spawned
|
|
29
|
+
* normally. It is NOT placed in its own process group, so a console Ctrl-C
|
|
30
|
+
* event still reaches it. (The child does still outlive the parent — GIO does
|
|
31
|
+
* not put children in a job object.)
|
|
32
|
+
*/
|
|
33
|
+
export declare function detachedPrefix(): string[] | null;
|
|
34
|
+
/**
|
|
35
|
+
* `argv0` cannot be honoured on Windows.
|
|
36
|
+
*
|
|
37
|
+
* There is no `exec -a` in `cmd.exe`, and `CreateProcess()`'s `lpCommandLine`
|
|
38
|
+
* is built by GLib's `protect_argv()` from `argv[0]` — `GSubprocess` never sets
|
|
39
|
+
* `G_SPAWN_FILE_AND_ARGV_ZERO`, so the executable path and the child's
|
|
40
|
+
* `argv[0]` cannot be decoupled through any introspectable API.
|
|
41
|
+
*
|
|
42
|
+
* We throw rather than silently ignore the option: a caller that asked for a
|
|
43
|
+
* specific `argv[0]` has no way to detect that it did not happen, and running
|
|
44
|
+
* the child with the wrong name is a correctness bug, not a cosmetic one.
|
|
45
|
+
*/
|
|
46
|
+
export declare function applyArgv0(argv0: string, _argv: string[]): string[];
|
|
47
|
+
/**
|
|
48
|
+
* Windows signal numbers are meaningless — `g_subprocess_send_signal()` is a
|
|
49
|
+
* documented no-op there. Node maps `SIGTERM`/`SIGKILL`/`SIGINT` onto
|
|
50
|
+
* `TerminateProcess()`; `force_exit()` is Gio's binding for exactly that, so
|
|
51
|
+
* every signal takes it.
|
|
52
|
+
*/
|
|
53
|
+
export declare function killProcess(proc: Gio.Subprocess, _signal: string | number | undefined): void;
|
|
54
|
+
/** Placeholder so the module shape matches `linux.ts` / `darwin.ts`. */
|
|
55
|
+
export declare const SIGNALS: Readonly<Record<string, number>>;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gjsify/child_process",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.23.0",
|
|
4
4
|
"description": "Node.js child_process module for Gjs",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"module": "lib/esm/index.js",
|
|
@@ -33,18 +33,18 @@
|
|
|
33
33
|
"child_process"
|
|
34
34
|
],
|
|
35
35
|
"devDependencies": {
|
|
36
|
-
"@gjsify/cli": "^0.
|
|
37
|
-
"@gjsify/dom-elements": "^0.
|
|
38
|
-
"@gjsify/unit": "^0.
|
|
36
|
+
"@gjsify/cli": "^0.23.0",
|
|
37
|
+
"@gjsify/dom-elements": "^0.23.0",
|
|
38
|
+
"@gjsify/unit": "^0.23.0",
|
|
39
39
|
"@types/node": "^25.9.2",
|
|
40
40
|
"typescript": "^6.0.3"
|
|
41
41
|
},
|
|
42
42
|
"dependencies": {
|
|
43
43
|
"@girs/gio-2.0": "^4.1.0",
|
|
44
44
|
"@girs/glib-2.0": "^4.1.0",
|
|
45
|
-
"@gjsify/buffer": "^0.
|
|
46
|
-
"@gjsify/events": "^0.
|
|
47
|
-
"@gjsify/utils": "^0.
|
|
45
|
+
"@gjsify/buffer": "^0.23.0",
|
|
46
|
+
"@gjsify/events": "^0.23.0",
|
|
47
|
+
"@gjsify/utils": "^0.23.0"
|
|
48
48
|
},
|
|
49
49
|
"gjsify": {
|
|
50
50
|
"runtimes": {
|