mirror of
https://github.com/bower/bower.git
synced 2026-02-11 22:44:58 -05:00
Implemented GitFsResolver, minor refactor to the GitRemoteResolver.
This commit is contained in:
@@ -1,43 +1,93 @@
|
||||
var util = require('util');
|
||||
var fs = require('fs');
|
||||
var Q = require('q');
|
||||
var Package = require('../Package');
|
||||
var mout = require('mout');
|
||||
var GitRemoteResolver = require('./GitRemoteResolver');
|
||||
var copy = require('../../util/copy');
|
||||
var cmd = require('../../util/cmd');
|
||||
|
||||
var GitFsPackage = function (endpoint, options) {
|
||||
Package.call(this, endpoint, options);
|
||||
var GitFsResolver = function (endpoint, options) {
|
||||
GitRemoteResolver.call(this, endpoint, options);
|
||||
};
|
||||
|
||||
util.inherits(GitFsPackage, Package);
|
||||
util.inherits(GitFsResolver, GitRemoteResolver);
|
||||
|
||||
// -----------------
|
||||
|
||||
GitFsPackage.prototype._resolveSelf = function () {
|
||||
var promise;
|
||||
GitFsResolver.prototype._resolveSelf = function () {
|
||||
var self = this.constructor;
|
||||
|
||||
console.log('_resolveSelf of git local package');
|
||||
promise = this._copy()
|
||||
return this._copy()
|
||||
.then(this._fetch.bind(this))
|
||||
.then(this._versions.bind(this))
|
||||
.then(self.findResolution.bind(self, this._tempDir, this._target))
|
||||
.then(this._checkout.bind(this));
|
||||
|
||||
return promise;
|
||||
};
|
||||
|
||||
GitFsPackage.prototype._copy = function () {
|
||||
// create temporary folder
|
||||
// copy over
|
||||
// -----------------
|
||||
|
||||
GitFsResolver.prototype._copy = function () {
|
||||
var tempDir = this._tempDir;
|
||||
|
||||
// Copy folder permissions
|
||||
return Q.nfcall(fs.stat, this._source)
|
||||
.then(function (stat) {
|
||||
return Q.nfcall(fs.chmod, tempDir, stat.mode);
|
||||
})
|
||||
// Copy folder contents
|
||||
.then(copy.bind(copy, this._source, tempDir))
|
||||
.then(function () {
|
||||
this._source = tempDir;
|
||||
}.bind(this));
|
||||
};
|
||||
|
||||
GitFsPackage.prototype._fetch = function () {
|
||||
// fetch origin
|
||||
// reset --hard
|
||||
GitFsResolver.prototype._fetch = function () {
|
||||
var dir = this._tempDir;
|
||||
|
||||
// Check if there is at least one remote
|
||||
cmd('git', ['remote'], { cwd: dir })
|
||||
.then(function (stdout) {
|
||||
var hasRemote = !!stdout.trim().length;
|
||||
|
||||
// If so, do a fetch to grab the new tags and refs
|
||||
if (hasRemote) {
|
||||
return cmd('git', ['fetch', '--prune']);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
GitFsPackage.prototype._versions = function () {
|
||||
// retrieve versions
|
||||
// Override the checkout function to work with the local copy
|
||||
GitFsResolver.prototype._checkout = function (resolution) {
|
||||
var dir = this._tempDir;
|
||||
|
||||
console.log(resolution);
|
||||
|
||||
// Checkout resolution
|
||||
cmd('git', ['checkout', '-f', resolution.tag || resolution.branch || resolution.commit], { cwd: dir })
|
||||
// Cleanup unstagged files
|
||||
.then(function () {
|
||||
return cmd('git', ['clean', '-f', '-d'], { cwd: dir });
|
||||
});
|
||||
};
|
||||
|
||||
GitFsPackage.prototype._checkout = function () {
|
||||
// resolve range to a specific version and check it out
|
||||
// -----------------
|
||||
|
||||
// Copy static stuff
|
||||
mout.object.mixIn(GitFsResolver, GitRemoteResolver);
|
||||
|
||||
// Override the fetch refs to grab them locally
|
||||
GitFsResolver.fetchRefs = function (source) {
|
||||
if (this._refs && this._refs[source]) {
|
||||
return Q.resolve(this._refs[source]);
|
||||
}
|
||||
|
||||
return cmd('git', ['show-ref', '--tags', '--heads'], { cwd : source })
|
||||
.then(function (stdout) {
|
||||
// Make them an array
|
||||
var refs = stdout.toString().split('\n');
|
||||
|
||||
this._refs = this._refs || {};
|
||||
return this._refs[source] = refs;
|
||||
}.bind(this));
|
||||
};
|
||||
|
||||
module.exports = GitFsPackage;
|
||||
module.exports = GitFsResolver;
|
||||
|
||||
@@ -14,8 +14,13 @@ util.inherits(GitRemoteResolver, Resolver);
|
||||
|
||||
// -----------------
|
||||
|
||||
GitRemoteResolver.prototype._resolveSelf = function () {
|
||||
return this.constructor.findResolution(this._source, this._target)
|
||||
.then(this._checkout.bind(this));
|
||||
};
|
||||
|
||||
GitRemoteResolver.prototype.hasNew = function (oldTarget, oldResolution) {
|
||||
return this._resolveTarget(this._target)
|
||||
return this.constructor.findResolution(this._source, this._target)
|
||||
.then(function (resolution) {
|
||||
// Resolution types are different
|
||||
if (oldResolution.type !== resolution.type) {
|
||||
@@ -28,33 +33,43 @@ GitRemoteResolver.prototype.hasNew = function (oldTarget, oldResolution) {
|
||||
return semver.neq(resolution.tag, oldResolution.tag);
|
||||
}
|
||||
|
||||
|
||||
// If resolved to a commit hash, just check if they are different
|
||||
// Use the same strategy if it the resolution is to a branch
|
||||
return resolution.commit !== oldResolution.commit;
|
||||
});
|
||||
};
|
||||
|
||||
GitRemoteResolver.prototype._resolveSelf = function () {
|
||||
var promise;
|
||||
// -----------------
|
||||
|
||||
promise = this._resolveTarget()
|
||||
.then(this._checkout.bind(this));
|
||||
GitRemoteResolver.prototype._checkout = function (resolution) {
|
||||
var dir = this._tempDir,
|
||||
branch;
|
||||
|
||||
return promise;
|
||||
console.log(resolution);
|
||||
|
||||
// If resolution is a commit, we need to clone the entire repo and checkit out
|
||||
// Because a commit is not a nammed ref, there's no better solution
|
||||
if (resolution.type === 'commit') {
|
||||
return cmd('git', ['clone', this._source, '.'], { cwd: dir })
|
||||
.then(function () {
|
||||
return cmd('git', ['checkout', resolution.commit], { cwd: dir });
|
||||
});
|
||||
// Otherwise we are checking out a named ref so we can optimize it
|
||||
} else {
|
||||
branch = resolution.tag || resolution.branch;
|
||||
return cmd('git', ['clone', this._source, '-b', branch, '--depth', 1, '.'], { cwd: dir });
|
||||
}
|
||||
};
|
||||
|
||||
GitRemoteResolver.prototype._resolveTarget = function () {
|
||||
var target = this._target,
|
||||
source = this._source,
|
||||
promise,
|
||||
branches,
|
||||
errorMessage,
|
||||
errorDetails;
|
||||
// ------------------------------
|
||||
|
||||
GitRemoteResolver.findResolution = function (source, target) {
|
||||
var promise,
|
||||
branches;
|
||||
|
||||
// Target is a range/version
|
||||
if (semver.valid(target) || semver.validRange(target)) {
|
||||
return GitRemoteResolver._fetchVersions(this._source)
|
||||
return this.fetchVersions(source)
|
||||
.then(function (versions) {
|
||||
// Find the highest one that satifies the target
|
||||
var version = mout.array.find(versions, function (version) {
|
||||
@@ -62,13 +77,11 @@ GitRemoteResolver.prototype._resolveTarget = function () {
|
||||
});
|
||||
|
||||
if (!version) {
|
||||
errorMessage = !semver.validRange(target) ?
|
||||
'Tag "' + target + '" does not exist' :
|
||||
'No tag found that was able to satisfy "' + target + '"';
|
||||
errorDetails = !versions.length ?
|
||||
'No tags found in "' + source + '"' :
|
||||
'Available tags in "' + source + '" are: ' + versions.join(', ');
|
||||
throw createError(errorMessage, 'ENORESTARGET', errorDetails);
|
||||
throw createError('No tag found that was able to satisfy "' + target + '"', 'ENORESTARGET', {
|
||||
details: !versions.length ?
|
||||
'No tags found in "' + source + '"' :
|
||||
'Available tags in "' + source + '" are: ' + versions.join(', ')
|
||||
});
|
||||
}
|
||||
|
||||
return { type: 'tag', tag: version };
|
||||
@@ -76,7 +89,7 @@ GitRemoteResolver.prototype._resolveTarget = function () {
|
||||
}
|
||||
|
||||
// Resolve the rest to a commit version
|
||||
promise = GitRemoteResolver._fetchHeads(this._source);
|
||||
promise = this.fetchHeads(source);
|
||||
|
||||
// Target is a commit, so it's a stale target (not a moving target)
|
||||
// There's nothing to do in this case
|
||||
@@ -93,41 +106,23 @@ GitRemoteResolver.prototype._resolveTarget = function () {
|
||||
return promise.then(function (heads) {
|
||||
if (!heads[target]) {
|
||||
branches = Object.keys(heads);
|
||||
errorDetails = !branches.length ?
|
||||
'No branches found in "' + source + '"' :
|
||||
'Available branches in "' + source + '" are: ' + branches.join(', ');
|
||||
|
||||
throw createError('Branch "' + target + '" does not exist', 'ENORESTARGET', errorDetails);
|
||||
throw createError('Branch "' + target + '" does not exist', 'ENORESTARGET', {
|
||||
details: !branches.length ?
|
||||
'No branches found in "' + source + '"' :
|
||||
'Available branches in "' + source + '" are: ' + branches.join(', ')
|
||||
});
|
||||
}
|
||||
|
||||
return { type: 'branch', branch: target, commit: heads[target] };
|
||||
});
|
||||
};
|
||||
|
||||
GitRemoteResolver.prototype._checkout = function (resolution) {
|
||||
var dir = this._tempDir,
|
||||
branch;
|
||||
|
||||
console.log(resolution);
|
||||
if (resolution.type === 'commit') {
|
||||
return Q.nfcall(cmd, 'git', ['clone', this._source, dir])
|
||||
.then(function () {
|
||||
return Q.nfcall(cmd, 'git', ['checkout', resolution.commit], { cwd: dir });
|
||||
});
|
||||
} else {
|
||||
branch = resolution.tag || resolution.branch;
|
||||
return Q.nfcall(cmd, 'git', ['clone', this._source, '-b', branch, '--depth', 1], { cwd: dir });
|
||||
}
|
||||
};
|
||||
|
||||
// ------------------------------
|
||||
|
||||
GitRemoteResolver._fetchRefs = function (source) {
|
||||
GitRemoteResolver.fetchRefs = function (source) {
|
||||
if (this._refs && this._refs[source]) {
|
||||
return Q.resolve(this._refs[source]);
|
||||
}
|
||||
|
||||
return Q.nfcall(cmd, 'git', ['ls-remote', '--tags', '--heads', source])
|
||||
return cmd('git', ['ls-remote', '--tags', '--heads', source])
|
||||
.then(function (stdout) {
|
||||
// Make them an array
|
||||
var refs = stdout.toString().split('\n');
|
||||
@@ -137,18 +132,18 @@ GitRemoteResolver._fetchRefs = function (source) {
|
||||
}.bind(this));
|
||||
};
|
||||
|
||||
GitRemoteResolver._fetchVersions = function (source) {
|
||||
GitRemoteResolver.fetchVersions = function (source) {
|
||||
if (this._versions && this._versions[source]) {
|
||||
return Q.resolve(this._versions[source]);
|
||||
}
|
||||
|
||||
return this._fetchRefs(source)
|
||||
return this.fetchRefs(source)
|
||||
.then(function (refs) {
|
||||
var versions = [];
|
||||
|
||||
// Parse each ref line, extracting the tag
|
||||
refs.forEach(function (line) {
|
||||
var match = line.match(/^[a-f0-9]{40}\s+refs\/tags\/(\S+)$/),
|
||||
var match = line.match(/^[a-f0-9]{40}\s+refs\/tags\/(\S+)/),
|
||||
cleaned;
|
||||
|
||||
// Ensure it's valid
|
||||
@@ -170,21 +165,21 @@ GitRemoteResolver._fetchVersions = function (source) {
|
||||
}.bind(this));
|
||||
};
|
||||
|
||||
GitRemoteResolver._fetchHeads = function (source) {
|
||||
GitRemoteResolver.fetchHeads = function (source) {
|
||||
if (this._heads && this._heads[source]) {
|
||||
return Q.resolve(this._heads[source]);
|
||||
}
|
||||
|
||||
return this._fetchRefs(source)
|
||||
return this.fetchRefs(source)
|
||||
.then(function (refs) {
|
||||
this._heads = this._heads || {};
|
||||
var heads = this._heads[source] = this._heads[source] || {};
|
||||
|
||||
// Foreach line in the refs, extract only the heads
|
||||
// Organize them in an object where keys are branches and values
|
||||
// the commit hash
|
||||
mout.array.forEach(refs, function (line) {
|
||||
var match = line.match(/^([a-f0-9]{40})\s+refs\/heads\/(\S+)$/);
|
||||
// the commit hashes
|
||||
refs.forEach(function (line) {
|
||||
var match = line.match(/^([a-f0-9]{40})\s+refs\/heads\/(\S+)/);
|
||||
|
||||
if (match) {
|
||||
heads[match[2]] = match[1];
|
||||
|
||||
Reference in New Issue
Block a user