ksa
Version:
Attempt at a browset package manager
154 lines (126 loc) • 4.92 kB
JavaScript
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;