UNPKG

ksa

Version:

Attempt at a browset package manager

154 lines (126 loc) 4.92 kB
var util = require('util'); var path = require('path'); var mout = require('mout'); var Q = require('q'); var GitRemoteResolver = require('./GitRemoteResolver'); var download = require('../../util/download'); var extract = require('../../util/extract'); var createError = require('../../util/createError'); function GitHubResolver(decEndpoint, config, logger) { var pair; GitRemoteResolver.call(this, decEndpoint, config, logger); // Grab the org/repo // /xxxxx/yyyyy.git or :xxxxx/yyyyy.git (.git is optional) pair = GitHubResolver.getOrgRepoPair(this._source); if (!pair) { throw createError('Invalid GitHub URL', 'EINVEND', { details: this._source + ' does not seem to be a valid GitHub URL' }); } this._org = pair.org; this._repo = pair.repo; // Ensure trailing for all protocols if (!mout.string.endsWith(this._source, '.git')) { this._source += '.git'; } // Check if it's public this._public = mout.string.startsWith(this._source, 'git://'); // Use https:// rather than git:// if on a proxy if (this._config.proxy || this._config.httpsProxy) { this._source = this._source.replace('git://', 'https://'); } // Enable shallow clones for GitHub repos this._shallowClone = function() { return Q.resolve(true); }; } util.inherits(GitHubResolver, GitRemoteResolver); mout.object.mixIn(GitHubResolver, GitRemoteResolver); // ----------------- GitHubResolver.prototype._checkout = function () { // Only fully works with public repositories and tags // Could work with https/ssh protocol but not with 100% certainty if (!this._public || !this._resolution.tag) { return GitRemoteResolver.prototype._checkout.call(this); } var msg; var tarballUrl = 'https://github.com/' + this._org + '/' + this._repo + '/archive/' + this._resolution.tag + '.tar.gz'; var file = path.join(this._tempDir, 'archive.tar.gz'); var reqHeaders = {}; var that = this; if (this._config.userAgent) { reqHeaders['User-Agent'] = this._config.userAgent; } this._logger.action('download', tarballUrl, { url: that._source, to: file }); // Download tarball return download(tarballUrl, file, { ca: this._config.ca.default, strictSSL: this._config.strictSsl, timeout: this._config.timeout, headers: reqHeaders }) .progress(function (state) { // Retry? if (state.retry) { msg = 'Download of ' + tarballUrl + ' failed with ' + state.error.code + ', '; msg += 'retrying in ' + (state.delay / 1000).toFixed(1) + 's'; that._logger.debug('error', state.error.message, { error: state.error }); return that._logger.warn('retry', msg); } // Progress msg = 'received ' + (state.received / 1024 / 1024).toFixed(1) + 'MB'; if (state.total) { msg += ' of ' + (state.total / 1024 / 1024).toFixed(1) + 'MB downloaded, '; msg += state.percent + '%'; } that._logger.info('progress', msg); }) .then(function () { // Extract archive that._logger.action('extract', path.basename(file), { archive: file, to: that._tempDir }); return extract(file, that._tempDir) // Fallback to standard git clone if extraction failed .fail(function (err) { msg = 'Decompression of ' + path.basename(file) + ' failed' + (err.code ? ' with ' + err.code : '') + ', '; msg += 'trying with git..'; that._logger.debug('error', err.message, { error: err }); that._logger.warn('retry', msg); return that._cleanTempDir() .then(GitRemoteResolver.prototype._checkout.bind(that)); }); // Fallback to standard git clone if download failed }, function (err) { msg = 'Download of ' + tarballUrl + ' failed' + (err.code ? ' with ' + err.code : '') + ', '; msg += 'trying with git..'; that._logger.debug('error', err.message, { error: err }); that._logger.warn('retry', msg); return that._cleanTempDir() .then(GitRemoteResolver.prototype._checkout.bind(that)); }); }; GitHubResolver.prototype._savePkgMeta = function (meta) { // Set homepage if not defined if (!meta.homepage) { meta.homepage = 'https://github.com/' + this._org + '/' + this._repo; } return GitRemoteResolver.prototype._savePkgMeta.call(this, meta); }; // ---------------- GitHubResolver.getOrgRepoPair = function (url) { var match; match = url.match(/(?:@|:\/\/)github.com[:\/]([^\/\s]+?)\/([^\/\s]+?)(?:\.git)?\/?$/i); if (!match) { return null; } return { org: match[1], repo: match[2] }; }; module.exports = GitHubResolver;