1
1
import * as path from "path" ;
2
+ import { BasePackageManager } from "./base-package-manager" ;
2
3
import { exported , cache } from "./common/decorators" ;
3
- import { isInteractive } from "./common/helpers" ;
4
4
import { CACACHE_DIRECTORY_NAME } from "./constants" ;
5
5
6
- export class NodePackageManager implements INodePackageManager {
6
+ export class NodePackageManager extends BasePackageManager implements INodePackageManager {
7
7
private static SCOPED_DEPENDENCY_REGEXP = / ^ ( @ .+ ?) (?: @ ( .+ ?) ) ? $ / ;
8
8
private static DEPENDENCY_REGEXP = / ^ ( .+ ?) (?: @ ( .+ ?) ) ? $ / ;
9
9
10
- constructor ( private $fs : IFileSystem ,
11
- private $hostInfo : IHostInfo ,
10
+ constructor (
11
+ $childProcess : IChildProcess ,
12
12
private $errors : IErrors ,
13
- private $childProcess : IChildProcess ,
13
+ private $fs : IFileSystem ,
14
+ $hostInfo : IHostInfo ,
14
15
private $logger : ILogger ,
15
- private $httpClient : Server . IHttpClient ) { }
16
+ private $httpClient : Server . IHttpClient ) {
17
+ super ( $childProcess , $hostInfo , 'npm' ) ;
18
+ }
16
19
17
20
@exported ( "npm" )
18
21
public async install ( packageName : string , pathToSave : string , config : INodePackageManagerInstallOptions ) : Promise < INpmInstallResultInfo > {
@@ -53,7 +56,7 @@ export class NodePackageManager implements INodePackageManager {
53
56
}
54
57
55
58
try {
56
- const spawnResult : ISpawnResult = await this . getNpmInstallResult ( params , cwd ) ;
59
+ const spawnResult : ISpawnResult = await this . processPackageManagerInstall ( params , { cwd } ) ;
57
60
58
61
// Whenever calling npm install without any arguments (hence installing all dependencies) no output is emitted on stdout
59
62
// Luckily, whenever you call npm install to install all dependencies chances are you won't need the name/version of the package you're installing because there is none.
@@ -66,7 +69,7 @@ export class NodePackageManager implements INodePackageManager {
66
69
// We cannot use the actual install with --json to get the information because of post-install scripts which may print on stdout
67
70
// dry-run install is quite fast when the dependencies are already installed even for many dependencies (e.g. angular) so we can live with this approach
68
71
// We need the --prefix here because without it no output is emitted on stdout because all the dependencies are already installed.
69
- const spawnNpmDryRunResult = await this . $childProcess . spawnFromEvent ( this . getNpmExecutableName ( ) , params , "close" ) ;
72
+ const spawnNpmDryRunResult = await this . $childProcess . spawnFromEvent ( this . getPackageManagerExecutableName ( ) , params , "close" ) ;
70
73
return this . parseNpmInstallResult ( spawnNpmDryRunResult . stdout , spawnResult . stdout , packageName ) ;
71
74
} catch ( err ) {
72
75
if ( err . message && err . message . indexOf ( "EPEERINVALID" ) !== - 1 ) {
@@ -136,43 +139,12 @@ export class NodePackageManager implements INodePackageManager {
136
139
return path . join ( cachePath . trim ( ) , CACACHE_DIRECTORY_NAME ) ;
137
140
}
138
141
139
- private getNpmExecutableName ( ) : string {
140
- let npmExecutableName = "npm" ;
141
-
142
- if ( this . $hostInfo . isWindows ) {
143
- npmExecutableName += ".cmd" ;
144
- }
145
-
146
- return npmExecutableName ;
147
- }
148
-
149
- private getFlagsString ( config : any , asArray : boolean ) : any {
150
- const array : Array < string > = [ ] ;
151
- for ( const flag in config ) {
152
- if ( flag === "global" ) {
153
- array . push ( `--${ flag } ` ) ;
154
- array . push ( `${ config [ flag ] } ` ) ;
155
- } else if ( config [ flag ] ) {
156
- if ( flag === "dist-tags" || flag === "versions" ) {
157
- array . push ( ` ${ flag } ` ) ;
158
- continue ;
159
- }
160
- array . push ( `--${ flag } ` ) ;
161
- }
162
- }
163
- if ( asArray ) {
164
- return array ;
165
- }
166
-
167
- return array . join ( " " ) ;
168
- }
169
-
170
142
private parseNpmInstallResult ( npmDryRunInstallOutput : string , npmInstallOutput : string , userSpecifiedPackageName : string ) : INpmInstallResultInfo {
171
143
// TODO: Add tests for this functionality
172
144
try {
173
145
const originalOutput : INpmInstallCLIResult | INpm5InstallCliResult = JSON . parse ( npmDryRunInstallOutput ) ;
174
- const npm5Output = < INpm5InstallCliResult > originalOutput ;
175
- const npmOutput = < INpmInstallCLIResult > originalOutput ;
146
+ const npm5Output = < INpm5InstallCliResult > originalOutput ;
147
+ const npmOutput = < INpmInstallCLIResult > originalOutput ;
176
148
let name : string ;
177
149
_ . forOwn ( npmOutput . dependencies , ( peerDependency : INpmPeerDependencyInfo , key : string ) => {
178
150
if ( ! peerDependency . required && ! peerDependency . peerMissing ) {
@@ -239,64 +211,6 @@ export class NodePackageManager implements INodePackageManager {
239
211
version
240
212
} ;
241
213
}
242
-
243
- private async getNpmInstallResult ( params : string [ ] , cwd : string ) : Promise < ISpawnResult > {
244
- return new Promise < ISpawnResult > ( ( resolve , reject ) => {
245
- const npmExecutable = this . getNpmExecutableName ( ) ;
246
- const stdioValue = isInteractive ( ) ? "inherit" : "pipe" ;
247
-
248
- const childProcess = this . $childProcess . spawn ( npmExecutable , params , { cwd, stdio : stdioValue } ) ;
249
-
250
- let isFulfilled = false ;
251
- let capturedOut = "" ;
252
- let capturedErr = "" ;
253
-
254
- if ( childProcess . stdout ) {
255
- childProcess . stdout . on ( "data" , ( data : string ) => {
256
- this . $logger . write ( data . toString ( ) ) ;
257
- capturedOut += data ;
258
- } ) ;
259
- }
260
-
261
- if ( childProcess . stderr ) {
262
- childProcess . stderr . on ( "data" , ( data : string ) => {
263
- capturedErr += data ;
264
- } ) ;
265
- }
266
-
267
- childProcess . on ( "close" , ( arg : any ) => {
268
- const exitCode = typeof arg === "number" ? arg : arg && arg . code ;
269
-
270
- if ( exitCode === 0 ) {
271
- isFulfilled = true ;
272
- const result = {
273
- stdout : capturedOut ,
274
- stderr : capturedErr ,
275
- exitCode
276
- } ;
277
-
278
- resolve ( result ) ;
279
- } else {
280
- let errorMessage = `Command ${ npmExecutable } ${ params && params . join ( " " ) } failed with exit code ${ exitCode } ` ;
281
- if ( capturedErr ) {
282
- errorMessage += ` Error output: \n ${ capturedErr } ` ;
283
- }
284
-
285
- if ( ! isFulfilled ) {
286
- isFulfilled = true ;
287
- reject ( new Error ( errorMessage ) ) ;
288
- }
289
- }
290
- } ) ;
291
-
292
- childProcess . on ( "error" , ( err : Error ) => {
293
- if ( ! isFulfilled ) {
294
- isFulfilled = true ;
295
- reject ( err ) ;
296
- }
297
- } ) ;
298
- } ) ;
299
- }
300
214
}
301
215
302
216
$injector . register ( "npm" , NodePackageManager ) ;
0 commit comments