Replace catalog.getLatestVersion with catalog.getLatestMainlineVersion,
which skips prerelease versions (those with dashes in the
version). Ensure that this function is only used by high-level commands
like 'meteor list'. Replace other uses of that function with other
equivalent functions.
Also, don't stack trace on 'meteor add' constraint failure.
Before, we were running the constraint solver with both the new and the
old constraint, which would fail if they were not simultaneously
satisfiable. (We were writing the right thing to disk if it succeeded,
at least.)
Drop the "at-least" constraint type entirely. It was not user-accessible
and was only used in the form ">=0.0.0" to represent a constraint with
no version constraint at all. This type of constraint is now called
"any-reasonable".
The definition of "any-reasonable" is:
- Any version that is not a pre-release (has no dash)
- Or a pre-release version that is explicitly mentioned in a TOP-LEVEL
constraint passed to the constraint solver
For example, constraints from .meteor/packages, constraints from the
release, and constraints from the command line of "meteor add" end up
being top-level.
Why only top-level-constrained pre-release versions, and not versions we
find explicitly desired by some other desired version 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.)
At the very least, this change should allow you to run meteor on a
preview branch like cordova-hcp without getting a conflict between the
prerelease package on the branch/release and the lack of an explicit
constraint in .meteor/packages on that package, because we are
reintepreting the .meteor/packages constraint as meaning "anything
reasonable" and the in-the-release version counts as reasonable.
The idea is that dotfiles in .meteor (like .id and .finished-upgraders)
aren't intended to be human-editable, whereas packages, release,
and versions are (although there are commands to edit them too).
Make sure 'meteor add foo' gives the same constraint to the solver as
'foo' from .meteor/packages: namely, '>=0.0.0' not
'unconstrained' (since the first rules out rcs and the second doesn't)
Make sure that project._ensureDepsUpToDate does not get run mid-update,
since it might decide that various things are not compatible with the
packages in the current release. When the update command runs the
constraint solver explicitly, it passes ignoreProjectDeps, but implicit
calls can lead to an unhappy process.exit.
We were accidentally considering this equivalent to 'meteor update
--release LATEST', meaning we could not update to an intermediate
release (and that it could update you backwards).
This before was just an uncaught exception. Now it's exit(1), which is
bad too. This should just use buildmessage, but for some reason that
doesn't work here.
Also removes 'update --minor' and 'add --force'.
In the constraint solver, previousSolution (ie, .meteor/versions) was
intended to be used for three purposes:
(a) The *heuristic* used in the state graph walk to decide what state
to look at next:
- VERY STRONGLY prefers not to downgrade *root* dependencies or
change them to incompatible newer versions
- Kinda Strongly prefers not to upgrade root dependencies far
- mildy prefers not to change transitive dependencies (in any
direction)
(b) Actual *constraints* are added to the set of constraints we are
trying to solve, which state that *root* dependencies are not
to be downgraded. Additionally, in most invocation contexts,
constraints are added that say that *root* dependencies are
not to be upgraded to incompatible versions (1.3.0 -> 2.0.0).
The only contexts that lack the secondary constraints are
part of 'update --minor', and 'add --force'.
(c) A more recent change (past few weeks): When running the constraint
solver, we actually run the core constraint solving algorithm
twice. The first time, we add *equality* constraints for all
of the previous versions. If that succeeds, great! We're not
changing any versions (we may add packages that we didn't have
before or drop packages that are no longer needed, though).
Otherwise, we run the constraint solver again without the equality
constraints.
However, due to a bug introduced in May in 0760ffbc36, (b) actually
*never happened*. The commit was the one that intended to make the
(b) constraints only be for root dependencies. But the line:
if (! _.contains(dependencies, uv.name))
is comparing 'uv.name' (something like 'foo#web.browser') to
'dependencies' (a list of things like 'foo'). So in fact, it thinks that
no dependencies are root and doesn't apply the constraints.
That's actually good, because this code is used in many more places than
just 'meteor update', and applying these things as strong constraints
would actually be problematic; eg, it would break 'meteor --release
slightlyolderrelease'!
In addition, the `update --minor` flag was actually not implemented (it
was not in the command declaration).
So for now, we're removing this dead code. We may reintroduce 'update
--minor' or 'add --force' later. We trust that the heuristic will do a
decent job of preventing unnecessary downgrades or incompatible upgrades
while still allowing you to run updates to an older version, eg.
(And in the future, we may change 'meteor update' to use the constraint
solver to figure out which release to update to, rather than going for
the latest one that there exists any solution for.)