From cfdc69bf717d3689e15bc7488a0a6dae30437cec Mon Sep 17 00:00:00 2001 From: Ben Newman Date: Tue, 8 Aug 2017 18:01:30 -0400 Subject: [PATCH] Support @~ version constraints and use them for core packages. (#8991) --- .../constraint-solver/constraint-solver.js | 4 + .../package-version-parser.js | 37 ++++- tools/project-context.js | 5 +- .../packages/tilde-constraints/README.md | 0 .../packages/tilde-constraints/package.js | 11 ++ .../tilde-constraints/tilde-constraints.js | 1 + .../packages/tilde-dependent/README.md | 0 .../packages/tilde-dependent/package.js | 12 ++ .../tilde-dependent/tilde-dependent.js | 1 + tools/tests/package-tests.js | 146 ++++++++++++++++++ 10 files changed, 207 insertions(+), 10 deletions(-) create mode 100644 tools/tests/apps/package-tests/packages/tilde-constraints/README.md create mode 100644 tools/tests/apps/package-tests/packages/tilde-constraints/package.js create mode 100644 tools/tests/apps/package-tests/packages/tilde-constraints/tilde-constraints.js create mode 100644 tools/tests/apps/package-tests/packages/tilde-dependent/README.md create mode 100644 tools/tests/apps/package-tests/packages/tilde-dependent/package.js create mode 100644 tools/tests/apps/package-tests/packages/tilde-dependent/tilde-dependent.js diff --git a/packages/constraint-solver/constraint-solver.js b/packages/constraint-solver/constraint-solver.js index 8e4b78be21..435c312769 100644 --- a/packages/constraint-solver/constraint-solver.js +++ b/packages/constraint-solver/constraint-solver.js @@ -186,6 +186,10 @@ CS.isConstraintSatisfied = function (pkg, vConstraint, version) { var cVersion = simpleConstraint.versionString; return (cVersion === version); } else if (type === 'compatible-with') { + if (typeof simpleConstraint.test === "function") { + return simpleConstraint.test(version); + } + var cv = PV.parse(simpleConstraint.versionString); var v = PV.parse(version); diff --git a/packages/package-version-parser/package-version-parser.js b/packages/package-version-parser/package-version-parser.js index 8d179d357e..7d651f7edc 100644 --- a/packages/package-version-parser/package-version-parser.js +++ b/packages/package-version-parser/package-version-parser.js @@ -244,20 +244,41 @@ var parseSimpleConstraint = function (constraintString) { throw new Error("Non-empty string required"); } - var type, versionString; + var result = {}; + var needToCheckValidity = true; if (constraintString.charAt(0) === '=') { - type = "exactly"; - versionString = constraintString.substr(1); + result.type = "exactly"; + result.versionString = constraintString.slice(1); + } else { - type = "compatible-with"; - versionString = constraintString; + result.type = "compatible-with"; + + if (constraintString.charAt(0) === "~") { + var semversion = PV.parse( + result.versionString = constraintString.slice(1) + ).semver; + + var range = new semver.Range("~" + semversion); + + result.test = function (version) { + return range.test(PV.parse(version).semver); + }; + + // Already checked by calling PV.parse above. + needToCheckValidity = false; + + } else { + result.versionString = constraintString; + } } - // This will throw if the version string is invalid. - PV.getValidServerVersion(versionString); + if (needToCheckValidity) { + // This will throw if the version string is invalid. + PV.getValidServerVersion(result.versionString); + } - return { type: type, versionString: versionString }; + return result; }; diff --git a/tools/project-context.js b/tools/project-context.js index 971041f68e..e2071e80d1 100644 --- a/tools/project-context.js +++ b/tools/project-context.js @@ -748,8 +748,9 @@ _.extend(ProjectContext.prototype, { var constraint = utils.parsePackageConstraint( // Note that this used to be an exact name@=version constraint, // before #7084 eliminated these constraints completely. They - // were reinstated in Meteor 1.4.3 as name@version constraints. - packageName + "@" + version); + // were reinstated in Meteor 1.4.3 as name@version constraints, + // and further refined to name@~version constraints in 1.5.2. + packageName + "@~" + version); // Add a constraint but no dependency (we don't automatically use // all local packages!): depsAndConstraints.constraints.push(constraint); diff --git a/tools/tests/apps/package-tests/packages/tilde-constraints/README.md b/tools/tests/apps/package-tests/packages/tilde-constraints/README.md new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tools/tests/apps/package-tests/packages/tilde-constraints/package.js b/tools/tests/apps/package-tests/packages/tilde-constraints/package.js new file mode 100644 index 0000000000..7215c5d3e3 --- /dev/null +++ b/tools/tests/apps/package-tests/packages/tilde-constraints/package.js @@ -0,0 +1,11 @@ +Package.describe({ + name: "tilde-constraints", + version: "0.4.2", + summary: "Package for testing @~ version constraints", + documentation: "README.md" +}); + +Package.onUse(function(api) { + api.use("ecmascript"); + api.mainModule("tilde-constraints.js"); +}); diff --git a/tools/tests/apps/package-tests/packages/tilde-constraints/tilde-constraints.js b/tools/tests/apps/package-tests/packages/tilde-constraints/tilde-constraints.js new file mode 100644 index 0000000000..2a8dc005b2 --- /dev/null +++ b/tools/tests/apps/package-tests/packages/tilde-constraints/tilde-constraints.js @@ -0,0 +1 @@ +console.log(module.id); diff --git a/tools/tests/apps/package-tests/packages/tilde-dependent/README.md b/tools/tests/apps/package-tests/packages/tilde-dependent/README.md new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tools/tests/apps/package-tests/packages/tilde-dependent/package.js b/tools/tests/apps/package-tests/packages/tilde-dependent/package.js new file mode 100644 index 0000000000..2c0a869d87 --- /dev/null +++ b/tools/tests/apps/package-tests/packages/tilde-dependent/package.js @@ -0,0 +1,12 @@ +Package.describe({ + name: "tilde-dependent", + version: "0.1.0", + summary: "Package for testing inter-package @~ constraints", + documentation: "README.md" +}); + +Package.onUse(function(api) { + api.use("ecmascript"); + api.use("tilde-constraints"); + api.mainModule("tilde-dependent.js"); +}); diff --git a/tools/tests/apps/package-tests/packages/tilde-dependent/tilde-dependent.js b/tools/tests/apps/package-tests/packages/tilde-dependent/tilde-dependent.js new file mode 100644 index 0000000000..2a8dc005b2 --- /dev/null +++ b/tools/tests/apps/package-tests/packages/tilde-dependent/tilde-dependent.js @@ -0,0 +1 @@ +console.log(module.id); diff --git a/tools/tests/package-tests.js b/tools/tests/package-tests.js index 4985056957..a897734477 100644 --- a/tools/tests/package-tests.js +++ b/tools/tests/package-tests.js @@ -955,3 +955,149 @@ selftest.define("show readme excerpt", function () { run.matchErr("Documentation not found"); run.expectExit(1); }); + +selftest.define("tilde version constraints", [], function () { + var s = new Sandbox(); + + s.set("METEOR_WATCH_PRIORITIZE_CHANGED", "false"); + + s.createApp("tilde-app", "package-tests"); + s.cd("tilde-app"); + + var run = s.run(); + + run.match("tilde-app"); + run.match("proxy"); + run.waitSecs(10); + run.match("MongoDB"); + run.waitSecs(10); + run.match("your app"); + run.waitSecs(10); + run.match("running at"); + run.waitSecs(60); + + var packages = s.read(".meteor/packages") + .replace(/\n*$/m, "\n"); + + function setTopLevelConstraint(constraint) { + s.write( + ".meteor/packages", + packages + "tilde-constraints" + ( + constraint ? "@" + constraint : "" + ) + "\n" + ); + } + + setTopLevelConstraint(""); + run.match(/tilde-constraints.*added, version 0\.4\.2/); + run.match("tilde-constraints.js"); + run.waitSecs(10); + + setTopLevelConstraint("0.4.0"); + run.match("tilde-constraints.js"); + run.match("server restarted"); + run.waitSecs(10); + + setTopLevelConstraint("~0.4.0"); + run.match("tilde-constraints.js"); + run.match("server restarted"); + run.waitSecs(10); + + setTopLevelConstraint("0.4.3"); + run.match("error: No version of tilde-constraints satisfies all constraints"); + run.waitSecs(10); + + setTopLevelConstraint("~0.4.3"); + run.match("error: No version of tilde-constraints satisfies all constraints"); + run.waitSecs(10); + + setTopLevelConstraint("0.3.0"); + run.match("tilde-constraints.js"); + run.match("server restarted"); + run.waitSecs(10); + + setTopLevelConstraint("~0.3.0"); + run.match("error: No version of tilde-constraints satisfies all constraints"); + run.waitSecs(10); + + setTopLevelConstraint("0.5.0"); + run.match("error: No version of tilde-constraints satisfies all constraints"); + run.waitSecs(10); + + setTopLevelConstraint("~0.5.0"); + run.match("error: No version of tilde-constraints satisfies all constraints"); + run.waitSecs(10); + + s.write( + ".meteor/packages", + packages + ); + run.match(/tilde-constraints.*removed/); + run.waitSecs(10); + + s.write( + ".meteor/packages", + packages + "tilde-dependent\n" + ); + run.match(/tilde-constraints.*added, version 0\.4\.2/); + run.match(/tilde-dependent.*added, version 0\.1\.0/); + run.match("tilde-constraints.js"); + run.match("tilde-dependent.js"); + run.waitSecs(10); + + var depPackageJsPath = "packages/tilde-dependent/package.js" + var depPackageJs = s.read(depPackageJsPath); + + function setDepConstraint(constraint) { + s.write( + depPackageJsPath, + depPackageJs.replace( + /tilde-constraints[^"]*/g, // Syntax highlighting hack: " + "tilde-constraints" + ( + constraint ? "@" + constraint : "" + ) + ) + ); + } + + setDepConstraint("0.4.0"); + run.match("tilde-constraints.js"); + run.match("tilde-dependent.js"); + run.match("server restarted"); + run.waitSecs(10); + + setDepConstraint("~0.4.0"); + run.match("tilde-constraints.js"); + run.match("tilde-dependent.js"); + run.match("server restarted"); + run.waitSecs(10); + + setDepConstraint("0.3.0"); + run.match("tilde-constraints.js"); + run.match("tilde-dependent.js"); + run.match("server restarted"); + run.waitSecs(10); + + // TODO The rest of these tests should cause version conflicts, but it + // seems like version constraints between local packages are ignored, + // which is a larger (preexisting) problem we should investigate. + /* + setDepConstraint("=0.4.0"); + run.match("error: No version of tilde-constraints satisfies all constraints"); + run.waitSecs(10); + + setDepConstraint("~0.3.0"); + run.match("error: No version of tilde-constraints satisfies all constraints"); + run.waitSecs(10); + + setDepConstraint("0.4.3"); + run.match("error: No version of tilde-constraints satisfies all constraints"); + run.waitSecs(10); + + setDepConstraint("~0.4.3"); + run.match("error: No version of tilde-constraints satisfies all constraints"); + run.waitSecs(10); + */ + + run.stop(); +});