mirror of
https://github.com/meteor/meteor.git
synced 2026-05-02 03:01:46 -04:00
Merge pull request #12262 from harryadel/underscore/constraint-solver
[constraint-solver] Remove underscore
This commit is contained in:
@@ -273,7 +273,7 @@ runBenchmarks && Tinytest.add("constraint solver - benchmark on gems - rails, gi
|
||||
var solution = r.resolve(args.dependencies, args.constraints, { previousSolution: previousSolution }).answer;
|
||||
|
||||
// check that root deps are the same
|
||||
_.each(args.dependencies, function (dep) {
|
||||
args.dependencies.forEach(function (dep) {
|
||||
if (previousSolution[dep])
|
||||
test.equal(solution[dep], previousSolution[dep], dep);
|
||||
});
|
||||
@@ -284,17 +284,17 @@ runBenchmarks && Tinytest.add("constraint solver - benchmark on gems - rails, gi
|
||||
function getCatalogStub (gems) {
|
||||
return {
|
||||
getSortedVersionRecords(name) {
|
||||
var versions = _.chain(gems)
|
||||
.filter(function (pv) { return pv.name === name; })
|
||||
.pluck('number')
|
||||
var versions = Object.values(gems.filter(function (pv) { return pv.name === name; })
|
||||
.map(function(gem) {
|
||||
return gem.number
|
||||
})
|
||||
.filter(function (v) {
|
||||
return PackageVersion.getValidServerVersion(v);
|
||||
})
|
||||
.sort(PackageVersion.compare)
|
||||
.uniq(true)
|
||||
.value();
|
||||
return _.map(versions, function (version) {
|
||||
var gem = _.find(gems, function (pv) {
|
||||
.sort(PackageVersion.compare));
|
||||
|
||||
return versions.map(function (version) {
|
||||
var gem = gems.find(function (pv) {
|
||||
return pv.name === name && pv.number === version;
|
||||
});
|
||||
|
||||
@@ -304,7 +304,7 @@ function getCatalogStub (gems) {
|
||||
dependencies: {}
|
||||
};
|
||||
|
||||
_.each(gem.dependencies, function (dep) {
|
||||
gem.dependencies.forEach(function (dep) {
|
||||
var name = dep[0];
|
||||
var constraint = dep[1];
|
||||
|
||||
@@ -332,4 +332,4 @@ function getCatalogStub (gems) {
|
||||
return result;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -38,8 +38,8 @@ Tinytest.add("constraint solver - CatalogCache", function (test) {
|
||||
var pvs = {};
|
||||
cache.eachPackageVersion(function (pv, deps) {
|
||||
check(pv, CS.PackageAndVersion);
|
||||
check(_.values(deps), [CS.Dependency]);
|
||||
pvs[pv.package+' '+pv.version] = _.keys(deps).sort();
|
||||
check(Object.values(deps), [CS.Dependency]);
|
||||
pvs[`${pv.package} ${pv.version}`] = Object.keys(deps).sort();
|
||||
});
|
||||
test.equal(pvs, {'foo 1.0.0': ['bar'],
|
||||
'foo 1.0.1': ['bar', 'bzzz', 'weakly1', 'weakly2']});
|
||||
@@ -52,9 +52,9 @@ Tinytest.add("constraint solver - CatalogCache", function (test) {
|
||||
test.equal(oneVersion.length, 1); // don't know which it is
|
||||
|
||||
var foos = [];
|
||||
_.each(cache.getPackageVersions('foo'), function (v) {
|
||||
cache.getPackageVersions('foo').forEach(function (v) {
|
||||
var depMap = cache.getDependencyMap('foo', v);
|
||||
foos.push([v, _.map(depMap, String).sort()]);
|
||||
foos.push([v, Object.values(depMap).map(String).sort()]);
|
||||
});
|
||||
// versions should come out sorted, just like this.
|
||||
test.equal(foos,
|
||||
@@ -81,4 +81,4 @@ Tinytest.add("constraint solver - CatalogCache", function (test) {
|
||||
return true;
|
||||
});
|
||||
test.equal(onePackage.length, 1); // don't know which package it is
|
||||
});
|
||||
});
|
||||
@@ -1,3 +1,6 @@
|
||||
const has = Npm.require('lodash.has');
|
||||
const memoize = Npm.require('lodash.memoize');
|
||||
|
||||
var CS = ConstraintSolver;
|
||||
var PV = PackageVersion;
|
||||
|
||||
@@ -18,7 +21,7 @@ CS.CatalogCache = function () {
|
||||
};
|
||||
|
||||
CS.CatalogCache.prototype.hasPackageVersion = function (pkg, version) {
|
||||
return _.has(this._dependencies, pvkey(pkg, version));
|
||||
return has(this._dependencies, pvkey(pkg, version));
|
||||
};
|
||||
|
||||
CS.CatalogCache.prototype.addPackageVersion = function (p, v, deps) {
|
||||
@@ -28,11 +31,11 @@ CS.CatalogCache.prototype.addPackageVersion = function (p, v, deps) {
|
||||
check(deps, [CS.Dependency]);
|
||||
|
||||
var key = pvkey(p, v);
|
||||
if (_.has(this._dependencies, key)) {
|
||||
if (has(this._dependencies, key)) {
|
||||
throw new Error("Already have an entry for " + key);
|
||||
}
|
||||
|
||||
if (! _.has(this._versions, p)) {
|
||||
if (!has(this._versions, p)) {
|
||||
this._versions[p] = [];
|
||||
}
|
||||
this._versions[p].push(v);
|
||||
@@ -40,9 +43,9 @@ CS.CatalogCache.prototype.addPackageVersion = function (p, v, deps) {
|
||||
|
||||
var depsByPackage = {};
|
||||
this._dependencies[key] = depsByPackage;
|
||||
_.each(deps, function (d) {
|
||||
deps.forEach(function (d) {
|
||||
var p2 = d.packageConstraint.package;
|
||||
if (_.has(depsByPackage, p2)) {
|
||||
if (has(depsByPackage, p2)) {
|
||||
throw new Error("Can't have two dependencies on " + p2 +
|
||||
" in " + key);
|
||||
}
|
||||
@@ -55,7 +58,7 @@ CS.CatalogCache.prototype.addPackageVersion = function (p, v, deps) {
|
||||
// `d.packageConstraint.package`. (Don't mutate the map.)
|
||||
CS.CatalogCache.prototype.getDependencyMap = function (p, v) {
|
||||
var key = pvkey(p, v);
|
||||
if (! _.has(this._dependencies, key)) {
|
||||
if (!has(this._dependencies, key)) {
|
||||
throw new Error("No entry for " + key);
|
||||
}
|
||||
return this._dependencies[key];
|
||||
@@ -64,14 +67,14 @@ CS.CatalogCache.prototype.getDependencyMap = function (p, v) {
|
||||
// Returns an array of version strings, sorted, possibly empty.
|
||||
// (Don't mutate the result.)
|
||||
CS.CatalogCache.prototype.getPackageVersions = function (pkg) {
|
||||
var result = (_.has(this._versions, pkg) ?
|
||||
var result = (has(this._versions, pkg) ?
|
||||
this._versions[pkg] : []);
|
||||
if ((!result.length) || result.sorted) {
|
||||
return result;
|
||||
} else {
|
||||
// sort in place, and record so that we don't sort redundantly
|
||||
// (we'll sort again if more versions are pushed onto the array)
|
||||
var pvParse = _.memoize(PV.parse);
|
||||
var pvParse = memoize(PV.parse);
|
||||
result.sort(function (a, b) {
|
||||
return PV.compare(pvParse(a), pvParse(b));
|
||||
});
|
||||
@@ -81,16 +84,16 @@ CS.CatalogCache.prototype.getPackageVersions = function (pkg) {
|
||||
};
|
||||
|
||||
CS.CatalogCache.prototype.hasPackage = function (pkg) {
|
||||
return _.has(this._versions, pkg);
|
||||
return has(this._versions, pkg);
|
||||
};
|
||||
|
||||
CS.CatalogCache.prototype.toJSONable = function () {
|
||||
var self = this;
|
||||
var data = {};
|
||||
_.each(self._dependencies, function (depsByPackage, key) {
|
||||
Object.entries(self._dependencies).forEach(function ([key, depsByPackage]) {
|
||||
// depsByPackage is a map of String -> Dependency.
|
||||
// Map over the values to get an array of String.
|
||||
data[key] = _.map(depsByPackage, function (dep) {
|
||||
data[key] = Object.values(depsByPackage).map(function (dep) {
|
||||
return dep.toString();
|
||||
});
|
||||
});
|
||||
@@ -101,12 +104,12 @@ CS.CatalogCache.fromJSONable = function (obj) {
|
||||
check(obj, { data: Object });
|
||||
|
||||
var cache = new CS.CatalogCache();
|
||||
_.each(obj.data, function (depsArray, pv) {
|
||||
Object.entries(obj.data).forEach(function ([pv, depsArray]) {
|
||||
check(depsArray, [String]);
|
||||
pv = CS.PackageAndVersion.fromString(pv);
|
||||
cache.addPackageVersion(
|
||||
pv.package, pv.version,
|
||||
_.map(depsArray, function (str) {
|
||||
depsArray.map(function (str) {
|
||||
return CS.Dependency.fromString(str);
|
||||
}));
|
||||
});
|
||||
@@ -118,8 +121,8 @@ CS.CatalogCache.fromJSONable = function (obj) {
|
||||
// iteration is stopped. There's no particular order to the iteration.
|
||||
CS.CatalogCache.prototype.eachPackageVersion = function (iter) {
|
||||
var self = this;
|
||||
_.find(self._dependencies, function (value, key) {
|
||||
var stop = iter(CS.PackageAndVersion.fromString(key), value);
|
||||
Object.keys(self._dependencies).find(function (key) {
|
||||
var stop = iter(CS.PackageAndVersion.fromString(key), self._dependencies[key]);
|
||||
return stop;
|
||||
});
|
||||
};
|
||||
@@ -129,8 +132,8 @@ CS.CatalogCache.prototype.eachPackageVersion = function (iter) {
|
||||
// If `iter` returns true, iteration is stopped.
|
||||
ConstraintSolver.CatalogCache.prototype.eachPackage = function (iter) {
|
||||
var self = this;
|
||||
_.find(_.keys(self._versions), function (key) {
|
||||
Object.keys(self._versions).find(function (key) {
|
||||
var stop = iter(key, self.getPackageVersions(key));
|
||||
return stop;
|
||||
});
|
||||
};
|
||||
};
|
||||
@@ -1,3 +1,5 @@
|
||||
const has = Npm.require('lodash.has');
|
||||
|
||||
var PV = PackageVersion;
|
||||
var CS = ConstraintSolver;
|
||||
|
||||
@@ -35,10 +37,10 @@ CS.CatalogLoader = function (fromCatalog, toCatalogCache) {
|
||||
};
|
||||
|
||||
var convertDeps = function (catalogDeps) {
|
||||
return _.map(catalogDeps, function (dep, pkg) {
|
||||
return Object.entries(catalogDeps).map(function ([pkg, dep], ) {
|
||||
// The dependency is strong if any of its "references"
|
||||
// (for different architectures) are strong.
|
||||
var isStrong = _.any(dep.references, function (ref) {
|
||||
var isStrong = dep.references.some(function (ref) {
|
||||
return !ref.weak;
|
||||
});
|
||||
|
||||
@@ -52,7 +54,7 @@ var convertDeps = function (catalogDeps) {
|
||||
// Since we don't fetch different versions of a package independently
|
||||
// at the moment, this helper is where we get our data.
|
||||
CS.CatalogLoader.prototype._getSortedVersionRecords = function (pkg) {
|
||||
if (! _.has(this._sortedVersionRecordsCache, pkg)) {
|
||||
if (!has(this._sortedVersionRecordsCache, pkg)) {
|
||||
this._sortedVersionRecordsCache[pkg] =
|
||||
this.catalog.getSortedVersionRecords(pkg);
|
||||
}
|
||||
@@ -65,8 +67,8 @@ CS.CatalogLoader.prototype.loadSingleVersion = function (pkg, version) {
|
||||
var cache = self.catalogCache;
|
||||
if (! cache.hasPackageVersion(pkg, version)) {
|
||||
var rec;
|
||||
if (_.has(self._sortedVersionRecordsCache, pkg)) {
|
||||
rec = _.find(self._sortedVersionRecordsCache[pkg],
|
||||
if (has(self._sortedVersionRecordsCache, pkg)) {
|
||||
rec = self._sortedVersionRecordsCache[pkg].find(
|
||||
function (r) {
|
||||
return r.version === version;
|
||||
});
|
||||
@@ -84,7 +86,7 @@ CS.CatalogLoader.prototype.loadAllVersions = function (pkg) {
|
||||
var self = this;
|
||||
var cache = self.catalogCache;
|
||||
var versionRecs = self._getSortedVersionRecords(pkg);
|
||||
_.each(versionRecs, function (rec) {
|
||||
versionRecs.forEach(function (rec) {
|
||||
var version = rec.version;
|
||||
if (! cache.hasPackageVersion(pkg, version)) {
|
||||
var deps = convertDeps(rec.dependencies);
|
||||
@@ -106,22 +108,22 @@ CS.CatalogLoader.prototype.loadAllVersionsRecursive = function (packageList) {
|
||||
var packagesEverEnqueued = {};
|
||||
|
||||
var enqueue = function (pkg) {
|
||||
if (! _.has(packagesEverEnqueued, pkg)) {
|
||||
if (!has(packagesEverEnqueued, pkg)) {
|
||||
packagesEverEnqueued[pkg] = true;
|
||||
loadQueue.push(pkg);
|
||||
}
|
||||
};
|
||||
|
||||
_.each(packageList, enqueue);
|
||||
packageList.forEach(enqueue);
|
||||
|
||||
while (loadQueue.length) {
|
||||
var pkg = loadQueue.pop();
|
||||
self.loadAllVersions(pkg);
|
||||
_.each(self.catalogCache.getPackageVersions(pkg), function (v) {
|
||||
self.catalogCache.getPackageVersions(pkg).forEach(function (v) {
|
||||
var depMap = self.catalogCache.getDependencyMap(pkg, v);
|
||||
_.each(depMap, function (dep, package2) {
|
||||
Object.entries(depMap).forEach(function ([package2, dep]) {
|
||||
enqueue(package2);
|
||||
});
|
||||
});
|
||||
}
|
||||
};
|
||||
};
|
||||
@@ -1,3 +1,7 @@
|
||||
const has = Npm.require('lodash.has');
|
||||
const isEqual = Npm.require('lodash.isequal');
|
||||
const isEmpty = Npm.require('lodash.isempty');
|
||||
|
||||
var PV = PackageVersion;
|
||||
var CS = ConstraintSolver;
|
||||
|
||||
@@ -18,7 +22,7 @@ CS.Input = function (dependencies, constraints, catalogCache, options) {
|
||||
// Convert them to our PackageConstraint class if necessary. (This is
|
||||
// just top-level constraints from .meteor/packages or running from
|
||||
// checkout, so it's not a lot of data.)
|
||||
constraints = _.map(constraints, function (c) {
|
||||
constraints = constraints.map(function (c) {
|
||||
if (c instanceof PV.PackageConstraint) {
|
||||
return c;
|
||||
} else {
|
||||
@@ -62,27 +66,27 @@ CS.Input = function (dependencies, constraints, catalogCache, options) {
|
||||
validatePackageName(packageName);
|
||||
});
|
||||
self.catalogCache.eachPackageVersion(function (packageName, depsMap) {
|
||||
_.each(depsMap, function (deps, depPackageName) {
|
||||
Object.entries(depsMap).forEach(function ([depPackageName, deps]) {
|
||||
validatePackageName(depPackageName);
|
||||
});
|
||||
});
|
||||
|
||||
_.each(self.dependencies, validatePackageName);
|
||||
_.each(self.upgrade, validatePackageName);
|
||||
_.each(self.constraints, function (c) {
|
||||
self.dependencies.forEach(validatePackageName);
|
||||
self.upgrade.forEach(validatePackageName);
|
||||
self.constraints.forEach(function (c) {
|
||||
validatePackageName(c.package);
|
||||
});
|
||||
if (self.previousSolution) {
|
||||
_.each(_.keys(self.previousSolution),
|
||||
Object.keys(self.previousSolution).forEach(
|
||||
validatePackageName);
|
||||
}
|
||||
|
||||
self._dependencySet = {}; // package name -> true
|
||||
_.each(self.dependencies, function (d) {
|
||||
self.dependencies.forEach(function (d) {
|
||||
self._dependencySet[d] = true;
|
||||
});
|
||||
self._upgradeSet = {};
|
||||
_.each(self.upgrade, function (u) {
|
||||
self.upgrade.forEach(function (u) {
|
||||
self._upgradeSet[u] = true;
|
||||
});
|
||||
};
|
||||
@@ -107,33 +111,33 @@ CS.Input.prototype.isKnownPackage = function (p) {
|
||||
};
|
||||
|
||||
CS.Input.prototype.isRootDependency = function (p) {
|
||||
return _.has(this._dependencySet, p);
|
||||
return has(this._dependencySet, p);
|
||||
};
|
||||
|
||||
CS.Input.prototype.isUpgrading = function (p) {
|
||||
return _.has(this._upgradeSet, p);
|
||||
return has(this._upgradeSet, p);
|
||||
};
|
||||
|
||||
CS.Input.prototype.isInPreviousSolution = function (p) {
|
||||
return !! (this.previousSolution && _.has(this.previousSolution, p));
|
||||
return !! (this.previousSolution && has(this.previousSolution, p));
|
||||
};
|
||||
|
||||
function getMentionedPackages(input) {
|
||||
var packages = {}; // package -> true
|
||||
|
||||
_.each(input.dependencies, function (pkg) {
|
||||
input.dependencies.forEach(function (pkg) {
|
||||
packages[pkg] = true;
|
||||
});
|
||||
_.each(input.constraints, function (constraint) {
|
||||
input.constraints.forEach(function (constraint) {
|
||||
packages[constraint.package] = true;
|
||||
});
|
||||
if (input.previousSolution) {
|
||||
_.each(input.previousSolution, function (version, pkg) {
|
||||
Object.entries(input.previousSolution).forEach(function ([pkg, version]) {
|
||||
packages[pkg] = true;
|
||||
});
|
||||
}
|
||||
|
||||
return _.keys(packages);
|
||||
return Object.keys(packages);
|
||||
}
|
||||
|
||||
CS.Input.prototype.loadFromCatalog = function (catalogLoader) {
|
||||
@@ -146,7 +150,7 @@ CS.Input.prototype.loadOnlyPreviousSolution = function (catalogLoader) {
|
||||
|
||||
// load just the exact versions from the previousSolution
|
||||
if (self.previousSolution) {
|
||||
_.each(self.previousSolution, function (version, pkg) {
|
||||
Object.entries(self.previousSolution).forEach(function ([pkg, version]) {
|
||||
catalogLoader.loadSingleVersion(pkg, version);
|
||||
});
|
||||
}
|
||||
@@ -170,7 +174,7 @@ CS.Input.prototype.isEqual = function (otherInput) {
|
||||
// the same input. So by omitting `catalogCache` we no longer need
|
||||
// to reload the entire relevant part of the catalog from SQLite on
|
||||
// every rebuild!
|
||||
return _.isEqual(
|
||||
return isEqual(
|
||||
a.toJSONable(true),
|
||||
b.toJSONable(true)
|
||||
);
|
||||
@@ -180,7 +184,7 @@ CS.Input.prototype.toJSONable = function (omitCatalogCache) {
|
||||
var self = this;
|
||||
var obj = {
|
||||
dependencies: self.dependencies,
|
||||
constraints: _.map(self.constraints, function (c) {
|
||||
constraints: self.constraints.map(function (c) {
|
||||
return c.toString();
|
||||
})
|
||||
};
|
||||
@@ -194,7 +198,7 @@ CS.Input.prototype.toJSONable = function (omitCatalogCache) {
|
||||
if (self.upgrade.length) {
|
||||
obj.upgrade = self.upgrade;
|
||||
}
|
||||
if (! _.isEmpty(self.anticipatedPrereleases)) {
|
||||
if (!isEmpty(self.anticipatedPrereleases)) {
|
||||
obj.anticipatedPrereleases = self.anticipatedPrereleases;
|
||||
}
|
||||
if (self.previousSolution !== null) {
|
||||
@@ -225,7 +229,7 @@ CS.Input.fromJSONable = function (obj) {
|
||||
|
||||
return new CS.Input(
|
||||
obj.dependencies,
|
||||
_.map(obj.constraints, function (cstr) {
|
||||
obj.constraints.map(function (cstr) {
|
||||
return PV.parsePackageConstraint(cstr);
|
||||
}),
|
||||
CS.CatalogCache.fromJSONable(obj.catalogCache),
|
||||
@@ -236,4 +240,4 @@ CS.Input.fromJSONable = function (obj) {
|
||||
allowIncompatibleUpdate: obj.allowIncompatibleUpdate,
|
||||
upgradeIndirectDepPatchVersions: obj.upgradeIndirectDepPatchVersions
|
||||
});
|
||||
};
|
||||
};
|
||||
@@ -1,16 +1,20 @@
|
||||
const has = Npm.require('lodash.has');
|
||||
const isString = Npm.require('lodash.isstring');
|
||||
const isEmpty = Npm.require('lodash.isempty');
|
||||
|
||||
var PV = PackageVersion;
|
||||
var CS = ConstraintSolver;
|
||||
|
||||
var makeResolver = function (data) {
|
||||
var Versions = new LocalCollection;
|
||||
|
||||
_.each(data, function (versionDescription) {
|
||||
data.forEach(function (versionDescription) {
|
||||
var packageName = versionDescription.shift();
|
||||
var version = versionDescription.shift();
|
||||
var deps = versionDescription.shift();
|
||||
|
||||
var constructedDeps = {};
|
||||
_.each(deps, function (constraint, name) {
|
||||
if (!isEmpty(deps)) {
|
||||
Object.entries(deps).forEach(function ([name, constraint]) {
|
||||
constructedDeps[name] = {
|
||||
constraint: constraint,
|
||||
references: [
|
||||
@@ -20,6 +24,7 @@ var makeResolver = function (data) {
|
||||
]
|
||||
};
|
||||
});
|
||||
}
|
||||
Versions.insert({ packageName: packageName, version: version,
|
||||
dependencies: constructedDeps });
|
||||
});
|
||||
@@ -73,8 +78,7 @@ var defaultResolver = makeResolver([
|
||||
// in the returned arrays.
|
||||
splitArgs = function (deps) {
|
||||
var dependencies = [], constraints = [];
|
||||
|
||||
_.each(deps, function (constr, dep) {
|
||||
Object.entries(deps).forEach(function ([dep, constr]) {
|
||||
if (constr && constr.charAt(0) === 'w') {
|
||||
constr = constr.slice(1);
|
||||
} else {
|
||||
@@ -89,7 +93,7 @@ splitArgs = function (deps) {
|
||||
|
||||
var testWithResolver = function (test, resolver, f) {
|
||||
var answerToString = function (answer) {
|
||||
var pvs = _.map(answer, function (v, p) { return p + ' ' + v; });
|
||||
var pvs = Object.keys(answer).map(function (p) { return p + ' ' + answer[p]; });
|
||||
return pvs.sort().join('\n');
|
||||
};
|
||||
var t = function (deps, expected, options) {
|
||||
@@ -306,7 +310,7 @@ Tinytest.add("constraint solver - previousSolution", function (test) {
|
||||
|
||||
Tinytest.add("constraint solver - no constraint dependency - anything", function (test) {
|
||||
var versions = defaultResolver.resolve(["sparkle"], []).answer;
|
||||
test.isTrue(_.isString(versions.sparkle));
|
||||
test.isTrue(isString(versions.sparkle));
|
||||
});
|
||||
|
||||
|
||||
@@ -333,9 +337,9 @@ Tinytest.add("constraint solver - input serialization", function (test) {
|
||||
test.equal(input1.upgradeIndirectDepPatchVersions, false);
|
||||
|
||||
var obj1 = input1.toJSONable();
|
||||
test.isFalse(_.has(obj1, 'upgrade'));
|
||||
test.isFalse(_.has(obj1, 'anticipatedPrereleases'));
|
||||
test.isFalse(_.has(obj1, 'previousSolution'));
|
||||
test.isFalse(has(obj1, 'upgrade'));
|
||||
test.isFalse(has(obj1, 'anticipatedPrereleases'));
|
||||
test.isFalse(has(obj1, 'previousSolution'));
|
||||
var input2 = CS.Input.fromJSONable(obj1);
|
||||
var obj2 = input2.toJSONable();
|
||||
|
||||
@@ -377,4 +381,4 @@ Tinytest.add("constraint solver - non-existent indirect package", function (test
|
||||
return error.message.match(/unknown package: bar/);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,3 +1,5 @@
|
||||
const isEqual = Npm.require('lodash.isequal');
|
||||
|
||||
var PV = PackageVersion;
|
||||
var CS = ConstraintSolver;
|
||||
|
||||
@@ -50,13 +52,17 @@ CS.PackagesResolver.prototype.resolve = function (dependencies, constraints,
|
||||
|
||||
var input;
|
||||
Profile.time("new CS.Input", function () {
|
||||
const { upgrade,
|
||||
anticipatedPrereleases,
|
||||
previousSolution,
|
||||
allowIncompatibleUpdate,
|
||||
upgradeIndirectDepPatchVersions } = options;
|
||||
input = new CS.Input(dependencies, constraints, self.catalogCache,
|
||||
_.pick(options,
|
||||
'upgrade',
|
||||
'anticipatedPrereleases',
|
||||
'previousSolution',
|
||||
'allowIncompatibleUpdate',
|
||||
'upgradeIndirectDepPatchVersions'));
|
||||
{ upgrade,
|
||||
anticipatedPrereleases,
|
||||
previousSolution,
|
||||
allowIncompatibleUpdate,
|
||||
upgradeIndirectDepPatchVersions });
|
||||
});
|
||||
|
||||
// The constraint solver avoids re-solving everything from scratch on
|
||||
@@ -78,14 +84,14 @@ CS.PackagesResolver.prototype.resolve = function (dependencies, constraints,
|
||||
resultCache = null;
|
||||
} else if (resultCache &&
|
||||
resultCache.lastInput &&
|
||||
_.isEqual(resultCache.lastInput,
|
||||
isEqual(resultCache.lastInput,
|
||||
input.toJSONable(true))) {
|
||||
return resultCache.lastOutput;
|
||||
}
|
||||
|
||||
if (options.supportedIsobuildFeaturePackages) {
|
||||
_.each(options.supportedIsobuildFeaturePackages, function (versions, pkg) {
|
||||
_.each(versions, function (version) {
|
||||
Object.entries(options.supportedIsobuildFeaturePackages).forEach(function ([pkg, versions]) {
|
||||
versions.forEach(function (version) {
|
||||
input.catalogCache.addPackageVersion(pkg, version, []);
|
||||
});
|
||||
});
|
||||
@@ -100,7 +106,7 @@ CS.PackagesResolver.prototype.resolve = function (dependencies, constraints,
|
||||
if (options.previousSolution && options.missingPreviousVersionIsError) {
|
||||
// see comment where missingPreviousVersionIsError is passed in
|
||||
Profile.time("check for previous versions in catalog", function () {
|
||||
_.each(options.previousSolution, function (version, pkg) {
|
||||
Object.entries(options.previousSolution).forEach(function ([pkg, version]) {
|
||||
if (! input.catalogCache.hasPackageVersion(pkg, version)) {
|
||||
CS.throwConstraintSolverError(
|
||||
"Package version not in catalog: " + pkg + " " + version);
|
||||
@@ -193,7 +199,7 @@ CS.PackagesResolver._resolveWithInput = function (input, options) {
|
||||
// with an `alternatives` property lifted from one.
|
||||
// - version: version String
|
||||
CS.isConstraintSatisfied = function (pkg, vConstraint, version) {
|
||||
return _.some(vConstraint.alternatives, function (simpleConstraint) {
|
||||
return vConstraint.alternatives.some(function (simpleConstraint) {
|
||||
var type = simpleConstraint.type;
|
||||
|
||||
if (type === "any-reasonable") {
|
||||
@@ -263,4 +269,4 @@ CS.DummyProfile = function (bucket, f) {
|
||||
};
|
||||
CS.DummyProfile.time = function (bucket, f) {
|
||||
return f();
|
||||
};
|
||||
};
|
||||
@@ -2,7 +2,7 @@ var PV = PackageVersion;
|
||||
var CS = ConstraintSolver;
|
||||
|
||||
Tinytest.add("constraint solver - datatypes - Dependency", function (test) {
|
||||
_.each(["foo", "foo@1.0.0"], function (foo) {
|
||||
["foo", "foo@1.0.0"].forEach(function (foo) {
|
||||
var d1 = new CS.Dependency(PV.parsePackageConstraint(foo));
|
||||
test.equal(d1.packageConstraint.toString(), foo);
|
||||
test.equal(d1.isWeak, false);
|
||||
|
||||
@@ -12,7 +12,7 @@ var CS = ConstraintSolver;
|
||||
// in that order. If that's not true, these tests will break.
|
||||
var sortKeys = function (obj) {
|
||||
var result = {};
|
||||
_.each(_.keys(obj).sort(), function (k) {
|
||||
Object.keys(obj).sort().forEach(function (k) {
|
||||
result[k] = obj[k];
|
||||
});
|
||||
return result;
|
||||
@@ -22,7 +22,7 @@ var formatSolution = function (obj) {
|
||||
// results into tests.
|
||||
return JSON.stringify({
|
||||
answer: sortKeys(obj.answer),
|
||||
allAnswers: obj.allAnswers && _.map(obj.allAnswers, sortKeys),
|
||||
allAnswers: obj.allAnswers && obj.allAnswers.map(sortKeys),
|
||||
neededToUseUnanticipatedPrereleases: obj.neededToUseUnanticipatedPrereleases
|
||||
}, null, 2);
|
||||
};
|
||||
@@ -36,7 +36,7 @@ var doTest = function (test, inputJSONable, outputJSONable, options) {
|
||||
}
|
||||
|
||||
if (typeof outputJSONable.neededToUseUnanticipatedPrereleases !== 'boolean') {
|
||||
outputJSONable = _.extend(outputJSONable, {
|
||||
outputJSONable = Object.assign(outputJSONable, {
|
||||
neededToUseUnanticipatedPrereleases: (
|
||||
!! outputJSONable.neededToUseUnanticipatedPrereleases)
|
||||
});
|
||||
|
||||
@@ -3,10 +3,20 @@ Package.describe({
|
||||
version: "1.2.0"
|
||||
});
|
||||
|
||||
Npm.depends({
|
||||
'lodash.has': '4.5.2',
|
||||
'lodash.memoize': '4.1.2',
|
||||
'lodash.isequal': '4.5.0',
|
||||
'lodash.isempty': '4.4.0',
|
||||
'lodash.zip': '4.2.0',
|
||||
'lodash.groupby': '4.6.0',
|
||||
'lodash.isstring': '4.0.1',
|
||||
'lodash.isobject': '3.0.2'
|
||||
});
|
||||
|
||||
Package.onUse(function (api) {
|
||||
api.export('ConstraintSolver');
|
||||
api.use([
|
||||
'underscore',
|
||||
'check',
|
||||
'package-version-parser',
|
||||
'logic-solver'
|
||||
@@ -27,7 +37,6 @@ Package.onTest(function (api) {
|
||||
'tinytest',
|
||||
'minimongo',
|
||||
'package-version-parser',
|
||||
'underscore',
|
||||
'check'
|
||||
]);
|
||||
|
||||
|
||||
@@ -1,3 +1,8 @@
|
||||
const has = Npm.require('lodash.has');
|
||||
const zip = Npm.require('lodash.zip');
|
||||
const memoize = Npm.require('lodash.memoize');
|
||||
const groupBy = Npm.require('lodash.groupby');
|
||||
|
||||
var CS = ConstraintSolver;
|
||||
var PV = PackageVersion;
|
||||
|
||||
@@ -16,10 +21,10 @@ CS.Solver = function (input, options) {
|
||||
self.errors = []; // [String]
|
||||
|
||||
self.pricer = new CS.VersionPricer();
|
||||
self.getConstraintFormula = _.memoize(_getConstraintFormula,
|
||||
function (p, vConstraint) {
|
||||
return p + "@" + vConstraint.raw;
|
||||
});
|
||||
self.getConstraintFormula = memoize(_getConstraintFormula,
|
||||
function (p, vConstraint) {
|
||||
return p + "@" + vConstraint.raw;
|
||||
});
|
||||
|
||||
self.options = options || {};
|
||||
self.Profile = (self.options.Profile || CS.DummyProfile);
|
||||
@@ -38,7 +43,7 @@ CS.Solver = function (input, options) {
|
||||
|
||||
CS.Solver.prototype.throwAnyErrors = function () {
|
||||
if (this.errors.length) {
|
||||
var multiline = _.any(this.errors, function (e) {
|
||||
var multiline = this.errors.some(function (e) {
|
||||
return /\n/.test(e);
|
||||
});
|
||||
CS.throwConstraintSolverError(this.errors.join(
|
||||
@@ -48,7 +53,7 @@ CS.Solver.prototype.throwAnyErrors = function () {
|
||||
|
||||
CS.Solver.prototype.getVersions = function (pkg) {
|
||||
var self = this;
|
||||
if (_.has(self.analysis.allowedVersions, pkg)) {
|
||||
if (has(self.analysis.allowedVersions, pkg)) {
|
||||
return self.analysis.allowedVersions[pkg];
|
||||
} else {
|
||||
return self.input.catalogCache.getPackageVersions(pkg);
|
||||
@@ -90,20 +95,20 @@ CS.Solver.prototype.analyze = function () {
|
||||
// track such packages in packagesWithNoAllowedVersions so that we
|
||||
// throw a good error later.
|
||||
Profile.time("analyze allowed versions", function () {
|
||||
_.each(_.groupBy(input.constraints, 'package'), function (cs, p) {
|
||||
Object.entries(groupBy(input.constraints, 'package')).forEach(function ([p, cs]) {
|
||||
var versions = cache.getPackageVersions(p);
|
||||
if (! versions.length) {
|
||||
if (!versions.length) {
|
||||
// deal with wholly unknown packages later
|
||||
return;
|
||||
}
|
||||
_.each(cs, function (constr) {
|
||||
versions = _.filter(versions, function (v) {
|
||||
cs.forEach(function (constr) {
|
||||
versions = versions.filter(function (v) {
|
||||
return CS.isConstraintSatisfied(p, constr.versionConstraint, v);
|
||||
});
|
||||
});
|
||||
if (! versions.length) {
|
||||
analysis.packagesWithNoAllowedVersions[p] = _.filter(cs, function (c) {
|
||||
return !! c.constraintString;
|
||||
if (!versions.length) {
|
||||
analysis.packagesWithNoAllowedVersions[p] = cs.filter(function (c) {
|
||||
return !!c.constraintString;
|
||||
});
|
||||
}
|
||||
analysis.allowedVersions[p] = versions;
|
||||
@@ -118,11 +123,11 @@ CS.Solver.prototype.analyze = function () {
|
||||
analysis.previousRootDepVersions = [];
|
||||
|
||||
Profile.time("analyze root dependencies", function () {
|
||||
_.each(input.dependencies, function (p) {
|
||||
if (! input.isKnownPackage(p)) {
|
||||
input.dependencies.forEach(function (p) {
|
||||
if (!input.isKnownPackage(p)) {
|
||||
analysis.unknownRootDeps.push(p);
|
||||
} else if (input.isInPreviousSolution(p) &&
|
||||
! input.isUpgrading(p)) {
|
||||
!input.isUpgrading(p)) {
|
||||
analysis.previousRootDepVersions.push(new CS.PackageAndVersion(
|
||||
p, input.previousSolution[p]));
|
||||
}
|
||||
@@ -130,7 +135,7 @@ CS.Solver.prototype.analyze = function () {
|
||||
|
||||
// throw if there are unknown packages in root deps
|
||||
if (analysis.unknownRootDeps.length) {
|
||||
_.each(analysis.unknownRootDeps, function (p) {
|
||||
analysis.unknownRootDeps.forEach(function (p) {
|
||||
if (CS.isIsobuildFeaturePackage(p)) {
|
||||
self.errors.push(
|
||||
'unsupported Isobuild feature "' + p +
|
||||
@@ -171,21 +176,21 @@ CS.Solver.prototype.analyze = function () {
|
||||
var markReachable = function (p) {
|
||||
analysis.reachablePackages[p] = true;
|
||||
|
||||
_.each(self.getVersions(p), function (v) {
|
||||
_.each(cache.getDependencyMap(p, v), function (dep) {
|
||||
self.getVersions(p).forEach(function (v) {
|
||||
Object.values(cache.getDependencyMap(p, v)).forEach(function (dep) {
|
||||
// `dep` is a CS.Dependency
|
||||
var p2 = dep.packageConstraint.package;
|
||||
if (! input.isKnownPackage(p2)) {
|
||||
if (!input.isKnownPackage(p2)) {
|
||||
// record this package so we will generate a variable
|
||||
// for it. we'll try not to select it, and ultimately
|
||||
// throw an error if we are forced to.
|
||||
if (! _.has(analysis.unknownPackages, p2)) {
|
||||
if (!has(analysis.unknownPackages, p2)) {
|
||||
analysis.unknownPackages[p2] = [];
|
||||
}
|
||||
analysis.unknownPackages[p2].push(pvVar(p, v));
|
||||
} else {
|
||||
if (! dep.isWeak) {
|
||||
if (! _.has(analysis.reachablePackages, p2)) {
|
||||
if (!dep.isWeak) {
|
||||
if (!has(analysis.reachablePackages, p2)) {
|
||||
markReachable(p2);
|
||||
}
|
||||
}
|
||||
@@ -195,7 +200,7 @@ CS.Solver.prototype.analyze = function () {
|
||||
};
|
||||
|
||||
Profile.time("analyze reachability", function () {
|
||||
_.each(input.dependencies, markReachable);
|
||||
input.dependencies.forEach(markReachable);
|
||||
});
|
||||
|
||||
////////// ANALYZE CONSTRAINTS
|
||||
@@ -217,9 +222,9 @@ CS.Solver.prototype.analyze = function () {
|
||||
// version constraints is a power-tool that should be used sparingly
|
||||
// by application developers, and never abused by package authors.
|
||||
var overrides = new Set;
|
||||
_.each(input.constraints, function (c) {
|
||||
input.constraints.forEach(function (c) {
|
||||
if (c.constraintString &&
|
||||
c.versionConstraint.override) {
|
||||
c.versionConstraint.override) {
|
||||
overrides.add(c.package);
|
||||
}
|
||||
});
|
||||
@@ -260,28 +265,28 @@ CS.Solver.prototype.analyze = function () {
|
||||
}
|
||||
|
||||
// top-level constraints
|
||||
_.each(input.constraints, function (c) {
|
||||
input.constraints.forEach(function (c) {
|
||||
if (c.constraintString) {
|
||||
analysis.constraints.push(new CS.Solver.Constraint(
|
||||
null, c.package, getVersionConstraint(c),
|
||||
"constraint#" + analysis.constraints.length));
|
||||
|
||||
if (c.versionConstraint.alternatives.length === 1 &&
|
||||
c.versionConstraint.alternatives[0].type === 'exactly') {
|
||||
c.versionConstraint.alternatives[0].type === 'exactly') {
|
||||
analysis.topLevelEqualityConstrainedPackages[c.package] = true;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// constraints specified in package dependencies
|
||||
_.each(_.keys(analysis.reachablePackages), function (p) {
|
||||
_.each(self.getVersions(p), function (v) {
|
||||
Object.keys(analysis.reachablePackages).forEach(function (p) {
|
||||
self.getVersions(p).forEach(function (v) {
|
||||
var pv = pvVar(p, v);
|
||||
_.each(cache.getDependencyMap(p, v), function (dep) {
|
||||
Object.values(cache.getDependencyMap(p, v)).forEach(function (dep) {
|
||||
// `dep` is a CS.Dependency
|
||||
var p2 = dep.packageConstraint.package;
|
||||
if (input.isKnownPackage(p2) &&
|
||||
dep.packageConstraint.constraintString) {
|
||||
dep.packageConstraint.constraintString) {
|
||||
analysis.constraints.push(new CS.Solver.Constraint(
|
||||
pv, p2, getVersionConstraint(dep.packageConstraint),
|
||||
"constraint#" + analysis.constraints.length));
|
||||
@@ -295,11 +300,11 @@ CS.Solver.prototype.analyze = function () {
|
||||
|
||||
Profile.time("analyze pre-releases", function () {
|
||||
var unanticipatedPrereleases = [];
|
||||
_.each(_.keys(analysis.reachablePackages), function (p) {
|
||||
Object.keys(analysis.reachablePackages).forEach(function (p) {
|
||||
var anticipatedPrereleases = input.anticipatedPrereleases[p];
|
||||
_.each(self.getVersions(p), function (v) {
|
||||
if (/-/.test(v) && ! (anticipatedPrereleases &&
|
||||
_.has(anticipatedPrereleases, v))) {
|
||||
self.getVersions(p).forEach(function (v) {
|
||||
if (/-/.test(v) && !(anticipatedPrereleases &&
|
||||
has(anticipatedPrereleases, v))) {
|
||||
unanticipatedPrereleases.push(pvVar(p, v));
|
||||
}
|
||||
});
|
||||
@@ -357,7 +362,7 @@ CS.Solver.Step.prototype.addTerm = function (term, weight) {
|
||||
if (typeof this.weights === 'number') {
|
||||
if (weight !== this.weights) {
|
||||
throw new Error("Can't specify a different weight now: " +
|
||||
weight + " != " + this.weights);
|
||||
weight + " != " + this.weights);
|
||||
}
|
||||
} else {
|
||||
this.weights.push(weight);
|
||||
@@ -374,9 +379,9 @@ var DEBUG = false;
|
||||
CS.Solver.prototype.minimize = function (step, options) {
|
||||
var self = this;
|
||||
|
||||
if (_.isArray(step)) {
|
||||
if (Array.isArray(step)) {
|
||||
// minimize([steps...], options)
|
||||
_.each(step, function (st) {
|
||||
step.forEach(function (st) {
|
||||
self.minimize(st, options);
|
||||
});
|
||||
return;
|
||||
@@ -389,7 +394,7 @@ CS.Solver.prototype.minimize = function (step, options) {
|
||||
var costWeights_ = arguments[2];
|
||||
var options_ = arguments[3];
|
||||
if (costWeights_ && typeof costWeights_ === 'object' &&
|
||||
! _.isArray(costWeights_)) {
|
||||
!Array.isArray(costWeights_)) {
|
||||
options_ = costWeights_;
|
||||
costWeights_ = null;
|
||||
}
|
||||
@@ -419,29 +424,29 @@ CS.Solver.prototype.minimize = function (step, options) {
|
||||
|
||||
self.setSolution(logic.minimizeWeightedSum(
|
||||
self.solution, optimized.costTerms, optimized.costWeights, {
|
||||
progress: function (status, cost) {
|
||||
if (self.options.nudge) {
|
||||
self.options.nudge();
|
||||
progress: function (status, cost) {
|
||||
if (self.options.nudge) {
|
||||
self.options.nudge();
|
||||
}
|
||||
if (DEBUG) {
|
||||
if (status === 'improving') {
|
||||
console.log(cost + " ... trying to improve ...");
|
||||
} else if (status === 'trying') {
|
||||
console.log("... trying " + cost + " ... ");
|
||||
}
|
||||
if (DEBUG) {
|
||||
if (status === 'improving') {
|
||||
console.log(cost + " ... trying to improve ...");
|
||||
} else if (status === 'trying') {
|
||||
console.log("... trying " + cost + " ... ");
|
||||
}
|
||||
}
|
||||
},
|
||||
strategy: (options && options.strategy)
|
||||
}));
|
||||
}
|
||||
},
|
||||
strategy: (options && options.strategy)
|
||||
}));
|
||||
|
||||
step.optimum = self.solution.getWeightedSum(costTerms, costWeights);
|
||||
if (DEBUG) {
|
||||
console.log(step.optimum + " is optimal");
|
||||
|
||||
if (step.optimum) {
|
||||
_.each(costTerms, function (t, i) {
|
||||
costTerms.forEach(function (t, i) {
|
||||
var w = (typeof costWeights === 'number' ? costWeights :
|
||||
costWeights[i]);
|
||||
costWeights[i]);
|
||||
if (w && self.solution.evaluate(t)) {
|
||||
console.log(" " + w + ": " + t);
|
||||
}
|
||||
@@ -474,32 +479,38 @@ var groupMutuallyExclusiveTerms = function (costTerms, costWeights) {
|
||||
// first space. So "foo 1.0.0" becomes "foo " and "foo" stays "foo".
|
||||
var getTermKey = function (t) {
|
||||
var firstSpace = t.indexOf(' ');
|
||||
return firstSpace < 0 ? t : t.slice(0, firstSpace+1);
|
||||
return firstSpace < 0 ? t : t.slice(0, firstSpace + 1);
|
||||
};
|
||||
|
||||
// costWeights, as usual, may be a number or an array
|
||||
if (typeof costWeights === 'number') {
|
||||
return {
|
||||
costTerms: _.map(_.groupBy(costTerms, getTermKey), function (group) {
|
||||
costTerms: Object.values(groupBy(costTerms, getTermKey)).map(function (group) {
|
||||
return Logic.or(group);
|
||||
}),
|
||||
costWeights: costWeights
|
||||
};
|
||||
} else if (! costTerms.length) {
|
||||
} else if (!costTerms.length) {
|
||||
return { costTerms: costTerms, costWeights: costWeights };
|
||||
} else {
|
||||
var weightedTerms = _.zip(costWeights, costTerms);
|
||||
var newWeightedTerms = _.map(_.groupBy(weightedTerms, function (wt) {
|
||||
var weightedTerms = zip(costWeights, costTerms);
|
||||
var newWeightedTerms = Object.values(groupBy(weightedTerms, function (wt) {
|
||||
// construct a string from the weight and term key, for grouping
|
||||
// purposes. since the weight comes first, there's no ambiguity
|
||||
// and the separator char could be pretty much anything.
|
||||
return wt[0] + ' ' + getTermKey(wt[1]);
|
||||
}), function (wts) {
|
||||
return [wts[0][0], Logic.or(_.pluck(wts, 1))];
|
||||
})).map(function (wts) {
|
||||
return [wts[0][0], Logic.or(wts.map(function(x){
|
||||
return x[1]
|
||||
}))];
|
||||
});
|
||||
return {
|
||||
costTerms: _.pluck(newWeightedTerms, 1),
|
||||
costWeights: _.pluck(newWeightedTerms, 0)
|
||||
costTerms: newWeightedTerms.map(function(x){
|
||||
return x[1]
|
||||
}),
|
||||
costWeights: newWeightedTerms.map(function(x){
|
||||
return x[0]
|
||||
})
|
||||
};
|
||||
}
|
||||
|
||||
@@ -513,7 +524,7 @@ CS.Solver.prototype.getStepContributions = function (step) {
|
||||
var solution = self.solution;
|
||||
var contributions = {};
|
||||
var weights = step.weights;
|
||||
_.each(step.terms, function (t, i) {
|
||||
step.terms.forEach(function (t, i) {
|
||||
var w = (typeof weights === 'number' ? weights : weights[i]);
|
||||
if (w && self.solution.evaluate(t)) {
|
||||
contributions[t] = w;
|
||||
@@ -523,7 +534,7 @@ CS.Solver.prototype.getStepContributions = function (step) {
|
||||
};
|
||||
|
||||
var addCostsToSteps = function (pkg, versions, costs, steps) {
|
||||
var pvs = _.map(versions, function (v) {
|
||||
var pvs = versions.map(function (v) {
|
||||
return pvVar(pkg, v);
|
||||
});
|
||||
for (var j = 0; j < steps.length; j++) {
|
||||
@@ -546,7 +557,7 @@ var addCostsToSteps = function (pkg, versions, costs, steps) {
|
||||
// the cost of every version of every package. This function iterates
|
||||
// over `packages` and puts the result into `Step` objects.
|
||||
CS.Solver.prototype.getVersionCostSteps = function (stepBaseName, packages,
|
||||
pricerMode) {
|
||||
pricerMode) {
|
||||
var self = this;
|
||||
var major = new CS.Solver.Step(stepBaseName + '_major');
|
||||
var minor = new CS.Solver.Step(stepBaseName + '_minor');
|
||||
@@ -556,7 +567,7 @@ CS.Solver.prototype.getVersionCostSteps = function (stepBaseName, packages,
|
||||
self.Profile.time(
|
||||
"calculate " + stepBaseName + " version costs",
|
||||
function () {
|
||||
_.each(packages, function (p) {
|
||||
packages.forEach(function (p) {
|
||||
var versions = self.getVersions(p);
|
||||
if (versions.length >= 2) {
|
||||
var costs = self.pricer.priceVersions(versions, pricerMode);
|
||||
@@ -574,8 +585,8 @@ CS.Solver.prototype.getVersionCostSteps = function (stepBaseName, packages,
|
||||
// as `packageAndVersion`. (Actually it's a complicated function of the
|
||||
// previous and new version.)
|
||||
CS.Solver.prototype.getVersionDistanceSteps = function (stepBaseName,
|
||||
packageAndVersions,
|
||||
takePatches) {
|
||||
packageAndVersions,
|
||||
takePatches) {
|
||||
var self = this;
|
||||
|
||||
var incompat = new CS.Solver.Step(stepBaseName + '_incompat');
|
||||
@@ -587,7 +598,7 @@ CS.Solver.prototype.getVersionDistanceSteps = function (stepBaseName,
|
||||
self.Profile.time(
|
||||
"calculate " + stepBaseName + " distance costs",
|
||||
function () {
|
||||
_.each(packageAndVersions, function (pvArg) {
|
||||
packageAndVersions.forEach(function (pvArg) {
|
||||
var pkg = pvArg.package;
|
||||
var previousVersion = pvArg.version;
|
||||
var versions = self.getVersions(pkg);
|
||||
@@ -595,7 +606,7 @@ CS.Solver.prototype.getVersionDistanceSteps = function (stepBaseName,
|
||||
var costs = self.pricer.priceVersionsWithPrevious(
|
||||
versions, previousVersion, takePatches);
|
||||
addCostsToSteps(pkg, versions, costs,
|
||||
[incompat, major, minor, patch, rest]);
|
||||
[incompat, major, minor, patch, rest]);
|
||||
}
|
||||
});
|
||||
});
|
||||
@@ -606,7 +617,7 @@ CS.Solver.prototype.getVersionDistanceSteps = function (stepBaseName,
|
||||
CS.Solver.prototype.currentVersionMap = function () {
|
||||
var self = this;
|
||||
var pvs = [];
|
||||
_.each(self.solution.getTrueVars(), function (x) {
|
||||
self.solution.getTrueVars().forEach(function (x) {
|
||||
if (x.indexOf(' ') >= 0) {
|
||||
// all variables with spaces in them are PackageAndVersions
|
||||
var pv = CS.PackageAndVersion.fromString(x);
|
||||
@@ -615,11 +626,11 @@ CS.Solver.prototype.currentVersionMap = function () {
|
||||
});
|
||||
|
||||
var versionMap = {};
|
||||
_.each(pvs, function (pv) {
|
||||
if (_.has(versionMap, pv.package)) {
|
||||
pvs.forEach(function (pv) {
|
||||
if (has(versionMap, pv.package)) {
|
||||
throw new Error("Assertion failure: Selected two versions of " +
|
||||
pv.package + ", " +versionMap[pv.package] +
|
||||
" and " + pv.version);
|
||||
pv.package + ", " + versionMap[pv.package] +
|
||||
" and " + pv.version);
|
||||
}
|
||||
versionMap[pv.package] = pv.version;
|
||||
});
|
||||
@@ -632,7 +643,7 @@ CS.Solver.prototype.currentVersionMap = function () {
|
||||
CS.Solver.prototype.setSolution = function (solution) {
|
||||
var self = this;
|
||||
self.solution = solution;
|
||||
if (! self.solution) {
|
||||
if (!self.solution) {
|
||||
throw new Error("Unexpected unsatisfiability");
|
||||
}
|
||||
// When we query a Solution, we always want to treat unknown variables
|
||||
@@ -671,19 +682,19 @@ CS.Solver.prototype._getAnswer = function (options) {
|
||||
|
||||
// require root dependencies
|
||||
Profile.time("require root dependencies", function () {
|
||||
_.each(input.dependencies, function (p) {
|
||||
input.dependencies.forEach(function (p) {
|
||||
logic.require(p);
|
||||
});
|
||||
});
|
||||
|
||||
// generate package version variables for known, reachable packages
|
||||
Profile.time("generate package variables", function () {
|
||||
_.each(_.keys(analysis.reachablePackages), function (p) {
|
||||
if (! _.has(analysis.packagesWithNoAllowedVersions, p)) {
|
||||
var versionVars = _.map(self.getVersions(p),
|
||||
function (v) {
|
||||
return pvVar(p, v);
|
||||
});
|
||||
Object.keys(analysis.reachablePackages).forEach(function (p) {
|
||||
if (!has(analysis.packagesWithNoAllowedVersions, p)) {
|
||||
var versionVars = self.getVersions(p).map(
|
||||
function (v) {
|
||||
return pvVar(p, v);
|
||||
});
|
||||
// At most one of ["foo 1.0.0", "foo 1.0.1", ...] is true.
|
||||
logic.require(Logic.atMostOne(versionVars));
|
||||
// The variable "foo" is true if and only if at least one of the
|
||||
@@ -695,11 +706,11 @@ CS.Solver.prototype._getAnswer = function (options) {
|
||||
|
||||
// generate strong dependency requirements
|
||||
Profile.time("generate dependency requirements", function () {
|
||||
_.each(_.keys(analysis.reachablePackages), function (p) {
|
||||
_.each(self.getVersions(p), function (v) {
|
||||
_.each(cache.getDependencyMap(p, v), function (dep) {
|
||||
Object.keys(analysis.reachablePackages).forEach(function (p) {
|
||||
self.getVersions(p).forEach(function (v) {
|
||||
Object.values(cache.getDependencyMap(p, v)).forEach(function (dep) {
|
||||
// `dep` is a CS.Dependency
|
||||
if (! dep.isWeak) {
|
||||
if (!dep.isWeak) {
|
||||
var p2 = dep.packageConstraint.package;
|
||||
logic.require(Logic.implies(pvVar(p, v), p2));
|
||||
}
|
||||
@@ -711,7 +722,7 @@ CS.Solver.prototype._getAnswer = function (options) {
|
||||
// generate constraints -- but technically don't enforce them, because
|
||||
// we haven't forced the conflictVars to be false
|
||||
Profile.time("generate constraints", function () {
|
||||
_.each(analysis.constraints, function (c) {
|
||||
analysis.constraints.forEach(function (c) {
|
||||
// We logically require that EITHER a constraint is marked as a
|
||||
// conflict OR it comes from a package version that is not selected
|
||||
// OR its constraint formula must be true.
|
||||
@@ -719,8 +730,8 @@ CS.Solver.prototype._getAnswer = function (options) {
|
||||
// then a version of it that satisfies our constraint must be true.)
|
||||
logic.require(
|
||||
Logic.or(c.conflictVar,
|
||||
c.fromVar ? Logic.not(c.fromVar) : [],
|
||||
self.getConstraintFormula(c.toPackage, c.vConstraint)));
|
||||
c.fromVar ? Logic.not(c.fromVar) : [],
|
||||
self.getConstraintFormula(c.toPackage, c.vConstraint)));
|
||||
});
|
||||
});
|
||||
|
||||
@@ -754,7 +765,7 @@ CS.Solver.prototype._getAnswer = function (options) {
|
||||
// initial solution before asking the solver if it's possible to
|
||||
// not use these packages.
|
||||
Profile.time("forbid packages with no matching versions", function () {
|
||||
_.each(analysis.packagesWithNoAllowedVersions, function (constrs, p) {
|
||||
Object.entries(analysis.packagesWithNoAllowedVersions).forEach(function ([p, constrs]) {
|
||||
var newSolution = logic.solveAssuming(Logic.not(p));
|
||||
if (newSolution) {
|
||||
self.setSolution(newSolution);
|
||||
@@ -762,9 +773,9 @@ CS.Solver.prototype._getAnswer = function (options) {
|
||||
} else {
|
||||
var error =
|
||||
'No version of ' + p + ' satisfies all constraints: ' +
|
||||
_.map(constrs, function (constr) {
|
||||
return '@' + constr.constraintString;
|
||||
}).join(', ');
|
||||
constrs.map(function (constr) {
|
||||
return '@' + constr.constraintString;
|
||||
}).join(', ');
|
||||
error += '\n' + self.listConstraintsOnPackage(p);
|
||||
self.errors.push(error);
|
||||
}
|
||||
@@ -776,7 +787,7 @@ CS.Solver.prototype._getAnswer = function (options) {
|
||||
// than 0, we'll throw an error later, after we apply the constraints
|
||||
// and the cost function, so that we can explain the problem to the
|
||||
// user in a convincing way.
|
||||
self.minimize('unknown_packages', _.keys(analysis.unknownPackages));
|
||||
self.minimize('unknown_packages', Object.keys(analysis.unknownPackages));
|
||||
|
||||
// try not to set the conflictVar on any constraint. If the minimum
|
||||
// is greater than 0, we'll throw an error later, after we've run the
|
||||
@@ -784,12 +795,14 @@ CS.Solver.prototype._getAnswer = function (options) {
|
||||
// If there are conflicts, this minimization can be time-consuming
|
||||
// (several seconds or more). The strategy 'bottom-up' helps by
|
||||
// looking for solutions with few conflicts first.
|
||||
self.minimize('conflicts', _.pluck(analysis.constraints, 'conflictVar'),
|
||||
{ strategy: 'bottom-up' });
|
||||
self.minimize('conflicts', analysis.constraints.map(function (constraint) {
|
||||
return constraint.conflictVar
|
||||
}),
|
||||
{ strategy: 'bottom-up' });
|
||||
|
||||
// Try not to use "unanticipated" prerelease versions
|
||||
self.minimize('unanticipated_prereleases',
|
||||
analysis.unanticipatedPrereleases);
|
||||
analysis.unanticipatedPrereleases);
|
||||
|
||||
var previousRootSteps = self.getVersionDistanceSteps(
|
||||
'previous_root', analysis.previousRootDepVersions);
|
||||
@@ -798,25 +811,25 @@ CS.Solver.prototype._getAnswer = function (options) {
|
||||
// the "previous_root_major", "previous_root_minor", etc. steps
|
||||
var previousRootVersionParts = previousRootSteps.slice(1);
|
||||
|
||||
var toUpdate = _.filter(input.upgrade, function (p) {
|
||||
var toUpdate = input.upgrade.filter(function (p) {
|
||||
return analysis.reachablePackages[p] === true;
|
||||
});
|
||||
|
||||
// make sure packages that are being updated can still count as
|
||||
// a previous_root for the purposes of previous_root_incompat
|
||||
Profile.time("add terms to previous_root_incompat", function () {
|
||||
_.each(toUpdate, function (p) {
|
||||
toUpdate.forEach(function (p) {
|
||||
if (input.isRootDependency(p) && input.isInPreviousSolution(p)) {
|
||||
var parts = self.pricer.partitionVersions(
|
||||
self.getVersions(p), input.previousSolution[p]);
|
||||
_.each(parts.older.concat(parts.higherMajor), function (v) {
|
||||
parts.older.concat(parts.higherMajor).forEach(function (v) {
|
||||
previousRootIncompat.addTerm(pvVar(p, v), 1);
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
if (! input.allowIncompatibleUpdate) {
|
||||
if (!input.allowIncompatibleUpdate) {
|
||||
// Enforce that we don't make breaking changes to your root dependencies,
|
||||
// unless you pass --allow-incompatible-update. It will actually be enforced
|
||||
// farther down, but for now, we want to apply this constraint before handling
|
||||
@@ -836,20 +849,20 @@ CS.Solver.prototype._getAnswer = function (options) {
|
||||
|
||||
self.minimize(previousRootVersionParts);
|
||||
|
||||
var otherPrevious = _.filter(_.map(input.previousSolution, function (v, p) {
|
||||
var otherPrevious = Object.entries(input.previousSolution || []).map(function ([p, v]) {
|
||||
return new CS.PackageAndVersion(p, v);
|
||||
}), function (pv) {
|
||||
}).filter(function (pv) {
|
||||
var p = pv.package;
|
||||
return analysis.reachablePackages[p] === true &&
|
||||
! input.isRootDependency(p);
|
||||
!input.isRootDependency(p);
|
||||
});
|
||||
|
||||
self.minimize(self.getVersionDistanceSteps(
|
||||
'previous_indirect', otherPrevious,
|
||||
input.upgradeIndirectDepPatchVersions));
|
||||
|
||||
var newRootDeps = _.filter(input.dependencies, function (p) {
|
||||
return ! input.isInPreviousSolution(p);
|
||||
var newRootDeps = input.dependencies.filter(function (p) {
|
||||
return !input.isInPreviousSolution(p);
|
||||
});
|
||||
|
||||
self.minimize(self.getVersionCostSteps(
|
||||
@@ -876,10 +889,10 @@ CS.Solver.prototype._getAnswer = function (options) {
|
||||
// signal. In other words, the user might be better off with some tie-breaker
|
||||
// that looks only at the important packages anyway.
|
||||
Profile.time("lock down important versions", function () {
|
||||
_.each(self.currentVersionMap(), function (v, pkg) {
|
||||
Object.entries(self.currentVersionMap()).forEach(function ([pkg, v]) {
|
||||
if (input.isRootDependency(pkg) ||
|
||||
input.isInPreviousSolution(pkg) ||
|
||||
input.isUpgrading(pkg)) {
|
||||
input.isInPreviousSolution(pkg) ||
|
||||
input.isUpgrading(pkg)) {
|
||||
logic.require(Logic.implies(pkg, pvVar(pkg, v)));
|
||||
}
|
||||
});
|
||||
@@ -887,10 +900,10 @@ CS.Solver.prototype._getAnswer = function (options) {
|
||||
|
||||
// new, indirect packages are the lowest priority
|
||||
var otherPackages = [];
|
||||
_.each(_.keys(analysis.reachablePackages), function (p) {
|
||||
if (! (input.isRootDependency(p) ||
|
||||
input.isInPreviousSolution(p) ||
|
||||
input.isUpgrading(p))) {
|
||||
Object.keys(analysis.reachablePackages).forEach(function (p) {
|
||||
if (!(input.isRootDependency(p) ||
|
||||
input.isInPreviousSolution(p) ||
|
||||
input.isUpgrading(p))) {
|
||||
otherPackages.push(p);
|
||||
}
|
||||
});
|
||||
@@ -899,17 +912,17 @@ CS.Solver.prototype._getAnswer = function (options) {
|
||||
'new_indirect', otherPackages,
|
||||
CS.VersionPricer.MODE_GRAVITY_WITH_PATCHES));
|
||||
|
||||
self.minimize('total_packages', _.keys(analysis.reachablePackages));
|
||||
self.minimize('total_packages', Object.keys(analysis.reachablePackages));
|
||||
|
||||
// throw errors about unknown packages
|
||||
if (self.stepsByName['unknown_packages'].optimum > 0) {
|
||||
Profile.time("generate error for unknown packages", function () {
|
||||
var unknownPackages = _.keys(analysis.unknownPackages);
|
||||
var unknownPackagesNeeded = _.filter(unknownPackages, function (p) {
|
||||
var unknownPackages = Object.keys(analysis.unknownPackages);
|
||||
var unknownPackagesNeeded = unknownPackages.filter(function (p) {
|
||||
return self.solution.evaluate(p);
|
||||
});
|
||||
_.each(unknownPackagesNeeded, function (p) {
|
||||
var requirers = _.filter(analysis.unknownPackages[p], function (pv) {
|
||||
unknownPackagesNeeded.forEach(function (p) {
|
||||
var requirers = analysis.unknownPackages[p].filter(function (pv) {
|
||||
return self.solution.evaluate(pv);
|
||||
});
|
||||
var errorStr;
|
||||
@@ -920,7 +933,7 @@ CS.Solver.prototype._getAnswer = function (options) {
|
||||
} else {
|
||||
errorStr = 'unknown package: ' + p;
|
||||
}
|
||||
_.each(requirers, function (pv) {
|
||||
requirers.forEach(function (pv) {
|
||||
errorStr += '\nRequired by: ' + pv;
|
||||
});
|
||||
self.errors.push(errorStr);
|
||||
@@ -934,36 +947,36 @@ CS.Solver.prototype._getAnswer = function (options) {
|
||||
self.throwConflicts();
|
||||
}
|
||||
|
||||
if ((! input.allowIncompatibleUpdate) &&
|
||||
self.stepsByName['previous_root_incompat'].optimum > 0) {
|
||||
if ((!input.allowIncompatibleUpdate) &&
|
||||
self.stepsByName['previous_root_incompat'].optimum > 0) {
|
||||
// we have some "incompatible root changes", where we needed to change a
|
||||
// version of a root dependency to a new version incompatible with the
|
||||
// original, but --allow-incompatible-update hasn't been passed in.
|
||||
// these are in the form of PackageAndVersion strings that we need.
|
||||
var incompatRootChanges = _.keys(self.getStepContributions(
|
||||
var incompatRootChanges = Object.keys(self.getStepContributions(
|
||||
self.stepsByName['previous_root_incompat']));
|
||||
|
||||
Profile.time("generate errors for incompatible root change", function () {
|
||||
var numActualErrors = 0;
|
||||
_.each(incompatRootChanges, function (pvStr) {
|
||||
incompatRootChanges.forEach(function (pvStr) {
|
||||
var pv = CS.PackageAndVersion.fromString(pvStr);
|
||||
// exclude packages with top-level equality constraints (added by user
|
||||
// or by the tool pinning a version)
|
||||
if (! _.has(analysis.topLevelEqualityConstrainedPackages, pv.package)) {
|
||||
if (!has(analysis.topLevelEqualityConstrainedPackages, pv.package)) {
|
||||
var prevVersion = input.previousSolution[pv.package];
|
||||
self.errors.push(
|
||||
'Potentially incompatible change required to ' +
|
||||
'top-level dependency: ' +
|
||||
pvStr + ', was ' + prevVersion + '.\n' +
|
||||
self.listConstraintsOnPackage(pv.package));
|
||||
'top-level dependency: ' +
|
||||
pvStr + ', was ' + prevVersion + '.\n' +
|
||||
self.listConstraintsOnPackage(pv.package));
|
||||
numActualErrors++;
|
||||
}
|
||||
});
|
||||
if (numActualErrors) {
|
||||
self.errors.push(
|
||||
'To allow potentially incompatible changes to top-level ' +
|
||||
'dependencies, you must pass --allow-incompatible-update ' +
|
||||
'on the command line.');
|
||||
'dependencies, you must pass --allow-incompatible-update ' +
|
||||
'on the command line.');
|
||||
}
|
||||
});
|
||||
self.throwAnyErrors();
|
||||
@@ -1001,13 +1014,13 @@ CS.Solver.prototype._getAnswer = function (options) {
|
||||
|
||||
// Get a list of package-version variables that satisfy a given constraint.
|
||||
var getOkVersions = function (toPackage, vConstraint, targetVersions) {
|
||||
return _.compact(_.map(targetVersions, function (v) {
|
||||
return (targetVersions.map(function (v) {
|
||||
if (CS.isConstraintSatisfied(toPackage, vConstraint, v)) {
|
||||
return pvVar(toPackage, v);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}));
|
||||
})).filter(Boolean);
|
||||
};
|
||||
|
||||
// The CS.Solver constructor turns this into a memoized method.
|
||||
@@ -1031,7 +1044,7 @@ CS.Solver.prototype.listConstraintsOnPackage = function (pkg) {
|
||||
|
||||
var result = 'Constraints on package "' + pkg + '":';
|
||||
|
||||
_.each(constraints, function (c) {
|
||||
constraints.forEach(function (c) {
|
||||
if (c.toPackage === pkg) {
|
||||
var paths;
|
||||
if (c.fromVar) {
|
||||
@@ -1040,7 +1053,7 @@ CS.Solver.prototype.listConstraintsOnPackage = function (pkg) {
|
||||
} else {
|
||||
paths = [['top level']];
|
||||
}
|
||||
_.each(paths, function (path) {
|
||||
paths.forEach(function (path) {
|
||||
result += '\n* ' + (new PV.PackageConstraint(
|
||||
pkg, c.vConstraint.raw)) + ' <- ' + path.join(' <- ');
|
||||
});
|
||||
@@ -1057,15 +1070,15 @@ CS.Solver.prototype.throwConflicts = function () {
|
||||
var constraints = self.analysis.constraints;
|
||||
|
||||
self.Profile.time("generate error about conflicts", function () {
|
||||
_.each(constraints, function (c) {
|
||||
constraints.forEach(function (c) {
|
||||
// c is a CS.Solver.Constraint
|
||||
if (solution.evaluate(c.conflictVar)) {
|
||||
// skipped this constraint
|
||||
var possibleVersions = self.getVersions(c.toPackage);
|
||||
var chosenVersion = _.find(possibleVersions, function (v) {
|
||||
var chosenVersion = possibleVersions.find(function (v) {
|
||||
return solution.evaluate(pvVar(c.toPackage, v));
|
||||
});
|
||||
if (! chosenVersion) {
|
||||
if (!chosenVersion) {
|
||||
// this can't happen, because for a constraint to be a problem,
|
||||
// we must have chosen some version of the package it applies to!
|
||||
throw new Error("Internal error: Version not found");
|
||||
@@ -1073,7 +1086,7 @@ CS.Solver.prototype.throwConflicts = function () {
|
||||
var error = (
|
||||
'Conflict: Constraint ' + (new PV.PackageConstraint(
|
||||
c.toPackage, c.vConstraint)) +
|
||||
' is not satisfied by ' + c.toPackage + ' ' + chosenVersion + '.');
|
||||
' is not satisfied by ' + c.toPackage + ' ' + chosenVersion + '.');
|
||||
|
||||
error += '\n' + self.listConstraintsOnPackage(c.toPackage);
|
||||
|
||||
@@ -1112,12 +1125,12 @@ CS.Solver.prototype.getPathsToPackageVersion = function (packageAndVersion) {
|
||||
var versionMap = self.currentVersionMap();
|
||||
var hasDep = function (p1, p2) {
|
||||
// Include weak dependencies, because their constraints matter.
|
||||
return _.has(cache.getDependencyMap(p1, versionMap[p1]), p2);
|
||||
return has(cache.getDependencyMap(p1, versionMap[p1]), p2);
|
||||
};
|
||||
var allPackages = _.keys(versionMap);
|
||||
var allPackages = Object.keys(versionMap);
|
||||
|
||||
var getPaths = function (pv, _ignorePackageSet) {
|
||||
if (! solution.evaluate(pv.toString())) {
|
||||
if (!solution.evaluate(pv.toString())) {
|
||||
return [];
|
||||
}
|
||||
var pkg = pv.package;
|
||||
@@ -1126,20 +1139,20 @@ CS.Solver.prototype.getPathsToPackageVersion = function (packageAndVersion) {
|
||||
return [[pv]];
|
||||
}
|
||||
|
||||
var newIgnorePackageSet = _.clone(_ignorePackageSet);
|
||||
var newIgnorePackageSet = Object.assign({}, _ignorePackageSet);
|
||||
newIgnorePackageSet[pkg] = true;
|
||||
|
||||
var paths = [];
|
||||
var shortestLength = null;
|
||||
|
||||
_.each(allPackages, function (p) {
|
||||
if ((! _.has(newIgnorePackageSet, p)) &&
|
||||
solution.evaluate(p) &&
|
||||
hasDep(p, pkg)) {
|
||||
allPackages.forEach(function (p) {
|
||||
if ((!has(newIgnorePackageSet, p)) &&
|
||||
solution.evaluate(p) &&
|
||||
hasDep(p, pkg)) {
|
||||
var newPV = new CS.PackageAndVersion(p, versionMap[p]);
|
||||
_.each(getPaths(newPV, newIgnorePackageSet), function (path) {
|
||||
getPaths(newPV, newIgnorePackageSet).forEach(function (path) {
|
||||
var newPath = [pv].concat(path);
|
||||
if ((! paths.length) || newPath.length < shortestLength) {
|
||||
if ((!paths.length) || newPath.length < shortestLength) {
|
||||
paths.push(newPath);
|
||||
shortestLength = newPath.length;
|
||||
}
|
||||
@@ -1166,4 +1179,4 @@ CS.Solver.Constraint = function (fromVar, toPackage, vConstraint, conflictVar) {
|
||||
check(this.toPackage, String); // package name
|
||||
check(this.vConstraint, PV.VersionConstraint);
|
||||
check(this.conflictVar, String);
|
||||
};
|
||||
};
|
||||
@@ -1,3 +1,6 @@
|
||||
const zip = Npm.require('lodash.zip');
|
||||
const isObject = Npm.require('lodash.isobject');
|
||||
|
||||
var CS = ConstraintSolver;
|
||||
var PV = PackageVersion;
|
||||
|
||||
@@ -7,24 +10,26 @@ Tinytest.add("constraint solver - version pricer", function (test) {
|
||||
var pricer = new CS.VersionPricer();
|
||||
|
||||
var testScanVersions = function (versions, mode, options, expected) {
|
||||
if (options && _.isArray(options)) {
|
||||
if (options && Array.isArray(options)) {
|
||||
expected = options;
|
||||
options = null;
|
||||
}
|
||||
var result, tuples;
|
||||
// Accepts either a mode like CS.VersionPricer.MODE_UPDATE or
|
||||
// an object that looks like `{ previous: version }`
|
||||
if (_.isObject(mode) && mode.previous) {
|
||||
if (isObject(mode) && mode.previous) {
|
||||
result = pricer.priceVersionsWithPrevious(versions, mode.previous);
|
||||
tuples = _.zip(versions, result[0], result[1], result[2], result[3],
|
||||
tuples = zip(versions, result[0], result[1], result[2], result[3],
|
||||
result[4]);
|
||||
} else {
|
||||
result = pricer.priceVersions(versions, mode, options);
|
||||
tuples = _.zip(versions, result[0], result[1], result[2], result[3]);
|
||||
tuples = zip(versions, result[0], result[1], result[2], result[3]);
|
||||
}
|
||||
test.equal(tuples.length, expected.length);
|
||||
test.equal(_.pluck(tuples, 0), versions);
|
||||
_.each(_.zip(tuples, expected), function (x) {
|
||||
test.equal(tuples.map(function(x){
|
||||
return x[0]
|
||||
}), versions);
|
||||
zip(tuples, expected).forEach(function (x) {
|
||||
var tuple = x[0];
|
||||
var expectedTuple = x[1];
|
||||
if (typeof expectedTuple[0] !== 'string') {
|
||||
@@ -200,4 +205,4 @@ Tinytest.add("constraint solver - version pricer", function (test) {
|
||||
["4.0.0", 1, 3, 0, 0, 1],
|
||||
["4.0.0_1", 1, 3, 0, 0, 0]]);
|
||||
|
||||
});
|
||||
});
|
||||
@@ -1,3 +1,5 @@
|
||||
const memoize = Npm.require('lodash.memoize');
|
||||
|
||||
var CS = ConstraintSolver;
|
||||
var PV = PackageVersion;
|
||||
|
||||
@@ -9,7 +11,7 @@ CS.VersionPricer = function () {
|
||||
//
|
||||
// The VersionPricer instance stores a memoization table for
|
||||
// efficiency.
|
||||
self.getVersionInfo = _.memoize(PV.parse);
|
||||
self.getVersionInfo = memoize(PV.parse);
|
||||
};
|
||||
|
||||
CS.VersionPricer.MODE_UPDATE = 1;
|
||||
|
||||
Reference in New Issue
Block a user