mirror of
https://github.com/bower/bower.git
synced 2026-04-24 03:00:19 -04:00
Read, use and update persistent resolutions.
Add --save-resolutions to deal with this. Also: - Adjust logging when using compact - Minor code adjustments.
This commit is contained in:
@@ -30,8 +30,9 @@ Manager.prototype.getResolutions = function () {
|
||||
return this._resolutions;
|
||||
};
|
||||
|
||||
Manager.prototype.setResolutions = function (resolutions) {
|
||||
Manager.prototype.setResolutions = function (resolutions, save) {
|
||||
this._resolutions = resolutions || {};
|
||||
this._saveResolutions = !!save;
|
||||
return this;
|
||||
};
|
||||
|
||||
@@ -74,6 +75,7 @@ Manager.prototype.resolve = function () {
|
||||
this._fetching = {};
|
||||
this._nrFetching = 0;
|
||||
this._failed = {};
|
||||
this._conflicted = {};
|
||||
this._hasFailed = false;
|
||||
this._deferred = Q.defer();
|
||||
|
||||
@@ -111,11 +113,7 @@ Manager.prototype.install = function () {
|
||||
var promise;
|
||||
var dest;
|
||||
var release = decEndpoint.pkgMeta._release;
|
||||
var data = {
|
||||
endpoint: mout.object.pick(decEndpoint, ['name', 'source', 'target']),
|
||||
canonicalPkg: decEndpoint.canonicalPkg,
|
||||
pkgMeta: decEndpoint.pkgMeta
|
||||
};
|
||||
var data = that._toData(decEndpoint);
|
||||
|
||||
that._logger.action('install', name + (release ? '#' + release : ''), data);
|
||||
|
||||
@@ -134,11 +132,11 @@ Manager.prototype.install = function () {
|
||||
return Q.all(promises);
|
||||
})
|
||||
.then(function () {
|
||||
// Resolve with an object where keys are names and values
|
||||
// are the package metas
|
||||
return mout.object.map(that._dissected, function (decEndpoint) {
|
||||
return decEndpoint.pkgMeta;
|
||||
});
|
||||
var data = this._toData(decEndpoint);
|
||||
data.dependencies = mout.object.map(decEndpoint.dependencies, this._toData, this);
|
||||
return data;
|
||||
}, that);
|
||||
})
|
||||
.fin(function () {
|
||||
this._working = false;
|
||||
@@ -340,6 +338,8 @@ Manager.prototype._failFast = function () {
|
||||
};
|
||||
|
||||
Manager.prototype._parseDependencies = function (decEndpoint, pkgMeta, jsonKey) {
|
||||
decEndpoint.dependencies = decEndpoint.dependencies || {};
|
||||
|
||||
// Parse package dependencies
|
||||
mout.object.forOwn(pkgMeta[jsonKey], function (value, key) {
|
||||
var resolved;
|
||||
@@ -347,6 +347,7 @@ Manager.prototype._parseDependencies = function (decEndpoint, pkgMeta, jsonKey)
|
||||
var compatible;
|
||||
var childDecEndpoint = endpointParser.json2decomposed(key, value);
|
||||
|
||||
decEndpoint.dependencies[key] = childDecEndpoint;
|
||||
childDecEndpoint.dependants = childDecEndpoint.dependants || [];
|
||||
childDecEndpoint.dependants.push(decEndpoint);
|
||||
|
||||
@@ -451,22 +452,40 @@ Manager.prototype._dissect = function () {
|
||||
});
|
||||
}, this);
|
||||
|
||||
// TODO: Remove resolutions that are not needed anymore (emitting a warn)
|
||||
// TODO: Change the final promise result to an array of decEndpoints
|
||||
// with dependencies included to be able to do a npm like tree
|
||||
|
||||
promise
|
||||
.then(function () {
|
||||
// Look for extraneous resolutions
|
||||
mout.object.forOwn(this._resolutions, function (resolution, name) {
|
||||
if (this._conflicted[name]) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this._saveResolutions) {
|
||||
this._logger.info('resolution', 'Removed unnecessary ' + name + '#' + resolution + ' resolution', {
|
||||
package: name,
|
||||
resolution: resolution,
|
||||
action: 'delete'
|
||||
});
|
||||
delete this._resolutions[name];
|
||||
} else {
|
||||
this._logger.warn('resolution', 'Unnecessary ' + name + '#' + resolution + ' resolution', {
|
||||
package: name,
|
||||
resolution: resolution
|
||||
});
|
||||
}
|
||||
}, this);
|
||||
|
||||
// Filter only packages that need to be installed
|
||||
this._dissected = mout.object.filter(suitables, function (decEndpoint, name) {
|
||||
var installedMeta = this._installed[name];
|
||||
return !installedMeta || installedMeta._release !== decEndpoint.pkgMeta._release;
|
||||
}, this);
|
||||
|
||||
// Resolve with the package metas of the dissected object
|
||||
return mout.object.map(this._dissected, function (decEndpoint) {
|
||||
return decEndpoint.pkgMeta;
|
||||
});
|
||||
var data = this._toData(decEndpoint);
|
||||
data.dependencies = mout.object.map(decEndpoint.dependencies, this._toData, this);
|
||||
return data;
|
||||
}, this);
|
||||
}.bind(this))
|
||||
.then(this._deferred.resolve, this._deferred.reject);
|
||||
};
|
||||
@@ -474,6 +493,7 @@ Manager.prototype._dissect = function () {
|
||||
Manager.prototype._electSuitable = function (name, semvers, nonSemvers) {
|
||||
var suitable;
|
||||
var resolution;
|
||||
var unresolvable;
|
||||
var dataPicks;
|
||||
var choices;
|
||||
var picks = [];
|
||||
@@ -507,6 +527,9 @@ Manager.prototype._electSuitable = function (name, semvers, nonSemvers) {
|
||||
picks.push.apply(picks, semvers);
|
||||
}
|
||||
|
||||
// At this point, there's a conflict
|
||||
this._conflicted[name] = true;
|
||||
|
||||
// Sort picks by version/release
|
||||
picks.sort(function (pick1, pick2) {
|
||||
var version1 = pick1.pkgMeta.version;
|
||||
@@ -543,23 +566,20 @@ Manager.prototype._electSuitable = function (name, semvers, nonSemvers) {
|
||||
|
||||
// Prepare data to be sent bellow
|
||||
dataPicks = picks.map(function (pick) {
|
||||
return {
|
||||
endpoint: mout.object.pick(pick, ['name', 'source', 'target']),
|
||||
pkgMeta: pick.pkgMeta,
|
||||
canonicalPkg: pick.canonicalPkg,
|
||||
dependants: pick.dependants.map(function (dependant) {
|
||||
return {
|
||||
endpoint: mout.object.pick(dependant, ['name', 'source', 'target']),
|
||||
pkgMeta: dependant.pkgMeta,
|
||||
canonicalPkg: dependant.canonicalPkg
|
||||
};
|
||||
})
|
||||
};
|
||||
});
|
||||
var dataPick = this._toData(pick);
|
||||
dataPick.dependants = pick.dependants.map(this._toData.bind(this), this);
|
||||
return dataPick;
|
||||
}, this);
|
||||
|
||||
// Check if there's a resolution that resolves the conflict
|
||||
// Note that if a target is marked as unresolvable, the resolution has
|
||||
// no effect
|
||||
resolution = this._resolutions[name];
|
||||
if (resolution) {
|
||||
unresolvable = mout.object.find(this._targets, function (target) {
|
||||
return target.name === name && target.unresolvable;
|
||||
});
|
||||
|
||||
if (resolution && !unresolvable) {
|
||||
if (semver.valid(resolution) != null || semver.validRange(resolution) != null) {
|
||||
suitable = mout.array.findIndex(picks, function (pick) {
|
||||
return semver.satisfies(pick.pkgMeta.version, resolution);
|
||||
@@ -570,15 +590,21 @@ Manager.prototype._electSuitable = function (name, semvers, nonSemvers) {
|
||||
});
|
||||
}
|
||||
|
||||
if (suitable) {
|
||||
this._logger.conflict('resolved', 'Unable to find suitable version for ' + name, {
|
||||
if (!suitable) {
|
||||
this._logger.conflict('warn', 'Unsuitable resolution for ' + name + ': ' + resolution, {
|
||||
name: name,
|
||||
picks: dataPicks,
|
||||
resolution: resolution,
|
||||
suitable: dataPicks[suitable]
|
||||
resolution: resolution
|
||||
});
|
||||
return Q.resolve(picks[suitable]);
|
||||
}
|
||||
|
||||
this._logger.conflict('solved', 'Unable to find suitable version for ' + name, {
|
||||
name: name,
|
||||
picks: dataPicks,
|
||||
resolution: resolution,
|
||||
suitable: dataPicks[suitable]
|
||||
});
|
||||
return Q.resolve(picks[suitable]);
|
||||
}
|
||||
|
||||
// If interactive is disabled, error out
|
||||
@@ -592,25 +618,44 @@ Manager.prototype._electSuitable = function (name, semvers, nonSemvers) {
|
||||
// At this point the user needs to make a decision
|
||||
this._logger.conflict('incompatible', 'Unable to find suitable version for ' + name, {
|
||||
name: name,
|
||||
picks: dataPicks
|
||||
picks: dataPicks,
|
||||
saveResolutions: this._saveResolutions
|
||||
});
|
||||
|
||||
choices = picks.map(function (pick, index) { return index + 1; });
|
||||
return Q.nfcall(promptly.choose, 'Choice:', choices)
|
||||
.then(function (choice) {
|
||||
var pick = picks[choice - 1];
|
||||
var resolution;
|
||||
|
||||
// Store choice into resolutions
|
||||
if (pick.target === '*') {
|
||||
this._resolutions[name] = pick.pkgMeta._release || '*';
|
||||
resolution = pick.pkgMeta._release || '*';
|
||||
} else {
|
||||
this._resolutions[name] = pick.target;
|
||||
resolution = pick.target;
|
||||
}
|
||||
|
||||
if (this._saveResolutions) {
|
||||
this._logger.info('resolution', 'Saved ' + name + '#' + resolution + ' as the resolution', {
|
||||
package: name,
|
||||
resolution: resolution,
|
||||
action: this._resolutions[name] ? 'edit' : 'add'
|
||||
});
|
||||
this._resolutions[name] = resolution;
|
||||
}
|
||||
|
||||
return pick;
|
||||
}.bind(this));
|
||||
};
|
||||
|
||||
Manager.prototype._toData = function (decEndpoint) {
|
||||
return {
|
||||
endpoint: mout.object.pick(decEndpoint, ['name', 'source', 'target']),
|
||||
canonicalPkg: decEndpoint.canonicalPkg,
|
||||
pkgMeta: decEndpoint.pkgMeta
|
||||
};
|
||||
};
|
||||
|
||||
Manager.prototype._getCap = function (comparators, side) {
|
||||
var matches;
|
||||
var candidate;
|
||||
|
||||
Reference in New Issue
Block a user