@@ -3,12 +3,14 @@ import { SpawnOptions } from 'child_process';
3
3
import * as child_process from 'child_process' ;
4
4
import { concat , defer , EMPTY , from } from 'rxjs' ;
5
5
import { repeat , takeLast } from 'rxjs/operators' ;
6
- import { getGlobalVariable } from './env' ;
6
+ import { getGlobalVariable , getGlobalVariablesEnv } from './env' ;
7
7
import { catchError } from 'rxjs/operators' ;
8
+ import { delimiter , join , resolve } from 'path' ;
8
9
const treeKill = require ( 'tree-kill' ) ;
9
10
10
11
interface ExecOptions {
11
12
silent ?: boolean ;
13
+ announce ?: boolean ;
12
14
waitForMatch ?: RegExp ;
13
15
env ?: { [ varname : string ] : string } ;
14
16
stdin ?: string ;
@@ -24,18 +26,22 @@ export type ProcessOutput = {
24
26
stderr : string ;
25
27
} ;
26
28
27
- function _exec ( options : ExecOptions , cmd : string , args : string [ ] ) : Promise < ProcessOutput > {
29
+ async function _exec ( options : ExecOptions , cmd : string , args : string [ ] ) : Promise < ProcessOutput > {
28
30
// Create a separate instance to prevent unintended global changes to the color configuration
29
31
// Create function is not defined in the typings. See: https://github.com/doowb/ansi-colors/pull/44
30
32
const colors = ( ansiColors as typeof ansiColors & { create : ( ) => typeof ansiColors } ) . create ( ) ;
31
33
34
+ const announce = options . announce ?? true ;
35
+
32
36
let stdout = '' ;
33
37
let stderr = '' ;
34
38
const cwd = options . cwd ?? process . cwd ( ) ;
35
39
const env = options . env ;
36
- console . log (
37
- `==========================================================================================` ,
38
- ) ;
40
+ if ( announce ) {
41
+ console . log (
42
+ `==========================================================================================` ,
43
+ ) ;
44
+ }
39
45
40
46
args = args . filter ( ( x ) => x !== undefined ) ;
41
47
const flags = [
@@ -46,9 +52,15 @@ function _exec(options: ExecOptions, cmd: string, args: string[]): Promise<Proce
46
52
. join ( ', ' )
47
53
. replace ( / ^ ( .+ ) $ / , ' [$1]' ) ; // Proper formatting.
48
54
49
- console . log ( colors . blue ( `Running \`${ cmd } ${ args . map ( ( x ) => `"${ x } "` ) . join ( ' ' ) } \`${ flags } ...` ) ) ;
50
- console . log ( colors . blue ( `CWD: ${ cwd } ` ) ) ;
51
- console . log ( colors . blue ( `ENV: ${ JSON . stringify ( env ) } ` ) ) ;
55
+ if ( announce ) {
56
+ console . log (
57
+ colors . blue ( `Running \`${ cmd } ${ args . map ( ( x ) => `"${ x } "` ) . join ( ' ' ) } \`${ flags } ...` ) ,
58
+ ) ;
59
+ console . log ( colors . blue ( `CWD: ${ cwd } ` ) ) ;
60
+
61
+ console . log ( colors . blue ( `ENV: ${ JSON . stringify ( env ) } ` ) ) ;
62
+ }
63
+
52
64
const spawnOptions : SpawnOptions = {
53
65
cwd,
54
66
...( env ? { env } : { } ) ,
@@ -140,7 +152,7 @@ function _exec(options: ExecOptions, cmd: string, args: string[]): Promise<Proce
140
152
} ) ;
141
153
}
142
154
143
- export function extractNpmEnv ( ) {
155
+ export function extractNpmEnv ( ) : { [ k : string ] : string } {
144
156
return Object . keys ( process . env )
145
157
. filter ( ( v ) => NPM_CONFIG_RE . test ( v ) )
146
158
. reduce (
@@ -154,6 +166,16 @@ export function extractNpmEnv() {
154
166
) ;
155
167
}
156
168
169
+ function getNpmSandboxEnv ( ) : { [ k : string ] : string } {
170
+ const tempRoot : string = getGlobalVariable ( 'tmp-root' ) ;
171
+ const npmModulesPrefix : string = getGlobalVariable ( 'npm-root' ) ;
172
+
173
+ return {
174
+ NPM_CONFIG_USERCONFIG : join ( tempRoot , '.npmrc' ) ,
175
+ NPM_CONFIG_PREFIX : npmModulesPrefix ,
176
+ } ;
177
+ }
178
+
157
179
export function waitForAnyProcessOutputToMatch (
158
180
match : RegExp ,
159
181
timeout = 30000 ,
@@ -299,22 +321,21 @@ export function silentNpm(
299
321
{
300
322
silent : true ,
301
323
cwd : ( options as { cwd ?: string } | undefined ) ?. cwd ,
302
- env : extractNpmEnv ( ) ,
303
324
} ,
304
325
'npm' ,
305
326
params ,
306
327
) ;
307
328
} else {
308
- return _exec ( { silent : true , env : extractNpmEnv ( ) } , 'npm' , args as string [ ] ) ;
329
+ return _exec ( { silent : true } , 'npm' , args as string [ ] ) ;
309
330
}
310
331
}
311
332
312
333
export function silentYarn ( ...args : string [ ] ) {
313
- return _exec ( { silent : true , env : extractNpmEnv ( ) } , 'yarn' , args ) ;
334
+ return _exec ( { silent : true } , 'yarn' , args ) ;
314
335
}
315
336
316
337
export function npm ( ...args : string [ ] ) {
317
- return _exec ( { env : extractNpmEnv ( ) } , 'npm' , args ) ;
338
+ return _exec ( { } , 'npm' , args ) ;
318
339
}
319
340
320
341
export function node ( ...args : string [ ] ) {
@@ -328,3 +349,40 @@ export function git(...args: string[]) {
328
349
export function silentGit ( ...args : string [ ] ) {
329
350
return _exec ( { silent : true } , 'git' , args ) ;
330
351
}
352
+
353
+ /**
354
+ * Launch the given entry in an child process isolated to the test environment.
355
+ *
356
+ * The test environment includes the local NPM registry, isolated NPM globals,
357
+ * the PATH variable only referencing the local node_modules and local NPM
358
+ * registry (not the test runner or standard global node_modules).
359
+ */
360
+ export async function launchTestProcess ( entry : string , ...args : any [ ] ) {
361
+ const tempRoot : string = getGlobalVariable ( 'tmp-root' ) ;
362
+
363
+ // Extract explicit environment variables for the test process.
364
+ const env = {
365
+ ...extractNpmEnv ( ) ,
366
+ ...getGlobalVariablesEnv ( ) ,
367
+ ...getNpmSandboxEnv ( ) ,
368
+ } ;
369
+
370
+ // Modify the PATH environment variable...
371
+ let paths = process . env . PATH . split ( delimiter ) ;
372
+
373
+ // Only include paths within the sandboxed test environment or external
374
+ // non angular-cli paths such as /usr/bin for generic commands.
375
+ paths = paths . filter ( ( p ) => p . startsWith ( tempRoot ) || ! p . includes ( 'angular-cli' ) ) ;
376
+
377
+ // Ensure the custom npm global bin is on the PATH
378
+ // https://docs.npmjs.com/cli/v8/configuring-npm/folders#executables
379
+ if ( process . platform . startsWith ( 'win' ) ) {
380
+ paths . unshift ( env . NPM_CONFIG_PREFIX ) ;
381
+ } else {
382
+ paths . unshift ( join ( env . NPM_CONFIG_PREFIX , 'bin' ) ) ;
383
+ }
384
+
385
+ env . PATH = paths . join ( delimiter ) ;
386
+
387
+ return _exec ( { env } , process . execPath , [ resolve ( __dirname , 'run_test_process' ) , entry , ...args ] ) ;
388
+ }
0 commit comments