mirror of
https://github.com/meteor/meteor.git
synced 2026-05-02 03:01:46 -04:00
Merge branch 'release-0.9.0.1' into devel
Conflicts: packages/autoupdate/autoupdate_client.js
This commit is contained in:
@@ -130,8 +130,7 @@ Autoupdate._retrySubscription = function () {
|
||||
attachStylesheetLink(newLink);
|
||||
});
|
||||
}
|
||||
else if (doc._id === 'version' && autoupdateVersion !== 'unknown' &&
|
||||
doc.version !== autoupdateVersion) {
|
||||
else if (doc._id === 'version' && doc.version !== autoupdateVersion) {
|
||||
handle && handle.stop();
|
||||
Package.reload.Reload._reload();
|
||||
}
|
||||
|
||||
@@ -45,11 +45,12 @@ ClientVersions = new Meteor.Collection("meteor_autoupdate_clientVersions",
|
||||
// runtime config before using the client hash as our default auto
|
||||
// update version id.
|
||||
|
||||
// Note: Tests allow people to override Autoupdate.autoupdateVersion before
|
||||
// startup.
|
||||
Autoupdate.autoupdateVersion = null;
|
||||
Autoupdate.autoupdateVersionRefreshable = null;
|
||||
|
||||
var syncQueue = new Meteor._SynchronousQueue();
|
||||
var startupVersion = null;
|
||||
|
||||
// updateVersions can only be called after the server has fully loaded.
|
||||
var updateVersions = function (shouldReloadClientProgram) {
|
||||
@@ -60,13 +61,18 @@ var updateVersions = function (shouldReloadClientProgram) {
|
||||
WebAppInternals.reloadClientProgram();
|
||||
}
|
||||
|
||||
if (startupVersion === null) {
|
||||
// If we just re-read the client program, or if we don't have an autoupdate
|
||||
// version, calculate it.
|
||||
if (shouldReloadClientProgram || Autoupdate.autoupdateVersion === null) {
|
||||
Autoupdate.autoupdateVersion =
|
||||
__meteor_runtime_config__.autoupdateVersion =
|
||||
process.env.AUTOUPDATE_VERSION ||
|
||||
process.env.SERVER_ID || // XXX COMPAT 0.6.6
|
||||
WebApp.calculateClientHashNonRefreshable();
|
||||
process.env.AUTOUPDATE_VERSION ||
|
||||
process.env.SERVER_ID || // XXX COMPAT 0.6.6
|
||||
WebApp.calculateClientHashNonRefreshable();
|
||||
}
|
||||
// If we just recalculated it OR if it was set by (eg) test-in-browser,
|
||||
// ensure it ends up in __meteor_runtime_config__.
|
||||
__meteor_runtime_config__.autoupdateVersion =
|
||||
Autoupdate.autoupdateVersion;
|
||||
|
||||
Autoupdate.autoupdateVersionRefreshable =
|
||||
__meteor_runtime_config__.autoupdateVersionRefreshable =
|
||||
@@ -115,9 +121,6 @@ var updateVersions = function (shouldReloadClientProgram) {
|
||||
};
|
||||
|
||||
Meteor.startup(function () {
|
||||
// Allow people to override Autoupdate.autoupdateVersion before startup.
|
||||
// Tests do this.
|
||||
startupVersion = Autoupdate.autoupdateVersion;
|
||||
updateVersions(false);
|
||||
});
|
||||
|
||||
|
||||
@@ -515,8 +515,10 @@ function getCatalogStub (gems) {
|
||||
});
|
||||
|
||||
var ecv = function (version) {
|
||||
// hard-code to "x.0.0"
|
||||
return parseInt(version) + ".0.0";
|
||||
// hard-coded, because lots of the constraints are > or >= which we
|
||||
// don't support anymore. But constant ECV means that "compatible-with"
|
||||
// is interpreted as >=.
|
||||
return "0.0.0";
|
||||
};
|
||||
|
||||
var packageVersion = {
|
||||
@@ -565,12 +567,10 @@ function convertConstraints (inp) {
|
||||
// '>=1.2.3' => '1.2.3'
|
||||
.map(function (s) {
|
||||
if (s.indexOf(">= 0") === 0)
|
||||
return "none";
|
||||
return "";
|
||||
var x = s.split(' ');
|
||||
if (x[0] === '~>')
|
||||
if (x[0] === '~>' || x[0] === '>' || x[0] === '>=')
|
||||
x[0] = '';
|
||||
else if (x[0] === '>' || x[0] === '>=')
|
||||
x[0] = '>=';
|
||||
else if (x[0] === '=')
|
||||
x[0] = '=';
|
||||
else
|
||||
|
||||
@@ -141,8 +141,10 @@ ConstraintSolver.PackagesResolver.prototype._loadPackageInfo = function (
|
||||
|
||||
// dependencies - an array of string names of packages (not slices)
|
||||
// constraints - an array of objects:
|
||||
// (almost, but not quite, what PackageVersion.parseConstraint returns)
|
||||
// - packageName - string name
|
||||
// - version - string constraint (ex.: "1.2.3", ">=2.3.4", "=3.3.3")
|
||||
// - version - string constraint
|
||||
// - type - constraint type
|
||||
// options:
|
||||
// - upgrade - list of dependencies for which upgrade is prioritized higher
|
||||
// than keeping the old version
|
||||
@@ -161,7 +163,9 @@ ConstraintSolver.PackagesResolver.prototype.resolve = function (
|
||||
check(dependencies, [String]);
|
||||
|
||||
check(constraints, [{
|
||||
packageName: String, version: String, type: String,
|
||||
packageName: String,
|
||||
version: Match.OneOf(String, null),
|
||||
type: String,
|
||||
constraintString: Match.Optional(Match.OneOf(String, null))
|
||||
}]);
|
||||
|
||||
@@ -281,15 +285,7 @@ ConstraintSolver.PackagesResolver.prototype._splitDepsToConstraints =
|
||||
});
|
||||
|
||||
_.each(inputConstraints, function (constraint) {
|
||||
if (!semver.valid(constraint.version))
|
||||
throw Error("Bad semver: " + constraint.version);
|
||||
var operator = "";
|
||||
if (constraint.type === "exactly")
|
||||
operator = "=";
|
||||
if (constraint.type === "at-least")
|
||||
operator = ">=";
|
||||
var constraintStr = operator + constraint.version;
|
||||
|
||||
var constraintStr = PackageVersion.constraintToVersionString(constraint);
|
||||
_.each(self._unibuildsForPackage(constraint.packageName), function (unibuildName) {
|
||||
constraints.push(self.resolver.getConstraint(unibuildName, constraintStr));
|
||||
});
|
||||
@@ -414,7 +410,6 @@ ConstraintSolver.PackagesResolver.prototype._getResolverOptions =
|
||||
resolverOptions.estimateCostFunction = function (state, options) {
|
||||
options = options || {};
|
||||
|
||||
var constraints = state.constraints;
|
||||
var cost = [0, 0, 0, 0];
|
||||
|
||||
state.eachDependency(function (dep, alternatives) {
|
||||
@@ -426,7 +421,7 @@ ConstraintSolver.PackagesResolver.prototype._getResolverOptions =
|
||||
|
||||
if (_.has(prevSolMapping, dep)) {
|
||||
var prev = prevSolMapping[dep];
|
||||
var prevVersionMatches = constraints.isSatisfied(prev, self.resolver);
|
||||
var prevVersionMatches = state.isSatisfied(prev);
|
||||
|
||||
// if it matches, assume we would pick it and the cost doesn't
|
||||
// increase
|
||||
|
||||
@@ -63,10 +63,12 @@ ConstraintSolver.ConstraintsList.prototype.push = function (c) {
|
||||
// Note that this is one of the only pieces of the constraint solver that
|
||||
// actually does logic on constraints (and thus relies on the restricted set
|
||||
// of constraints that we support).
|
||||
var minimal = mori.get(newList.minimalVersion, c.name);
|
||||
if (!minimal || semver.lt(c.version, minimal)) {
|
||||
newList.minimalVersion = mori.assoc(
|
||||
newList.minimalVersion, c.name, c.version);
|
||||
if (c.type !== 'any-reasonable') {
|
||||
var minimal = mori.get(newList.minimalVersion, c.name);
|
||||
if (!minimal || semver.lt(c.version, minimal)) {
|
||||
newList.minimalVersion = mori.assoc(
|
||||
newList.minimalVersion, c.name, c.version);
|
||||
}
|
||||
}
|
||||
return newList;
|
||||
};
|
||||
@@ -102,13 +104,13 @@ ConstraintSolver.ConstraintsList.prototype.each = function (iter) {
|
||||
|
||||
// Checks if the passed unit version satisfies all of the constraints.
|
||||
ConstraintSolver.ConstraintsList.prototype.isSatisfied = function (
|
||||
uv, resolver) {
|
||||
uv, resolver, resolveContext) {
|
||||
var self = this;
|
||||
|
||||
var satisfied = true;
|
||||
|
||||
self.forPackage(uv.name, function (c) {
|
||||
if (! c.isSatisfied(uv, resolver)) {
|
||||
if (! c.isSatisfied(uv, resolver, resolveContext)) {
|
||||
satisfied = false;
|
||||
return BREAK;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
ResolverState = function (resolver) {
|
||||
ResolverState = function (resolver, resolveContext) {
|
||||
var self = this;
|
||||
self._resolver = resolver;
|
||||
self._resolveContext = resolveContext;
|
||||
// The versions we've already chosen.
|
||||
// unitName -> UnitVersion
|
||||
self.choices = mori.hash_map();
|
||||
@@ -23,7 +24,8 @@ _.extend(ResolverState.prototype, {
|
||||
self.constraints = self.constraints.push(constraint);
|
||||
|
||||
var chosen = mori.get(self.choices, constraint.name);
|
||||
if (chosen && !constraint.isSatisfied(chosen, self._resolver)) {
|
||||
if (chosen &&
|
||||
!constraint.isSatisfied(chosen, self._resolver, self._resolveContext)) {
|
||||
// This constraint conflicts with a choice we've already made!
|
||||
self.error = "conflict: " + constraint.toString({removeUnibuild: true}) +
|
||||
" vs " + chosen.version;
|
||||
@@ -34,7 +36,8 @@ _.extend(ResolverState.prototype, {
|
||||
if (alternatives) {
|
||||
// Note: filter preserves order, which is important.
|
||||
var newAlternatives = filter(alternatives, function (unitVersion) {
|
||||
return constraint.isSatisfied(unitVersion, self._resolver);
|
||||
return constraint.isSatisfied(
|
||||
unitVersion, self._resolver, self._resolveContext);
|
||||
});
|
||||
if (mori.is_empty(newAlternatives)) {
|
||||
// XXX we should mention other constraints that are active
|
||||
@@ -68,7 +71,7 @@ _.extend(ResolverState.prototype, {
|
||||
// Note: relying on sortedness of unitsVersions so that alternatives is
|
||||
// sorted too (the estimation function uses this).
|
||||
var alternatives = filter(self._resolver.unitsVersions[unitName], function (uv) {
|
||||
return self.constraints.isSatisfied(uv, self._resolver);
|
||||
return self.isSatisfied(uv);
|
||||
// XXX hang on to list of violated constraints and use it in error
|
||||
// message
|
||||
});
|
||||
@@ -99,7 +102,7 @@ _.extend(ResolverState.prototype, {
|
||||
self = self._clone();
|
||||
|
||||
// Does adding this choice break some constraints we already have?
|
||||
if (!self.constraints.isSatisfied(uv, self._resolver)) {
|
||||
if (!self.isSatisfied(uv)) {
|
||||
// XXX improve error
|
||||
self.error = "conflict: " + uv.toString({removeUnibuild: true}) +
|
||||
" can't be chosen";
|
||||
@@ -132,9 +135,13 @@ _.extend(ResolverState.prototype, {
|
||||
mori.last(nameAndAlternatives));
|
||||
}, self._dependencies);
|
||||
},
|
||||
isSatisfied: function (uv) {
|
||||
var self = this;
|
||||
return self.constraints.isSatisfied(uv, self._resolver, self._resolveContext);
|
||||
},
|
||||
_clone: function () {
|
||||
var self = this;
|
||||
var clone = new ResolverState(self._resolver);
|
||||
var clone = new ResolverState(self._resolver, self._resolveContext);
|
||||
_.each(['choices', '_dependencies', 'constraints', 'error'], function (field) {
|
||||
clone[field] = self[field];
|
||||
});
|
||||
|
||||
@@ -153,22 +153,29 @@ Tinytest.add("constraint solver - resolver, don't pick rcs", function (test) {
|
||||
|
||||
resolver.addUnitVersion(A100rc1);
|
||||
resolver.addUnitVersion(A100);
|
||||
var initialConstraint = resolver.getConstraint("A", ">=0.0.0");
|
||||
var basicConstraint = resolver.getConstraint("A", "");
|
||||
var rcConstraint = resolver.getConstraint("A", "1.0.0-rc1");
|
||||
|
||||
var solution = resolver.resolve(["A"], [initialConstraint], {
|
||||
costFunction: function (state) {
|
||||
return mori.reduce(mori.sum, 0, mori.map(function (nameAndUv) {
|
||||
var name = mori.first(nameAndUv);
|
||||
var uv = mori.last(nameAndUv);
|
||||
// Make the non-rc one more costly. But we still shouldn't choose it!
|
||||
if (uv.version === "1.0.0")
|
||||
return 100;
|
||||
return 0;
|
||||
}, state.choices));
|
||||
}
|
||||
});
|
||||
// Make the non-rc one more costly. But we still shouldn't choose it unless it
|
||||
// was specified in an initial constraint!
|
||||
var proRcCostFunction = function (state) {
|
||||
return mori.reduce(mori.sum, 0, mori.map(function (nameAndUv) {
|
||||
var name = mori.first(nameAndUv);
|
||||
var uv = mori.last(nameAndUv);
|
||||
// Make the non-rc one more costly. But we still shouldn't choose it!
|
||||
if (uv.version === "1.0.0")
|
||||
return 100;
|
||||
return 0;
|
||||
}, state.choices));
|
||||
};
|
||||
|
||||
var solution = resolver.resolve(
|
||||
["A"], [basicConstraint], {costFunction: proRcCostFunction });
|
||||
resultEquals(test, solution, [A100]);
|
||||
|
||||
solution = resolver.resolve(
|
||||
["A"], [rcConstraint], {costFunction: proRcCostFunction });
|
||||
resultEquals(test, solution, [A100rc1]);
|
||||
});
|
||||
|
||||
function semver2number (semverStr) {
|
||||
|
||||
@@ -140,17 +140,41 @@ ConstraintSolver.Resolver.prototype.resolve = function (
|
||||
}
|
||||
}, options);
|
||||
|
||||
var resolveContext = new ResolveContext;
|
||||
|
||||
// Mapping that assigns every package an integer priority. We compute this
|
||||
// dynamically and in the process of resolution we try to resolve packages
|
||||
// with higher priority first. This helps the resolver a lot because if some
|
||||
// package has a higher weight to the solution (like a direct dependency) or
|
||||
// is more likely to break our solution in the future than others, it would be
|
||||
// great to try out and evaluate all versions early in the decision tree.
|
||||
// XXX this could go on ResolveContext
|
||||
var resolutionPriority = {};
|
||||
|
||||
var startState = new ResolverState(self);
|
||||
var startState = new ResolverState(self, resolveContext);
|
||||
_.each(constraints, function (constraint) {
|
||||
startState = startState.addConstraint(constraint);
|
||||
|
||||
// Keep track of any top-level constraints that mention a pre-release.
|
||||
// These will be the only pre-release versions that count as "reasonable"
|
||||
// for "any-reasonable" (ie, unconstrained) constraints.
|
||||
//
|
||||
// Why only top-level mentions, and not mentions we find while walking the
|
||||
// graph? The constraint solver assumes that adding a constraint to the
|
||||
// resolver state can't make previously impossible choices now possible. If
|
||||
// pre-releases mentioned anywhere worked, then applying the constraints
|
||||
// "any reasonable" followed by "1.2.3-rc1" would result in "1.2.3-rc1"
|
||||
// ruled first impossible and then possible again. That's no good, so we
|
||||
// have to fix the meaning based on something at the start. (We could try
|
||||
// to apply our prerelease-avoidance tactics solely in the cost functions,
|
||||
// but then it becomes a much less strict rule.)
|
||||
if (constraint.version && /-/.test(constraint.version)) {
|
||||
if (!_.has(resolveContext.topLevelPrereleases, constraint.name)) {
|
||||
resolveContext.topLevelPrereleases[constraint.name] = {};
|
||||
}
|
||||
resolveContext.topLevelPrereleases[constraint.name][constraint.version]
|
||||
= true;
|
||||
}
|
||||
});
|
||||
_.each(dependencies, function (unitName) {
|
||||
startState = startState.addDependency(unitName);
|
||||
@@ -329,58 +353,75 @@ _.extend(ConstraintSolver.UnitVersion.prototype, {
|
||||
ConstraintSolver.Constraint = function (name, versionString) {
|
||||
var self = this;
|
||||
|
||||
if (versionString) {
|
||||
if (versionString !== undefined) {
|
||||
_.extend(self,
|
||||
PackageVersion.parseVersionConstraint(
|
||||
versionString, {allowAtLeast: true}));
|
||||
PackageVersion.parseVersionConstraint(versionString));
|
||||
self.name = name;
|
||||
} else {
|
||||
// borrows the structure from the parseVersionConstraint format:
|
||||
// - type - String [compatibl-with|exactly|at-least]
|
||||
// - type - String [compatible-with|exactly|any-reasonable]
|
||||
// - version - String - semver string
|
||||
_.extend(self, PackageVersion.parseConstraint(name, {allowAtLeast: true}));
|
||||
_.extend(self, PackageVersion.parseConstraint(name));
|
||||
}
|
||||
// See comment in UnitVersion constructor.
|
||||
self.version = self.version.replace(/\+.*$/, '');
|
||||
if (self.version)
|
||||
self.version = self.version.replace(/\+.*$/, '');
|
||||
};
|
||||
|
||||
ConstraintSolver.Constraint.prototype.toString = function (options) {
|
||||
var self = this;
|
||||
options = options || {};
|
||||
var operator = "";
|
||||
if (self.type === "exactly")
|
||||
operator = "=";
|
||||
if (self.type === "at-least")
|
||||
operator = ">=";
|
||||
var name = options.removeUnibuild ? removeUnibuild(self.name) : self.name;
|
||||
return name + "@" + operator + self.version;
|
||||
return name + "@" + PackageVersion.constraintToVersionString(self);
|
||||
};
|
||||
|
||||
|
||||
ConstraintSolver.Constraint.prototype.isSatisfied = function (candidateUV,
|
||||
resolver) {
|
||||
ConstraintSolver.Constraint.prototype.isSatisfied = function (
|
||||
candidateUV, resolver, resolveContext) {
|
||||
var self = this;
|
||||
check(candidateUV, ConstraintSolver.UnitVersion);
|
||||
|
||||
if (self.name !== candidateUV.name) {
|
||||
throw Error("asking constraint on " + self.name + " about " +
|
||||
candidateUV.name);
|
||||
}
|
||||
|
||||
if (self.type === "any-reasonable") {
|
||||
// Non-prerelease versions are always reasonable.
|
||||
if (!/-/.test(candidateUV.version))
|
||||
return true;
|
||||
|
||||
// Is it a pre-release version that was explicitly mentioned at the top
|
||||
// level?
|
||||
if (_.has(resolveContext.topLevelPrereleases, self.name) &&
|
||||
_.has(resolveContext.topLevelPrereleases[self.name],
|
||||
candidateUV.version)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Otherwise, not this pre-release!
|
||||
return false;
|
||||
}
|
||||
|
||||
if (self.type === "exactly") {
|
||||
return self.version === candidateUV.version;
|
||||
}
|
||||
|
||||
if (self.type !== "compatible-with") {
|
||||
throw Error("Unknown constraint type: " + self.type);
|
||||
}
|
||||
|
||||
// Pre-releases only match precisely; @1.2.3-rc1 doesn't necessarily match
|
||||
// 1.2.4, and @1.2.3 doesn't necessarily match 1.2.4-rc1.
|
||||
if (/-/.test(candidateUV.version) || /-/.test(self.version)) {
|
||||
return self.version === candidateUV.version;
|
||||
}
|
||||
|
||||
if (self.type === "exactly")
|
||||
return self.version === candidateUV.version;
|
||||
|
||||
// If the candidate version is less than the version named in the constraint,
|
||||
// we are not satisfied.
|
||||
if (semver.lt(candidateUV.version, self.version))
|
||||
return false;
|
||||
|
||||
// If we only care about "at-least" and not backwards-incompatible changes in
|
||||
// the middle, then candidateUV is good enough.
|
||||
if (self.type === "at-least")
|
||||
return true;
|
||||
|
||||
var myECV = resolver.getEarliestCompatibleVersion(self.name, self.version);
|
||||
// If the constraint is "@1.2.3" and 1.2.3 doesn't exist, then nothing can
|
||||
// match. This is because we don't know the ECV (compatibility class) of
|
||||
@@ -395,17 +436,11 @@ ConstraintSolver.Constraint.prototype.isSatisfied = function (candidateUV,
|
||||
return myECV === candidateUV.earliestCompatibleVersion;
|
||||
};
|
||||
|
||||
// Returns any unit version satisfying the constraint in the resolver
|
||||
ConstraintSolver.Constraint.prototype.getSatisfyingUnitVersion = function (
|
||||
resolver) {
|
||||
// An object that records the general context of a resolve call. It can be
|
||||
// different for different resolve calls on the same Resolver, but is the same
|
||||
// for every ResolverState in a given call.
|
||||
var ResolveContext = function () {
|
||||
var self = this;
|
||||
|
||||
if (self.type === "exactly") {
|
||||
return resolver.getUnitVersion(self.name, self.version);
|
||||
}
|
||||
|
||||
// XXX this chooses a random UV, not the earliest or latest. Is that OK?
|
||||
return _.find(resolver.unitsVersions[self.name], function (uv) {
|
||||
return self.isSatisfied(uv, resolver);
|
||||
});
|
||||
// unitName -> version string -> true
|
||||
self.topLevelPrereleases = {};
|
||||
};
|
||||
|
||||
@@ -17,8 +17,8 @@ var FAIL = function (versionString) {
|
||||
Tinytest.add("Smart Package version string parsing - old format", function (test) {
|
||||
currentTest = test;
|
||||
|
||||
t("foo", { name: "foo", version: null, type: "compatible-with" });
|
||||
t("foo-1234", { name: "foo-1234", version: null, type: "compatible-with" });
|
||||
t("foo", { name: "foo", version: null, type: "any-reasonable" });
|
||||
t("foo-1234", { name: "foo-1234", version: null, type: "any-reasonable" });
|
||||
FAIL("my_awesome_InconsitentPackage123");
|
||||
});
|
||||
|
||||
@@ -37,6 +37,8 @@ Tinytest.add("Smart Package version string parsing - compatible version, compati
|
||||
FAIL("foo@x.y.z");
|
||||
FAIL("foo@<1.2");
|
||||
FAIL("foo<1.2");
|
||||
|
||||
t("foo", { name: "foo", version: null, type: "any-reasonable" });
|
||||
});
|
||||
|
||||
Tinytest.add("Smart Package version string parsing - compatible version, exactly", function (test) {
|
||||
@@ -54,32 +56,10 @@ Tinytest.add("Smart Package version string parsing - compatible version, exactly
|
||||
FAIL("foo@=<1.2");
|
||||
FAIL("foo@<=1.2");
|
||||
FAIL("foo<=1.2");
|
||||
});
|
||||
|
||||
Tinytest.add("Smart Package version string parsing - compatible version, at-least", function (test) {
|
||||
var t = function (versionString, expected, descr) {
|
||||
test.equal(
|
||||
_.omit(PackageVersion.parseConstraint(versionString,
|
||||
{allowAtLeast: true}),
|
||||
'constraintString'),
|
||||
expected,
|
||||
descr);
|
||||
test.throws(function () {
|
||||
PackageVersion.parseConstraint(versionString);
|
||||
});
|
||||
};
|
||||
|
||||
var FAIL = function (versionString) {
|
||||
test.throws(function () {
|
||||
PackageVersion.parseConstraint(versionString, {allowAtLeast: true});
|
||||
});
|
||||
test.throws(function () {
|
||||
PackageVersion.parseConstraint(versionString);
|
||||
});
|
||||
};
|
||||
|
||||
t("foo@>=1.2.3", { name: "foo", version: "1.2.3", type: "at-least" });
|
||||
t("foo-bar@>=3.2.1", { name: "foo-bar", version: "3.2.1", type: "at-least" });
|
||||
// We no longer support @>=.
|
||||
FAIL("foo@>=1.2.3");
|
||||
FAIL("foo-bar@>=3.2.1");
|
||||
FAIL("42@>=0.2.0");
|
||||
FAIL("foo@>=1.2.3.4");
|
||||
FAIL("foo@>=1.4");
|
||||
|
||||
@@ -197,15 +197,20 @@ _.extend(baseCatalog.BaseCatalog.prototype, {
|
||||
|
||||
// As getVersion, but returns info on the latest version of the
|
||||
// package, or null if the package doesn't exist or has no versions.
|
||||
getLatestVersion: function (name) {
|
||||
// It does not include prereleases (with dashes in the version);
|
||||
getLatestMainlineVersion: function (name) {
|
||||
var self = this;
|
||||
self._requireInitialized();
|
||||
buildmessage.assertInCapture();
|
||||
|
||||
var versions = self.getSortedVersions(name);
|
||||
if (versions.length === 0)
|
||||
versions.reverse();
|
||||
var latest = _.find(versions, function (version) {
|
||||
return !/-/.test(version);
|
||||
});
|
||||
if (!latest)
|
||||
return null;
|
||||
return self.getVersion(name, versions[versions.length - 1]);
|
||||
return self.getVersion(name, latest);
|
||||
},
|
||||
|
||||
// If this package has any builds at this version, return an array of builds
|
||||
|
||||
@@ -453,7 +453,8 @@ _.extend(CompleteCatalog.prototype, {
|
||||
|
||||
// Constraints for uniload should just be packages with no version
|
||||
// constraint and one local version (since they should all be in core).
|
||||
if (!_.has(constraint, 'packageName') || _.size(constraint) !== 1) {
|
||||
if (!_.has(constraint, 'packageName') ||
|
||||
constraint.type !== 'any-reasonable') {
|
||||
throw Error("Surprising constraint: " + JSON.stringify(constraint));
|
||||
}
|
||||
if (!_.has(self.versions, constraint.packageName)) {
|
||||
@@ -499,9 +500,7 @@ _.extend(CompleteCatalog.prototype, {
|
||||
deps.push(constraint.packageName);
|
||||
}
|
||||
delete constraint.weak;
|
||||
if (constraint.version) {
|
||||
constr.push(constraint);
|
||||
}
|
||||
constr.push(constraint);
|
||||
});
|
||||
|
||||
// If we are called with 'ignore projectDeps', then we don't even look to
|
||||
@@ -519,6 +518,13 @@ _.extend(CompleteCatalog.prototype, {
|
||||
});
|
||||
}
|
||||
|
||||
// Local packages can only be loaded from the version we have the source
|
||||
// for: that's a weak exact constraint.
|
||||
_.each(self.packageSources, function (packageSource, name) {
|
||||
constr.push({packageName: name, version: packageSource.version,
|
||||
type: 'exactly'});
|
||||
});
|
||||
|
||||
var patience = new utils.Patience({
|
||||
messageAfterMs: 1000,
|
||||
message: "Figuring out the best package versions to use. This may take a moment."
|
||||
@@ -1004,8 +1010,9 @@ _.extend(CompleteCatalog.prototype, {
|
||||
}
|
||||
});
|
||||
}
|
||||
// And put a build record for it in the catalog
|
||||
var versionId = self.getLatestVersion(name);
|
||||
// And put a build record for it in the catalog. There is only one version
|
||||
// for this package!
|
||||
var versionId = _.values(self.versions[name])._id;
|
||||
|
||||
// XXX why isn't this build just happening through the package cache
|
||||
// directly?
|
||||
|
||||
@@ -966,6 +966,7 @@ main.registerCommand({
|
||||
return _.extend({ buildArchitectures: myStringBuilds },
|
||||
versionRecord);
|
||||
};
|
||||
// XXX should this skip pre-releases?
|
||||
var versions = catalog.official.getSortedVersions(name);
|
||||
if (full.length > 1) {
|
||||
versions = [full[1]];
|
||||
@@ -1081,7 +1082,7 @@ main.registerCommand({
|
||||
|
||||
var vr;
|
||||
doOrDie(function () {
|
||||
vr = catalog.official.getLatestVersion(name);
|
||||
vr = catalog.official.getLatestMainlineVersion(name);
|
||||
});
|
||||
return vr && !vr.unmigrated;
|
||||
};
|
||||
@@ -1118,7 +1119,7 @@ main.registerCommand({
|
||||
_.each(allPackages, function (pack) {
|
||||
if (selector(pack, false)) {
|
||||
var vr = doOrDie(function () {
|
||||
return catalog.official.getLatestVersion(pack);
|
||||
return catalog.official.getLatestMainlineVersion(pack);
|
||||
});
|
||||
if (vr) {
|
||||
matchingPackages.push(
|
||||
@@ -1200,8 +1201,12 @@ main.registerCommand({
|
||||
}
|
||||
|
||||
var versionAddendum = "" ;
|
||||
var latest = catalog.complete.getLatestVersion(name, version);
|
||||
var latest = catalog.complete.getLatestMainlineVersion(name, version);
|
||||
var semver = require('semver');
|
||||
if (version !== latest.version &&
|
||||
// If we're currently running a prerelease, "latest" may be older than
|
||||
// what we're at, so don't tell us we're outdated!
|
||||
semver.lt(version, latest.version) &&
|
||||
!catalog.complete.isLocalPackage(name)) {
|
||||
versionAddendum = "*";
|
||||
newVersionsAvailable = true;
|
||||
@@ -1738,6 +1743,24 @@ main.registerCommand({
|
||||
} else {
|
||||
process.stdout.write("The version constraint will be removed.\n");
|
||||
}
|
||||
// Now remove the old constraint from what we're going to calculate
|
||||
// with.
|
||||
// This matches code in calculateCombinedConstraints.
|
||||
var oldConstraint = _.extend(
|
||||
{packageName: constraint.name},
|
||||
utils.parseVersionConstraint(packages[constraint.name]));
|
||||
var removed = false;
|
||||
for (var i = 0; i < allPackages.length; ++i) {
|
||||
if (_.isEqual(oldConstraint, allPackages[i])) {
|
||||
removed = true;
|
||||
allPackages.splice(i, 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!removed) {
|
||||
throw Error("Couldn't find constraint to remove: " +
|
||||
JSON.stringify(oldConstraint));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1761,33 +1784,44 @@ main.registerCommand({
|
||||
}
|
||||
|
||||
var downloaded, versions, newVersions;
|
||||
var messages = buildmessage.capture(function () {
|
||||
// Get the contents of our versions file. We need to pass them to the
|
||||
// constraint solver, because our contract with the user says that we will
|
||||
// never downgrade a dependency.
|
||||
versions = project.getVersions();
|
||||
|
||||
// Call the constraint solver.
|
||||
newVersions = catalog.complete.resolveConstraints(
|
||||
allPackages,
|
||||
{ previousSolution: versions },
|
||||
{ ignoreProjectDeps: true });
|
||||
if ( ! newVersions) {
|
||||
// XXX: Better error handling.
|
||||
process.stderr.write("Cannot resolve package dependencies.\n");
|
||||
return;
|
||||
}
|
||||
try {
|
||||
var messages = buildmessage.capture(function () {
|
||||
// Get the contents of our versions file. We need to pass them to the
|
||||
// constraint solver, because our contract with the user says that we will
|
||||
// never downgrade a dependency.
|
||||
versions = project.getVersions();
|
||||
|
||||
// Don't tell the user what all the operations were until we finish -- we
|
||||
// don't want to give a false sense of completeness until everything is
|
||||
// written to disk.
|
||||
var messageLog = [];
|
||||
// Call the constraint solver.
|
||||
newVersions = catalog.complete.resolveConstraints(
|
||||
allPackages,
|
||||
{ previousSolution: versions },
|
||||
{ ignoreProjectDeps: true });
|
||||
if ( ! newVersions) {
|
||||
// XXX: Better error handling.
|
||||
process.stderr.write("Cannot resolve package dependencies.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
// Install the new versions. If all new versions were installed
|
||||
// successfully, then change the .meteor/packages and .meteor/versions to
|
||||
// match expected reality.
|
||||
downloaded = project.addPackages(constraints, newVersions);
|
||||
});
|
||||
// Don't tell the user what all the operations were until we finish -- we
|
||||
// don't want to give a false sense of completeness until everything is
|
||||
// written to disk.
|
||||
var messageLog = [];
|
||||
|
||||
// Install the new versions. If all new versions were installed
|
||||
// successfully, then change the .meteor/packages and .meteor/versions to
|
||||
// match expected reality.
|
||||
downloaded = project.addPackages(constraints, newVersions);
|
||||
});
|
||||
} catch (e) {
|
||||
if (!e.constraintSolverError)
|
||||
throw e;
|
||||
// XXX this is too many forms of error handling!
|
||||
process.stderr.write(
|
||||
"Could not satisfy all the specified constraints:\n"
|
||||
+ e + "\n");
|
||||
return 1;
|
||||
}
|
||||
if (messages.hasMessages()) {
|
||||
process.stderr.write(messages.formatMessages());
|
||||
return 1;
|
||||
|
||||
@@ -54,22 +54,6 @@ var hostedWithGalaxy = function (site) {
|
||||
return !! require('./deploy-galaxy.js').discoverGalaxy(site);
|
||||
};
|
||||
|
||||
// Get all local packages available. Returns a map from the package name to the
|
||||
// version record for that package.
|
||||
var getLocalPackages = function () {
|
||||
var ret = {};
|
||||
buildmessage.assertInCapture();
|
||||
|
||||
var names = catalog.complete.getAllPackageNames();
|
||||
_.each(names, function (name) {
|
||||
if (catalog.complete.isLocalPackage(name)) {
|
||||
ret[name] = catalog.complete.getLatestVersion(name);
|
||||
}
|
||||
});
|
||||
|
||||
return ret;
|
||||
};
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// options that act like commands
|
||||
@@ -950,18 +934,8 @@ main.registerCommand({
|
||||
}, function (options) {
|
||||
var testPackages;
|
||||
if (options.args.length === 0) {
|
||||
// Only test local packages if no package is specified.
|
||||
// XXX should this use the new getLocalPackageNames?
|
||||
var packageList = commandsPackages.doOrDie(function () {
|
||||
return getLocalPackages();
|
||||
});
|
||||
if (! packageList) {
|
||||
// Couldn't load the package list, probably because some package
|
||||
// has a parse error. Bail out -- this kind of sucks; we would
|
||||
// like to find a way to get reloading.
|
||||
return 1;
|
||||
}
|
||||
testPackages = _.keys(packageList);
|
||||
// Test all local packages if no package is specified.
|
||||
testPackages = catalog.complete.getLocalPackageNames();
|
||||
} else {
|
||||
var messages = buildmessage.capture(function () {
|
||||
testPackages = _.map(options.args, function (p) {
|
||||
@@ -978,16 +952,15 @@ main.registerCommand({
|
||||
}
|
||||
// Check to see if this is a real package, and if it is a real
|
||||
// package, if it has tests.
|
||||
var versionRec = catalog.complete.getLatestVersion(p);
|
||||
if (!versionRec) {
|
||||
buildmessage.error(
|
||||
"Unknown package: " + p );
|
||||
}
|
||||
if (!catalog.complete.isLocalPackage(p)) {
|
||||
buildmessage.error(
|
||||
"Not a local package, cannot test: " + p );
|
||||
"Not a known local package, cannot test: " + p );
|
||||
return p;
|
||||
}
|
||||
var versionNames = catalog.complete.getSortedVersions(p);
|
||||
if (versionNames.length !== 1)
|
||||
throw Error("local package should have one version?");
|
||||
var versionRec = catalog.complete.getVersion(p, versionNames[0]);
|
||||
if (versionRec && !versionRec.testName) {
|
||||
buildmessage.error(
|
||||
"There are no tests for package: " + p );
|
||||
@@ -1058,7 +1031,10 @@ main.registerCommand({
|
||||
var tests = [];
|
||||
var messages = buildmessage.capture(function () {
|
||||
_.each(testPackages, function(name) {
|
||||
var versionRecord = catalog.complete.getLatestVersion(name);
|
||||
var versionNames = catalog.complete.getSortedVersions(name);
|
||||
if (versionNames.length !== 1)
|
||||
throw Error("local package should have one version?");
|
||||
var versionRecord = catalog.complete.getVersion(name, versionNames[0]);
|
||||
if (versionRecord && versionRecord.testName) {
|
||||
tests.push(versionRecord.testName);
|
||||
}
|
||||
|
||||
@@ -179,10 +179,7 @@ var determineBuildTimeDependencies = function (packageSource,
|
||||
var constraints_array = [];
|
||||
_.each(dependencyMetadata, function (info, packageName) {
|
||||
constraints[packageName] = info.constraint;
|
||||
var version = null;
|
||||
if (info.constraint) {
|
||||
version = utils.parseVersionConstraint(info.constraint) ;
|
||||
}
|
||||
var version = utils.parseVersionConstraint(info.constraint || '') ;
|
||||
constraints_array.push(_.extend({ packageName: packageName }, version));
|
||||
});
|
||||
|
||||
@@ -230,12 +227,9 @@ var determineBuildTimeDependencies = function (packageSource,
|
||||
_.each(info.use, function (spec) {
|
||||
var parsedSpec = utils.splitConstraint(spec);
|
||||
constraints[parsedSpec.package] = parsedSpec.constraint || null;
|
||||
var version = null;
|
||||
if (parsedSpec.constraint) {
|
||||
version = utils.parseVersionConstraint(info.constraint) ;
|
||||
}
|
||||
constraints_array.push({packageName: parsedSpec.package,
|
||||
version: version });
|
||||
var version = utils.parseVersionConstraint(info.constraint || '');
|
||||
constraints_array.push(_.extend({packageName: parsedSpec.package},
|
||||
version));
|
||||
});
|
||||
|
||||
var pluginVersion = pluginVersions[info.name] || {};
|
||||
|
||||
@@ -23,32 +23,28 @@ var __ = inTool ? require('underscore') : _;
|
||||
// 2. "exactly" - A@=x.y.z - constraints package A only to version x.y.z and
|
||||
// nothing else.
|
||||
// "pick A exactly at x.y.z"
|
||||
// 3. "at-least" - A@>=x.y.z - constraints package A to version x.y.z or higher.
|
||||
// "pick A at least at x.y.z"
|
||||
// This one is only used internally by the constraint solver --- end users
|
||||
// shouldn't be allowed to specify it, and you need to specially request it
|
||||
// with the "allowAtLeast" option.
|
||||
// 3. "any-reasonable" - "A"
|
||||
// Basically, this means any version of A ... other than ones that have
|
||||
// dashes in the version (ie, are prerelease) ... unless the prerelease
|
||||
// version has been explicitly selected (which at this stage in the game
|
||||
// means they are mentioned in a top-level constraint in the top-level
|
||||
// call to the resolver).
|
||||
PV.parseVersionConstraint = function (versionString, options) {
|
||||
options = options || {};
|
||||
var versionDesc = { version: null, type: "compatible-with",
|
||||
var versionDesc = { version: null, type: "any-reasonable",
|
||||
constraintString: versionString };
|
||||
|
||||
if (versionString === "none" || versionString === null) {
|
||||
versionDesc.type = "at-least";
|
||||
versionDesc.version = "0.0.0";
|
||||
if (!versionString) {
|
||||
return versionDesc;
|
||||
}
|
||||
|
||||
if (versionString.charAt(0) === '=') {
|
||||
versionDesc.type = "exactly";
|
||||
versionString = versionString.substr(1);
|
||||
} else if (options.allowAtLeast && versionString.substr(0, 2) === '>=') {
|
||||
versionDesc.type = "at-least";
|
||||
versionString = versionString.substr(2);
|
||||
} else {
|
||||
versionDesc.type = "compatible-with";
|
||||
}
|
||||
|
||||
// XXX check for a dash in the version in case of foo@1.2.3-rc0
|
||||
|
||||
if (! semver.valid(versionString)) {
|
||||
throwVersionParserError(
|
||||
"Version string must look like semver (eg '1.2.3'), not '"
|
||||
@@ -68,7 +64,7 @@ PV.parseConstraint = function (constraintString, options) {
|
||||
var splitted = constraintString.split('@');
|
||||
|
||||
var constraint = { name: "", version: null,
|
||||
type: "compatible-with", constraintString: null };
|
||||
type: "any-reasonable", constraintString: null };
|
||||
var name = splitted[0];
|
||||
var versionString = splitted[1];
|
||||
|
||||
@@ -124,3 +120,20 @@ var throwVersionParserError = function (message) {
|
||||
e.versionParserError = true;
|
||||
throw e;
|
||||
};
|
||||
|
||||
// XXX if we were better about consistently only using functions in this file,
|
||||
// we could just do this using the constraintString field
|
||||
PV.constraintToVersionString = function (parsedConstraint) {
|
||||
if (parsedConstraint.type === "any-reasonable")
|
||||
return "";
|
||||
if (parsedConstraint.type === "compatible-with")
|
||||
return parsedConstraint.version;
|
||||
if (parsedConstraint.type === "exactly")
|
||||
return "=" + parsedConstraint.version;
|
||||
throw Error("Unknown constraint type: " + parsedConstraint.type);
|
||||
};
|
||||
|
||||
PV.constraintToFullString = function (parsedConstraint) {
|
||||
return parsedConstraint.name + "@" + PV.constraintToVersionString(
|
||||
parsedConstraint);
|
||||
};
|
||||
|
||||
@@ -234,6 +234,7 @@ _.extend(Project.prototype, {
|
||||
var allDeps = [];
|
||||
// First, we process the contents of the .meteor/packages file. The
|
||||
// self.constraints variable is always up to date.
|
||||
// Note that two parts of the "add" command run code that matches this.
|
||||
_.each(self.constraints, function (constraint, packageName) {
|
||||
allDeps.push(_.extend({packageName: packageName},
|
||||
utils.parseVersionConstraint(constraint)));
|
||||
@@ -281,7 +282,7 @@ _.extend(Project.prototype, {
|
||||
// someday, this will make sense. (The conditional here allows us to work
|
||||
// in tests with releases that have no packages.)
|
||||
if (catalog.complete.getPackage("ctl")) {
|
||||
allDeps.push({packageName: "ctl", version: null });
|
||||
allDeps.push({packageName: "ctl", version: null, type: 'any-reasonable'});
|
||||
}
|
||||
|
||||
return allDeps;
|
||||
|
||||
@@ -713,7 +713,7 @@ _.extend(Sandbox.prototype, {
|
||||
['autopublish', 'standard-app-packages', 'insecure'],
|
||||
function (name) {
|
||||
var versionRec = doOrThrow(function () {
|
||||
return catalog.official.getLatestVersion(name);
|
||||
return catalog.official.getLatestMainlineVersion(name);
|
||||
});
|
||||
if (!versionRec) {
|
||||
catalog.official.offline = false;
|
||||
@@ -722,7 +722,7 @@ _.extend(Sandbox.prototype, {
|
||||
});
|
||||
catalog.official.offline = true;
|
||||
versionRec = doOrThrow(function () {
|
||||
return catalog.official.getLatestVersion(name);
|
||||
return catalog.official.getLatestMainlineVersion(name);
|
||||
});
|
||||
if (!versionRec) {
|
||||
throw new Error(" hack fails for " + name);
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
Package.describe({
|
||||
summary: "Test package.",
|
||||
version: "1.0.4-rc3"
|
||||
});
|
||||
@@ -172,7 +172,7 @@ selftest.define("list-with-a-new-version",
|
||||
run = s.run("list");
|
||||
run.waitSecs(10);
|
||||
run.match(fullPackageName);
|
||||
run.match("1.0.0");
|
||||
run.match("1.0.0 ");
|
||||
run.forbidAll("New versions");
|
||||
run.expectExit(0);
|
||||
});
|
||||
@@ -194,6 +194,74 @@ selftest.define("list-with-a-new-version",
|
||||
run.match("New versions");
|
||||
run.match("meteor update");
|
||||
run.expectExit(0);
|
||||
|
||||
// Switch to the other version.
|
||||
run = s.run("add", fullPackageName + "@1.0.1");
|
||||
run.waitSecs(100);
|
||||
run.expectExit(0);
|
||||
run = s.run("list");
|
||||
run.waitSecs(10);
|
||||
run.match(fullPackageName);
|
||||
run.match("1.0.1 ");
|
||||
run.forbidAll("New versions");
|
||||
run.expectExit(0);
|
||||
|
||||
// Switch back to the first version.
|
||||
run = s.run("add", fullPackageName + "@=1.0.0");
|
||||
run.waitSecs(100);
|
||||
run.expectExit(0);
|
||||
run = s.run("list");
|
||||
run.waitSecs(10);
|
||||
run.match(fullPackageName);
|
||||
run.match("1.0.0*");
|
||||
run.match("New versions");
|
||||
run.match("meteor update");
|
||||
run.expectExit(0);
|
||||
|
||||
// ... and back to the second version
|
||||
run = s.run("add", fullPackageName + "@=1.0.1");
|
||||
run.waitSecs(100);
|
||||
run.expectExit(0);
|
||||
run = s.run("list");
|
||||
run.waitSecs(10);
|
||||
run.match(fullPackageName);
|
||||
run.match("1.0.1 ");
|
||||
run.forbidAll("New versions");
|
||||
run.expectExit(0);
|
||||
});
|
||||
|
||||
// Now publish an 1.0.4-rc4.
|
||||
s.cp(fullPackageName+'/packagerc.js', fullPackageName+'/package.js');
|
||||
s.cd(fullPackageName, function () {
|
||||
run = s.run("publish");
|
||||
run.waitSecs(15);
|
||||
run.expectExit(0);
|
||||
run.match("Done");
|
||||
});
|
||||
|
||||
s.cd('mapp', function () {
|
||||
// //
|
||||
// run = s.run("search", "asdf");
|
||||
// run.waitSecs(100);
|
||||
// run.expectExit(0);
|
||||
|
||||
// Because it's an RC, we shouldn't see an update message.
|
||||
run = s.run("list");
|
||||
run.waitSecs(10);
|
||||
run.match(fullPackageName);
|
||||
run.match("1.0.1 ");
|
||||
run.forbidAll("New versions");
|
||||
run.expectExit(0);
|
||||
|
||||
// It works if ask for it, though.
|
||||
run = s.run("add", fullPackageName + "@1.0.4-rc3");
|
||||
run.waitSecs(100);
|
||||
run.expectExit(0);
|
||||
run = s.run("list");
|
||||
run.waitSecs(10);
|
||||
run.match(fullPackageName);
|
||||
run.match("1.0.4-rc3 ");
|
||||
run.forbidAll("New versions");
|
||||
run.expectExit(0);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -307,9 +307,19 @@ _.extend(Unipackage.prototype, {
|
||||
// An sorted array of all the architectures included in this package.
|
||||
architectures: function () {
|
||||
var self = this;
|
||||
var arches = _.uniq(
|
||||
_.pluck(self.unibuilds, 'arch').concat(self._toolArchitectures())
|
||||
).sort();
|
||||
var archSet = {};
|
||||
_.each(self.unibuilds, function (unibuild) {
|
||||
archSet[unibuild.arch] = true;
|
||||
});
|
||||
_.each(self._toolArchitectures(), function (arch) {
|
||||
archSet[arch] = true;
|
||||
});
|
||||
_.each(self.plugins, function (plugin, name) {
|
||||
_.each(plugin, function (plug, arch) {
|
||||
archSet[arch] = true;
|
||||
});
|
||||
});
|
||||
var arches = _.keys(archSet).sort();
|
||||
// Ensure that our buildArchitectures string does not look like
|
||||
// web+os+os.osx.x86_64
|
||||
// This would happen if there is an 'os' unibuild but a platform-specific
|
||||
|
||||
Reference in New Issue
Block a user