@@ -5,14 +5,12 @@ var rimraf = require('rimraf');
5
5
var request = require ( 'request' ) ;
6
6
var expandTilde = require ( 'expand-tilde' ) ;
7
7
8
- var Promise = require ( 'rsvp' ) . Promise ;
9
- var asp = require ( 'rsvp ' ) . denodeify ;
8
+ var Promise = require ( 'bluebird' ) ;
9
+ var asp = require ( 'bluebird ' ) . Promise . promisify ;
10
10
11
11
var tar = require ( 'tar' ) ;
12
12
var zlib = require ( 'zlib' ) ;
13
13
14
- var yauzl = require ( 'yauzl' ) ;
15
-
16
14
var semver = require ( 'semver' ) ;
17
15
18
16
var which = require ( 'which' ) ;
@@ -252,31 +250,7 @@ function configureCredentials(config, ui) {
252
250
} ) ;
253
251
}
254
252
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 ;
280
254
281
255
// static configuration function
282
256
GithubLocation . configure = function ( config , ui ) {
@@ -421,31 +395,48 @@ GithubLocation.prototype = {
421
395
if ( meta . vPrefix )
422
396
version = 'v' + version ;
423
397
424
- return asp ( request ) ( extend ( {
398
+ var self = this ;
399
+ var ui = this . ui ;
400
+
401
+ return asp ( request ) ( {
425
402
uri : this . apiRemoteString + 'repos/' + repo + '/contents/package.json' ,
426
403
headers : {
427
404
'User-Agent' : 'jspm' ,
428
405
'Accept' : 'application/vnd.github.v3.raw'
429
406
} ,
430
407
qs : {
431
408
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 ;
432
420
}
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 ) ;
442
431
}
443
-
444
432
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 + '.' ) ;
446
434
447
- var packageJSON ;
435
+ // it is quite valid for a repo not to have a package.json
436
+ if ( res . statusCode == 404 )
437
+ return { } ;
448
438
439
+ var packageJSON ;
449
440
try {
450
441
packageJSON = JSON . parse ( res . body ) ;
451
442
}
@@ -540,243 +531,40 @@ GithubLocation.prototype = {
540
531
541
532
var self = this ;
542
533
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 ) ;
680
544
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.' ) ;
690
547
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 ( ) ;
720
549
721
- pkgRes . resume ( ) ;
550
+ var gzip = zlib . createGunzip ( ) ;
722
551
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 ) ;
728
563
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 ( ) ;
739
565
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
- }
753
566
} )
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 . filter ( function ( asset ) {
761
- if ( asset . name . substr ( asset . name . length - 7 , 7 ) == '.tar.gz' || asset . name . substr ( asset . name . length - 4 , 4 ) == '.tgz' )
762
- asset . fileType = 'tar' ;
763
- else if ( asset . name . substr ( asset . name . length - 4 , 4 ) == '.zip' )
764
- asset . fileType = 'zip' ;
765
- return ! ! asset . fileType ;
766
- } )
767
- . sort ( function ( asset ) {
768
- // src.zip comes after file.zip
769
- return asset . name . indexOf ( 'src' ) == - 1 ? - 1 : 1 ;
770
- } ) [ 0 ] ;
771
-
772
- if ( ! firstAsset )
773
- return false ;
774
-
775
- return { url : firstAsset . url , type : firstAsset . fileType } ;
776
- }
777
- }
778
- return false ;
779
- } ) ;
567
+ . on ( 'error' , reject ) ;
780
568
} ) ;
781
569
} ,
782
570
0 commit comments