Skip to content
This repository was archived by the owner on Feb 18, 2024. It is now read-only.

Commit de4e1ae

Browse files
committed
remove releases API use, bluebird promises
1 parent 9d566b0 commit de4e1ae

File tree

2 files changed

+62
-275
lines changed

2 files changed

+62
-275
lines changed

github.js

Lines changed: 60 additions & 272 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,12 @@ var rimraf = require('rimraf');
55
var request = require('request');
66
var 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

1111
var tar = require('tar');
1212
var zlib = require('zlib');
1313

14-
var yauzl = require('yauzl');
15-
1614
var semver = require('semver');
1715

1816
var which = require('which');
@@ -252,31 +250,7 @@ function configureCredentials(config, ui) {
252250
});
253251
}
254252

255-
function checkRateLimit(headers) {
256-
if (headers.status.match(/^401/))
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(/^406/))
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
282256
GithubLocation.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(/^401/))
423+
return apiFailWarn('lack of authorization', true);
424+
if (res.headers.status.match(/^406/))
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,243 +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(/^.*Link$/);
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(/^.*Link$/);
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(/^.*Link$/);
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.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);
780568
});
781569
},
782570

0 commit comments

Comments
 (0)