@@ -5,14 +5,12 @@ var rimraf = require('rimraf');
55var request = require ( 'request' ) ;
66var expandTilde = require ( 'expand-tilde' ) ;
77
8- var Promise = require ( 'rsvp' ) . Promise ;
9- var asp = require ( 'rsvp ' ) . denodeify ;
8+ var Promise = require ( 'bluebird' ) ;
9+ var asp = require ( 'bluebird ' ) . Promise . promisify ;
1010
1111var tar = require ( 'tar' ) ;
1212var zlib = require ( 'zlib' ) ;
1313
14- var yauzl = require ( 'yauzl' ) ;
15-
1614var semver = require ( 'semver' ) ;
1715
1816var which = require ( 'which' ) ;
@@ -252,31 +250,7 @@ function configureCredentials(config, ui) {
252250 } ) ;
253251}
254252
255- function checkRateLimit ( headers ) {
256- if ( headers . status . match ( / ^ 4 0 1 / ) )
257- throw 'Unauthorized response for GitHub API.\n' +
258- 'Use %jspm registry config github% to reconfigure the credentials, or update them in your ~/.netrc file.' ;
259- if ( headers . status . match ( / ^ 4 0 6 / ) )
260- throw 'Unauthorized response for GitHub API.\n' +
261- 'If using an access token ensure it has public_repo access.\n' +
262- 'Use %jspm registry config github% to configure the credentials, or add them to your ~/.netrc file.' ;
263-
264- if ( headers [ 'x-ratelimit-remaining' ] != '0' )
265- return ;
266-
267- var remaining = ( headers [ 'x-ratelimit-reset' ] * 1000 - new Date ( headers . date ) . getTime ( ) ) / 60000 ;
268-
269- if ( this . auth )
270- return Promise . reject ( '\nGitHub rate limit reached, with authentication enabled.' +
271- '\nThe rate limit will reset in `' + Math . round ( remaining ) + ' minutes`.' ) ;
272-
273- var err = new Error ( 'GitHub rate limit reached.' ) ;
274- err . config = true ;
275- err . hideStack = true ;
276-
277- return Promise . reject ( err ) ;
278- }
279-
253+ var apiWarned = false ;
280254
281255// static configuration function
282256GithubLocation . configure = function ( config , ui ) {
@@ -421,31 +395,48 @@ GithubLocation.prototype = {
421395 if ( meta . vPrefix )
422396 version = 'v' + version ;
423397
424- return asp ( request ) ( extend ( {
398+ var self = this ;
399+ var ui = this . ui ;
400+
401+ return asp ( request ) ( {
425402 uri : this . apiRemoteString + 'repos/' + repo + '/contents/package.json' ,
426403 headers : {
427404 'User-Agent' : 'jspm' ,
428405 'Accept' : 'application/vnd.github.v3.raw'
429406 } ,
430407 qs : {
431408 ref : version
409+ } ,
410+ strictSSL : this . strictSSL
411+ } ) . then ( function ( res ) {
412+ // API auth failure warnings
413+ function apiFailWarn ( reason , showAuthCommand ) {
414+ if ( apiWarned )
415+ return ;
416+
417+ ui . log ( 'warn' , 'Unable to use the GitHub API to speed up dependency downloads due to ' + reason
418+ + ( showAuthCommand ? '\nTo resolve use %jspm registry config github% to configure the credentials, or update them in your ~/.netrc file.' : '' ) ) ;
419+ apiWarned = true ;
432420 }
433- } , this . defaultRequestOptions
434- ) ) . then ( function ( res ) {
435- var rateLimitResponse = checkRateLimit . call ( this , res . headers ) ;
436- if ( rateLimitResponse )
437- return rateLimitResponse ;
438-
439- if ( res . statusCode == 404 ) {
440- // it is quite valid for a repo not to have a package.json
441- return { } ;
421+
422+ if ( res . headers . status . match ( / ^ 4 0 1 / ) )
423+ return apiFailWarn ( 'lack of authorization' , true ) ;
424+ if ( res . headers . status . match ( / ^ 4 0 6 / ) )
425+ return apiFailWarn ( 'insufficient permissions. Ensure you have public_repo access.' ) ;
426+ if ( res . headers [ 'x-ratelimit-remaining' ] == '0' ) {
427+ if ( self . auth )
428+ return apiFailWarn ( 'the rate limit being reached, which will be reset in `' +
429+ Math . round ( ( res . headers [ 'x-ratelimit-reset' ] * 1000 - new Date ( res . headers . date ) . getTime ( ) ) / 60000 ) + ' minutes`.' ) ;
430+ return apiFailWarn ( 'the rate limit being reached.' , true ) ;
442431 }
443-
444432 if ( res . statusCode != 200 )
445- throw 'Unable to check repo package.json for release, status code ' + res . statusCode ;
433+ return apiFailWarn ( 'invalid response code ' + res . statusCode + '.' ) ;
446434
447- var packageJSON ;
435+ // it is quite valid for a repo not to have a package.json
436+ if ( res . statusCode == 404 )
437+ return { } ;
448438
439+ var packageJSON ;
449440 try {
450441 packageJSON = JSON . parse ( res . body ) ;
451442 }
@@ -540,241 +531,40 @@ GithubLocation.prototype = {
540531
541532 var self = this ;
542533
543- return this . checkReleases ( repo , version )
544- . then ( function ( release ) {
545- if ( ! release )
546- return true ;
547-
548- // Download from the release archive
549- return new Promise ( function ( resolve , reject ) {
550- var inPipe ;
551-
552- if ( release . type == 'tar' ) {
553- ( inPipe = zlib . createGunzip ( ) )
554- . pipe ( tar . Extract ( {
555- path : outDir ,
556- strip : 0 ,
557- filter : function ( ) {
558- return ! this . type . match ( / ^ .* L i n k $ / ) ;
559- }
560- } ) )
561- . on ( 'end' , function ( ) {
562- resolve ( ) ;
563- } )
564- . on ( 'error' , reject ) ;
565- }
566- else if ( release . type == 'zip' ) {
567- var tmpDir = path . resolve ( execOpt . cwd , 'release-' + repo . replace ( '/' , '#' ) + '-' + version ) ;
568- var tmpFile = tmpDir + '.' + release . type ;
569-
570- var repoDir ;
571-
572- inPipe = fs . createWriteStream ( tmpFile )
573- . on ( 'finish' , function ( ) {
574- return clearDir ( tmpDir )
575- . then ( function ( ) {
576- return asp ( fs . mkdir ( tmpDir ) ) ;
577- } )
578- . then ( function ( ) {
579- return new Promise ( function ( resolve , reject ) {
580- var files = [ ] ;
581- yauzl . open ( tmpFile , function ( err , zipFile ) {
582- if ( err )
583- return reject ( err ) ;
584-
585- zipFile . on ( 'entry' , function ( entry ) {
586- var fileName = tmpDir + '/' + entry . fileName ;
587-
588- if ( fileName [ fileName . length - 1 ] == '/' )
589- return ;
590-
591- zipFile . openReadStream ( entry , function ( err , readStream ) {
592- if ( err )
593- return reject ( err ) ;
594- mkdirp ( path . dirname ( fileName ) , function ( err ) {
595- if ( err )
596- return reject ( err ) ;
597- files . push ( new Promise ( function ( _resolve , _reject ) {
598- var p = fs . createWriteStream ( fileName ) . on ( "close" , function ( err ) {
599- if ( err ) _reject ( err ) ;
600- _resolve ( ) ;
601- } ) ;
602- readStream . pipe ( p ) ;
603- } ) ) ;
604- } ) ;
605- } ) ;
606- } ) ;
607- zipFile . on ( 'close' , function ( ) {
608- Promise . all ( files ) . then ( function ( ) {
609- resolve ( ) ;
610- } ) . catch ( function ( e ) {
611- reject ( e ) ;
612- } ) ;
613- } ) ;
614- } ) ;
615-
616-
617- } )
618- } )
619- . then ( function ( ) {
620- return checkStripDir ( tmpDir ) ;
621- } )
622- . then ( function ( _repoDir ) {
623- repoDir = _repoDir ;
624- return asp ( fs . rmdir ) ( outDir ) ;
625- } )
626- . then ( function ( ) {
627- return asp ( fs . rename ) ( repoDir , outDir ) ;
628- } )
629- . then ( function ( ) {
630- return asp ( fs . unlink ) ( tmpFile ) ;
631- } )
632- . then ( resolve , reject ) ;
633- } )
634- . on ( 'error' , reject ) ;
635- }
636- else {
637- throw 'GitHub release found, but no archive present.' ;
638- }
639-
640- // now that the inPipe is ready, do the request
641- request ( extend ( {
642- uri : release . url ,
643- headers : {
644- 'accept' : 'application/octet-stream' ,
645- 'user-agent' : 'jspm'
646- } ,
647- followRedirect : false ,
648- auth : self . auth && {
649- user : self . auth . username ,
650- pass : self . auth . password
651- }
652- } , self . defaultRequestOptions
653- ) ) . on ( 'response' , function ( archiveRes ) {
654- var rateLimitResponse = checkRateLimit . call ( this , archiveRes . headers ) ;
655- if ( rateLimitResponse )
656- return rateLimitResponse . then ( resolve , reject ) ;
657-
658- if ( archiveRes . statusCode != 302 )
659- return reject ( 'Bad response code ' + archiveRes . statusCode + '\n' + JSON . stringify ( archiveRes . headers ) ) ;
660-
661- request ( extend ( {
662- uri : archiveRes . headers . location , headers : {
663- 'accept' : 'application/octet-stream' ,
664- 'user-agent' : 'jspm'
665- }
666- } , self . defaultRequestOptions
667- ) )
668- . on ( 'response' , function ( archiveRes ) {
669-
670- if ( max_repo_size && archiveRes . headers [ 'content-length' ] > max_repo_size )
671- return reject ( 'Response too large.' ) ;
672-
673- archiveRes . pause ( ) ;
674-
675- archiveRes . pipe ( inPipe ) ;
676-
677- archiveRes . on ( 'error' , reject ) ;
678-
679- archiveRes . resume ( ) ;
534+ // Download from the git archive
535+ return new Promise ( function ( resolve , reject ) {
536+ request ( {
537+ uri : remoteString + repo + '/archive/' + version + '.tar.gz' ,
538+ headers : { 'accept' : 'application/octet-stream' } ,
539+ strictSSL : self . strictSSL
540+ } )
541+ . on ( 'response' , function ( pkgRes ) {
542+ if ( pkgRes . statusCode != 200 )
543+ return reject ( 'Bad response code ' + pkgRes . statusCode ) ;
680544
681- } )
682- . on ( 'error' , reject ) ;
683- } )
684- . on ( 'error' , reject ) ;
685- } ) ;
686- } )
687- . then ( function ( git ) {
688- if ( ! git )
689- return ;
545+ if ( max_repo_size && pkgRes . headers [ 'content-length' ] > max_repo_size )
546+ return reject ( 'Response too large.' ) ;
690547
691- // Download from the git archive
692- return new Promise ( function ( resolve , reject ) {
693- request ( extend ( {
694- uri : remoteString + repo + '/archive/' + version + '.tar.gz' ,
695- headers : { 'accept' : 'application/octet-stream' }
696- } , self . defaultRequestOptions
697- ) )
698- . on ( 'response' , function ( pkgRes ) {
699- if ( pkgRes . statusCode != 200 )
700- return reject ( 'Bad response code ' + pkgRes . statusCode ) ;
701-
702- if ( max_repo_size && pkgRes . headers [ 'content-length' ] > max_repo_size )
703- return reject ( 'Response too large.' ) ;
704-
705- pkgRes . pause ( ) ;
706-
707- var gzip = zlib . createGunzip ( ) ;
708-
709- pkgRes
710- . pipe ( gzip )
711- . pipe ( tar . Extract ( {
712- path : outDir ,
713- strip : 1 ,
714- filter : function ( ) {
715- return ! this . type . match ( / ^ .* L i n k $ / ) ;
716- }
717- } ) )
718- . on ( 'error' , reject )
719- . on ( 'end' , resolve ) ;
548+ pkgRes . pause ( ) ;
720549
721- pkgRes . resume ( ) ;
550+ var gzip = zlib . createGunzip ( ) ;
722551
723- } )
724- . on ( 'error' , reject ) ;
725- } ) ;
726- } ) ;
727- } ,
552+ pkgRes
553+ . pipe ( gzip )
554+ . pipe ( tar . Extract ( {
555+ path : outDir ,
556+ strip : 1 ,
557+ filter : function ( ) {
558+ return ! this . type . match ( / ^ .* L i n k $ / ) ;
559+ }
560+ } ) )
561+ . on ( 'error' , reject )
562+ . on ( 'end' , resolve ) ;
728563
729- checkReleases : function ( repo , version ) {
730- // NB cache this on disk with etags
731- var reqOptions = extend ( {
732- uri : this . apiRemoteString + 'repos/' + repo + '/releases' ,
733- headers : {
734- 'User-Agent' : 'jspm' ,
735- 'Accept' : 'application/vnd.github.v3+json'
736- } ,
737- followRedirect : false
738- } , this . defaultRequestOptions ) ;
564+ pkgRes . resume ( ) ;
739565
740- return asp ( request ) ( reqOptions )
741- . then ( function ( res ) {
742- var rateLimitResponse = checkRateLimit . call ( this , res . headers ) ;
743- if ( rateLimitResponse )
744- return rateLimitResponse ;
745- return Promise . resolve ( )
746- . then ( function ( ) {
747- try {
748- return JSON . parse ( res . body ) ;
749- }
750- catch ( e ) {
751- throw 'Unable to parse GitHub API response' ;
752- }
753566 } )
754- . then ( function ( releases ) {
755- // run through releases list to see if we have this version tag
756- for ( var i = 0 ; i < releases . length ; i ++ ) {
757- var tagName = ( releases [ i ] . tag_name || '' ) . trim ( ) ;
758-
759- if ( tagName == version ) {
760- var firstAsset = releases [ i ] . assets [ 0 ] ;
761- if ( ! firstAsset )
762- return false ;
763-
764- var assetType ;
765-
766- if ( firstAsset . name . substr ( firstAsset . name . length - 7 , 7 ) == '.tar.gz' || firstAsset . name . substr ( firstAsset . name . length - 4 , 4 ) == '.tgz' )
767- assetType = 'tar' ;
768- else if ( firstAsset . name . substr ( firstAsset . name . length - 4 , 4 ) == '.zip' )
769- assetType = 'zip' ;
770- else
771- return false ;
772-
773- return { url : firstAsset . url , type : assetType } ;
774- }
775- }
776- return false ;
777- } ) ;
567+ . on ( 'error' , reject ) ;
778568 } ) ;
779569 } ,
780570
0 commit comments