mirror of
https://github.com/bower/bower.git
synced 2026-04-24 03:00:19 -04:00
Merge pull request #709 from bower/several-improv
Several improvements and fixes
This commit is contained in:
@@ -161,7 +161,14 @@ function setDependencies(project, json, answers) {
|
||||
// TODO: The final expanded source is used instead of the original source
|
||||
// While this the most correct it might be confusing to users
|
||||
extraneous.forEach(function (extra) {
|
||||
var jsonEndpoint = endpointParser.decomposed2json(extra.endpoint);
|
||||
var jsonEndpoint;
|
||||
|
||||
// Skip linked packages
|
||||
if (extra.linked) {
|
||||
return;
|
||||
}
|
||||
|
||||
jsonEndpoint = endpointParser.decomposed2json(extra.endpoint);
|
||||
mout.object.mixIn(json.dependencies, jsonEndpoint);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -16,18 +16,18 @@ function list(options, config) {
|
||||
project = new Project(config, logger);
|
||||
|
||||
project.getTree()
|
||||
.spread(function (tree, flattened, extraneous) {
|
||||
.spread(function (tree, flattened) {
|
||||
if (options.paths) {
|
||||
return logger.emit('end', paths(flattened));
|
||||
}
|
||||
|
||||
if (config.offline) {
|
||||
return logger.emit('end', normal(tree, extraneous));
|
||||
return logger.emit('end', tree);
|
||||
}
|
||||
|
||||
return checkVersions(project, tree, logger)
|
||||
.then(function () {
|
||||
logger.emit('end', normal(tree, extraneous));
|
||||
logger.emit('end', tree);
|
||||
});
|
||||
})
|
||||
.fail(function (error) {
|
||||
@@ -110,17 +110,6 @@ function paths(flattened) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
function normal(tree, extraneous) {
|
||||
// Merge extraneous as root dependencies
|
||||
// but signal it with a flag
|
||||
extraneous.forEach(function (decEndpoint) {
|
||||
decEndpoint.extraneous = true;
|
||||
tree.dependencies[decEndpoint.endpoint.name] = decEndpoint;
|
||||
});
|
||||
|
||||
return tree;
|
||||
}
|
||||
|
||||
// -------------------
|
||||
|
||||
list.line = function (argv) {
|
||||
|
||||
@@ -4,40 +4,50 @@ var Project = require('../core/Project');
|
||||
var cli = require('../util/cli');
|
||||
var defaultConfig = require('../config');
|
||||
|
||||
function prune(names, config) {
|
||||
function prune(config) {
|
||||
var project;
|
||||
var logger = new Logger();
|
||||
|
||||
config = mout.object.deepFillIn(config || {}, defaultConfig);
|
||||
project = new Project(config, logger);
|
||||
|
||||
// If names is an empty array, null them
|
||||
if (names && !names.length) {
|
||||
names = null;
|
||||
}
|
||||
|
||||
// Figure out extraneous
|
||||
project.getTree()
|
||||
.spread(function (tree, flattened, extraneous) {
|
||||
var names;
|
||||
|
||||
names = extraneous.map(function (extra) {
|
||||
return extra.endpoint.name;
|
||||
});
|
||||
|
||||
// Uninstall them
|
||||
project.uninstall(names)
|
||||
.then(function (removed) {
|
||||
logger.emit('end', removed);
|
||||
})
|
||||
.fail(function (error) {
|
||||
logger.emit('error', error);
|
||||
});
|
||||
clean(project)
|
||||
.then(function (removed) {
|
||||
logger.emit('end', removed);
|
||||
})
|
||||
.fail(function (error) {
|
||||
logger.emit('error', error);
|
||||
});
|
||||
|
||||
return logger;
|
||||
}
|
||||
|
||||
function clean(project, removed) {
|
||||
removed = removed || {};
|
||||
|
||||
// Continually call clean until there is no more extraneous
|
||||
// dependencies to remove
|
||||
return project.getTree()
|
||||
.spread(function (tree, flattened, extraneous) {
|
||||
var names = extraneous.map(function (extra) {
|
||||
return extra.endpoint.name;
|
||||
});
|
||||
|
||||
// Uninstall extraneous
|
||||
project.uninstall(names)
|
||||
.then(function (uninstalled) {
|
||||
// Are we done?
|
||||
if (!mout.object.size(uninstalled)) {
|
||||
return removed;
|
||||
}
|
||||
|
||||
// Not yet, recurse!
|
||||
mout.object.mixIn(removed, uninstalled);
|
||||
return clean(project, removed);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// -------------------
|
||||
|
||||
prune.line = function () {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
var mout = require('mout');
|
||||
var Logger = require('bower-logger');
|
||||
var Q = require('q');
|
||||
var Project = require('../core/Project');
|
||||
var cli = require('../util/cli');
|
||||
var defaultConfig = require('../config');
|
||||
@@ -12,14 +13,28 @@ function uninstall(names, options, config) {
|
||||
config = mout.object.deepFillIn(config || {}, defaultConfig);
|
||||
project = new Project(config, logger);
|
||||
|
||||
// If names is an empty array, null them
|
||||
if (names && !names.length) {
|
||||
names = null;
|
||||
}
|
||||
project.getTree()
|
||||
.spread(function (tree, flattened) {
|
||||
// Uninstall nodes
|
||||
return project.uninstall(names, options)
|
||||
// Clean out non-shared uninstalled dependencies
|
||||
.then(function (uninstalled) {
|
||||
var names = Object.keys(uninstalled);
|
||||
var children = [];
|
||||
|
||||
project.uninstall(names, options)
|
||||
.then(function (removed) {
|
||||
logger.emit('end', removed);
|
||||
// Grab the dependencies of packages that were uninstalled
|
||||
mout.object.forOwn(flattened, function (node) {
|
||||
if (names.indexOf(node.endpoint.name) !== -1) {
|
||||
children.push.apply(children, mout.object.keys(node.dependencies));
|
||||
}
|
||||
});
|
||||
|
||||
// Clean them!
|
||||
return clean(project, children, uninstalled);
|
||||
});
|
||||
})
|
||||
.then(function (uninstalled) {
|
||||
logger.emit('end', uninstalled);
|
||||
})
|
||||
.fail(function (error) {
|
||||
logger.emit('error', error);
|
||||
@@ -28,6 +43,55 @@ function uninstall(names, options, config) {
|
||||
return logger;
|
||||
}
|
||||
|
||||
function clean(project, names, removed) {
|
||||
removed = removed || {};
|
||||
|
||||
return project.getTree()
|
||||
.spread(function (tree, flattened) {
|
||||
var nodes = [];
|
||||
|
||||
// Grab the nodes of each specified name
|
||||
mout.object.forOwn(flattened, function (node) {
|
||||
if (names.indexOf(node.endpoint.name) !== -1) {
|
||||
nodes.push(node);
|
||||
}
|
||||
});
|
||||
|
||||
// Filter out those that have dependants
|
||||
nodes = nodes.filter(function (node) {
|
||||
return !node.nrDependants;
|
||||
});
|
||||
|
||||
// Are we done?
|
||||
if (!nodes.length) {
|
||||
return Q.resolve(removed);
|
||||
}
|
||||
|
||||
// Grab the nodes after filtering
|
||||
names = nodes.map(function (node) {
|
||||
return node.endpoint.name;
|
||||
});
|
||||
|
||||
// Uninstall them
|
||||
return project.uninstall(names)
|
||||
// Clean out non-shared uninstalled dependencies
|
||||
.then(function (uninstalled) {
|
||||
var children;
|
||||
|
||||
mout.object.mixIn(removed, uninstalled);
|
||||
|
||||
// Grab the dependencies of packages that were uninstalled
|
||||
children = [];
|
||||
nodes.forEach(function (node) {
|
||||
children.push.apply(children, mout.object.keys(node.dependencies));
|
||||
});
|
||||
|
||||
// Recurse!
|
||||
return clean(project, children, removed);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// -------------------
|
||||
|
||||
uninstall.line = function (argv) {
|
||||
|
||||
@@ -146,8 +146,11 @@ Manager.prototype.install = function () {
|
||||
var json = JSON.parse(contents.toString());
|
||||
|
||||
json._target = decEndpoint.target;
|
||||
json = JSON.stringify(json, null, ' ');
|
||||
if (decEndpoint.newly) {
|
||||
json._direct = true;
|
||||
}
|
||||
|
||||
json = JSON.stringify(json, null, ' ');
|
||||
return Q.nfcall(fs.writeFile, metaFile, json);
|
||||
});
|
||||
});
|
||||
@@ -195,6 +198,8 @@ Manager.prototype.toData = function (decEndpoint, extraKeys) {
|
||||
}, this);
|
||||
}
|
||||
|
||||
data.nrDependants = mout.object.size(decEndpoint.dependants);
|
||||
|
||||
return data;
|
||||
};
|
||||
|
||||
@@ -371,9 +376,10 @@ Manager.prototype._parseDependencies = function (decEndpoint, pkgMeta, jsonKey)
|
||||
return this._areCompatible(childDecEndpoint, resolved);
|
||||
}, this);
|
||||
|
||||
// If we found one, add as resolved as resolved
|
||||
// If we found one, add as resolved
|
||||
// and copy resolved properties from the compatible one
|
||||
if (compatible) {
|
||||
decEndpoint.dependencies[key] = compatible;
|
||||
childDecEndpoint.canonicalDir = compatible.canonicalDir;
|
||||
childDecEndpoint.pkgMeta = compatible.pkgMeta;
|
||||
childDecEndpoint.dependencies = compatible.dependencies;
|
||||
|
||||
@@ -30,6 +30,7 @@ function Project(config, logger) {
|
||||
// -----------------
|
||||
|
||||
Project.prototype.install = function (endpoints, options) {
|
||||
var decEndpoints;
|
||||
var that = this;
|
||||
var targets = [];
|
||||
var resolved = {};
|
||||
@@ -46,7 +47,7 @@ Project.prototype.install = function (endpoints, options) {
|
||||
// Analyse the project
|
||||
return this._analyse()
|
||||
.spread(function (json, tree) {
|
||||
// Walk down the tree adding targets, resolved and incompatibles
|
||||
// Recover tree
|
||||
that.walkTree(tree, function (node, name) {
|
||||
if (node.missing) {
|
||||
targets.push(node);
|
||||
@@ -61,19 +62,24 @@ Project.prototype.install = function (endpoints, options) {
|
||||
if (node.linked) {
|
||||
return false;
|
||||
}
|
||||
}, true);
|
||||
});
|
||||
|
||||
// Add endpoints as targets
|
||||
if (endpoints) {
|
||||
endpoints.forEach(function (endpoint) {
|
||||
decEndpoints = endpoints.map(function (endpoint) {
|
||||
var decEndpoint = endpointParser.decompose(endpoint);
|
||||
targets.push(decEndpoint);
|
||||
|
||||
// Mark as new so that a conflict for this target
|
||||
// always require a choice
|
||||
// Also allows for the target to be converted in case
|
||||
// of being *
|
||||
decEndpoint.newly = true;
|
||||
targets.push(decEndpoint);
|
||||
|
||||
return decEndpoint;
|
||||
});
|
||||
} else {
|
||||
decEndpoints = [];
|
||||
}
|
||||
|
||||
// Bootstrap the process
|
||||
@@ -82,8 +88,11 @@ Project.prototype.install = function (endpoints, options) {
|
||||
.then(function (installed) {
|
||||
// Handle save and saveDev options
|
||||
if (that._options.save || that._options.saveDev) {
|
||||
mout.object.forOwn(targets, function (decEndpoint) {
|
||||
var jsonEndpoint = endpointParser.decomposed2json(decEndpoint);
|
||||
// Cycle through the specified endpoints
|
||||
decEndpoints.forEach(function (decEndpoint) {
|
||||
var jsonEndpoint;
|
||||
|
||||
jsonEndpoint = endpointParser.decomposed2json(decEndpoint);
|
||||
|
||||
if (that._options.save) {
|
||||
that._json.dependencies = mout.object.mixIn(that._json.dependencies || {}, jsonEndpoint);
|
||||
@@ -128,16 +137,15 @@ Project.prototype.update = function (names, options) {
|
||||
if (!names) {
|
||||
// Mark each root dependency as targets
|
||||
that.walkTree(tree, function (node) {
|
||||
// Ignore linked extraneous because
|
||||
// we don't know their real sources
|
||||
if (node.extraneous && node.linked) {
|
||||
return false;
|
||||
}
|
||||
|
||||
targets.push(node);
|
||||
return false;
|
||||
}, true);
|
||||
|
||||
// Mark extraneous as targets
|
||||
mout.object.forOwn(flattened, function (decEndpoint) {
|
||||
if (decEndpoint.extraneous && !decEndpoint.linked) {
|
||||
targets.push(decEndpoint);
|
||||
}
|
||||
});
|
||||
// Otherwise, selectively update the specified ones
|
||||
} else {
|
||||
// Error out if some of the specified names
|
||||
@@ -152,21 +160,19 @@ Project.prototype.update = function (names, options) {
|
||||
|
||||
// Add packages whose names are specified to be updated
|
||||
that.walkTree(tree, function (node, name) {
|
||||
// Ignore linked extraneous because
|
||||
// we don't know their real source
|
||||
if (node.extraneous && node.linked) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (names.indexOf(name) !== -1) {
|
||||
targets.push(node);
|
||||
return false;
|
||||
}
|
||||
}, true);
|
||||
|
||||
// Add extraneous whose names are specified to be updated
|
||||
mout.object.forOwn(flattened, function (decEndpoint, name) {
|
||||
if (decEndpoint.extraneous && !decEndpoint.linked && names.indexOf(name) !== -1) {
|
||||
targets.push(decEndpoint);
|
||||
}
|
||||
});
|
||||
|
||||
// Walk down the tree adding missing, incompatible
|
||||
// and resolved
|
||||
// Recover tree
|
||||
that.walkTree(tree, function (node, name) {
|
||||
if (node.missing) {
|
||||
targets.push(node);
|
||||
@@ -314,8 +320,10 @@ Project.prototype.getTree = function () {
|
||||
return this._analyse()
|
||||
.spread(function (json, tree, flattened) {
|
||||
var extraneous = [];
|
||||
var additionalKeys = ['missing', 'extraneous', 'linked'];
|
||||
|
||||
tree = this._manager.toData(tree, ['missing', 'incompatible', 'linked']);
|
||||
// Convert tree
|
||||
tree = this._manager.toData(tree, additionalKeys);
|
||||
|
||||
// Mark incompatibles
|
||||
this.walkTree(tree, function (node) {
|
||||
@@ -336,13 +344,18 @@ Project.prototype.getTree = function () {
|
||||
}
|
||||
}, true);
|
||||
|
||||
// Find extraneous
|
||||
// Convert extraneous
|
||||
mout.object.forOwn(flattened, function (pkg) {
|
||||
if (pkg.extraneous) {
|
||||
extraneous.push(this._manager.toData(pkg, ['missing', 'incompatible', 'linked']));
|
||||
extraneous.push(this._manager.toData(pkg, additionalKeys));
|
||||
}
|
||||
}, this);
|
||||
|
||||
// Convert flattened
|
||||
flattened = mout.object.map(flattened, function (node) {
|
||||
return this._manager.toData(node);
|
||||
}, this);
|
||||
|
||||
return [tree, flattened, extraneous];
|
||||
}.bind(this));
|
||||
};
|
||||
@@ -444,17 +457,31 @@ Project.prototype._analyse = function () {
|
||||
])
|
||||
.spread(function (json, installed, links) {
|
||||
var root;
|
||||
var jsonCopy = mout.lang.deepClone(json);
|
||||
var flattened = mout.object.mixIn({}, installed, links);
|
||||
|
||||
root = {
|
||||
name: json.name,
|
||||
source: this._config.cwd,
|
||||
target: json.version || '*',
|
||||
pkgMeta: json,
|
||||
pkgMeta: jsonCopy,
|
||||
canonicalDir: this._config.cwd,
|
||||
root: true
|
||||
};
|
||||
|
||||
// Mix direct extraneous as dependencies
|
||||
// (dependencies installed without --save/--save-dev)
|
||||
jsonCopy.dependencies = jsonCopy.dependencies || {};
|
||||
mout.object.forOwn(installed, function (decEndpoint, key) {
|
||||
var pkgMeta = decEndpoint.pkgMeta;
|
||||
|
||||
// The _direct propery is saved by the manager when .newly is specified
|
||||
if (!jsonCopy.dependencies[key] && pkgMeta._direct) {
|
||||
decEndpoint.extraneous = true;
|
||||
jsonCopy.dependencies[key] = pkgMeta._source + '#' + pkgMeta._target;
|
||||
}
|
||||
});
|
||||
|
||||
// Restore the original dependencies cross-references,
|
||||
// that is, the parent-child relationships
|
||||
this._restoreNode(root, flattened, 'dependencies');
|
||||
@@ -463,13 +490,13 @@ Project.prototype._analyse = function () {
|
||||
this._restoreNode(root, flattened, 'devDependencies');
|
||||
}
|
||||
|
||||
// Parse extraneous
|
||||
mout.object.forOwn(flattened, function (decEndpoint) {
|
||||
// Restore the rest of the extraneousv (not installed directly)
|
||||
mout.object.forOwn(flattened, function (decEndpoint, name) {
|
||||
if (!decEndpoint.dependants) {
|
||||
decEndpoint.extraneous = true;
|
||||
|
||||
// Restore it
|
||||
this._restoreNode(decEndpoint, flattened, 'dependencies');
|
||||
// Note that it has no dependants, just dependencies!
|
||||
root.dependencies[name] = decEndpoint;
|
||||
}
|
||||
}, this);
|
||||
|
||||
@@ -618,6 +645,7 @@ Project.prototype._readLinks = function () {
|
||||
that._logger.warn('deprecated', 'Package ' + name + ' is using the deprecated ' + deprecated);
|
||||
}
|
||||
|
||||
json._direct = true; // Mark as a direct dep of root
|
||||
decEndpoints[name] = {
|
||||
name: name,
|
||||
source: dir,
|
||||
@@ -709,6 +737,7 @@ Project.prototype._restoreNode = function (node, flattened, jsonKey) {
|
||||
node.dependencies = node.dependencies || {};
|
||||
node.dependants = node.dependants || {};
|
||||
|
||||
// Only process deps that are yet processed
|
||||
deps = mout.object.filter(node.pkgMeta[jsonKey], function (value, key) {
|
||||
return !node.dependencies[key];
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user