@@ -14,28 +14,22 @@ export class NodePackageManager implements INodePackageManager {
1414 private static NPM_REGISTRY_URL = "http://registry.npmjs.org/" ;
1515
1616 private versionsCache : IDictionary < string [ ] > ;
17- private isLoaded : boolean ;
1817
1918 constructor ( private $logger : ILogger ,
2019 private $errors : IErrors ,
2120 private $httpClient : Server . IHttpClient ,
22- private $staticConfig : IStaticConfig ,
23- private $fs : IFileSystem ) {
21+ private $fs : IFileSystem ,
22+ private $lockfile : ILockFile ) {
2423 this . versionsCache = { } ;
24+ this . load ( ) . wait ( ) ;
2525 }
2626
27- public getCacheRootPath ( ) : IFuture < string > {
28- return ( ( ) => {
29- this . load ( ) . wait ( ) ;
30- return npm . cache ;
31- } ) . future < string > ( ) ( ) ;
27+ public getCacheRootPath ( ) : string {
28+ return npm . cache ;
3229 }
3330
3431 public addToCache ( packageName : string , version : string ) : IFuture < void > {
35- return ( ( ) => {
36- this . load ( ) . wait ( ) ;
37- this . addToCacheCore ( packageName , version ) . wait ( ) ;
38- } ) . future < void > ( ) ( ) ;
32+ return this . addToCacheCore ( packageName , version ) ;
3933 }
4034
4135 public load ( config ?: any ) : IFuture < void > {
@@ -52,29 +46,21 @@ export class NodePackageManager implements INodePackageManager {
5246
5347 public install ( packageName : string , opts ?: INpmInstallOptions ) : IFuture < string > {
5448 return ( ( ) => {
55- try {
56- this . load ( ) . wait ( ) ; // It's obligatory to execute load before whatever npm function
49+ this . $lockfile . lock ( ) . wait ( ) ;
5750
51+ try {
5852 var packageToInstall = packageName ;
5953 var pathToSave = ( opts && opts . pathToSave ) || npm . cache ;
6054 var version = ( opts && opts . version ) || null ;
61- var isSemanticVersioningDisabled = options . frameworkPath ? true : false ; // We need to disable sem versioning for local packages
62-
63- if ( version ) {
64- this . validateVersion ( packageName , version ) . wait ( ) ;
65- packageToInstall = packageName + "@" + version ;
66- }
6755
68- this . installCore ( packageToInstall , pathToSave , isSemanticVersioningDisabled ) . wait ( ) ;
56+ return this . installCore ( packageToInstall , pathToSave , version ) . wait ( ) ;
6957 } catch ( error ) {
7058 this . $logger . debug ( error ) ;
71- this . $errors . fail ( NodePackageManager . NPM_LOAD_FAILED ) ;
59+ this . $errors . fail ( "%s. Error: %s" , NodePackageManager . NPM_LOAD_FAILED , error ) ;
60+ } finally {
61+ this . $lockfile . unlock ( ) . wait ( ) ;
7262 }
7363
74- var pathToNodeModules = path . join ( pathToSave , "node_modules" ) ;
75- var folders = this . $fs . readDirectory ( pathToNodeModules ) . wait ( ) ;
76- return path . join ( pathToNodeModules , folders [ 0 ] ) ;
77-
7864 } ) . future < string > ( ) ( ) ;
7965 }
8066
@@ -86,21 +72,39 @@ export class NodePackageManager implements INodePackageManager {
8672 } ) . future < string > ( ) ( ) ;
8773 }
8874
89- private installCore ( packageName : string , pathToSave : string , isSemanticVersioningDisabled : boolean ) : IFuture < void > {
90- var currentVersion = this . $staticConfig . version ;
91- if ( ! semver . valid ( currentVersion ) ) {
92- this . $errors . fail ( "Invalid version." ) ;
93- }
75+ private installCore ( packageName : string , pathToSave : string , version : string ) : IFuture < string > {
76+ return ( ( ) => {
77+ if ( options . frameworkPath ) {
78+ if ( this . $fs . getFsStats ( options . frameworkPath ) . wait ( ) . isFile ( ) ) {
79+ this . npmInstall ( packageName , pathToSave , version ) . wait ( ) ;
80+ var pathToNodeModules = path . join ( pathToSave , "node_modules" ) ;
81+ var folders = this . $fs . readDirectory ( pathToNodeModules ) . wait ( ) ;
82+ return path . join ( pathToNodeModules , folders [ 0 ] ) ;
83+ }
84+ return options . frameworkPath ;
85+ } else {
86+ var version = version || this . getLatestVersion ( packageName ) . wait ( ) ;
87+ var packagePath = path . join ( npm . cache , packageName , version , "package" ) ;
88+ if ( ! this . isPackageCached ( packagePath ) . wait ( ) ) {
89+ this . addToCacheCore ( packageName , version ) . wait ( ) ;
90+ }
9491
95- if ( ! isSemanticVersioningDisabled ) {
96- var incrementedVersion = semver . inc ( currentVersion , constants . ReleaseType . MINOR ) ;
97- if ( packageName . indexOf ( "@" ) < 0 ) {
98- packageName = packageName + "@<" + incrementedVersion ;
92+ if ( ! this . isPackageUnpacked ( packagePath ) . wait ( ) ) {
93+ this . cacheUnpack ( packageName , version ) . wait ( ) ;
94+ }
95+ return packagePath ;
9996 }
100- }
97+ } ) . future < string > ( ) ( ) ;
98+ }
10199
100+ private npmInstall ( packageName : string , pathToSave : string , version : string ) : IFuture < void > {
102101 this . $logger . out ( "Installing " , packageName ) ;
103102
103+ var incrementedVersion = semver . inc ( version , constants . ReleaseType . MINOR ) ;
104+ if ( ! options . frameworkPath && packageName . indexOf ( "@" ) < 0 ) {
105+ packageName = packageName + "@<" + incrementedVersion ;
106+ }
107+
104108 var future = new Future < void > ( ) ;
105109 npm . commands [ "install" ] ( pathToSave , packageName , ( err : Error , data : any ) => {
106110 if ( err ) {
@@ -113,6 +117,17 @@ export class NodePackageManager implements INodePackageManager {
113117 return future ;
114118 }
115119
120+ private isPackageCached ( packagePath : string ) : IFuture < boolean > {
121+ return this . $fs . exists ( packagePath ) ;
122+ }
123+
124+ private isPackageUnpacked ( packagePath : string ) : IFuture < boolean > {
125+ return ( ( ) => {
126+ return this . $fs . getFsStats ( packagePath ) . wait ( ) . isDirectory ( ) &&
127+ helpers . enumerateFilesInDirectorySync ( packagePath ) . length > 1 ;
128+ } ) . future < boolean > ( ) ( ) ;
129+ }
130+
116131 private addToCacheCore ( packageName : string , version : string ) : IFuture < void > {
117132 var future = new Future < void > ( ) ;
118133 npm . commands [ "cache" ] . add ( packageName , version , undefined , ( err : Error , data : any ) => {
@@ -150,14 +165,5 @@ export class NodePackageManager implements INodePackageManager {
150165 return this . versionsCache [ packageName ] ;
151166 } ) . future < string [ ] > ( ) ( ) ;
152167 }
153-
154- private validateVersion ( packageName : string , version : string ) : IFuture < void > {
155- return ( ( ) => {
156- var versions = this . getAvailableVersions ( packageName ) . wait ( ) ;
157- if ( ! _ . contains ( versions , version ) ) {
158- this . $errors . fail ( "Invalid version. Valid versions are: %s" , helpers . formatListOfNames ( versions , "and" ) ) ;
159- }
160- } ) . future < void > ( ) ( ) ;
161- }
162168}
163169$injector . register ( "npm" , NodePackageManager ) ;
0 commit comments