1
- import { StdioOptions , spawn , ChildProcess } from 'child_process' ;
2
1
import fs from 'fs' ;
3
2
import path from 'path' ;
4
3
import semver from 'semver' ;
@@ -7,11 +6,9 @@ import * as debugUtils from './debugUtil
7
6
import * as folderUtils from './folderUtils' ;
8
7
import * as fsUtils from './fsUtils' ;
9
8
import * as httpUtils from './httpUtils' ;
10
- import { Context } from './main ' ;
9
+ import * as nodeUtils from './nodeUtils ' ;
11
10
import { RegistrySpec , Descriptor , Locator , PackageManagerSpec } from './types' ;
12
11
13
- declare const __non_webpack_require__ : unknown ;
14
-
15
12
export async function fetchAvailableTags ( spec : RegistrySpec ) : Promise < Record < string , string > > {
16
13
switch ( spec . type ) {
17
14
case `npm` : {
@@ -133,7 +130,10 @@ export async function installVersion(installTarget: string, locator: Locator, {s
133
130
return installFolder ;
134
131
}
135
132
136
- export async function runVersion ( installSpec : { location : string , spec : PackageManagerSpec } , locator : Locator , binName : string , args : Array < string > , context : Context ) {
133
+ /**
134
+ * Loads the binary, taking control of the current process.
135
+ */
136
+ export async function runVersion ( installSpec : { location : string , spec : PackageManagerSpec } , binName : string , args : Array < string > ) : Promise < void > {
137
137
let binPath : string | null = null ;
138
138
if ( Array . isArray ( installSpec . spec . bin ) ) {
139
139
if ( installSpec . spec . bin . some ( bin => bin === binName ) ) {
@@ -155,82 +155,23 @@ export async function runVersion(installSpec: { location: string, spec: PackageM
155
155
if ( ! binPath )
156
156
throw new Error ( `Assertion failed: Unable to locate path for bin '${ binName } '` ) ;
157
157
158
- return new Promise < number > ( ( resolve , reject ) => {
159
- process . on ( `SIGINT` , ( ) => {
160
- // We don't want to exit the process before the child, so we just
161
- // ignore SIGINT and wait for the regular exit to happen (the child
162
- // will receive SIGINT too since it's part of the same process grp)
163
- } ) ;
164
-
165
- const stdio : StdioOptions = [ `pipe` , `pipe` , `pipe` ] ;
166
-
167
- if ( context . stdin === process . stdin )
168
- stdio [ 0 ] = `inherit` ;
169
- if ( context . stdout === process . stdout )
170
- stdio [ 1 ] = `inherit` ;
171
- if ( context . stderr === process . stderr )
172
- stdio [ 2 ] = `inherit` ;
173
-
174
- const v8CompileCache = typeof __non_webpack_require__ !== `undefined`
175
- ? eval ( `require` ) . resolve ( `./vcc.js` )
176
- : eval ( `require` ) . resolve ( `corepack/dist/vcc.js` ) ;
177
-
178
- const child = spawn ( process . execPath , [ `--require` , v8CompileCache , binPath ! , ...args ] , {
179
- cwd : context . cwd ,
180
- stdio,
181
- env : {
182
- ...process . env ,
183
- COREPACK_ROOT : path . dirname ( eval ( `__dirname` ) ) ,
184
- } ,
185
- } ) ;
186
-
187
- activeChildren . add ( child ) ;
188
-
189
- if ( activeChildren . size === 1 ) {
190
- process . on ( `SIGINT` , sigintHandler ) ;
191
- process . on ( `SIGTERM` , sigtermHandler ) ;
192
- }
193
-
194
- if ( context . stdin !== process . stdin )
195
- context . stdin . pipe ( child . stdin ! ) ;
196
- if ( context . stdout !== process . stdout )
197
- child . stdout ! . pipe ( context . stdout ) ;
198
- if ( context . stderr !== process . stderr )
199
- child . stderr ! . pipe ( context . stderr ) ;
158
+ nodeUtils . registerV8CompileCache ( ) ;
200
159
201
- child . on ( `error` , error => {
202
- activeChildren . delete ( child ) ;
160
+ // We load the binary into the current process,
161
+ // while making it think it was spawned.
203
162
204
- if ( activeChildren . size === 0 ) {
205
- process . off ( `SIGINT` , sigintHandler ) ;
206
- process . off ( `SIGTERM` , sigtermHandler ) ;
207
- }
163
+ // Non-exhaustive list of requirements:
164
+ // - Yarn uses process.argv[1] to determine its own path: https://github.com/yarnpkg/berry/blob/0da258120fc266b06f42aed67e4227e81a2a900f/packages/yarnpkg-cli/sources/main.ts#L80
165
+ // - pnpm uses `require.main == null` to determine its own version: https://github.com/pnpm/pnpm/blob/e2866dee92991e979b2b0e960ddf5a74f6845d90/packages/cli-meta/src/index.ts#L14
208
166
209
- reject ( error ) ;
210
- } ) ;
167
+ process . env . COREPACK_ROOT = path . dirname ( eval ( `__dirname` ) ) ;
211
168
212
- child . on ( `exit` , exitCode => {
213
- activeChildren . delete ( child ) ;
169
+ process . argv = [
170
+ process . execPath ,
171
+ binPath ,
172
+ ...args ,
173
+ ] ;
174
+ process . execArgv = [ ] ;
214
175
215
- if ( activeChildren . size === 0 ) {
216
- process . off ( `SIGINT` , sigintHandler ) ;
217
- process . off ( `SIGTERM` , sigtermHandler ) ;
218
- }
219
-
220
- resolve ( exitCode !== null ? exitCode : 1 ) ;
221
- } ) ;
222
- } ) ;
223
- }
224
-
225
- const activeChildren = new Set < ChildProcess > ( ) ;
226
-
227
- function sigintHandler ( ) {
228
- // We don't want SIGINT to kill our process; we want it to kill the
229
- // innermost process, whose end will cause our own to exit.
230
- }
231
-
232
- function sigtermHandler ( ) {
233
- for ( const child of activeChildren ) {
234
- child . kill ( ) ;
235
- }
176
+ return nodeUtils . loadMainModule ( binPath ) ;
236
177
}
0 commit comments