22
33const debug = require ( 'debug' ) ( 'npminstall:download:npm' ) ;
44const bytes = require ( 'bytes' ) ;
5- const fs = require ( 'mz/fs' ) ;
5+ const { createWriteStream, createReadStream, rmSync } = require ( 'fs' ) ;
6+ const fs = require ( 'fs/promises' ) ;
67const path = require ( 'path' ) ;
78const crypto = require ( 'crypto' ) ;
89const tar = require ( 'tar' ) ;
@@ -80,6 +81,8 @@ async function resolve(pkg, options) {
8081 let fixScripts ;
8182
8283 if ( ! realPkgVersion ) {
84+ // remove disk cache
85+ await removeCacheInfo ( pkg . name , options ) ;
8386 throw new Error ( `[${ pkg . displayName } ] Can\'t find package ${ pkg . name } @${ pkg . rawSpec } ` ) ;
8487 }
8588
@@ -113,6 +116,8 @@ async function resolve(pkg, options) {
113116
114117 const realPkg = packageMeta . versions [ realPkgVersion ] ;
115118 if ( ! realPkg ) {
119+ // remove disk cache
120+ await removeCacheInfo ( pkg . name , options ) ;
116121 throw new Error ( `[${ pkg . displayName } ] Can\'t find package ${ pkg . name } \'s version: ${ realPkgVersion } ` ) ;
117122 }
118123
@@ -131,48 +136,69 @@ async function resolve(pkg, options) {
131136 return realPkg ;
132137}
133138
134- function getScope ( name ) {
139+ function _getScope ( name ) {
135140 if ( name [ 0 ] === '@' ) return name . slice ( 0 , name . indexOf ( '/' ) ) ;
136141}
137142
138- async function getFullPackageMeta ( name , globalOptions ) {
143+ async function _getCacheInfo ( fullname , globalOptions ) {
139144 // check name has scope
140145 let registry = globalOptions . registry ;
141- const scope = getScope ( name ) ;
146+ const scope = _getScope ( fullname ) ;
142147 if ( scope ) {
143148 registry = config . get ( scope + ':registry' ) || globalOptions . registry ;
144149 }
145-
146- const pkgUrl = utils . formatPackageUrl ( registry , name ) ;
150+ const info = {
151+ pkgUrl : utils . formatPackageUrl ( registry , fullname ) ,
152+ cacheFile : '' ,
153+ cache : null ,
154+ } ;
147155 if ( ! globalOptions . cacheDir ) {
148- const result = await _fetchFullPackageMeta ( pkgUrl , globalOptions ) ;
149- return result . data ;
156+ return info ;
150157 }
151- const hash = utility . md5 ( pkgUrl ) ;
158+ const hash = utility . md5 ( info . pkgUrl ) ;
152159 const parentDir = path . join ( globalOptions . cacheDir , 'manifests' , hash [ 0 ] , hash [ 1 ] , hash [ 2 ] ) ;
153160 // { etag, age, headers, manifests }
154- const cacheFile = path . join ( parentDir , `${ hash } .json` ) ;
155- const exists = await fs . exists ( cacheFile ) ;
161+ info . cacheFile = path . join ( parentDir , `${ hash } .json` ) ;
162+ const exists = await utils . exists ( info . cacheFile ) ;
156163 // cache not exists
157164 if ( ! exists ) {
158165 await utils . mkdirp ( parentDir ) ;
159- return await _fetchFullPackageMetaWithCache ( pkgUrl , globalOptions , cacheFile ) ;
166+ return info ;
160167 }
161168 // cache exists
162- const cacheContent = await fs . readFile ( cacheFile ) ;
163- let cache ;
169+ const cacheContent = await fs . readFile ( info . cacheFile ) ;
164170 try {
165- cache = JSON . parse ( cacheContent ) ;
171+ info . cache = JSON . parse ( cacheContent ) ;
166172 } catch ( _ ) {
167- globalOptions . console . warn ( '[npminstall:download:npm] Ignore invalid cache file %s' , cacheFile ) ;
173+ globalOptions . console . warn ( '[npminstall:download:npm] Ignore invalid cache file %s' , info . cacheFile ) ;
174+ }
175+ return info ;
176+ }
177+
178+ async function removeCacheInfo ( fullname , globalOptions ) {
179+ const info = await _getCacheInfo ( fullname , globalOptions ) ;
180+ if ( info . cache ) {
181+ await fs . rm ( info . cacheFile , { force : true } ) ;
182+ }
183+ }
184+
185+ async function getFullPackageMeta ( fullname , globalOptions ) {
186+ const info = await _getCacheInfo ( fullname , globalOptions ) ;
187+ if ( ! info . cacheFile ) {
188+ const result = await _fetchFullPackageMeta ( info . pkgUrl , globalOptions ) ;
189+ return result . data ;
190+ }
191+ // cache file not exists
192+ if ( ! info . cache ) {
193+ return await _fetchFullPackageMetaWithCache ( info . pkgUrl , globalOptions , info . cacheFile ) ;
168194 }
169195 // check is expired or not
170- if ( cache && cache . expired > Date . now ( ) ) {
196+ if ( info . cache . expired > Date . now ( ) ) {
171197 globalOptions . totalCacheJSONCount += 1 ;
172- return cache . manifests ;
198+ return info . cache . manifests ;
173199 }
174200 // use etag to request
175- return await _fetchFullPackageMetaWithCache ( pkgUrl , globalOptions , cacheFile , cache ) ;
201+ return await _fetchFullPackageMetaWithCache ( info . pkgUrl , globalOptions , info . cacheFile , info . cache ) ;
176202}
177203
178204async function _fetchFullPackageMetaWithCache ( pkgUrl , globalOptions , cacheFile , cache ) {
@@ -384,7 +410,7 @@ async function download(pkg, options) {
384410 // ignore https protocol check on: node_modules/node-pre-gyp/lib/util/versioning.js
385411 if ( / n o d e - p r e - g y p i n s t a l l / . test ( pkg . scripts . install ) ) {
386412 const versioningFile = path . join ( ungzipDir , 'node_modules/node-pre-gyp/lib/util/versioning.js' ) ;
387- if ( await fs . exists ( versioningFile ) ) {
413+ if ( await utils . exists ( versioningFile ) ) {
388414 let content = await fs . readFile ( versioningFile , 'utf-8' ) ;
389415 content = content . replace ( 'if (protocol === \'http:\') {' ,
390416 'if (false && protocol === \'http:\') { // hack by npminstall' ) ;
@@ -426,7 +452,7 @@ async function download(pkg, options) {
426452 options . console . info ( '%s download from binary mirror: %j, targetPlatform: %s' ,
427453 chalk . gray ( `${ pkg . name } @${ pkg . version } ` ) , binaryMirror , targetPlatform ) ;
428454 const downloadFile = path . join ( ungzipDir , 'lib/tasks/download.js' ) ;
429- if ( await fs . exists ( downloadFile ) ) {
455+ if ( await utils . exists ( downloadFile ) ) {
430456 let content = await fs . readFile ( downloadFile , 'utf-8' ) ;
431457 // return version ? prepend('desktop/' + version) : prepend('desktop');
432458 const afterContent = 'return "' + binaryMirror . host + '/" + version + "/' + targetPlatform + '/cypress.zip"; // hack by npminstall\n' ;
@@ -446,7 +472,7 @@ async function download(pkg, options) {
446472 if ( pkg . name === 'node-pre-gyp' ) {
447473 // ignore https protocol check on: lib/util/versioning.js
448474 const versioningFile = path . join ( ungzipDir , 'lib/util/versioning.js' ) ;
449- if ( await fs . exists ( versioningFile ) ) {
475+ if ( await utils . exists ( versioningFile ) ) {
450476 let content = await fs . readFile ( versioningFile , 'utf-8' ) ;
451477 content = content . replace ( 'if (protocol === \'http:\') {' ,
452478 'if (false && protocol === \'http:\') { // hack by npminstall' ) ;
@@ -527,7 +553,7 @@ async function getTarballStream(tarballUrl, pkg, options) {
527553 paths . push ( pkg . name ) ;
528554 const parentDir = path . join ( ...paths ) ;
529555 const tarballFile = path . join ( parentDir , `${ pkg . version } -${ pkg . dist . shasum } .tgz` ) ;
530- let exists = await fs . exists ( tarballFile ) ;
556+ let exists = await utils . exists ( tarballFile ) ;
531557 if ( ! exists ) {
532558 // try to remove expired tmp dirs
533559 const dirs = [ ] ;
@@ -552,25 +578,25 @@ async function getTarballStream(tarballUrl, pkg, options) {
552578 timeout : options . streamingTimeout || options . timeout ,
553579 followRedirect : true ,
554580 formatRedirectUrl,
555- writeStream : fs . createWriteStream ( tmpFile ) ,
581+ writeStream : createWriteStream ( tmpFile ) ,
556582 } , options ) ;
557583
558584 if ( result . status !== 200 ) {
559585 throw new Error ( `Download ${ tarballUrl } status: ${ result . status } error, should be 200` ) ;
560586 }
561587 // make sure tarball file is not exists again
562- exists = await fs . exists ( tarballFile ) ;
588+ exists = await utils . exists ( tarballFile ) ;
563589 if ( ! exists ) {
564590 try {
565591 await fs . rename ( tmpFile , tarballFile ) ;
566592 } catch ( err ) {
567593 if ( err . code === 'EPERM' ) {
568594 // Error: EPERM: operation not permitted, rename
569- exists = await fs . exists ( tarballFile ) ;
595+ exists = await utils . exists ( tarballFile ) ;
570596 if ( exists ) {
571597 // parallel execution case same file exists, ignore rename error
572598 // clean tmpFile
573- await fs . unlink ( tmpFile ) ;
599+ await fs . rm ( tmpFile , { force : true } ) ;
574600 } else {
575601 // rename error
576602 throw err ;
@@ -582,15 +608,15 @@ async function getTarballStream(tarballUrl, pkg, options) {
582608 }
583609 } else {
584610 // clean tmpFile
585- await fs . unlink ( tmpFile ) ;
611+ await fs . rm ( tmpFile , { force : true } ) ;
586612 }
587613 const stat = await fs . stat ( tarballFile ) ;
588614 debug ( '[%s@%s] saved %s %s => %s' ,
589615 pkg . name , pkg . version , bytes ( stat . size ) , tarballUrl , tarballFile ) ;
590616 options . totalTarballSize += stat . size ;
591617 }
592618
593- const stream = fs . createReadStream ( tarballFile ) ;
619+ const stream = createReadStream ( tarballFile ) ;
594620 stream . tarballFile = tarballFile ;
595621 stream . tarballUrl = tarballUrl ;
596622 return stream ;
@@ -752,12 +778,12 @@ function checkShasumAndUngzip(ungzipDir, readstream, pkg, useTarFormat, options)
752778 // make sure readstream will be destroy
753779 destroy ( readstream ) ;
754780 err . message += ` (${ pkg . name } @${ pkg . version } )` ;
755- if ( readstream . tarballFile && fs . existsSync ( readstream . tarballFile ) ) {
781+ if ( readstream . tarballFile && utils . existsSync ( readstream . tarballFile ) ) {
756782 err . message += ` (${ readstream . tarballFile } )` ;
757783 debug ( '[%s@%s] remove tarball file: %s, because %s' ,
758784 pkg . name , pkg . version , readstream . tarballFile , err ) ;
759785 // remove tarball cache file
760- fs . unlinkSync ( readstream . tarballFile ) ;
786+ rmSync ( readstream . tarballFile , { force : true } ) ;
761787 }
762788 return reject ( err ) ;
763789 }
@@ -792,8 +818,8 @@ function checkShasumAndUngzip(ungzipDir, readstream, pkg, useTarFormat, options)
792818 } ) ;
793819}
794820
795- async function replaceHostInFile ( pkg , filepath , binaryMirror , options ) {
796- const exists = await fs . exists ( filepath ) ;
821+ async function replaceHostInFile ( pkg , filepath , binaryMirror , globalOptions ) {
822+ const exists = await utils . exists ( filepath ) ;
797823 if ( ! exists ) {
798824 return ;
799825 }
@@ -827,7 +853,7 @@ async function replaceHostInFile(pkg, filepath, binaryMirror, options) {
827853 }
828854 debug ( '%s: \n%s' , filepath , content ) ;
829855 await fs . writeFile ( filepath , content ) ;
830- options . console . info ( '%s download from mirrors: %j, changed file: %s' ,
856+ globalOptions . console . info ( '%s download from mirrors: %j, changed file: %s' ,
831857 chalk . gray ( `${ pkg . name } @${ pkg . version } ` ) ,
832858 replaceHostMap ,
833859 filepath ) ;
0 commit comments