mirror of
https://github.com/bower/bower.git
synced 2026-04-24 03:00:19 -04:00
Add update command and also finish install.
This commit is contained in:
@@ -18,7 +18,6 @@ function Project(config) {
|
||||
// -----------------
|
||||
|
||||
Project.prototype.install = function (endpoints, options) {
|
||||
var repairResult;
|
||||
var that = this;
|
||||
|
||||
// If already working, error out
|
||||
@@ -26,6 +25,9 @@ Project.prototype.install = function (endpoints, options) {
|
||||
return Q.reject(createError('Already working', 'EWORKING'));
|
||||
}
|
||||
|
||||
options = options || {};
|
||||
this._production = !!options.production;
|
||||
|
||||
// If no endpoints were specified, simply repair the project
|
||||
// Note that we also repair incompatible packages
|
||||
if (!endpoints) {
|
||||
@@ -38,58 +40,155 @@ Project.prototype.install = function (endpoints, options) {
|
||||
// Start by repairing the project, installing only missing packages
|
||||
return this._repair()
|
||||
// Analyse the project
|
||||
.then(function (result) {
|
||||
repairResult = result;
|
||||
return that._analyse();
|
||||
})
|
||||
.then(that._analyse.bind(this))
|
||||
.spread(function (json, tree, flattened) {
|
||||
var targetNames = {};
|
||||
var targets = [];
|
||||
var installed = {};
|
||||
var targets = {};
|
||||
var resolved = {};
|
||||
var installed;
|
||||
|
||||
// Mark targets
|
||||
endpoints.forEach(function (target) {
|
||||
var decEndpoint = endpointParser.decompose(target);
|
||||
targetNames[decEndpoint.name] = true;
|
||||
targets.push(decEndpoint);
|
||||
endpoints.forEach(function (endpoint) {
|
||||
var decEndpoint = endpointParser.decompose(endpoint);
|
||||
targets[decEndpoint.name] = decEndpoint;
|
||||
});
|
||||
|
||||
// Mark every package from the tree as installed
|
||||
// if they are not a target or a non-shared descendant of a target
|
||||
// TODO: We should traverse the tree (deep first) and
|
||||
// add each leaf to the resolved
|
||||
// If a leaf is a target, we abort traversal of it
|
||||
mout.object.forOwn(flattened, function (decEndpoint, name) {
|
||||
if (targetNames[name]) {
|
||||
// Mark every package from the tree as resolved
|
||||
// if it's not a target or a non-shared descendant of a target
|
||||
// This is done by walking the tree (deep first) and abort traversal
|
||||
// as soon as one target was found
|
||||
that._walkTree(tree, function (node, name) {
|
||||
if (targets[name]) {
|
||||
return false; // Abort traversal
|
||||
}
|
||||
resolved[name] = node.pkgMeta;
|
||||
});
|
||||
|
||||
installed = mout.object.map(flattened, function (decEndpoint) {
|
||||
return decEndpoint.pkgMeta;
|
||||
});
|
||||
|
||||
// Bootstrap the process
|
||||
return that._bootstrap(targets, resolved, installed)
|
||||
// Handle save and saveDev options
|
||||
.then(function () {
|
||||
var key;
|
||||
|
||||
if (!options.save && !options.saveDev) {
|
||||
return;
|
||||
}
|
||||
|
||||
installed[name] = decEndpoint.pkgMeta;
|
||||
});
|
||||
key = options.save ? 'dependencies' : 'devDependencies';
|
||||
that._json[key] = that._json[key] || {};
|
||||
|
||||
// Configure the manager and kick in the resolve process
|
||||
return that._manager
|
||||
.configure(targets, installed)
|
||||
.resolve()
|
||||
// Install resolved ones
|
||||
.then(function () {
|
||||
return that._manager.install();
|
||||
})
|
||||
// Resolve the promise with the repair and install results,
|
||||
// by merging them together
|
||||
.then(function (result) {
|
||||
return mout.object.fillIn(result, repairResult);
|
||||
mout.object.forOwn(targets, function (decEndpoint) {
|
||||
var source = decEndpoint.source === decEndpoint.registryName ? '' : decEndpoint.source;
|
||||
var target = decEndpoint.pkgMeta.version ? '~' + decEndpoint.pkgMeta.version : decEndpoint.target;
|
||||
that._json[key][decEndpoint.name] = mout.string.ltrim(source + '#' + target, ['#']);
|
||||
});
|
||||
|
||||
return that._saveJson()
|
||||
.progress(function (notification) {
|
||||
return notification;
|
||||
});
|
||||
});
|
||||
})
|
||||
.fin(function () {
|
||||
that._working = false;
|
||||
});
|
||||
|
||||
// TODO: handle save saveDev production
|
||||
};
|
||||
|
||||
Project.prototype.update = function (names) {
|
||||
Project.prototype.update = function (names, options) {
|
||||
var that = this;
|
||||
var targets;
|
||||
var resolved;
|
||||
var installed;
|
||||
var repaired;
|
||||
var promise;
|
||||
|
||||
// If already working, error out
|
||||
if (this._working) {
|
||||
return Q.reject(createError('Already working', 'EWORKING'));
|
||||
}
|
||||
|
||||
options = options || {};
|
||||
this._production = !!options.production;
|
||||
|
||||
// If no names were specified, we update every package
|
||||
if (!names) {
|
||||
// Analyse the project
|
||||
promise = this._analyse()
|
||||
.spread(function (json, tree, flattened) {
|
||||
// Mark each json entry as targets
|
||||
targets = mout.object.map(json.dependencies, function (value, key) {
|
||||
return endpointParser.json2decomposed(key, value);
|
||||
});
|
||||
|
||||
// Mark installed
|
||||
installed = mout.object.map(flattened, function (decEndpoint) {
|
||||
return decEndpoint.pkgMeta;
|
||||
});
|
||||
});
|
||||
// Otherwise we selectively update the specified ones
|
||||
} else {
|
||||
// Start by repairing the project
|
||||
// Note that we also repair incompatible packages
|
||||
promise = this._repair(true)
|
||||
// Analyse the project
|
||||
.then(function (result) {
|
||||
repaired = result;
|
||||
return that._analyse();
|
||||
})
|
||||
.spread(function (json, tree, flattened) {
|
||||
targets = {};
|
||||
resolved = {};
|
||||
|
||||
// Mark targets
|
||||
names.forEach(function (name) {
|
||||
var decEndpoint = flattened[name];
|
||||
var jsonEntry;
|
||||
|
||||
if (!decEndpoint) {
|
||||
throw createError('Package ' + name + ' is not installed', 'ENOTINSTALLED');
|
||||
}
|
||||
|
||||
// If it was repaired, don't include in the targets
|
||||
if (repaired[name]) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Use json entry if available,
|
||||
// fallbacking to the installed one
|
||||
jsonEntry = json.dependencies && json.dependencies[name];
|
||||
if (jsonEntry) {
|
||||
targets[name] = endpointParser.json2decomposed(name, jsonEntry);
|
||||
} else {
|
||||
targets[name] = decEndpoint;
|
||||
}
|
||||
});
|
||||
|
||||
// Mark every package from the tree as resolved
|
||||
// if it's not a target or a non-shared descendant of a target
|
||||
that._walkTree(tree, function (node, name) {
|
||||
if (targets[name]) {
|
||||
return false; // Abort traversal
|
||||
}
|
||||
resolved[name] = node.pkgMeta;
|
||||
});
|
||||
|
||||
// Mark installed
|
||||
installed = mout.object.map(flattened, function (decEndpoint) {
|
||||
return decEndpoint.pkgMeta;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// Bootstrap the process
|
||||
return promise.then(function () {
|
||||
return that._bootstrap(targets, resolved, installed);
|
||||
})
|
||||
.fin(function () {
|
||||
that._working = false;
|
||||
});
|
||||
};
|
||||
|
||||
Project.prototype.uninstall = function (names, options) {
|
||||
@@ -100,10 +199,6 @@ Project.prototype.getTree = function () {
|
||||
|
||||
};
|
||||
|
||||
Project.prototype.getFlatTree = function () {
|
||||
|
||||
};
|
||||
|
||||
// -----------------
|
||||
|
||||
Project.prototype._analyse = function () {
|
||||
@@ -117,28 +212,50 @@ Project.prototype._analyse = function () {
|
||||
|
||||
root = {
|
||||
name: json.name,
|
||||
source: this._config.cwd,
|
||||
target: json.version,
|
||||
dir: this._config.cwd,
|
||||
pkgMeta: json
|
||||
};
|
||||
|
||||
|
||||
// Restore the original dependencies cross-references,
|
||||
// that is, the parent-child relationships
|
||||
this._restoreNode(root, flattened);
|
||||
// Do the same for the dev dependencies
|
||||
if (!this._config.production) {
|
||||
if (!this._production) {
|
||||
this._restoreNode(root, flattened, 'devDependencies');
|
||||
}
|
||||
|
||||
// Parse extraneous
|
||||
mout.object.forOwn(flattened, function (decEndpoint) {
|
||||
if (!decEndpoint.dependants) {
|
||||
decEndpoint.extraneous = true;
|
||||
}
|
||||
});
|
||||
|
||||
return [json, root, flattened];
|
||||
}.bind(this));
|
||||
};
|
||||
|
||||
Project.prototype._bootstrap = function (targets, resolved, installed) {
|
||||
// Configure the manager and kick in the resolve process
|
||||
return this._manager
|
||||
.configure(mout.object.values(targets), resolved, installed)
|
||||
.resolve()
|
||||
// Install resolved ones
|
||||
.then(function () {
|
||||
return this._manager.install();
|
||||
}.bind(this));
|
||||
};
|
||||
|
||||
Project.prototype._repair = function (incompatible) {
|
||||
var that = this;
|
||||
|
||||
return this._analyse()
|
||||
.spread(function (json, tree, flattened) {
|
||||
var targets = [];
|
||||
var installed = {};
|
||||
var resolved = {};
|
||||
var isBroken = false;
|
||||
|
||||
// Figure out which are the missing/incompatible ones
|
||||
@@ -150,8 +267,8 @@ Project.prototype._repair = function (incompatible) {
|
||||
} else if (incompatible && decEndpoint.incompatible) {
|
||||
targets.push(decEndpoint);
|
||||
isBroken = true;
|
||||
} else {
|
||||
installed[name] = decEndpoint.pkgMeta;
|
||||
} else if (!decEndpoint.extraneous) {
|
||||
resolved[name] = decEndpoint.pkgMeta;
|
||||
}
|
||||
});
|
||||
|
||||
@@ -161,23 +278,22 @@ Project.prototype._repair = function (incompatible) {
|
||||
}
|
||||
|
||||
// Configure the manager and kick in the resolve process
|
||||
return that._manager
|
||||
.configure(targets, installed)
|
||||
.resolve()
|
||||
// Install after resolve
|
||||
.then(function () {
|
||||
return that._manager.install();
|
||||
});
|
||||
return that._bootstrap(targets, resolved);
|
||||
});
|
||||
};
|
||||
|
||||
Project.prototype._readJson = function () {
|
||||
var deferred = Q.defer();
|
||||
var that = this;
|
||||
var deferred;
|
||||
|
||||
// TODO: refactor!
|
||||
if (this._json) {
|
||||
return Q.resolve(this._json);
|
||||
}
|
||||
|
||||
deferred = Q.defer();
|
||||
|
||||
// Read local json
|
||||
Q.nfcall(bowerJson.find, this._config.cwd)
|
||||
this._json = Q.nfcall(bowerJson.find, this._config.cwd)
|
||||
.then(function (filename) {
|
||||
// If it is a component.json, warn about the deprecation
|
||||
if (path.basename(filename) === 'component.json') {
|
||||
@@ -193,6 +309,8 @@ Project.prototype._readJson = function () {
|
||||
});
|
||||
}
|
||||
|
||||
that._jsonFile = filename;
|
||||
|
||||
// Read it
|
||||
return Q.nfcall(bowerJson.read, filename)
|
||||
.fail(function (err) {
|
||||
@@ -202,9 +320,36 @@ Project.prototype._readJson = function () {
|
||||
});
|
||||
}, function () {
|
||||
// No json file was found, assume one
|
||||
return Q.nfcall(bowerJson.parse, { name: path.basename(this._config.cwd) });
|
||||
}.bind(this))
|
||||
.then(deferred.resolve, deferred.reject, deferred.notify);
|
||||
return Q.nfcall(bowerJson.parse, {
|
||||
name: path.basename(that._config.cwd)
|
||||
});
|
||||
})
|
||||
.then(function (json) {
|
||||
that._json = json;
|
||||
deferred.resolve(json);
|
||||
}, deferred.reject, deferred.notify);
|
||||
|
||||
return deferred.promise;
|
||||
};
|
||||
|
||||
Project.prototype._saveJson = function (json) {
|
||||
var deferred = Q.defer();
|
||||
|
||||
if (!this._jsonFile) {
|
||||
process.nextTick(function () {
|
||||
deferred.notify({
|
||||
level: 'warn',
|
||||
id: 'no-json',
|
||||
message: 'No bower.json file to save to'
|
||||
});
|
||||
deferred.resolve();
|
||||
});
|
||||
} else {
|
||||
json = json || this._json;
|
||||
|
||||
Q.nfcall(fs.writeFile, this._jsonFile, JSON.stringify(json, null, ' '))
|
||||
.then(deferred.resolve, deferred.reject, deferred.notify);
|
||||
}
|
||||
|
||||
return deferred.promise;
|
||||
};
|
||||
@@ -212,7 +357,6 @@ Project.prototype._readJson = function () {
|
||||
Project.prototype._readInstalled = function () {
|
||||
var componentsDir = path.join(this._config.cwd, this._config.directory);
|
||||
|
||||
// TODO: refactor
|
||||
// Gather all folders that are actual packages by
|
||||
// looking for the package metadata file
|
||||
return Q.nfcall(glob, '*/.bower.json', {
|
||||
@@ -227,14 +371,18 @@ Project.prototype._readInstalled = function () {
|
||||
filenames.forEach(function (filename) {
|
||||
var promise;
|
||||
var name = path.dirname(filename);
|
||||
var jsonFile = path.join(componentsDir, filename);
|
||||
|
||||
// Read package metadata
|
||||
promise = Q.nfcall(fs.readFile, path.join(componentsDir, filename))
|
||||
promise = Q.nfcall(fs.readFile, jsonFile)
|
||||
.then(function (contents) {
|
||||
var pkgMeta = JSON.parse(contents.toString());
|
||||
|
||||
decEndpoints[name] = {
|
||||
name: name,
|
||||
source: pkgMeta._source,
|
||||
target: pkgMeta.version,
|
||||
dir: path.dirname(jsonFile),
|
||||
pkgMeta: pkgMeta
|
||||
};
|
||||
});
|
||||
@@ -251,6 +399,22 @@ Project.prototype._readInstalled = function () {
|
||||
});
|
||||
};
|
||||
|
||||
Project.prototype._walkTree = function (node, fn) {
|
||||
var queue = [node];
|
||||
var result;
|
||||
|
||||
while (queue.length) {
|
||||
node = queue.shift();
|
||||
result = fn(node, node.name);
|
||||
|
||||
if (result === false) {
|
||||
continue;
|
||||
}
|
||||
|
||||
queue.unshift.apply(queue, mout.object.values(node.dependencies));
|
||||
}
|
||||
};
|
||||
|
||||
Project.prototype._restoreNode = function (node, flattened, jsonKey) {
|
||||
// Do not restore if already processed or if the node is
|
||||
// missing or incompatible
|
||||
@@ -267,15 +431,14 @@ Project.prototype._restoreNode = function (node, flattened, jsonKey) {
|
||||
|
||||
// Check if the dependency is not installed
|
||||
if (!local) {
|
||||
local = json;
|
||||
flattened[key] = local = json;
|
||||
local.missing = true;
|
||||
flattened[key] = local;
|
||||
// Even if it is installed, check if it's compatible
|
||||
} else if (!local.incompatible && !this._manager.areCompatible(local.pkgMeta.version || '*', json.target)) {
|
||||
json.pkgMeta = local.pkgMeta;
|
||||
flattened[key] = local = json;
|
||||
local = json;
|
||||
local.incompatible = true;
|
||||
flattened[key] = local;
|
||||
}
|
||||
|
||||
// Cross reference
|
||||
|
||||
Reference in New Issue
Block a user