Merge branch 'release-0.9.0.1' into devel

Conflicts:
	packages/autoupdate/autoupdate_client.js
This commit is contained in:
David Glasser
2014-08-27 00:00:15 -07:00
20 changed files with 360 additions and 220 deletions

View File

@@ -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();
}

View File

@@ -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);
});

View File

@@ -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

View File

@@ -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

View File

@@ -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;
}

View File

@@ -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];
});

View File

@@ -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) {

View File

@@ -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 = {};
};

View File

@@ -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");

View File

@@ -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

View File

@@ -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?

View File

@@ -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;

View File

@@ -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);
}

View File

@@ -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] || {};

View File

@@ -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);
};

View File

@@ -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;

View File

@@ -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);

View File

@@ -0,0 +1,4 @@
Package.describe({
summary: "Test package.",
version: "1.0.4-rc3"
});

View File

@@ -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);
});
});

View File

@@ -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