mirror of
https://github.com/bower/bower.git
synced 2026-04-24 03:00:19 -04:00
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:
3
lib/commands/cache/clean.js
vendored
3
lib/commands/cache/clean.js
vendored
@@ -42,7 +42,8 @@ function clean(packages, options, config) {
|
||||
])
|
||||
.spread(function (entries) {
|
||||
emitter.emit('end', entries);
|
||||
}, function (error) {
|
||||
})
|
||||
.fail(function (error) {
|
||||
emitter.emit('error', error);
|
||||
});
|
||||
|
||||
|
||||
3
lib/commands/cache/list.js
vendored
3
lib/commands/cache/list.js
vendored
@@ -30,7 +30,8 @@ function list(packages, options, config) {
|
||||
}
|
||||
|
||||
emitter.emit('end', entries);
|
||||
}, function (error) {
|
||||
})
|
||||
.fail(function (error) {
|
||||
emitter.emit('error', error);
|
||||
});
|
||||
|
||||
|
||||
@@ -27,6 +27,9 @@ function info(pkg, property, config) {
|
||||
name: pkg.name,
|
||||
versions: versions
|
||||
});
|
||||
})
|
||||
.fail(function (error) {
|
||||
emitter.emit('error', error);
|
||||
});
|
||||
// Otherwise fetch version and retrieve package meta
|
||||
} else {
|
||||
@@ -45,7 +48,8 @@ function info(pkg, property, config) {
|
||||
}
|
||||
|
||||
emitter.emit('end', pkgMeta);
|
||||
}, function (error) {
|
||||
})
|
||||
.fail(function (error) {
|
||||
emitter.emit('error', error);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -22,7 +22,8 @@ function install(endpoints, options, config) {
|
||||
project.install(endpoints, options)
|
||||
.then(function (installed) {
|
||||
emitter.emit('end', installed);
|
||||
}, function (error) {
|
||||
})
|
||||
.fail(function (error) {
|
||||
emitter.emit('error', error);
|
||||
});
|
||||
|
||||
|
||||
@@ -1,34 +1,41 @@
|
||||
var EventEmitter = require('events').EventEmitter;
|
||||
var path = require('path');
|
||||
var mout = require('mout');
|
||||
var semver = require('semver');
|
||||
var Q = require('q');
|
||||
var Project = require('../core/Project');
|
||||
var PackageRepository = require('../core/PackageRepository');
|
||||
var Logger = require('../core/Logger');
|
||||
var cli = require('../util/cli');
|
||||
var defaultConfig = require('../config');
|
||||
|
||||
function list(options, config) {
|
||||
var project;
|
||||
var repository;
|
||||
var emitter = new EventEmitter();
|
||||
var logger = new Logger();
|
||||
|
||||
options = options || {};
|
||||
config = mout.object.deepMixIn(config || {}, defaultConfig);
|
||||
project = new Project(config, logger);
|
||||
|
||||
// TODO: look for new versions
|
||||
repository = new PackageRepository(config, logger);
|
||||
|
||||
project.getTree()
|
||||
.spread(function (tree, flattened, extraneous) {
|
||||
var ret;
|
||||
|
||||
if (options.paths) {
|
||||
ret = paths(flattened);
|
||||
} else {
|
||||
ret = normal(tree, extraneous);
|
||||
return emitter.emit('end', paths(flattened));
|
||||
}
|
||||
|
||||
emitter.emit('end', ret);
|
||||
}, function (error) {
|
||||
if (config.offline) {
|
||||
return emitter.emit('end', normal(tree, extraneous));
|
||||
}
|
||||
|
||||
return checkVersions(project, tree, logger, config)
|
||||
.then(function () {
|
||||
emitter.emit('end', normal(tree, extraneous));
|
||||
});
|
||||
})
|
||||
.fail(function (error) {
|
||||
emitter.emit('error', error);
|
||||
});
|
||||
|
||||
@@ -37,6 +44,44 @@ function list(options, config) {
|
||||
return logger.pipe(emitter);
|
||||
}
|
||||
|
||||
function checkVersions(project, tree, logger, config) {
|
||||
var promises;
|
||||
var nodes = [];
|
||||
var repository = new PackageRepository(config, logger);
|
||||
|
||||
// Gather all nodes
|
||||
project.walkTree(tree, function (node) {
|
||||
nodes.push(node);
|
||||
}, true);
|
||||
|
||||
if (nodes.length) {
|
||||
logger.info('check-new', 'Checking for new versions of the project dependencies..');
|
||||
}
|
||||
|
||||
// Check for new versions for each node
|
||||
promises = nodes.map(function (node) {
|
||||
var target = node.endpoint.target;
|
||||
|
||||
return repository.versions(node.endpoint.source)
|
||||
.then(function (versions) {
|
||||
node.versions = versions;
|
||||
|
||||
// Do not check if node's target is not a valid semver one
|
||||
if (versions.length && semver.validRange(target)) {
|
||||
node.update = {
|
||||
target: semver.maxSatisfying(versions, target),
|
||||
latest: semver.maxSatisfying(versions, '*')
|
||||
};
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// Set the versions also for the root node
|
||||
tree.versions = [];
|
||||
|
||||
return Q.all(promises);
|
||||
}
|
||||
|
||||
function paths(flattened) {
|
||||
var ret = {};
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
var EventEmitter = require('events').EventEmitter;
|
||||
var mout = require('mout');
|
||||
var Q = require('q');
|
||||
var RegistryClient = require('bower-registry-client');
|
||||
var cli = require('../util/cli');
|
||||
var defaultConfig = require('../config');
|
||||
@@ -12,17 +13,18 @@ function lookup(name, config) {
|
||||
config.cache = config.storage.registry;
|
||||
|
||||
registryClient = new RegistryClient(config);
|
||||
registryClient.lookup(name, function (error, entry) {
|
||||
if (error) {
|
||||
return emitter.emit('error', error);
|
||||
}
|
||||
|
||||
Q.nfcall(registryClient.lookup.bind(registryClient), name)
|
||||
.then(function (entry) {
|
||||
// TODO: Handle entry.type.. for now it's only 'alias'
|
||||
// When we got published packages, this needs to be adjusted
|
||||
emitter.emit('end', !entry ? null : {
|
||||
name: name,
|
||||
url: entry && entry.url
|
||||
});
|
||||
})
|
||||
.fail(function (error) {
|
||||
emitter.emit('error', error);
|
||||
});
|
||||
|
||||
return emitter;
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
var EventEmitter = require('events').EventEmitter;
|
||||
var mout = require('mout');
|
||||
var Q = require('q');
|
||||
var RegistryClient = require('bower-registry-client');
|
||||
var cli = require('../util/cli');
|
||||
var defaultConfig = require('../config');
|
||||
|
||||
function search(name, config) {
|
||||
var registryClient;
|
||||
var promise;
|
||||
var emitter = new EventEmitter();
|
||||
|
||||
config = mout.object.deepMixIn(config || {}, defaultConfig);
|
||||
@@ -15,23 +17,23 @@ function search(name, config) {
|
||||
|
||||
// If no name was specified, list all packages
|
||||
if (!name) {
|
||||
registryClient.list(onResults.bind(onResults, emitter));
|
||||
promise = Q.nfcall(registryClient.list.bind(registryClient));
|
||||
// Otherwise search it
|
||||
} else {
|
||||
registryClient.search(name, onResults.bind(onResults, emitter));
|
||||
promise = Q.nfcall(registryClient.search.bind(registryClient), name);
|
||||
}
|
||||
|
||||
promise
|
||||
.then(function (results) {
|
||||
emitter.emit('end', results);
|
||||
})
|
||||
.fail(function (error) {
|
||||
emitter.emit('error', error);
|
||||
});
|
||||
|
||||
return emitter;
|
||||
}
|
||||
|
||||
function onResults(emitter, error, results) {
|
||||
if (error) {
|
||||
return emitter.emit('error', error);
|
||||
}
|
||||
|
||||
emitter.emit('end', results);
|
||||
}
|
||||
|
||||
// -------------------
|
||||
|
||||
search.line = function (argv) {
|
||||
|
||||
@@ -24,7 +24,8 @@ function uninstall(names, options, config) {
|
||||
project.uninstall(names, options)
|
||||
.then(function (installed) {
|
||||
emitter.emit('end', installed);
|
||||
}, function (error) {
|
||||
})
|
||||
.fail(function (error) {
|
||||
emitter.emit('error', error);
|
||||
});
|
||||
|
||||
|
||||
@@ -22,7 +22,8 @@ function update(names, options, config) {
|
||||
project.update(names, options)
|
||||
.then(function (installed) {
|
||||
emitter.emit('end', installed);
|
||||
}, function (error) {
|
||||
})
|
||||
.fail(function (error) {
|
||||
emitter.emit('error', error);
|
||||
});
|
||||
|
||||
|
||||
@@ -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);
|
||||
});
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -44,7 +44,7 @@ StandardRenderer.prototype.error = function (err) {
|
||||
err.id = err.code || 'error';
|
||||
err.level = 'error';
|
||||
|
||||
str = this._prefix(err) + ' ' + err.message.trim() + '\n';
|
||||
str = this._prefix(err) + ' ' + err.message.replace(/\r?\n/g, ' ').trim() + '\n';
|
||||
this._write(process.stderr, 'bower ' + str);
|
||||
|
||||
// Check if additional details were provided
|
||||
@@ -59,7 +59,7 @@ StandardRenderer.prototype.error = function (err) {
|
||||
// TODO: In some situations, err.stack is meaningless
|
||||
// Investigate why and find alternatives
|
||||
str = '\nStack trace:\n'.yellow;
|
||||
str += err.stack;
|
||||
str += err.stack + '\n';
|
||||
this._write(process.stderr, str);
|
||||
}
|
||||
};
|
||||
@@ -323,11 +323,13 @@ StandardRenderer.prototype._tree2archy = function (node) {
|
||||
var dependencies = mout.object.values(node.dependencies);
|
||||
var version = !node.missing ? node.pkgMeta._release || node.pkgMeta.version : null;
|
||||
var label = node.endpoint.name + (version ? '#' + version : '');
|
||||
var update;
|
||||
|
||||
if (node.root) {
|
||||
label += ' ' + node.canonicalDir;
|
||||
}
|
||||
|
||||
// State lables
|
||||
if (node.missing) {
|
||||
label += ' missing'.red;
|
||||
return label;
|
||||
@@ -343,6 +345,23 @@ StandardRenderer.prototype._tree2archy = function (node) {
|
||||
label += ' extraneous'.green;
|
||||
}
|
||||
|
||||
// New versions
|
||||
if (node.update) {
|
||||
update = '';
|
||||
|
||||
if (node.update.target && node.pkgMeta.version !== node.update.target) {
|
||||
update += node.update.target + ' available';
|
||||
}
|
||||
|
||||
if (update && node.update.latest !== node.update.target) {
|
||||
update += ', latest is ' + node.update.latest;
|
||||
}
|
||||
|
||||
if (update) {
|
||||
label += ' (' + update.cyan + ')';
|
||||
}
|
||||
}
|
||||
|
||||
if (!dependencies.length) {
|
||||
return label;
|
||||
}
|
||||
|
||||
@@ -49,6 +49,23 @@ function json2decomposed(key, value) {
|
||||
return decompose(endpoint);
|
||||
}
|
||||
|
||||
function decomposed2json(decEndpoint) {
|
||||
var key = decEndpoint.name;
|
||||
var value = '';
|
||||
var ret = {};
|
||||
|
||||
if (decEndpoint.source !== decEndpoint.name) {
|
||||
value += decEndpoint.source + '#';
|
||||
}
|
||||
|
||||
value += decEndpoint.target;
|
||||
|
||||
ret[key] = value;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
module.exports.decompose = decompose;
|
||||
module.exports.compose = compose;
|
||||
module.exports.json2decomposed = json2decomposed;
|
||||
module.exports.decomposed2json = decomposed2json;
|
||||
|
||||
Reference in New Issue
Block a user