Implement check of newer versions in the list command.

Also:
- Fix some errors not being emitted when a command failed.
- Update semver module; no need to check .valid against null.
This commit is contained in:
André Cruz
2013-07-03 14:37:28 +01:00
parent deee654426
commit 7becb19da4
16 changed files with 199 additions and 87 deletions

View File

@@ -164,13 +164,13 @@ Manager.prototype.areCompatible = function (candidate, resolved) {
}
// If target is a version, compare against the resolved version
if (semver.valid(candidate.target) != null) {
if (semver.valid(candidate.target)) {
return semver.eq(candidate.target, resolvedVersion);
}
// If target is a range, check if the max versions of the range are the same
// and if the resolved version satisfies the candidate target
if (semver.validRange(candidate.target) != null) {
if (semver.validRange(candidate.target)) {
highestCandidate = this._getCap(semver.toComparators(candidate.target), 'highest');
highestResolved = this._getCap(semver.toComparators(resolved.target), 'highest');
@@ -580,7 +580,7 @@ Manager.prototype._electSuitable = function (name, semvers, nonSemvers) {
});
if (resolution && !unresolvable) {
if (semver.valid(resolution) != null || semver.validRange(resolution) != null) {
if (semver.validRange(resolution)) {
suitable = mout.array.findIndex(picks, function (pick) {
return semver.satisfies(pick.pkgMeta.version, resolution);
});

View File

@@ -3,6 +3,7 @@ var path = require('path');
var fs = require('graceful-fs');
var crypto = require('crypto');
var Q = require('q');
var semver = require('semver');
var mout = require('mout');
var rimraf = require('rimraf');
var promptly = require('promptly');
@@ -44,7 +45,7 @@ Project.prototype.install = function (endpoints, options) {
return this._analyse()
.spread(function (json, tree) {
// Walk down the tree adding targets, resolved and incompatibles
that._walkTree(tree, function (node, name) {
that.walkTree(tree, function (node, name) {
if (node.missing || node.linked) {
targets.push(node);
} else if (node.incompatible) {
@@ -72,18 +73,14 @@ Project.prototype.install = function (endpoints, options) {
// Handle save and saveDev options
if (options.save || options.saveDev) {
mout.object.forOwn(targets, function (decEndpoint) {
var source = decEndpoint.source === decEndpoint.name ? '' : decEndpoint.source;
var target = decEndpoint.target;
var endpoint = mout.string.ltrim(source + '#' + target, ['#']);
var jsonEndpoint = endpointParser.decomposed2json(decEndpoint);
if (options.save) {
that._json.dependencies = that._json.dependencies || {};
that._json.dependencies[decEndpoint.name] = endpoint;
that._json.dependencies = mout.object.mixIn(that._json.dependencies || {}, jsonEndpoint);
}
if (options.saveDev) {
that._json.devDependencies = that._json.devDependencies || {};
that._json.devDependencies[decEndpoint.name] = endpoint;
that._json.devDependencies = mout.object.mixIn(that._json.devDependencies || {}, jsonEndpoint);
}
});
}
@@ -121,7 +118,7 @@ Project.prototype.update = function (names, options) {
// If no names were specified, update every package
if (!names) {
// Mark each root dependency as targets
that._walkTree(tree, function (node) {
that.walkTree(tree, function (node) {
targets.push(node);
return false;
}, true);
@@ -146,7 +143,7 @@ Project.prototype.update = function (names, options) {
// Walk down the tree adding missing, incompatible
// and resolved
that._walkTree(tree, function (node, name) {
that.walkTree(tree, function (node, name) {
if (node.missing || node.linked) {
targets.push(node);
} else if (node.incompatible) {
@@ -157,7 +154,7 @@ Project.prototype.update = function (names, options) {
}, true);
// Add root packages whose names are specified to be updated
that._walkTree(tree, function (node, name) {
that.walkTree(tree, function (node, name) {
if (!node.missing && !node.linked && names.indexOf(name) !== -1) {
targets.push(node);
}
@@ -221,7 +218,7 @@ Project.prototype.uninstall = function (names, options) {
var dependants = [];
// Walk the down the tree, gathering dependants of the package
that._walkTree(tree, function (node, nodeName) {
that.walkTree(tree, function (node, nodeName) {
if (name === nodeName) {
dependants.push.apply(dependants, mout.object.values(node.dependants));
}
@@ -301,8 +298,22 @@ Project.prototype.getTree = function () {
.spread(function (json, tree, flattened) {
var extraneous = [];
tree = this._manager.toData(tree, ['missing', 'incompatible', 'linked']);
tree = this._manager.toData(tree, ['missing', 'linked']);
// Mark incompatibles
this.walkTree(tree, function (node) {
var version;
var target = node.endpoint.target;
if (target !== '*' && semver.validRange(target)) {
version = node.pkgMeta.version;
if (!version || !semver.satisfies(version, target)) {
node.incompatible = true;
}
}
}, true);
// Find extraneous
mout.object.forOwn(flattened, function (pkg) {
if (pkg.extraneous) {
extraneous.push(this._manager.toData(pkg, ['linked']));
@@ -317,6 +328,47 @@ Project.prototype.getJson = function () {
return this._readJson();
};
Project.prototype.walkTree = function (node, fn, onlyOnce) {
var result;
var dependencies;
var queue = mout.object.values(node.dependencies);
if (onlyOnce === true) {
onlyOnce = [];
}
while (queue.length) {
node = queue.shift();
result = fn(node, node.name);
// Abort traversal if result is false
if (result === false) {
continue;
}
// Add dependencies to the queue
dependencies = mout.object.values(node.dependencies);
// If onlyOnce was true, do not add if already traversed
if (onlyOnce) {
dependencies = dependencies.filter(function (dependency) {
return !mout.array.find(onlyOnce, function (stacked) {
if (dependency.endpoint) {
return mout.object.equals(dependency.endpoint, stacked.endpoint);
}
return dependency.name === stacked.name &&
dependency.source === stacked.source &&
dependency.target === stacked.target;
});
});
onlyOnce.push.apply(onlyOnce, dependencies);
}
queue.unshift.apply(queue, dependencies);
}
};
// -----------------
Project.prototype._analyse = function () {
@@ -613,41 +665,6 @@ Project.prototype._removePackages = function (packages, options) {
});
};
Project.prototype._walkTree = function (node, fn, onlyOnce) {
var queue = mout.object.values(node.dependencies);
var result;
var dependencies;
if (onlyOnce === true) {
onlyOnce = [];
}
while (queue.length) {
node = queue.shift();
result = fn(node, node.name);
if (onlyOnce) {
onlyOnce.push(node);
}
// Abort traversal if result is false
if (result === false) {
continue;
}
// Add dependencies to the queue
dependencies = mout.object.values(node.dependencies);
// If onlyOnce was true, do not add if already traversed
if (onlyOnce) {
dependencies = dependencies.filter(function (dependency) {
return onlyOnce.indexOf(dependency) === -1;
});
}
queue.unshift.apply(queue, dependencies);
}
};
Project.prototype._restoreNode = function (node, flattened, jsonKey) {
var deps;

View File

@@ -47,7 +47,7 @@ ResolveCache.prototype.retrieve = function (source, target) {
var suitable;
// If target is a semver, find a suitable version
if (semver.valid(target) != null || semver.validRange(target) != null) {
if (semver.validRange(target)) {
suitable = mout.array.find(versions, function (version) {
return semver.satisfies(version, target);
});
@@ -100,7 +100,7 @@ ResolveCache.prototype.versions = function (source) {
return this._getVersions(sourceId)
.spread(function (versions) {
return versions.filter(function (version) {
return semver.valid(version) != null;
return semver.valid(version);
});
});
};
@@ -331,8 +331,8 @@ ResolveCache.prototype._getVersions = function (sourceId) {
ResolveCache.prototype._sortVersions = function (versions) {
// Sort DESC
versions.sort(function (version1, version2) {
var validSemver1 = semver.valid(version1) != null;
var validSemver2 = semver.valid(version2) != null;
var validSemver1 = semver.valid(version1);
var validSemver2 = semver.valid(version2);
// If both are semvers, compare them
if (validSemver1 && validSemver2) {