diff --git a/History.md b/History.md index 5b53fda203..c66a5a8fba 100644 --- a/History.md +++ b/History.md @@ -3,6 +3,17 @@ * Spacebars: Allow curly braces to be escaped, with special sequences `{{|` and `{{{|` to insert a literal `{{` or `{{{`. +* Corporate HTTP proxy support is now implemented using our websocket library's + new built-in implementation instead of a custom implementation. #2515 + +* Some packages are no longer released as part of the core release process: + amplify, backbone, bootstrap, d3, jquery-history, and jquery-layout. + +* Rework how Meteor packages get loaded into the command-line tool + +* Remove support for the undocumented earliestCompatibleVersion feature of the + package system. + * Upgraded dependencies: - node: 0.10.33 (from 0.10.29) - source-map-support: 0.2.8 (from 0.2.5) @@ -15,6 +26,7 @@ - http-proxy: 1.6.0 (from a fork of 1.0.2) - esprima: 1.2.2 (from an unreleased 1.1-era commit) - openssl in mongo: 1.0.1j (from 1.0.1g) + - faye-websocket: 0.8.1 (from using websocket-driver instead) - MongoDB: 2.4.12 (from 2.4.9) ## v1.0 diff --git a/docs/client/full-api/packages.html b/docs/client/full-api/packages.html index 2c877f4cc8..8df3ab2772 100644 --- a/docs/client/full-api/packages.html +++ b/docs/client/full-api/packages.html @@ -17,6 +17,7 @@ and removed with: $ meteor remove Meteor Development Group maintains the following packages: +{{> pkg_appcache}} {{> pkg_accounts_ui}} {{> pkg_audit_argument_checks}} {{> pkg_coffeescript}} diff --git a/docs/client/full-api/packages/appcache.html b/docs/client/full-api/packages/appcache.html new file mode 100644 index 0000000000..58c0696662 --- /dev/null +++ b/docs/client/full-api/packages/appcache.html @@ -0,0 +1,84 @@ + diff --git a/meteor b/meteor index 0308a63402..596b92df9d 100755 --- a/meteor +++ b/meteor @@ -1,6 +1,6 @@ #!/bin/bash -BUNDLE_VERSION=0.3.62 +BUNDLE_VERSION=0.3.64 # 0.3.63 on the Windows branch # OS Check. Put here because here is where we download the precompiled # bundles that are arch specific. diff --git a/packages/constraint-solver/benchmark-tests.js b/packages/constraint-solver/benchmark-tests.js new file mode 100644 index 0000000000..dd957ab046 --- /dev/null +++ b/packages/constraint-solver/benchmark-tests.js @@ -0,0 +1,738 @@ +// "Benchmarks" here are just slow tests of the constraint solver. +// You can see roughly how long they take by looking at how long the +// test takes to run. Because they are slow, they don't run when you +// run tests unless you turn them on with an environment variable. + +var runBenchmarks = !!process.env.CONSTRAINT_SOLVER_BENCHMARK; + + +runBenchmarks && Tinytest.add("constraint solver - benchmark on gems - sinatra", function (test) { + var r = new ConstraintSolver.PackagesResolver(getCatalogStub(sinatraGems)); + + var args = splitArgs({ + 'capistrano': '2.14.2', + 'data-mapper': '1.2.0', + 'dm-core': '1.2.0', + 'dm-sqlite-adapter': '1.2.0', + 'dm-timestamps': '1.2.0', + 'haml': '3.1.7', + 'sass': '3.2.1', + 'shotgun': '0.9.0', + 'sinatra': '1.3.5', + 'sqlite3': '1.3.7' + }); + + r.resolve(args.dependencies, args.constraints); +}); + +// Add a few versions that are referenced by other versions but don't exist. We +// now require referenced versions to exist. +railsGems.push({name: "bcrypt", number: "3.0.0", dependencies: []}); +railsGems.push({name: "mime-types", number: "1.16.0", dependencies: []}); +railsGems.push({"name":"pyu-ruby-sasl","number":"0.3.1","platform":"ruby","dependencies":[]}); +railsGems.push({"name":"backports","number":"3.0.0","platform":"ruby","dependencies":[]}); +railsGems.push({"name":"diff-lcs","number":"1.1.0","platform":"ruby","dependencies":[]}); +var railsCatalog = getCatalogStub(railsGems); +runBenchmarks && Tinytest.add("constraint solver - benchmark on gems - rails", function (test) { + var r = new ConstraintSolver.PackagesResolver(railsCatalog); + + var args = splitArgs({ + 'rails': '4.0.4' + }); + + r.resolve(args.dependencies, args.constraints); +}); + +runBenchmarks && Tinytest.add("constraint solver - benchmark on gems - rails, gitlabhq", function (test) { + var r = new ConstraintSolver.PackagesResolver(railsCatalog); + + var args = splitArgs({ + 'rails': '4.0.0', + 'protected-attributes': null, + 'rails-observers': null, + 'actionpack-page-caching': null, + 'actionpack-action-caching': null, + 'default-value-for': '3.0.0', + 'mysql2': null, + 'devise': '3.0.4', + 'devise-async': '0.8.0', + 'omniauth': '1.1.3', + 'omniauth-google-oauth2': null, + 'omniauth-twitter': null, + 'omniauth-github': null, + 'gitlab-git': '5.7.1', + 'gitlab-grack': '2.0.0', + 'gitlab-omniauth-ldap': '1.0.4', + 'gitlab-gollum-lib': '1.1.0', + 'gitlab-linguist': '3.0.0', + 'grape': '0.6.1', + 'rack-cors': null, + 'email-validator': '1.4.0', + 'stamp': null, + 'enumerize': null, + 'kaminari': '0.15.1', + 'haml-rails': null, + 'carrierwave': null, + 'fog': '1.3.1', + 'six': null, + 'seed-fu': null, + 'redcarpet': '2.2.2', + 'github-markup': null, + 'asciidoctor': null, + 'unicorn': '4.6.3', + 'unicorn-worker-killer': null, + 'state-machine': null, + 'acts-as-taggable-on': null, + 'slim': null, + 'sinatra': null, + 'sidekiq': null, + 'httparty': null, + 'colored': null, + 'settingslogic': null, + 'foreman': null, + 'version-sorter': null, + 'redis-rails': null, + 'tinder': '1.9.2', + 'hipchat': '0.14.0', + 'gemnasium-gitlab-service': '0.2.1', + 'slack-notifier': '0.2.0', + 'd3-rails': '3.1.4', + 'underscore-rails': '1.4.4', + 'sanitize': null, + 'rack-attack': null, + 'ace-rails-ap': null, + 'sass-rails': null, + 'coffee-rails': null, + 'uglifier': null, + 'therubyracer': null, + 'turbolinks': null, + 'jquery-turbolinks': null, + 'select2-rails': null, + 'jquery-atwho-rails': '0.3.3', + 'jquery-rails': '2.1.3', + 'jquery-ui-rails': '2.0.2', + 'modernizr': '2.6.2', + 'raphael-rails': '2.1.2', + 'bootstrap-sass': '3.0.0', + 'font-awesome-rails': '3.2.0', + 'gitlab-emoji': '0.0.1', + 'gon': '5.0.0' + }); + + r.resolve(args.dependencies, args.constraints); +}); + +runBenchmarks && Tinytest.add("constraint solver - benchmark on gems - rails, gitlabhq, additions to the existing smaller solution", function (test) { + var r = new ConstraintSolver.PackagesResolver(railsCatalog); + + var args = splitArgs({ + 'rails': '4.0.0', + 'protected-attributes': null, + 'rails-observers': null, + 'actionpack-page-caching': null, + 'actionpack-action-caching': null, + 'default-value-for': '3.0.0', + 'mysql2': null, + 'devise': '3.0.4', + 'devise-async': '0.8.0', + 'omniauth': '1.1.3', + 'omniauth-google-oauth2': null, + 'omniauth-twitter': null, + 'omniauth-github': null, + 'gitlab-git': '5.7.1', + 'gitlab-grack': '2.0.0', + 'gitlab-omniauth-ldap': '1.0.4', + 'gitlab-gollum-lib': '1.1.0', + 'gitlab-linguist': '3.0.0', + 'grape': '0.6.1', + 'rack-cors': null, + 'email-validator': '1.4.0', + 'stamp': null, + 'enumerize': null, + 'kaminari': '0.15.1', + 'haml-rails': null, + 'carrierwave': null, + 'fog': '1.3.1', + 'six': null, + 'seed-fu': null, + 'redcarpet': '2.2.2', + 'github-markup': null, + 'asciidoctor': null, + 'unicorn': '4.6.3', + 'unicorn-worker-killer': null, + 'state-machine': null, + 'acts-as-taggable-on': null, + 'slim': null, + 'sinatra': null, + 'sidekiq': null, + 'httparty': null, + 'colored': null, + 'settingslogic': null, + 'foreman': null, + 'version-sorter': null, + 'redis-rails': null, + 'tinder': '1.9.2', + 'hipchat': '0.14.0', + 'gemnasium-gitlab-service': '0.2.1', + 'slack-notifier': '0.2.0', + 'd3-rails': '3.1.4', + 'underscore-rails': '1.4.4', + 'sanitize': null, + 'rack-attack': null, + 'ace-rails-ap': null, + 'sass-rails': null, + 'coffee-rails': null, + 'uglifier': null, + 'therubyracer': null, + 'turbolinks': null, + 'jquery-turbolinks': null, + 'select2-rails': null, + 'jquery-atwho-rails': '0.3.3', + 'jquery-rails': '2.1.3', + 'jquery-ui-rails': '2.0.2', + 'modernizr': '2.6.2', + 'raphael-rails': '2.1.2', + 'bootstrap-sass': '3.0.0', + 'font-awesome-rails': '3.2.0', + 'gitlab-emoji': '0.0.1', + 'gon': '5.0.0' + }); + + var previousSolution = { + "actionmailer": "4.0.0", + "actionpack": "4.0.0", + "activemodel": "4.0.0", + "activerecord": "4.0.0", + "activerecord-deprecated-finders": "1.0.3", + "activesupport": "4.0.0", + "arel": "4.0.2", + "asciidoctor": "0.1.4", + "bcrypt": "3.1.7", + "bcrypt-ruby": "3.1.5", + "builder": "3.1.4", + "carrierwave": "0.10.0", + "coffee-rails": "4.0.1", + "coffee-script": "2.2.0", + "coffee-script-source": "1.7.0", + "d3-rails": "3.1.4", + "default-value-for": "3.0.0", + "devise": "3.0.4", + "devise-async": "0.8.0", + "erubis": "2.7.0", + "execjs": "2.0.2", + "faraday": "0.9.0", + "github-markup": "1.1.0", + "haml": "4.0.5", + "haml-rails": "0.5.1", + "hashie": "2.0.3", + "hike": "1.2.3", + "httpauth": "0.2.1", + "i18n": "0.6.9", + "jquery-turbolinks": "2.0.2", + "json": "1.8.1", + "jwt": "0.1.10", + "kaminari": "0.15.1", + "mail": "2.5.4", + "mime-types": "1.25.1", + "minitest": "4.7.5", + "multi-json": "1.9.0", + "multipart-post": "2.0.0", + "oauth": "0.4.7", + "oauth2": "0.8.1", + "omniauth": "1.1.4", + "omniauth-github": "1.0.2", + "omniauth-google-oauth2": "0.2.2", + "omniauth-oauth": "1.0.1", + "omniauth-oauth2": "1.1.1", + "omniauth-twitter": "1.0.1", + "orm-adapter": "0.5.0", + "polyglot": "0.3.4", + "posix-spawn": "0.3.8", + "protected-attributes": "1.0.3", + "rack": "1.5.2", + "rack-test": "0.6.2", + "rails": "4.0.0", + "rails-observers": "0.1.2", + "railties": "4.0.0", + "rake": "10.1.1", + "redcarpet": "2.2.2", + "ref": "1.0.5", + "sass": "3.2.17", + "sass-rails": "4.0.2", + "seed-fu": "2.3.0", + "six": "0.2.0", + "sprockets": "2.11.0", + "sprockets-rails": "2.0.1", + "therubyracer": "0.12.1", + "thor": "0.19.1", + "thread-safe": "0.3.1", + "tilt": "1.4.1", + "treetop": "1.4.15", + "turbolinks": "2.2.0", + "tzinfo": "0.3.39", + "uglifier": "2.5.0", + "warden": "1.2.3" + }; + + var solution = r.resolve(args.dependencies, args.constraints, { previousSolution: previousSolution }).answer; + + // check that root deps are the same + _.each(args.dependencies, function (dep) { + if (previousSolution[dep]) + test.equal(solution[dep], previousSolution[dep], dep); + }); +}); + + +// Given a set of gems definitions returns a Catalog-like object +function getCatalogStub (gems) { + return { + getAllPackageNames: function () { + return _.uniq(_.pluck(gems, 'name')); + }, + getPackage: function (name) { + return !!_.findWhere(gems, {name: name}); + }, + getSortedVersions: function (name) { + return _.chain(gems) + .filter(function (pv) { return pv.name === name; }) + .pluck('number') + .map(function (version) { + var nv = exactVersion(version); + if (nv.length < version.length && version.split(".").length === 2) + return version; + return nv; + }) + .filter(function (v) { + return PackageVersion.getValidServerVersion(v); + }) + .sort(PackageVersion.compare) + .uniq(true) + .value(); + }, + getVersion: function (name, version) { + var gem = _.find(gems, function (pv) { + return pv.name === name && exactVersion(pv.number) === version; + }); + + var packageVersion = { + packageName: gem.name, + version: gem.number, + dependencies: {} + }; + + _.each(gem.dependencies, function (dep) { + var name = dep[0]; + var constraint = dep[1]; + + packageVersion.dependencies[name] = { + constraint: constraint, + references: [{ + "arch": "web" + }, { + "arch": "os" }] + }; + }); + + return packageVersion; + } + }; +} + +// Naively converts ruby-gems style constraints string to either exact +// constraint or a regular constraint. +function convertConstraints (inp) { + var out = inp.split(",").map(function (s) { + return s.trim(); + }) + // remove the constraints we don't support + .filter(function (s) { + return !/ 1.2.3 + // and 0.2 => 0.2.0 + .map(function (s) { + var x = s.split(" "); + return [x[0], exactVersion(x[1])].join(" "); + }) + // convert '= 1.2.3' => '=1.2.3' + // '~>1.2.3' => '1.2.3' + // '>=1.2.3' => '1.2.3' + .map(function (s) { + if (s.indexOf(">= 0") === 0) + return ""; + var x = s.split(' '); + if (x[0] === '~>' || x[0] === '>' || x[0] === '>=') + x[0] = ''; + else if (x[0] === '=') + x[0] = '='; + else + throw new Error('unknown operator: ' + x[0]); + return x.join(""); + }); + + return out; +} + +function exactVersion (s) { + s = s.match(/\d+(\.\d+(\.\d+)?)?/)[0]; + if (s.split('.').length < 3) + s += ".0"; + if (s.split('.').length < 3) + s += ".0"; + return s; +} + +// XXX This test is supposed to reproduce issue #2968 by taking +// "forever" but it doesn't. Fix it (by remaking it). + +/*runBenchmarks && Tinytest.add("issue 2968", function (test) { +var resolver = makeResolver([ +["iron:router", '0.9.0', {'meteor': null, 'reactive-dict': '1.0.0', 'deps': '1.0.0', 'underscore': '1.0.0', 'ejson': '1.0.0', 'webapp': '1.0.0', 'iron:layout': '0.3.0', 'cmather:iron-router': '0.8.2', 'jquery': '1.0.0', 'ui': '1.0.0', }], +["meteor", '1.1.3+local', {'underscore': null, }], +["meteor", '1.0.0', {'underscore': null, }], +["meteor", '1.0.2', {'underscore': null, }], +["underscore", '1.0.1+local', {'meteor': null, }], +["underscore", '1.0.0', {'meteor': null, }], +["reactive-dict", '1.0.4+local', {'meteor': null, 'underscore': null, 'tracker': null, 'ejson': null, 'mongo': null, }], +["reactive-dict", '1.0.0', {'meteor': null, 'underscore': null, 'tracker': null, 'ejson': null, 'mongo': null, }], +["tracker", '1.0.3+local', {'meteor': null, }], +["tracker", '1.0.0', {'meteor': null, }], +["ejson", '1.0.4+local', {'meteor': null, 'json': null, 'underscore': null, 'base64': null, }], +["ejson", '1.0.0', {'meteor': null, 'json': null, 'underscore': null, 'base64': null, }], +["json", '1.0.1+local', {'meteor': null, }], +["base64", '1.0.1+local', {'meteor': null, }], +["mongo", '1.0.8+local', {'meteor': null, 'random': null, 'ejson': null, 'json': null, 'underscore': null, 'minimongo': null, 'logging': null, 'ddp': null, 'tracker': null, 'application-configuration': null, 'check': null, 'binary-heap': null, 'insecure': null, 'autopublish': null, 'disable-oplog': null, 'webapp': null, 'facts': null, 'callback-hook': null, }], +["random", '1.0.1+local', {'meteor': null, 'underscore': null, }], +["minimongo", '1.0.5+local', {'meteor': null, 'underscore': null, 'json': null, 'ejson': null, 'id-map': null, 'ordered-dict': null, 'tracker': null, 'random': null, 'geojson-utils': null, }], +["minimongo", '1.0.0', {'meteor': null, 'underscore': null, 'json': null, 'ejson': null, 'id-map': null, 'ordered-dict': null, 'tracker': null, 'random': null, 'geojson-utils': null, }], +["id-map", '1.0.1+local', {'meteor': null, 'underscore': null, 'json': null, 'ejson': null, }], +["ordered-dict", '1.0.1+local', {'meteor': null, 'underscore': null, }], +["geojson-utils", '1.0.1+local', {'meteor': null, }], +["id-map", '1.0.0', {'meteor': null, 'underscore': null, 'json': null, 'ejson': null, }], +["ordered-dict", '1.0.0', {'meteor': null, 'underscore': null, }], +["geojson-utils", '1.0.0', {'meteor': null, }], +["logging", '1.0.5+local', {'meteor': null, 'underscore': null, 'ejson': null, }], +["ddp", '1.0.11+local', {'meteor': null, 'check': null, 'random': null, 'ejson': null, 'json': null, 'underscore': null, 'tracker': null, 'logging': null, 'retry': null, 'webapp': null, 'routepolicy': null, 'audit-argument-checks': null, 'autopublish': null, 'facts': null, 'callback-hook': null, 'minimongo': null, 'reload': null, }], +["check", '1.0.2+local', {'meteor': null, 'underscore': null, 'ejson': null, }], +["retry", '1.0.1+local', {'meteor': null, 'underscore': null, 'random': null, }], +["webapp", '1.1.4+local', {'meteor': null, 'logging': null, 'underscore': null, 'routepolicy': null, 'boilerplate-generator': null, 'spacebars': null, 'htmljs': null, 'blaze': null, 'webapp-hashing': null, 'application-configuration': null, 'follower-livedata': null, }], +["webapp", '1.0.0', {'meteor': null, 'logging': null, 'underscore': null, 'routepolicy': null, 'boilerplate-generator': null, 'spacebars': null, 'htmljs': null, 'blaze': null, 'webapp-hashing': null, 'application-configuration': null, 'follower-livedata': null, }], +["routepolicy", '1.0.2+local', {'meteor': null, 'underscore': null, 'webapp': null, }], +["boilerplate-generator", '1.0.1+local', {'meteor': null, 'underscore': null, 'spacebars-compiler': null, 'spacebars': null, 'htmljs': null, 'ui': null, }], +["spacebars-compiler", '1.0.3+local', {'meteor': null, 'htmljs': null, 'html-tools': null, 'blaze-tools': null, 'underscore': null, 'minifiers': null, }], +["htmljs", '1.0.2+local', {'meteor': null, 'deps': null, }], +["deps", '1.0.5+local', {'meteor': null, 'tracker': null, }], +["deps", '1.0.0', {'meteor': null, 'tracker': null, }], +["html-tools", '1.0.2+local', {'meteor': null, 'htmljs': null, }], +["blaze-tools", '1.0.1+local', {'meteor': null, 'htmljs': null, 'underscore': null, }], +["minifiers", '1.1.2+local', {'meteor': null, 'underscore': null, }], +["spacebars", '1.0.3+local', {'meteor': null, 'htmljs': null, 'blaze': null, 'observe-sequence': null, 'templating': null, }], +["spacebars", '1.0.0', {'meteor': null, 'htmljs': null, 'blaze': null, 'observe-sequence': null, 'templating': null, }], +["blaze", '2.0.3+local', {'meteor': null, 'jquery': null, 'tracker': null, 'underscore': null, 'htmljs': null, 'observe-sequence': null, 'reactive-var': null, }], +["blaze", '2.0.0', {'meteor': null, 'jquery': null, 'tracker': null, 'underscore': null, 'htmljs': null, 'observe-sequence': null, 'reactive-var': null, }], +["blaze", '1.0.0', {'meteor': null, 'jquery': null, 'tracker': null, 'underscore': null, 'htmljs': null, 'observe-sequence': null, 'reactive-var': null, }], +["jquery", '1.0.1', {'meteor': null, }], +["jquery", '1.0.0', {'meteor': null, }], +["observe-sequence", '1.0.3+local', {'meteor': null, 'tracker': null, 'minimongo': null, 'underscore': null, 'random': null, }], +["reactive-var", '1.0.3+local', {'meteor': null, 'tracker': null, }], +["reactive-var", '1.0.0', {'meteor': null, 'tracker': null, }], +["templating", '1.0.9+local', {'meteor': null, 'underscore': null, 'blaze': null, }], +["templating", '1.0.0', {'meteor': null, 'underscore': null, 'blaze': null, }], +["ui", '1.0.4+local', {'meteor': null, 'blaze': null, }], +["ui", '1.0.0', {'meteor': null, 'blaze': null, }], +["webapp-hashing", '1.0.1+local', {'meteor': null, 'underscore': null, }], +["webapp-hashing", '1.0.0', {'meteor': null, 'underscore': null, }], +["application-configuration", '1.0.3+local', {'meteor': null, 'logging': null, 'underscore': null, 'ddp': null, 'ejson': null, 'follower-livedata': null, 'mongo': null, }], +["follower-livedata", '1.0.2+local', {'meteor': null, 'logging': null, 'underscore': null, 'ddp': null, 'ejson': null, }], +["audit-argument-checks", '1.0.1+local', {'meteor': null, }], +["autopublish", '1.0.1+local', {'meteor': null, }], +["facts", '1.0.2+local', {'meteor': null, 'underscore': null, 'autopublish': null, 'ddp': null, 'templating': null, 'mongo': null, }], +["callback-hook", '1.0.1+local', {'meteor': null, 'underscore': null, }], +["reload", '1.1.1+local', {'meteor': null, 'underscore': null, 'logging': null, 'json': null, }], +["binary-heap", '1.0.1+local', {'meteor': null, 'underscore': null, 'id-map': null, }], +["insecure", '1.0.1+local', {'meteor': null, }], +["disable-oplog", '1.0.1+local', {'meteor': null, }], +["iron:layout", '0.3.0', {'templating': '1.0.0', 'ui': '1.0.0', 'meteor': '1.0.0', 'underscore': '1.0.0', 'iron:core': '0.3.2', 'iron:dynamic-template': '0.3.0', 'cmather:blaze-layout': '0.2.5', 'cmather:iron-layout': '0.2.0', }], +["iron:core", '0.3.0', {'meteor': null, 'underscore': '1.0.0', 'ejson': '1.0.0', 'cmather:iron-core': '0.2.0', }], +["cmather:iron-core", '0.1.0', {'meteor': null, 'underscore': '1.0.0', 'ejson': '1.0.0', }], +["cmather:iron-core", '0.2.0', {'meteor': null, 'underscore': '1.0.0', 'ejson': '1.0.0', }], +["iron:core", '0.3.1', {'meteor': null, 'underscore': '1.0.0', 'ejson': '1.0.0', 'cmather:iron-core': '0.2.0', }], +["iron:core", '0.3.2', {'meteor': null, 'underscore': '1.0.0', 'ejson': '1.0.0', 'cmather:iron-core': '0.2.0', }], +["iron:core", '0.3.3-rc0', {'meteor': null, 'underscore': '1.0.0', 'ejson': '1.0.1-rc0', 'cmather:iron-core': '0.2.0', }], +["iron:core", '0.3.4-rc0', {'meteor': null, 'underscore': '1.0.0', 'ejson': '1.0.1-rc0', 'cmather:iron-core': '0.2.0', }], +["iron:core", '0.3.4', {'meteor': null, 'underscore': '1.0.0', 'ejson': '1.0.1', 'cmather:iron-core': '0.2.0', }], +["iron:core", '1.0.0-pre0', {'meteor': null, 'underscore': '1.0.0', 'ejson': '1.0.1-rc0', 'cmather:iron-core': '0.2.0', }], +["iron:core", '1.0.0-pre1', {'meteor': null, 'underscore': '1.0.0', 'ejson': '1.0.2', 'cmather:iron-core': '0.2.0', }], +["iron:core", '1.0.0-pre2', {'meteor': null, 'underscore': '1.0.0', 'ejson': '1.0.2', 'cmather:iron-core': '0.2.0', }], +["iron:core", '1.0.0-pre3', {'meteor': null, 'underscore': '1.0.0', 'ejson': '1.0.2', 'cmather:iron-core': '0.2.0', }], +["iron:core", '1.0.0-pre4', {'meteor': null, 'underscore': '1.0.0', 'ejson': '1.0.2', 'cmather:iron-core': '0.2.0', }], +["iron:core", '1.0.0-pre5', {'meteor': null, 'underscore': '1.0.0', 'ejson': '1.0.2', 'cmather:iron-core': '0.2.0', }], +["iron:core", '1.0.0-rc.1', {'meteor': null, 'underscore': '1.0.0', 'ejson': '1.0.2', 'cmather:iron-core': '0.2.0', }], +["iron:core", '1.0.0', {'meteor': null, 'underscore': '1.0.0', 'ejson': '1.0.2', 'cmather:iron-core': '0.2.0', }], +["iron:dynamic-template", '0.3.0', {'meteor': null, 'blaze': '1.0.0', 'underscore': '1.0.0', 'ui': '1.0.0', 'jquery': '1.0.0', 'deps': '1.0.0', 'templating': '1.0.0', 'iron:core': '0.3.2', }], +["iron:dynamic-template", '0.4.0-rc0', {'meteor': null, 'blaze': '2.0.0-rc0', 'underscore': '1.0.0', 'ui': '1.0.1-rc0', 'jquery': '1.0.0', 'deps': '1.0.2-rc1', 'templating': '1.0.5-rc0', 'iron:core': '0.3.2', }], +["iron:dynamic-template", '0.4.0-rc1', {'meteor': null, 'blaze': '2.0.0-rc1', 'underscore': '1.0.0', 'ui': '1.0.1-rc0', 'jquery': '1.0.0', 'deps': '1.0.2-rc1', 'templating': '1.0.5-rc2', 'iron:core': '0.3.2', }], +["iron:dynamic-template", '0.4.0-rc2', {'meteor': null, 'blaze': '2.0.0-rc1', 'underscore': '1.0.0', 'ui': '1.0.1-rc0', 'jquery': '1.0.0', 'deps': '1.0.2-rc1', 'templating': '1.0.5-rc2', 'iron:core': '0.3.3-rc0', }], +["iron:dynamic-template", '0.4.1-rc0', {'meteor': null, 'blaze': '2.0.0-rc1', 'underscore': '1.0.0', 'ui': '1.0.1-rc0', 'jquery': '1.0.0', 'deps': '1.0.2-rc1', 'templating': '1.0.6-rc0', 'iron:core': '0.3.4-rc0', }], +["iron:dynamic-template", '0.4.1', {'meteor': null, 'blaze': '2.0.0', 'underscore': '1.0.0', 'ui': '1.0.1', 'jquery': '1.0.0', 'deps': '1.0.2', 'templating': '1.0.5', 'iron:core': '0.3.4', }], +["iron:dynamic-template", '1.0.0-pre0', {'meteor': null, 'blaze': '2.0.0-rc1', 'underscore': '1.0.0', 'ui': '1.0.1-rc0', 'jquery': '1.0.0', 'tracker': '1.0.2-rc1', 'reactive-var': '1.0.1-rc0', 'templating': '1.0.6-rc0', 'iron:core': '1.0.0-pre0', }], +["iron:dynamic-template", '1.0.0-pre1', {'meteor': null, 'blaze': '2.0.0', 'underscore': '1.0.0', 'ui': '1.0.2', 'jquery': '1.0.0', 'tracker': '1.0.2', 'reactive-var': '1.0.1', 'templating': '1.0.6', 'iron:core': '1.0.0-pre1', }], +["iron:dynamic-template", '1.0.0-pre2', {'meteor': null, 'blaze': '2.0.0', 'underscore': '1.0.0', 'ui': '1.0.2', 'jquery': '1.0.0', 'tracker': '1.0.2', 'reactive-var': '1.0.1', 'templating': '1.0.6', 'iron:core': '1.0.0-pre2', }], +["iron:dynamic-template", '1.0.0-pre3', {'meteor': null, 'blaze': '2.0.0', 'underscore': '1.0.0', 'ui': '1.0.2', 'jquery': '1.0.0', 'tracker': '1.0.2', 'reactive-var': '1.0.1', 'templating': '1.0.6', 'iron:core': '1.0.0-pre3', }], +["iron:dynamic-template", '1.0.0-pre4', {'meteor': null, 'blaze': '2.0.0', 'underscore': '1.0.0', 'ui': '1.0.2', 'jquery': '1.0.0', 'tracker': '1.0.2', 'reactive-var': '1.0.1', 'templating': '1.0.6', 'random': '1.0.0', 'iron:core': '1.0.0-pre4', }], +["iron:dynamic-template", '1.0.0-pre5', {'meteor': null, 'blaze': '2.0.0', 'underscore': '1.0.0', 'ui': '1.0.2', 'jquery': '1.0.0', 'tracker': '1.0.2', 'reactive-var': '1.0.1', 'templating': '1.0.6', 'random': '1.0.0', 'iron:core': '1.0.0-pre5', }], +["iron:dynamic-template", '1.0.0-rc.1', {'meteor': null, 'blaze': '2.0.0', 'underscore': '1.0.0', 'ui': '1.0.2', 'jquery': '1.0.0', 'tracker': '1.0.2', 'reactive-var': '1.0.1', 'templating': '1.0.6', 'random': '1.0.0', 'iron:core': '1.0.0-rc.1', }], +["iron:dynamic-template", '1.0.0', {'meteor': null, 'blaze': '2.0.0', 'underscore': '1.0.0', 'ui': '1.0.2', 'jquery': '1.0.0', 'tracker': '1.0.2', 'reactive-var': '1.0.1', 'templating': '1.0.6', 'random': '1.0.0', 'iron:core': '1.0.0', }], +["cmather:blaze-layout", '0.0.1', {'meteor': null, }], +["cmather:blaze-layout", '0.1.0', {'meteor': null, }], +["cmather:blaze-layout", '0.2.0', {'meteor': null, }], +["cmather:blaze-layout", '0.2.1', {'meteor': null, }], +["cmather:blaze-layout", '0.2.2', {'meteor': null, }], +["cmather:blaze-layout", '0.2.3', {'meteor': null, }], +["cmather:blaze-layout", '0.2.4', {'meteor': null, }], +["cmather:blaze-layout", '0.2.5', {'meteor': null, 'templating': '1.0.0', 'ui': '1.0.0', 'reactive-dict': '1.0.0', 'underscore': '1.0.0' }], // We removed iron-router from here! +["cmather:iron-layout", '0.1.0', {'meteor': null, }], +["cmather:iron-layout", '0.1.1', {'meteor': null, }], +["cmather:iron-layout", '0.1.2', {'meteor': null, }], +["cmather:iron-layout", '0.2.0', {'templating': '1.0.0', 'ui': '1.0.0', 'meteor': '1.0.0', 'underscore': '1.0.0', 'cmather:iron-core': '0.2.0', 'cmather:iron-dynamic-template': '0.2.1', 'cmather:blaze-layout': '0.2.5', }], +["cmather:iron-dynamic-template", '0.1.0', {'meteor': null, }], +["cmather:iron-dynamic-template", '0.2.0', {'meteor': null, }], +["cmather:iron-dynamic-template", '0.2.1', {'meteor': null, 'blaze': '1.0.0', 'underscore': '1.0.0', 'ui': '1.0.0', 'spacebars': '1.0.0', 'jquery': '1.0.0', 'deps': '1.0.0', 'templating': '1.0.0', 'cmather:iron-core': '0.2.0', }], +["iron:layout", '0.4.0-rc0', {'meteor': null, 'templating': '1.0.5-rc0', 'blaze': '2.0.0-rc0', 'underscore': '1.0.0', 'iron:core': '0.3.2', 'iron:dynamic-template': '0.4.0-rc0', 'cmather:blaze-layout': '0.2.5', 'cmather:iron-layout': '0.2.0', }], +["iron:layout", '0.4.0-rc1', {'meteor': null, 'templating': '1.0.5-rc2', 'blaze': '2.0.0-rc1', 'underscore': '1.0.0', 'iron:core': '0.3.2', 'iron:dynamic-template': '0.4.0-rc1', 'cmather:blaze-layout': '0.2.5', 'cmather:iron-layout': '0.2.0', }], +["iron:layout", '0.4.0-rc2', {'meteor': null, 'templating': '1.0.5-rc2', 'blaze': '2.0.0-rc1', 'underscore': '1.0.0', 'iron:core': '0.3.3-rc0', 'iron:dynamic-template': '0.4.0-rc2', 'cmather:blaze-layout': '0.2.5', 'cmather:iron-layout': '0.2.0', }], +["iron:layout", '0.4.1-rc0', {'meteor': null, 'templating': '1.0.6-rc0', 'blaze': '2.0.0-rc1', 'underscore': '1.0.0', 'iron:core': '0.3.4-rc0', 'iron:dynamic-template': '0.4.1-rc0', 'cmather:blaze-layout': '0.2.5', 'cmather:iron-layout': '0.2.0', }], +["iron:layout", '0.4.1', {'meteor': null, 'templating': '1.0.5', 'blaze': '2.0.0', 'underscore': '1.0.0', 'iron:core': '0.3.4', 'iron:dynamic-template': '0.4.1', 'cmather:blaze-layout': '0.2.5', 'cmather:iron-layout': '0.2.0', }], +["iron:layout", '1.0.0-pre0', {'meteor': null, 'templating': '1.0.6-rc0', 'blaze': '2.0.0-rc1', 'underscore': '1.0.0', 'iron:core': '1.0.0-pre0', 'iron:dynamic-template': '1.0.0-pre0', 'cmather:blaze-layout': '0.2.5', 'cmather:iron-layout': '0.2.0', }], +["iron:layout", '1.0.0-pre1', {'meteor': null, 'templating': '1.0.6', 'blaze': '2.0.0', 'underscore': '1.0.0', 'iron:core': '1.0.0-pre1', 'iron:dynamic-template': '1.0.0-pre1', 'cmather:blaze-layout': '0.2.5', 'cmather:iron-layout': '0.2.0', }], +["iron:layout", '1.0.0-pre2', {'meteor': null, 'templating': '1.0.6', 'blaze': '2.0.0', 'underscore': '1.0.0', 'iron:core': '1.0.0-pre2', 'iron:dynamic-template': '1.0.0-pre2', 'cmather:blaze-layout': '0.2.5', 'cmather:iron-layout': '0.2.0', }], +["iron:layout", '1.0.0-pre3', {'meteor': null, 'templating': '1.0.6', 'blaze': '2.0.0', 'underscore': '1.0.0', 'iron:core': '1.0.0-pre3', 'iron:dynamic-template': '1.0.0-pre3', 'cmather:blaze-layout': '0.2.5', 'cmather:iron-layout': '0.2.0', }], +["iron:layout", '1.0.0-pre4', {'meteor': null, 'templating': '1.0.6', 'blaze': '2.0.0', 'underscore': '1.0.0', 'iron:core': '1.0.0-pre4', 'iron:dynamic-template': '1.0.0-pre4', 'cmather:blaze-layout': '0.2.5', 'cmather:iron-layout': '0.2.0', }], +["iron:layout", '1.0.0-pre5', {'meteor': null, 'templating': '1.0.6', 'blaze': '2.0.0', 'underscore': '1.0.0', 'iron:core': '1.0.0-pre5', 'iron:dynamic-template': '1.0.0-pre5', 'cmather:blaze-layout': '0.2.5', 'cmather:iron-layout': '0.2.0', }], +["iron:layout", '1.0.0-rc.1', {'meteor': null, 'templating': '1.0.6', 'blaze': '2.0.0', 'underscore': '1.0.0', 'iron:core': '1.0.0-rc.1', 'iron:dynamic-template': '1.0.0-rc.1', 'cmather:blaze-layout': '0.2.5', 'cmather:iron-layout': '0.2.0', }], +["iron:layout", '1.0.0', {'meteor': null, 'templating': '1.0.6', 'blaze': '2.0.0', 'underscore': '1.0.0', 'iron:core': '1.0.0', 'iron:dynamic-template': '1.0.0', 'cmather:blaze-layout': '0.2.5', 'cmather:iron-layout': '0.2.0', }], +["cmather:iron-router", '0.5.3', {'meteor': null, }], +["cmather:iron-router", '0.5.4', {'meteor': null, }], +["cmather:iron-router", '0.6.0', {'meteor': null, 'reactive-dict': '1.0.0', 'deps': '1.0.0', 'underscore': '1.0.0', 'ejson': '1.0.0', 'webapp': '1.0.0', 'templating': '1.0.0', 'handlebars': '1.0.0', 'jquery': '1.0.0', }], +["handlebars", '1.0.1+local', {'meteor': null, }], +["cmather:iron-router", '0.6.1', {'meteor': null, 'reactive-dict': '1.0.0', 'deps': '1.0.0', 'underscore': '1.0.0', 'ejson': '1.0.0', 'webapp': '1.0.0', 'templating': '1.0.0', 'handlebars': '1.0.0', 'jquery': '1.0.0', }], +["cmather:iron-router", '0.6.2', {'meteor': null, 'reactive-dict': '1.0.0', 'deps': '1.0.0', 'underscore': '1.0.0', 'ejson': '1.0.0', 'webapp': '1.0.0', 'templating': '1.0.0', 'handlebars': '1.0.0', 'jquery': '1.0.0', }], +["cmather:iron-router", '0.6.3', {'meteor': null, 'reactive-dict': '1.0.0', 'deps': '1.0.0', 'underscore': '1.0.0', 'ejson': '1.0.0', 'webapp': '1.0.0', 'templating': '1.0.0', 'handlebars': '1.0.0', 'jquery': '1.0.0', }], +["cmather:iron-router", '0.6.4', {'meteor': null, 'reactive-dict': '1.0.0', 'deps': '1.0.0', 'underscore': '1.0.0', 'ejson': '1.0.0', 'webapp': '1.0.0', 'templating': '1.0.0', 'handlebars': '1.0.0', 'jquery': '1.0.0', }], +["cmather:iron-router", '0.7.0', {'meteor': null, }], +["cmather:iron-router", '0.7.1', {'meteor': null, }], +["cmather:iron-router", '0.8.0', {'meteor': null, }], +["cmather:iron-router", '0.8.1', {'meteor': null, }], +["cmather:iron-router", '0.8.2', {'meteor': null, 'reactive-dict': '1.0.0', 'deps': '1.0.0', 'underscore': '1.0.0', 'ejson': '1.0.0', 'cmather:iron-layout': '0.2.0', 'webapp': '1.0.0', 'jquery': '1.0.0', 'ui': '1.0.0', }], +["iron:router", '0.9.1', {'meteor': null, 'reactive-dict': '1.0.0', 'deps': '1.0.0', 'underscore': '1.0.0', 'ejson': '1.0.0', 'webapp': '1.0.0', 'iron:layout': '0.3.0', 'cmather:iron-router': '0.8.2', 'jquery': '1.0.0', 'ui': '1.0.0', }], +["iron:router", '0.9.2-rc0', {'meteor': null, 'reactive-dict': '1.0.1-rc0', 'deps': '1.0.2-rc1', 'underscore': '1.0.0', 'ejson': '1.0.1-rc0', 'webapp': '1.0.3-rc0', 'iron:layout': '0.4.0-rc0', 'cmather:iron-router': '0.8.2', 'jquery': '1.0.0', 'blaze': '2.0.0-rc0', }], +["iron:router", '0.9.2-rc2', {'meteor': null, 'reactive-dict': '1.0.1-rc1', 'deps': '1.0.2-rc1', 'underscore': '1.0.0', 'ejson': '1.0.1-rc0', 'webapp': '1.0.3-rc0', 'iron:layout': '0.4.0-rc2', 'cmather:iron-router': '0.8.2', 'jquery': '1.0.0', 'blaze': '2.0.0-rc1', }], +["iron:router", '0.9.3-rc0', {'meteor': null, 'reactive-dict': '1.0.1-rc1', 'deps': '1.0.2-rc1', 'underscore': '1.0.0', 'ejson': '1.0.1-rc0', 'webapp': '1.1.0-rc1', 'iron:layout': '0.4.1-rc0', 'cmather:iron-router': '0.8.2', 'jquery': '1.0.0', 'blaze': '2.0.0-rc1', }], +["iron:router", '0.9.3', {'meteor': null, 'reactive-dict': '1.0.1', 'deps': '1.0.2', 'underscore': '1.0.0', 'ejson': '1.0.1', 'webapp': '1.0.3', 'iron:layout': '0.4.1', 'cmather:iron-router': '0.8.2', 'jquery': '1.0.0', 'blaze': '2.0.0', }], +["iron:router", '0.9.4', {'meteor': null, 'reactive-dict': '1.0.1', 'deps': '1.0.2', 'underscore': '1.0.0', 'ejson': '1.0.1', 'webapp': '1.0.3', 'iron:layout': '0.4.1', 'cmather:iron-router': '0.8.2', 'jquery': '1.0.0', 'blaze': '2.0.0', }], +["iron:router", '1.0.0-pre0', {'underscore': '1.0.0', 'webapp': '1.1.0-rc1', 'ui': '1.0.1-rc0', 'templating': '1.0.6-rc0', 'meteor': '1.1.0-rc0', 'iron:core': '1.0.0-pre0', 'iron:layout': '1.0.0-pre0', 'iron:middleware-stack': '1.0.0-pre0', 'iron:url': '1.0.0-pre0', 'iron:location': '1.0.0-pre0', 'iron:controller': '1.0.0-pre0', 'deps': '1.0.2-rc1', }], +["iron:middleware-stack", '1.0.0-pre0', {'meteor': null, 'iron:core': '1.0.0-pre0', 'iron:url': '1.0.0-pre0', }], +["iron:url", '1.0.0-pre0', {'meteor': null, 'underscore': '1.0.0', 'iron:core': '1.0.0-pre0', }], +["iron:url", '1.0.0-pre1', {'meteor': null, 'underscore': '1.0.0', 'iron:core': '1.0.0-pre1', }], +["iron:url", '1.0.0-pre2', {'meteor': null, 'underscore': '1.0.0', 'iron:core': '1.0.0-pre2', }], +["iron:url", '1.0.0-pre3', {'meteor': null, 'underscore': '1.0.0', 'iron:core': '1.0.0-pre3', }], +["iron:url", '1.0.0-pre4', {'meteor': null, 'underscore': '1.0.0', 'iron:core': '1.0.0-pre4', }], +["iron:url", '1.0.0-pre5', {'meteor': null, 'underscore': '1.0.0', 'iron:core': '1.0.0-pre5', }], +["iron:url", '1.0.0-rc.1', {'meteor': null, 'underscore': '1.0.0', 'iron:core': '1.0.0-rc.1', }], +["iron:url", '1.0.0', {'meteor': null, 'underscore': '1.0.0', 'iron:core': '1.0.0', }], +["iron:middleware-stack", '1.0.0-pre1', {'meteor': null, 'iron:core': '1.0.0-pre1', 'iron:url': '1.0.0-pre1', }], +["iron:middleware-stack", '1.0.0-pre2', {'meteor': null, 'iron:core': '1.0.0-pre2', 'iron:url': '1.0.0-pre2', }], +["iron:middleware-stack", '1.0.0-pre3', {'meteor': null, 'iron:core': '1.0.0-pre3', 'iron:url': '1.0.0-pre3', }], +["iron:middleware-stack", '1.0.0-pre4', {'meteor': null, 'underscore': '1.0.0', 'iron:core': '1.0.0-pre4', 'iron:url': '1.0.0-pre4', }], +["iron:middleware-stack", '1.0.0-pre5', {'meteor': null, 'underscore': '1.0.0', 'iron:core': '1.0.0-pre5', 'iron:url': '1.0.0-pre5', }], +["iron:middleware-stack", '1.0.0-rc.1', {'meteor': null, 'underscore': '1.0.0', 'iron:core': '1.0.0-rc.1', 'iron:url': '1.0.0-rc.1', }], +["iron:middleware-stack", '1.0.0', {'meteor': null, 'underscore': '1.0.0', 'iron:core': '1.0.0', 'iron:url': '1.0.0', }], +["iron:location", '1.0.0-pre0', {'meteor': null, 'underscore': '1.0.0', 'tracker': '1.0.2-rc1', 'jquery': '1.0.0', 'iron:core': '1.0.0-pre0', 'iron:url': '1.0.0-pre0', }], +["iron:location", '1.0.0-pre1', {'meteor': null, 'underscore': '1.0.0', 'tracker': '1.0.2', 'jquery': '1.0.0', 'iron:core': '1.0.0-pre1', 'iron:url': '1.0.0-pre1', }], +["iron:location", '1.0.0-pre2', {'meteor': null, 'underscore': '1.0.0', 'tracker': '1.0.2', 'jquery': '1.0.0', 'iron:core': '1.0.0-pre2', 'iron:url': '1.0.0-pre2', }], +["iron:location", '1.0.0-pre3', {'meteor': null, 'underscore': '1.0.0', 'tracker': '1.0.2', 'jquery': '1.0.0', 'iron:core': '1.0.0-pre3', 'iron:url': '1.0.0-pre3', }], +["iron:location", '1.0.0-pre4', {'meteor': null, 'underscore': '1.0.0', 'tracker': '1.0.2', 'jquery': '1.0.0', 'iron:core': '1.0.0-pre4', 'iron:url': '1.0.0-pre4', }], +["iron:location", '1.0.0-pre5', {'meteor': null, 'underscore': '1.0.0', 'tracker': '1.0.2', 'jquery': '1.0.0', 'iron:core': '1.0.0-pre5', 'iron:url': '1.0.0-pre5', 'appcache': '1.0.0-cordova1', }], +["appcache", '1.0.2+local', {'meteor': null, 'webapp': null, 'routepolicy': null, 'underscore': null, 'autoupdate': null, 'reload': null, }], +["autoupdate", '1.1.3+local', {'meteor': null, 'webapp': null, 'ddp': null, 'mongo': null, 'underscore': null, 'tracker': null, 'retry': null, 'reload': null, 'http': null, 'random': null, }], +["http", '1.0.8+local', {'meteor': null, 'underscore': null, 'url': null, }], +["url", '1.0.2+local', {'meteor': null, 'underscore': null, }], +["iron:location", '1.0.0-rc.1', {'meteor': null, 'underscore': '1.0.0', 'tracker': '1.0.2', 'jquery': '1.0.0', 'iron:core': '1.0.0-rc.1', 'iron:url': '1.0.0-rc.1', 'appcache': '1.0.0-cordova1', }], +["iron:location", '1.0.0', {'meteor': null, 'underscore': '1.0.0', 'tracker': '1.0.2', 'jquery': '1.0.0', 'iron:core': '1.0.0', 'iron:url': '1.0.0', 'appcache': '1.0.0-cordova1', }], +["iron:controller", '1.0.0-pre0', {'meteor': null, 'underscore': '1.0.0', 'tracker': '1.0.2-rc1', 'reactive-dict': '1.0.1-rc1', 'iron:core': '1.0.0-pre0', 'iron:layout': '1.0.0-pre0', 'iron:dynamic-template': '1.0.0-pre0', }], +["iron:controller", '1.0.0-pre1', {'meteor': null, 'underscore': '1.0.0', 'tracker': '1.0.2', 'reactive-dict': '1.0.2', 'iron:core': '1.0.0-pre1', 'iron:layout': '1.0.0-pre1', 'iron:dynamic-template': '1.0.0-pre1', }], +["iron:controller", '1.0.0-pre2', {'meteor': null, 'underscore': '1.0.0', 'tracker': '1.0.2', 'reactive-dict': '1.0.2', 'iron:core': '1.0.0-pre2', 'iron:layout': '1.0.0-pre2', 'iron:dynamic-template': '1.0.0-pre2', }], +["iron:controller", '1.0.0-pre3', {'meteor': null, 'underscore': '1.0.0', 'tracker': '1.0.2', 'reactive-dict': '1.0.2', 'iron:core': '1.0.0-pre3', 'iron:layout': '1.0.0-pre3', 'iron:dynamic-template': '1.0.0-pre3', }], +["iron:controller", '1.0.0-pre4', {'meteor': null, 'underscore': '1.0.0', 'tracker': '1.0.2', 'reactive-dict': '1.0.2', 'templating': '1.0.6', 'iron:core': '1.0.0-pre4', 'iron:layout': '1.0.0-pre4', 'iron:dynamic-template': '1.0.0-pre4', }], +["iron:controller", '1.0.0-pre5', {'meteor': null, 'underscore': '1.0.0', 'tracker': '1.0.2', 'reactive-dict': '1.0.2', 'templating': '1.0.6', 'iron:core': '1.0.0-pre5', 'iron:layout': '1.0.0-pre5', 'iron:dynamic-template': '1.0.0-pre5', }], +["iron:controller", '1.0.0-rc.1', {'meteor': null, 'underscore': '1.0.0', 'tracker': '1.0.2', 'reactive-dict': '1.0.2', 'templating': '1.0.6', 'iron:core': '1.0.0-rc.1', 'iron:layout': '1.0.0-rc.1', 'iron:dynamic-template': '1.0.0-rc.1', }], +["iron:controller", '1.0.0', {'meteor': null, 'underscore': '1.0.0', 'tracker': '1.0.2', 'reactive-dict': '1.0.2', 'templating': '1.0.6', 'iron:core': '1.0.0', 'iron:layout': '1.0.0', 'iron:dynamic-template': '1.0.0', }], +["iron:router", '1.0.0-pre1', {'underscore': '1.0.0', 'webapp': '1.1.1', 'ui': '1.0.2', 'templating': '1.0.6', 'meteor': '1.1.0', 'iron:core': '1.0.0-pre1', 'iron:layout': '1.0.0-pre1', 'iron:middleware-stack': '1.0.0-pre1', 'iron:url': '1.0.0-pre1', 'iron:location': '1.0.0-pre1', 'iron:controller': '1.0.0-pre1', 'deps': '1.0.3', }], +["iron:router", '1.0.0-pre2', {'underscore': '1.0.0', 'webapp': '1.1.1', 'ui': '1.0.2', 'templating': '1.0.6', 'meteor': '1.1.0', 'iron:core': '1.0.0-pre2', 'iron:layout': '1.0.0-pre2', 'iron:middleware-stack': '1.0.0-pre2', 'iron:url': '1.0.0-pre2', 'iron:location': '1.0.0-pre2', 'iron:controller': '1.0.0-pre2', 'deps': '1.0.3', }], +["iron:router", '1.0.0-pre3', {'underscore': '1.0.0', 'webapp': '1.1.1', 'ui': '1.0.2', 'templating': '1.0.6', 'meteor': '1.1.0', 'iron:core': '1.0.0-pre3', 'iron:layout': '1.0.0-pre3', 'iron:middleware-stack': '1.0.0-pre3', 'iron:url': '1.0.0-pre3', 'iron:location': '1.0.0-pre3', 'iron:controller': '1.0.0-pre3', 'deps': '1.0.3', }], +["iron:router", '1.0.0-pre4', {'underscore': '1.0.0', 'webapp': '1.1.1', 'ui': '1.0.2', 'templating': '1.0.6', 'ejson': '1.0.2', 'meteor': '1.1.0', 'iron:core': '1.0.0-pre4', 'iron:layout': '1.0.0-pre4', 'iron:middleware-stack': '1.0.0-pre4', 'iron:url': '1.0.0-pre4', 'iron:location': '1.0.0-pre4', 'iron:controller': '1.0.0-pre4', 'deps': '1.0.3', }], +["iron:router", '1.0.0-pre5', {'underscore': '1.0.0', 'webapp': '1.1.1', 'ui': '1.0.2', 'templating': '1.0.6', 'ejson': '1.0.2', 'meteor': '1.1.0', 'iron:core': '1.0.0-pre5', 'iron:layout': '1.0.0-pre5', 'iron:middleware-stack': '1.0.0-pre5', 'iron:url': '1.0.0-pre5', 'iron:location': '1.0.0-pre5', 'iron:controller': '1.0.0-pre5', 'deps': '1.0.3', }], +["iron:router", '1.0.0-rc.0', {'underscore': '1.0.0', 'webapp': '1.1.1', 'ui': '1.0.2', 'templating': '1.0.6', 'ejson': '1.0.2', 'meteor': '1.1.0', 'iron:core': '1.0.0-pre5', 'iron:layout': '1.0.0-pre5', 'iron:middleware-stack': '1.0.0-pre5', 'iron:url': '1.0.0-pre5', 'iron:location': '1.0.0-pre5', 'iron:controller': '1.0.0-pre5', 'deps': '1.0.3', }], +["iron:router", '1.0.0-rc.1', {'underscore': '1.0.0', 'webapp': '1.1.1', 'ui': '1.0.2', 'templating': '1.0.6', 'ejson': '1.0.2', 'meteor': '1.1.0', 'iron:core': '1.0.0-rc.1', 'iron:layout': '1.0.0-rc.1', 'iron:middleware-stack': '1.0.0-rc.1', 'iron:url': '1.0.0-rc.1', 'iron:location': '1.0.0-rc.1', 'iron:controller': '1.0.0-rc.1', 'deps': '1.0.3', }], +["iron:router", '1.0.0', {'underscore': '1.0.0', 'webapp': '1.1.1', 'ui': '1.0.2', 'templating': '1.0.6', 'ejson': '1.0.2', 'meteor': '1.1.0', 'iron:core': '1.0.0', 'iron:layout': '1.0.0', 'iron:middleware-stack': '1.0.0', 'iron:url': '1.0.0', 'iron:location': '1.0.0', 'iron:controller': '1.0.0', 'deps': '1.0.3', }], +["matb33:collection-hooks", '0.7.3', {'meteor': '1.0.0', 'underscore': '1.0.0', 'ejson': '1.0.0', 'mongo-livedata': '1.0.0', 'minimongo': '1.0.0', 'deps': '1.0.0', 'accounts-base': '1.0.0', }], +["mongo-livedata", '1.0.6+local', {'meteor': null, 'mongo': null, }], +["mongo-livedata", '1.0.0', {'meteor': null, 'mongo': null, }], +["accounts-base", '1.1.2+local', {'meteor': null, 'underscore': null, 'check': null, 'random': null, 'ejson': null, 'callback-hook': null, 'service-configuration': null, 'ddp': null, 'mongo': null, 'autopublish': null, 'oauth-encryption': null, 'localstorage': null, 'tracker': null, 'blaze': null, }], +["accounts-base", '1.0.0', {'meteor': null, 'underscore': null, 'check': null, 'random': null, 'ejson': null, 'callback-hook': null, 'service-configuration': null, 'ddp': null, 'mongo': null, 'autopublish': null, 'oauth-encryption': null, 'localstorage': null, 'tracker': null, 'blaze': null, }], +["service-configuration", '1.0.2+local', {'meteor': null, 'accounts-base': null, 'mongo': null, }], +["oauth-encryption", '1.0.1+local', {'meteor': null, 'npm-node-aes-gcm': '=0.1.3', 'underscore': null, }], +["npm-node-aes-gcm", '0.1.3', {'meteor': null, }], +["localstorage", '1.0.1+local', {'meteor': null, 'random': null, }], +["matb33:collection-hooks", '0.7.5', {'meteor': null, 'mongo': '1.0.4', 'tracker': '1.0.2', 'underscore': '1.0.0', 'ejson': '1.0.0', 'minimongo': '1.0.1', 'accounts-base': '1.0.0', }], +["matb33:collection-hooks", '0.7.6', {'meteor': null, 'mongo': '1.0.4', 'tracker': '1.0.2', 'underscore': '1.0.0', 'ejson': '1.0.1', 'minimongo': '1.0.2', 'accounts-base': '1.0.1', }], +["mizzao:timesync", '0.1.0', {'meteor': null, 'coffeescript': '1.0.0', 'deps': '1.0.0', }], +["coffeescript", '1.0.4+local', {'meteor': null, }], +["coffeescript", '1.0.0', {'meteor': null, }], +["mizzao:timesync", '0.1.1', {'meteor': null, 'coffeescript': '1.0.0', 'deps': '1.0.0', }], +["mizzao:timesync", '0.1.2', {'meteor': null, 'coffeescript': '1.0.0', 'deps': '1.0.0', }], +["mizzao:timesync", '0.1.3', {'meteor': null, 'coffeescript': '1.0.0', 'deps': '1.0.0', }], +["mizzao:timesync", '0.1.4', {'meteor': null, 'webapp': '1.0.0', 'deps': '1.0.0', 'http': '1.0.0', }], +["mizzao:timesync", '0.1.5', {'meteor': null, 'webapp': '1.0.0', 'deps': '1.0.0', 'http': '1.0.0', }], +["mizzao:timesync", '0.1.6', {'meteor': null, 'webapp': '1.0.0', 'deps': '1.0.0', 'http': '1.0.0', }], +["mizzao:timesync", '0.2.0', {'meteor': null, 'webapp': '1.0.0', 'deps': '1.0.0', 'http': '1.0.0', }], +["mizzao:timesync", '0.2.1', {'meteor': null, 'webapp': '1.0.0', 'deps': '1.0.0', 'http': '1.0.0', }], +["mizzao:timesync", '0.2.2', {'meteor': null, 'webapp': '1.0.0', 'deps': '1.0.0', 'http': '1.0.0', }], +["mrt:jquery-ui-sortable", '1.10.3', {'meteor': null, 'jquery': '1.0.0', }], +["mrt:moment", '1.7.0', {'meteor': null, }], +["mrt:moment", '2.2.1', {'meteor': null, }], +["mrt:moment", '2.5.1', {'meteor': null, }], +["mrt:moment", '2.6.0', {'meteor': null, }], +["mrt:moment", '2.8.1', {'meteor': null, }], +["skinnygeek1010:parse-form", '0.1.0', {'meteor': null, 'jquery': '1.0.0', }], +["skinnygeek1010:parse-form", '0.2.0', {'meteor': null, 'jquery': '1.0.0', }], +["skinnygeek1010:parse-form", '0.2.1', {'meteor': null, 'jquery': '1.0.0', }], +["splendido:accounts-templates-semantic-ui", '0.0.1', {'meteor': null, }], +["splendido:accounts-templates-semantic-ui", '0.0.2', {'meteor': null, }], +["splendido:accounts-templates-semantic-ui", '0.0.3', {'meteor': null, }], +["splendido:accounts-templates-semantic-ui", '0.0.4', {'meteor': null, }], +["splendido:accounts-templates-semantic-ui", '0.0.20', {'meteor': null, 'service-configuration': '1.0.0', 'accounts-password': '1.0.0', 'accounts-base': '1.0.0', 'splendido:accounts-templates-core': '0.0.20', 'templating': '1.0.4', 'less': '1.0.5', }], +["accounts-password", '1.0.4+local', {'meteor': null, 'npm-bcrypt': '=0.7.7', 'accounts-base': null, 'srp': null, 'sha': null, 'email': null, 'random': null, 'check': null, 'underscore': null, 'ddp': null, }], +["npm-bcrypt", '0.7.7', {'meteor': null, }], +["srp", '1.0.1+local', {'meteor': null, 'random': null, 'check': null, 'sha': null, 'underscore': null, }], +["sha", '1.0.1+local', {'meteor': null, }], +["email", '1.0.4+local', {'meteor': null, 'underscore': null, 'application-configuration': null, }], +["splendido:accounts-templates-core", '0.0.1', {'meteor': null, }], +["splendido:accounts-templates-core", '0.0.2', {'meteor': null, }], +["splendido:accounts-templates-core", '0.0.3', {'meteor': null, }], +["splendido:accounts-templates-core", '0.0.4', {'meteor': null, }], +["splendido:accounts-templates-core", '0.0.5', {'meteor': null, }], +["splendido:accounts-templates-core", '0.0.6', {'meteor': null, }], +["splendido:accounts-templates-core", '0.0.7', {'meteor': null, }], +["splendido:accounts-templates-core", '0.0.8', {'meteor': null, }], +["splendido:accounts-templates-core", '0.0.9', {'meteor': null, }], +["splendido:accounts-templates-core", '0.0.10', {'meteor': null, }], +["splendido:accounts-templates-core", '0.0.11', {'meteor': null, }], +["splendido:accounts-templates-core", '0.0.20', {'meteor': null, 'check': '1.0.0', 'deps': '1.0.1', 'accounts-base': '1.0.0', 'mrt:accounts-t9n': '0.0.13', 'iron:router': '0.9.1', 'underscore': '1.0.0', 'minimongo': '1.0.1', 'mongo-livedata': '1.0.3', 'sha': '1.0.0', 'templating': '1.0.4', }], +["mrt:accounts-t9n", '0.0.1', {'meteor': null, 'coffeescript': '1.0.0', 'handlebars': '1.0.0', 'deps': '1.0.0', 'mrt:just-i18n': '0.3.0', }], +["mrt:just-i18n", '0.1.0', {'meteor': null, 'underscore': '1.0.0', 'handlebars': '1.0.0', 'deps': '1.0.0', }], +["mrt:just-i18n", '0.1.1', {'meteor': null, 'underscore': '1.0.0', 'handlebars': '1.0.0', 'deps': '1.0.0', }], +["mrt:just-i18n", '0.2.0', {'meteor': null, 'underscore': '1.0.0', 'handlebars': '1.0.0', 'deps': '1.0.0', }], +["mrt:just-i18n", '0.2.1', {'meteor': null, 'underscore': '1.0.0', 'handlebars': '1.0.0', 'deps': '1.0.0', }], +["mrt:just-i18n", '0.2.2', {'meteor': null, 'underscore': '1.0.0', 'handlebars': '1.0.0', 'deps': '1.0.0', }], +["mrt:just-i18n", '0.2.3', {'meteor': null, 'underscore': '1.0.0', 'handlebars': '1.0.0', 'deps': '1.0.0', }], +["mrt:just-i18n", '0.2.4', {'meteor': null, 'underscore': '1.0.0', 'ui': '1.0.0', 'deps': '1.0.0', }], +["mrt:just-i18n", '0.3.0', {'meteor': null, 'underscore': '1.0.0', 'ui': '1.0.0', 'deps': '1.0.0', }], +["mrt:accounts-t9n", '0.0.2', {'meteor': null, 'coffeescript': '1.0.0', 'handlebars': '1.0.0', 'deps': '1.0.0', 'mrt:just-i18n': '0.3.0', }], +["mrt:accounts-t9n", '0.0.3', {'meteor': null, 'coffeescript': '1.0.0', 'handlebars': '1.0.0', 'deps': '1.0.0', }], +["mrt:accounts-t9n", '0.0.4', {'meteor': null, 'coffeescript': '1.0.0', 'handlebars': '1.0.0', 'deps': '1.0.0', }], +["mrt:accounts-t9n", '0.0.7', {'meteor': null, 'coffeescript': '1.0.0', 'handlebars': '1.0.0', 'deps': '1.0.0', }], +["mrt:accounts-t9n", '0.0.10', {'meteor': null, 'coffeescript': '1.0.0', 'handlebars': '1.0.0', 'deps': '1.0.0', }], +["mrt:accounts-t9n", '0.0.11', {'meteor': null, 'coffeescript': '1.0.0', 'handlebars': '1.0.0', 'deps': '1.0.0', }], +["mrt:accounts-t9n", '0.0.12', {'meteor': null, 'coffeescript': '1.0.0', 'handlebars': '1.0.0', 'deps': '1.0.0', }], +["mrt:accounts-t9n", '0.0.13', {'meteor': null, 'coffeescript': '1.0.0', 'handlebars': '1.0.0', 'deps': '1.0.0', }], +["splendido:accounts-templates-core", '0.0.21', {'meteor': null, 'check': '1.0.0', 'deps': '1.0.1', 'accounts-base': '1.0.0', 'mrt:accounts-t9n': '0.0.13', 'iron:router': '0.9.1', 'underscore': '1.0.0', 'minimongo': '1.0.1', 'mongo-livedata': '1.0.3', 'sha': '1.0.0', 'templating': '1.0.4', }], +["splendido:accounts-templates-core", '0.0.22', {'meteor': null, 'check': '1.0.0', 'deps': '1.0.1', 'accounts-base': '1.0.0', 'mrt:accounts-t9n': '0.0.13', 'iron:router': '0.9.1', 'underscore': '1.0.0', 'minimongo': '1.0.1', 'mongo-livedata': '1.0.3', 'sha': '1.0.0', 'templating': '1.0.4', }], +["splendido:accounts-templates-core", '0.0.23', {'meteor': null, 'check': '1.0.0', 'deps': '1.0.1', 'accounts-base': '1.0.0', 'mrt:accounts-t9n': '0.0.13', 'iron:router': '0.9.1', 'underscore': '1.0.0', 'minimongo': '1.0.1', 'mongo-livedata': '1.0.3', 'sha': '1.0.0', 'templating': '1.0.4', }], +["splendido:accounts-templates-core", '0.0.24', {'meteor': null, 'mrt:accounts-t9n': '0.0.13', 'iron:router': '0.9.1', 'check': '1.0.0', 'deps': '1.0.1', 'accounts-base': '1.0.0', 'underscore': '1.0.0', 'minimongo': '1.0.1', 'mongo-livedata': '1.0.3', 'sha': '1.0.0', 'templating': '1.0.4', }], +["splendido:accounts-templates-core", '0.0.25', {'meteor': null, 'mrt:accounts-t9n': '0.0.13', 'iron:router': '0.9.1', 'check': '1.0.0', 'deps': '1.0.1', 'accounts-base': '1.0.0', 'underscore': '1.0.0', 'minimongo': '1.0.1', 'mongo-livedata': '1.0.3', 'sha': '1.0.0', 'templating': '1.0.4', }], +["splendido:accounts-templates-core", '0.0.26', {'meteor': null, 'softwarerero:accounts-t9n': '0.0.17', 'iron:router': '0.9.3', 'check': '1.0.0', 'deps': '1.0.1', 'accounts-base': '1.0.0', 'underscore': '1.0.0', 'minimongo': '1.0.1', 'mongo-livedata': '1.0.3', 'sha': '1.0.0', 'templating': '1.0.4', }], +["softwarerero:accounts-t9n", '0.0.17', {'meteor': null, 'coffeescript': '1.0.2', 'deps': '1.0.1', }], +["softwarerero:accounts-t9n", '0.0.18', {'meteor': null, 'coffeescript': '1.0.2', 'deps': '1.0.1', }], +["softwarerero:accounts-t9n", '0.0.19', {'meteor': null, 'coffeescript': '1.0.2', 'deps': '1.0.1', }], +["softwarerero:accounts-t9n", '0.0.20', {'meteor': null, 'coffeescript': '1.0.2', 'deps': '1.0.1', }], +["softwarerero:accounts-t9n", '1.0.0', {'meteor': null, 'coffeescript': '1.0.2', 'deps': '1.0.1', }], +["softwarerero:accounts-t9n", '1.0.1', {'meteor': null, 'coffeescript': '1.0.2', 'deps': '1.0.1', }], +["softwarerero:accounts-t9n", '1.0.2', {'meteor': null, 'coffeescript': '1.0.2', 'deps': '1.0.1', }], +["splendido:accounts-templates-core", '0.0.27', {'meteor': null, 'softwarerero:accounts-t9n': '0.0.17', 'iron:router': '0.9.3', 'check': '1.0.0', 'deps': '1.0.1', 'accounts-base': '1.0.0', 'underscore': '1.0.0', 'minimongo': '1.0.1', 'mongo-livedata': '1.0.3', 'sha': '1.0.0', 'templating': '1.0.4', }], +["splendido:accounts-templates-core", '0.0.28', {'meteor': null, 'softwarerero:accounts-t9n': '0.0.17', 'iron:router': '0.9.3', 'check': '1.0.0', 'deps': '1.0.1', 'accounts-base': '1.0.0', 'underscore': '1.0.0', 'minimongo': '1.0.1', 'mongo-livedata': '1.0.3', 'sha': '1.0.0', 'templating': '1.0.4', }], +["splendido:accounts-templates-core", '0.9.0', {'meteor': null, 'check': '1.0.0', 'accounts-base': '1.0.1', 'underscore': '1.0.0', 'iron:router': '0.9.3', 'softwarerero:accounts-t9n': '0.0.20', 'blaze': '2.0.0', 'reactive-dict': '1.0.1', 'sha': '1.0.0', 'templating': '1.0.5', }], +["splendido:accounts-templates-core", '0.9.1', {'meteor': null, 'check': '1.0.0', 'accounts-base': '1.0.1', 'underscore': '1.0.0', 'iron:router': '0.9.3', 'softwarerero:accounts-t9n': '0.0.20', 'blaze': '2.0.0', 'reactive-dict': '1.0.1', 'sha': '1.0.0', 'templating': '1.0.5', }], +["splendido:accounts-templates-core", '0.9.2', {'meteor': null, 'accounts-base': '1.1.0', 'check': '1.0.0', 'underscore': '1.0.0', 'softwarerero:accounts-t9n': '0.0.20', 'iron:router': '0.9.3', 'blaze': '2.0.0', 'reactive-dict': '1.0.2', 'sha': '1.0.0', 'templating': '1.0.6', }], +["splendido:accounts-templates-core", '0.9.3', {'meteor': null, 'accounts-base': '1.1.0', 'check': '1.0.0', 'underscore': '1.0.0', 'iron:router': '0.9.3', 'softwarerero:accounts-t9n': '0.0.20', 'blaze': '2.0.0', 'reactive-dict': '1.0.2', 'sha': '1.0.0', 'templating': '1.0.6', }], +["splendido:accounts-templates-core", '0.9.4', {'meteor': null, 'accounts-base': '1.1.0', 'check': '1.0.0', 'underscore': '1.0.0', 'iron:router': '0.9.3', 'softwarerero:accounts-t9n': '0.0.20', 'blaze': '2.0.0', 'reactive-dict': '1.0.2', 'sha': '1.0.0', 'templating': '1.0.6', }], +["splendido:accounts-templates-core", '0.9.5', {'meteor': null, 'accounts-base': '1.1.0', 'check': '1.0.0', 'underscore': '1.0.0', 'iron:router': '0.9.3', 'softwarerero:accounts-t9n': '1.0.0', 'blaze': '2.0.0', 'reactive-dict': '1.0.2', 'sha': '1.0.0', 'templating': '1.0.6', }], +["splendido:accounts-templates-core", '0.9.6', {'meteor': null, 'accounts-base': '1.1.0', 'check': '1.0.0', 'underscore': '1.0.0', 'iron:router': '0.9.3', 'softwarerero:accounts-t9n': '1.0.0', 'blaze': '2.0.0', 'reactive-dict': '1.0.2', 'sha': '1.0.0', 'templating': '1.0.6', }], +["splendido:accounts-templates-core", '0.9.7', {'meteor': null, 'accounts-base': '1.1.0', 'check': '1.0.0', 'underscore': '1.0.0', 'iron:router': '0.9.3', 'softwarerero:accounts-t9n': '1.0.0', 'blaze': '2.0.0', 'reactive-dict': '1.0.2', 'sha': '1.0.0', 'templating': '1.0.6', }], +["splendido:accounts-templates-core", '0.9.8', {'meteor': null, 'accounts-base': '1.1.0', 'check': '1.0.0', 'underscore': '1.0.0', 'iron:router': '0.9.3', 'softwarerero:accounts-t9n': '1.0.0', 'blaze': '2.0.0', 'reactive-dict': '1.0.2', 'sha': '1.0.0', 'templating': '1.0.6', }], +["splendido:accounts-templates-core", '0.9.9', {'meteor': null, 'accounts-base': '1.1.0', 'check': '1.0.0', 'underscore': '1.0.0', 'iron:router': '0.9.3', 'softwarerero:accounts-t9n': '1.0.0', 'blaze': '2.0.0', 'reactive-dict': '1.0.2', 'sha': '1.0.0', 'templating': '1.0.6', }], +["splendido:accounts-templates-core", '0.9.10', {'meteor': null, 'accounts-base': '1.1.0', 'check': '1.0.0', 'underscore': '1.0.0', 'iron:router': '0.9.3', 'softwarerero:accounts-t9n': '1.0.0', 'blaze': '2.0.0', 'reactive-dict': '1.0.2', 'sha': '1.0.0', 'templating': '1.0.6', }], +["splendido:accounts-templates-core", '0.9.11', {'meteor': null, 'accounts-base': '1.1.0', 'check': '1.0.0', 'underscore': '1.0.0', 'iron:router': '0.9.3', 'softwarerero:accounts-t9n': '1.0.0', 'blaze': '2.0.0', 'reactive-dict': '1.0.2', 'sha': '1.0.0', 'templating': '1.0.6', }], +["splendido:accounts-templates-core", '0.9.12', {'meteor': null, 'accounts-base': '1.1.0', 'check': '1.0.0', 'underscore': '1.0.0', 'iron:router': '0.9.3', 'softwarerero:accounts-t9n': '1.0.0', 'blaze': '2.0.0', 'reactive-dict': '1.0.2', 'sha': '1.0.0', 'templating': '1.0.6', }], +["splendido:accounts-templates-core", '0.9.13', {'meteor': null, 'accounts-base': '1.1.0', 'check': '1.0.0', 'underscore': '1.0.0', 'iron:router': '0.9.3', 'softwarerero:accounts-t9n': '1.0.0', 'blaze': '2.0.0', 'reactive-dict': '1.0.2', 'sha': '1.0.0', 'templating': '1.0.6', }], +["splendido:accounts-templates-core", '0.9.14', {'meteor': null, 'accounts-base': '1.1.0', 'check': '1.0.0', 'underscore': '1.0.0', 'iron:router': '0.9.3', 'softwarerero:accounts-t9n': '1.0.0', 'blaze': '2.0.0', 'reactive-dict': '1.0.2', 'sha': '1.0.0', 'templating': '1.0.6', }], +["splendido:accounts-templates-core", '0.9.15', {'meteor': null, 'accounts-base': '1.1.0', 'check': '1.0.0', 'underscore': '1.0.0', 'iron:router': '0.9.3', 'softwarerero:accounts-t9n': '1.0.0', 'blaze': '2.0.0', 'reactive-dict': '1.0.2', 'sha': '1.0.0', 'templating': '1.0.6', }], +["splendido:accounts-templates-core", '0.9.16-iron-v1.1', {'meteor': null, 'accounts-base': '1.1.0', 'check': '1.0.0', 'underscore': '1.0.0', 'iron:router': '1.0.0-pre4', 'softwarerero:accounts-t9n': '1.0.0', 'blaze': '2.0.0', 'reactive-dict': '1.0.2', 'sha': '1.0.0', 'templating': '1.0.6', }], +["splendido:accounts-templates-core", '0.9.16', {'meteor': null, 'accounts-base': '1.1.0', 'check': '1.0.0', 'underscore': '1.0.0', 'iron:router': '0.9.4', 'softwarerero:accounts-t9n': '1.0.0', 'blaze': '2.0.0', 'reactive-dict': '1.0.2', 'sha': '1.0.0', 'templating': '1.0.6', }], +["splendido:accounts-templates-core", '0.10.0', {'meteor': null, 'accounts-base': '1.1.0', 'check': '1.0.0', 'underscore': '1.0.0', 'iron:router': '0.9.4', 'softwarerero:accounts-t9n': '1.0.0', 'blaze': '2.0.0', 'reactive-dict': '1.0.2', 'sha': '1.0.0', 'templating': '1.0.6', }], +["splendido:accounts-templates-core", '0.11.0', {'meteor': null, 'accounts-base': '1.1.0', 'check': '1.0.0', 'underscore': '1.0.0', 'iron:router': '0.9.4', 'softwarerero:accounts-t9n': '1.0.0', 'blaze': '2.0.0', 'reactive-dict': '1.0.2', 'sha': '1.0.0', 'templating': '1.0.6', }], +["less", '1.0.11+local', {'meteor': null, }], +["splendido:accounts-templates-semantic-ui", '0.0.21', {'meteor': null, 'service-configuration': '1.0.0', 'accounts-password': '1.0.0', 'accounts-base': '1.0.0', 'splendido:accounts-templates-core': '0.0.21', 'templating': '1.0.4', 'less': '1.0.5', }], +["splendido:accounts-templates-semantic-ui", '0.0.24', {'meteor': null, 'service-configuration': '1.0.0', 'accounts-password': '1.0.0', 'accounts-base': '1.0.0', 'splendido:accounts-templates-core': '0.0.24', 'templating': '1.0.4', 'less': '1.0.5', }], +["splendido:accounts-templates-semantic-ui", '0.0.25', {'meteor': null, 'service-configuration': '1.0.0', 'accounts-password': '1.0.0', 'accounts-base': '1.0.0', 'splendido:accounts-templates-core': '0.0.25', 'templating': '1.0.4', 'less': '1.0.5', }], +["splendido:accounts-templates-semantic-ui", '0.0.26', {'meteor': null, 'service-configuration': '1.0.0', 'accounts-password': '1.0.0', 'accounts-base': '1.0.0', 'splendido:accounts-templates-core': '0.0.26', 'templating': '1.0.4', 'less': '1.0.5', }], +["splendido:accounts-templates-semantic-ui", '0.0.27', {'meteor': null, 'service-configuration': '1.0.0', 'accounts-password': '1.0.0', 'accounts-base': '1.0.0', 'splendido:accounts-templates-core': '0.0.27', 'templating': '1.0.4', 'less': '1.0.5', }], +["splendido:accounts-templates-semantic-ui", '0.0.28-1', {'meteor': null, 'service-configuration': '1.0.0', 'accounts-password': '1.0.0', 'accounts-base': '1.0.0', 'splendido:accounts-templates-core': '0.0.28', 'templating': '1.0.4', 'less': '1.0.5', }], +["splendido:accounts-templates-semantic-ui", '0.0.28', {'meteor': null, 'service-configuration': '1.0.0', 'accounts-password': '1.0.0', 'accounts-base': '1.0.0', 'splendido:accounts-templates-core': '0.0.28', 'templating': '1.0.4', 'less': '1.0.5', }], +["splendido:accounts-templates-semantic-ui", '0.0.29', {'meteor': null, 'service-configuration': '1.0.0', 'accounts-password': '1.0.0', 'accounts-base': '1.0.0', 'splendido:accounts-templates-core': '0.0.28', 'templating': '1.0.4', 'less': '1.0.5', }], +["splendido:accounts-templates-semantic-ui", '0.0.30', {'meteor': null, 'service-configuration': '1.0.0', 'accounts-password': '1.0.0', 'accounts-base': '1.0.0', 'splendido:accounts-templates-core': '0.0.28', 'templating': '1.0.4', 'less': '1.0.5', }], +["splendido:accounts-templates-semantic-ui", '0.9.4', {'meteor': null, 'splendido:accounts-templates-core': '0.9.4', 'less': '1.0.8', 'templating': '1.0.6', }], +["splendido:accounts-templates-semantic-ui", '0.9.5', {'meteor': null, 'splendido:accounts-templates-core': '0.9.5', 'less': '1.0.8', 'templating': '1.0.6', }], +["splendido:accounts-templates-semantic-ui", '0.9.6', {'meteor': null, 'splendido:accounts-templates-core': '0.9.6', 'less': '1.0.8', 'templating': '1.0.6', }], +["splendido:accounts-templates-semantic-ui", '0.9.7', {'meteor': null, 'splendido:accounts-templates-core': '0.9.7', 'less': '1.0.8', 'templating': '1.0.6', }], +["splendido:accounts-templates-semantic-ui", '0.9.8', {'meteor': null, 'splendido:accounts-templates-core': '0.9.8', 'less': '1.0.8', 'templating': '1.0.6', }], +["splendido:accounts-templates-semantic-ui", '0.9.9', {'meteor': null, 'splendido:accounts-templates-core': '0.9.9', 'less': '1.0.8', 'templating': '1.0.6', }], +["splendido:accounts-templates-semantic-ui", '0.9.10', {'meteor': null, 'splendido:accounts-templates-core': '0.9.10', 'less': '1.0.8', 'templating': '1.0.6', }], +["splendido:accounts-templates-semantic-ui", '0.9.11', {'meteor': null, 'splendido:accounts-templates-core': '0.9.11', 'less': '1.0.8', 'templating': '1.0.6', }], +["splendido:accounts-templates-semantic-ui", '0.9.12', {'meteor': null, 'splendido:accounts-templates-core': '0.9.12', 'less': '1.0.8', 'templating': '1.0.6', }], +["splendido:accounts-templates-semantic-ui", '0.9.13', {'meteor': null, 'splendido:accounts-templates-core': '0.9.13', 'less': '1.0.8', 'templating': '1.0.6', }], +["splendido:accounts-templates-semantic-ui", '0.9.14', {'meteor': null, 'splendido:accounts-templates-core': '0.9.14', 'less': '1.0.8', 'templating': '1.0.6', }], +["splendido:accounts-templates-semantic-ui", '0.9.15', {'meteor': null, 'splendido:accounts-templates-core': '0.9.15', 'less': '1.0.8', 'templating': '1.0.6', }], +["splendido:accounts-templates-semantic-ui", '0.9.16-iron-v1.1', {'meteor': null, 'splendido:accounts-templates-core': '0.9.16-iron-v1.1', 'less': '1.0.8', 'templating': '1.0.6', }], +["splendido:accounts-templates-semantic-ui", '0.9.16', {'meteor': null, 'splendido:accounts-templates-core': '0.9.16', 'less': '1.0.8', 'templating': '1.0.6', }], +["splendido:accounts-templates-semantic-ui", '0.10.0', {'meteor': null, 'splendido:accounts-templates-core': '0.10.0', 'less': '1.0.8', 'templating': '1.0.6', }], +["splendido:accounts-templates-semantic-ui", '0.11.0', {'meteor': null, 'splendido:accounts-templates-core': '0.11.0', 'less': '1.0.8', 'templating': '1.0.6', }], +["u2622:persistent-session", '0.1.0', {'meteor': null, 'amplify': '1.0.0', 'session': '1.0.0', 'underscore': '1.0.0', }], +["amplify", '1.0.0', {'jquery': '1.0.0', 'meteor': '1.0.2', }], +["session", '1.0.4+local', {'meteor': null, 'underscore': null, 'reactive-dict': null, 'ejson': null, 'reload': null, }], +["session", '1.0.0', {'meteor': null, 'underscore': null, 'reactive-dict': null, 'ejson': null, 'reload': null, }], +["u2622:persistent-session", '0.1.1', {'meteor': null, 'amplify': '1.0.0', 'session': '1.0.0', 'underscore': '1.0.0', }], +["u2622:persistent-session", '0.1.2', {'meteor': null, 'amplify': '1.0.0', 'session': '1.0.0', 'underscore': '1.0.0', }], +["u2622:persistent-session", '0.1.3', {'meteor': null, 'jquery': '1.0.0', 'amplify': '1.0.0', 'session': '1.0.0', 'underscore': '1.0.0', }], +["u2622:persistent-session", '0.1.4', {'meteor': null, 'jquery': '1.0.0', 'amplify': '1.0.0', 'session': '1.0.0', 'underscore': '1.0.0', }], +["u2622:persistent-session", '0.2.0', {'meteor': null, 'jquery': '1.0.0', 'amplify': '1.0.0', 'session': '1.0.1', 'underscore': '1.0.0', }], +["u2622:persistent-session", '0.2.1', {'meteor': null, 'jquery': '1.0.0', 'amplify': '1.0.0', 'session': '1.0.1', 'underscore': '1.0.0', }], +["ctl", '1.0.2+local', {'meteor': null, 'underscore': null, 'ddp': null, 'mongo': null, 'ctl-helper': null, 'application-configuration': null, 'follower-livedata': null, }], +["ctl-helper", '1.0.4+local', {'meteor': null, 'logging': null, 'underscore': null, 'ddp': null, 'mongo': null, 'follower-livedata': null, 'application-configuration': null, }], +]); + +testWithResolver(test, resolver, function(t) { + t({ "iron:router": null, + "matb33:collection-hooks": null, + "mizzao:timesync" : null, + "mrt:jquery-ui-sortable": null, + "mrt:moment": null, + "skinnygeek1010:parse-form": null, + "splendido:accounts-templates-semantic-ui": null, + "u2622:persistent-session": null, + "ctl": null }, + {}, {_testing: false}); // use real cost function! +}); + +});*/ diff --git a/packages/constraint-solver/constraint-solver-tests.js b/packages/constraint-solver/constraint-solver-tests.js index 2f023fcf01..bb897c3f3d 100644 --- a/packages/constraint-solver/constraint-solver-tests.js +++ b/packages/constraint-solver/constraint-solver-tests.js @@ -1,3 +1,4 @@ + var makeResolver = function (data) { var Packages = new LocalCollection; var Versions = new LocalCollection; @@ -6,9 +7,6 @@ var makeResolver = function (data) { _.each(data, function (versionDescription) { var packageName = versionDescription.shift(); var version = versionDescription.shift(); - var ecv = (typeof versionDescription[0] === "string" - ? versionDescription.shift() - : PackageVersion.defaultECV(version)); var deps = versionDescription.shift(); if (!Packages.findOne({name: packageName})) { @@ -22,13 +20,12 @@ var makeResolver = function (data) { references: [ { arch: "os" }, { arch: "web.browser"}, - { arch: "web.cordova"}, + { arch: "web.cordova"} ] }; }); Versions.insert({ packageName: packageName, version: version, - earliestCompatibleVersion: ecv, - dependencies: constructedDeps }); + dependencies: constructedDeps }); Builds.insert({ packageName: packageName, version: version, buildArchitectures: "os+web.cordova+web.browser" }); }); @@ -65,23 +62,31 @@ var defaultResolver = makeResolver([ ["sparky-forms", "1.1.2", {"forms": "=1.0.1", "sparkle": "=2.1.1"}], ["sparky-forms", "1.0.0", {"awesome-dropdown": "=1.4.0"}], ["forms", "1.0.1", {"sparkle": "2.1.0", "jquery-widgets": "1.0.0"}], - ["sparkle", "2.1.0", "2.1.0", {"jquery": "1.8.2"}], - ["sparkle", "2.1.1", "2.1.0", {"jquery": "1.8.2"}], + ["sparkle", "2.1.0", {"jquery": "1.8.2"}], + ["sparkle", "2.1.1", {"jquery": "1.8.2"}], ["sparkle", "1.0.0"], ["awesome-dropdown", "1.4.0", {"dropdown": "=1.2.2"}], ["awesome-dropdown", "1.5.0", {"dropdown": "=1.2.2"}], ["dropdown", "1.2.2", {"jquery-widgets": "1.0.0"}], ["jquery-widgets", "1.0.0", {"jquery": "1.8.0", "sparkle": "2.1.1"}], ["jquery-widgets", "1.0.2", {"jquery": "1.8.0", "sparkle": "2.1.1"}], - ["jquery", "1.8.0", "1.8.0"], - ["jquery", "1.8.2", "1.8.0"] + ["jquery", "1.8.0"], + ["jquery", "1.8.2"] ]); -var splitArgs = function (deps) { +// Take a map of `{ dependency: constraint }`, where `dependency` +// is a package name string and `constraint` is a constraint string, +// and return an array of dependencies (package name strings) +// and an array of constraint objects. +// +// If a constraint is prefixed with 'w', the dependency is a weak +// dependency, so it will generate a constraint but not a dependency +// in the returned arrays. +splitArgs = function (deps) { var dependencies = [], constraints = []; _.each(deps, function (constr, dep) { - if (constr && constr[0] === 'w') { + if (constr && constr.charAt(0) === 'w') { constr = constr.slice(1); } else { dependencies.push(dep); @@ -136,6 +141,7 @@ Tinytest.add("constraint solver - simple exact + regular deps", function (test) }); }); + Tinytest.add("constraint solver - non-exact direct dependency", function (test) { testWithResolver(test, defaultResolver, function (t) { // sparky-forms 1.0.0 won't be chosen because it depends on a very old @@ -319,389 +325,3 @@ Tinytest.add("constraint solver - no constraint dependency - transitive dep stil { _testing: true }).answer; test.equal(versions.sparkle, "2.1.1"); }); - -var runBenchmarks = !!process.env.CONSTRAINT_SOLVER_BENCHMARK; - -runBenchmarks && Tinytest.add("constraint solver - benchmark on gems - sinatra", function (test) { - var r = new ConstraintSolver.PackagesResolver(getCatalogStub(sinatraGems)); - - var args = splitArgs({ - 'capistrano': '2.14.2', - 'data-mapper': '1.2.0', - 'dm-core': '1.2.0', - 'dm-sqlite-adapter': '1.2.0', - 'dm-timestamps': '1.2.0', - 'haml': '3.1.7', - 'sass': '3.2.1', - 'shotgun': '0.9.0', - 'sinatra': '1.3.5', - 'sqlite3': '1.3.7' - }); - - r.resolve(args.dependencies, args.constraints); -}); - -// Add a few versions that are referenced by other versions but don't exist. We -// now require referenced versions to exist. -railsGems.push({name: "bcrypt", number: "3.0.0", dependencies: []}); -railsGems.push({name: "mime-types", number: "1.16.0", dependencies: []}); -railsGems.push({"name":"pyu-ruby-sasl","number":"0.3.1","platform":"ruby","dependencies":[]}); -railsGems.push({"name":"backports","number":"3.0.0","platform":"ruby","dependencies":[]}); -railsGems.push({"name":"diff-lcs","number":"1.1.0","platform":"ruby","dependencies":[]}); -var railsCatalog = getCatalogStub(railsGems); -runBenchmarks && Tinytest.add("constraint solver - benchmark on gems - rails", function (test) { - var r = new ConstraintSolver.PackagesResolver(railsCatalog); - - var args = splitArgs({ - 'rails': '4.0.4' - }); - - r.resolve(args.dependencies, args.constraints); -}); - -runBenchmarks && Tinytest.add("constraint solver - benchmark on gems - rails, gitlabhq", function (test) { - var r = new ConstraintSolver.PackagesResolver(railsCatalog); - - var args = splitArgs({ - 'rails': '4.0.0', - 'protected-attributes': null, - 'rails-observers': null, - 'actionpack-page-caching': null, - 'actionpack-action-caching': null, - 'default-value-for': '3.0.0', - 'mysql2': null, - 'devise': '3.0.4', - 'devise-async': '0.8.0', - 'omniauth': '1.1.3', - 'omniauth-google-oauth2': null, - 'omniauth-twitter': null, - 'omniauth-github': null, - 'gitlab-git': '5.7.1', - 'gitlab-grack': '2.0.0', - 'gitlab-omniauth-ldap': '1.0.4', - 'gitlab-gollum-lib': '1.1.0', - 'gitlab-linguist': '3.0.0', - 'grape': '0.6.1', - 'rack-cors': null, - 'email-validator': '1.4.0', - 'stamp': null, - 'enumerize': null, - 'kaminari': '0.15.1', - 'haml-rails': null, - 'carrierwave': null, - 'fog': '1.3.1', - 'six': null, - 'seed-fu': null, - 'redcarpet': '2.2.2', - 'github-markup': null, - 'asciidoctor': null, - 'unicorn': '4.6.3', - 'unicorn-worker-killer': null, - 'state-machine': null, - 'acts-as-taggable-on': null, - 'slim': null, - 'sinatra': null, - 'sidekiq': null, - 'httparty': null, - 'colored': null, - 'settingslogic': null, - 'foreman': null, - 'version-sorter': null, - 'redis-rails': null, - 'tinder': '1.9.2', - 'hipchat': '0.14.0', - 'gemnasium-gitlab-service': '0.2.1', - 'slack-notifier': '0.2.0', - 'd3-rails': '3.1.4', - 'underscore-rails': '1.4.4', - 'sanitize': null, - 'rack-attack': null, - 'ace-rails-ap': null, - 'sass-rails': null, - 'coffee-rails': null, - 'uglifier': null, - 'therubyracer': null, - 'turbolinks': null, - 'jquery-turbolinks': null, - 'select2-rails': null, - 'jquery-atwho-rails': '0.3.3', - 'jquery-rails': '2.1.3', - 'jquery-ui-rails': '2.0.2', - 'modernizr': '2.6.2', - 'raphael-rails': '2.1.2', - 'bootstrap-sass': '3.0.0', - 'font-awesome-rails': '3.2.0', - 'gitlab-emoji': '0.0.1', - 'gon': '5.0.0' - }); - - r.resolve(args.dependencies, args.constraints); -}); - -runBenchmarks && Tinytest.add("constraint solver - benchmark on gems - rails, gitlabhq, additions to the existing smaller solution", function (test) { - var r = new ConstraintSolver.PackagesResolver(railsCatalog); - - var args = splitArgs({ - 'rails': '4.0.0', - 'protected-attributes': null, - 'rails-observers': null, - 'actionpack-page-caching': null, - 'actionpack-action-caching': null, - 'default-value-for': '3.0.0', - 'mysql2': null, - 'devise': '3.0.4', - 'devise-async': '0.8.0', - 'omniauth': '1.1.3', - 'omniauth-google-oauth2': null, - 'omniauth-twitter': null, - 'omniauth-github': null, - 'gitlab-git': '5.7.1', - 'gitlab-grack': '2.0.0', - 'gitlab-omniauth-ldap': '1.0.4', - 'gitlab-gollum-lib': '1.1.0', - 'gitlab-linguist': '3.0.0', - 'grape': '0.6.1', - 'rack-cors': null, - 'email-validator': '1.4.0', - 'stamp': null, - 'enumerize': null, - 'kaminari': '0.15.1', - 'haml-rails': null, - 'carrierwave': null, - 'fog': '1.3.1', - 'six': null, - 'seed-fu': null, - 'redcarpet': '2.2.2', - 'github-markup': null, - 'asciidoctor': null, - 'unicorn': '4.6.3', - 'unicorn-worker-killer': null, - 'state-machine': null, - 'acts-as-taggable-on': null, - 'slim': null, - 'sinatra': null, - 'sidekiq': null, - 'httparty': null, - 'colored': null, - 'settingslogic': null, - 'foreman': null, - 'version-sorter': null, - 'redis-rails': null, - 'tinder': '1.9.2', - 'hipchat': '0.14.0', - 'gemnasium-gitlab-service': '0.2.1', - 'slack-notifier': '0.2.0', - 'd3-rails': '3.1.4', - 'underscore-rails': '1.4.4', - 'sanitize': null, - 'rack-attack': null, - 'ace-rails-ap': null, - 'sass-rails': null, - 'coffee-rails': null, - 'uglifier': null, - 'therubyracer': null, - 'turbolinks': null, - 'jquery-turbolinks': null, - 'select2-rails': null, - 'jquery-atwho-rails': '0.3.3', - 'jquery-rails': '2.1.3', - 'jquery-ui-rails': '2.0.2', - 'modernizr': '2.6.2', - 'raphael-rails': '2.1.2', - 'bootstrap-sass': '3.0.0', - 'font-awesome-rails': '3.2.0', - 'gitlab-emoji': '0.0.1', - 'gon': '5.0.0' - }); - - var previousSolution = { - "actionmailer": "4.0.0", - "actionpack": "4.0.0", - "activemodel": "4.0.0", - "activerecord": "4.0.0", - "activerecord-deprecated-finders": "1.0.3", - "activesupport": "4.0.0", - "arel": "4.0.2", - "asciidoctor": "0.1.4", - "bcrypt": "3.1.7", - "bcrypt-ruby": "3.1.5", - "builder": "3.1.4", - "carrierwave": "0.10.0", - "coffee-rails": "4.0.1", - "coffee-script": "2.2.0", - "coffee-script-source": "1.7.0", - "d3-rails": "3.1.4", - "default-value-for": "3.0.0", - "devise": "3.0.4", - "devise-async": "0.8.0", - "erubis": "2.7.0", - "execjs": "2.0.2", - "faraday": "0.9.0", - "github-markup": "1.1.0", - "haml": "4.0.5", - "haml-rails": "0.5.1", - "hashie": "2.0.3", - "hike": "1.2.3", - "httpauth": "0.2.1", - "i18n": "0.6.9", - "jquery-turbolinks": "2.0.2", - "json": "1.8.1", - "jwt": "0.1.10", - "kaminari": "0.15.1", - "mail": "2.5.4", - "mime-types": "1.25.1", - "minitest": "4.7.5", - "multi-json": "1.9.0", - "multipart-post": "2.0.0", - "oauth": "0.4.7", - "oauth2": "0.8.1", - "omniauth": "1.1.4", - "omniauth-github": "1.0.2", - "omniauth-google-oauth2": "0.2.2", - "omniauth-oauth": "1.0.1", - "omniauth-oauth2": "1.1.1", - "omniauth-twitter": "1.0.1", - "orm-adapter": "0.5.0", - "polyglot": "0.3.4", - "posix-spawn": "0.3.8", - "protected-attributes": "1.0.3", - "rack": "1.5.2", - "rack-test": "0.6.2", - "rails": "4.0.0", - "rails-observers": "0.1.2", - "railties": "4.0.0", - "rake": "10.1.1", - "redcarpet": "2.2.2", - "ref": "1.0.5", - "sass": "3.2.17", - "sass-rails": "4.0.2", - "seed-fu": "2.3.0", - "six": "0.2.0", - "sprockets": "2.11.0", - "sprockets-rails": "2.0.1", - "therubyracer": "0.12.1", - "thor": "0.19.1", - "thread-safe": "0.3.1", - "tilt": "1.4.1", - "treetop": "1.4.15", - "turbolinks": "2.2.0", - "tzinfo": "0.3.39", - "uglifier": "2.5.0", - "warden": "1.2.3" - }; - - var solution = r.resolve(args.dependencies, args.constraints, { previousSolution: previousSolution }).answer; - - // check that root deps are the same - _.each(args.dependencies, function (dep) { - if (previousSolution[dep]) - test.equal(solution[dep], previousSolution[dep], dep); - }); -}); - -// Given a set of gems definitions returns a Catalog-like object -function getCatalogStub (gems) { - return { - getAllPackageNames: function () { - return _.uniq(_.pluck(gems, 'name')); - }, - getPackage: function (name) { - return !!_.findWhere(gems, {name: name}); - }, - getSortedVersions: function (name) { - return _.chain(gems) - .filter(function (pv) { return pv.name === name; }) - .pluck('number') - .map(function (version) { - var nv = exactVersion(version); - if (nv.length < version.length && version.split(".").length === 2) - return version; - return nv; - }) - .filter(function (v) { - return PackageVersion.getValidServerVersion(v); - }) - .sort(PackageVersion.compare) - .uniq(true) - .value(); - }, - getVersion: function (name, version) { - var gem = _.find(gems, function (pv) { - return pv.name === name && exactVersion(pv.number) === version; - }); - - var ecv = function (version) { - // 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 = { - packageName: gem.name, - version: gem.number, - earliestCompatibleVersion: PackageVersion.defaultECV(gem.number), - dependencies: {} - }; - - _.each(gem.dependencies, function (dep) { - var name = dep[0]; - var constraints = dep[1]; - - packageVersion.dependencies[name] = { - constraint: constraints, - references: [{ - "arch": "web" - }, { - "arch": "os" }] - }; - }); - - return packageVersion; - } - }; -} - -// Naively converts ruby-gems style constraints string to either exact -// constraint or a regular constraint. -function convertConstraints (inp) { - var out = inp.split(",").map(function (s) { - return s.trim(); - }) - // remove the constraints we don't support - .filter(function (s) { - return !/ 1.2.3 - // and 0.2 => 0.2.0 - .map(function (s) { - var x = s.split(" "); - return [x[0], exactVersion(x[1])].join(" "); - }) - // convert '= 1.2.3' => '=1.2.3' - // '~>1.2.3' => '1.2.3' - // '>=1.2.3' => '1.2.3' - .map(function (s) { - if (s.indexOf(">= 0") === 0) - return ""; - var x = s.split(' '); - if (x[0] === '~>' || x[0] === '>' || x[0] === '>=') - x[0] = ''; - else if (x[0] === '=') - x[0] = '='; - else - throw new Error('unknown operator: ' + x[0]); - return x.join(""); - }); - - return out; -} - -function exactVersion (s) { - s = s.match(/\d+(\.\d+(\.\d+)?)?/)[0]; - if (s.split('.').length < 3) - s += ".0"; - if (s.split('.').length < 3) - s += ".0"; - return s; -} diff --git a/packages/constraint-solver/constraint-solver.js b/packages/constraint-solver/constraint-solver.js index 052ade40fa..be91c75a07 100644 --- a/packages/constraint-solver/constraint-solver.js +++ b/packages/constraint-solver/constraint-solver.js @@ -1,4 +1,8 @@ // Copied from archinfo.matches() in tools/ +// +// archMatches("os", "os") => true +// archMatches("web.cordova", "web") => true +// archMatches("web.cordova", "web.cordova") => true var archMatches = function (arch, baseArch) { return arch.substr(0, baseArch.length) === baseArch && (arch.length === baseArch.length || @@ -73,8 +77,7 @@ ConstraintSolver.PackagesResolver.prototype._loadPackageInfo = function ( _.each(allArchs, function (arch) { var unitName = packageName + "#" + arch; - unibuilds[unitName] = new ConstraintSolver.UnitVersion( - unitName, version, versionDef.earliestCompatibleVersion); + unibuilds[unitName] = new ConstraintSolver.UnitVersion(unitName, version); self.resolver.addUnitVersion(unibuilds[unitName]); }); @@ -122,19 +125,6 @@ ConstraintSolver.PackagesResolver.prototype._loadPackageInfo = function ( }); }); }); - - // We need to be aware of the earliestCompatibleVersion values for any - // packages that are overridden by local packages, in order to evaluate - // 'compatible-with' constraints that name that version. - // (Some of the test fixtures don't bother to implement this method.) - if (self.catalog.getForgottenECVs) { - _.each(self.catalog.getForgottenECVs(packageName), function (ecv, version) { - _.each(allArchs, function (arch) { - var unitName = packageName + '#' + arch; - self.resolver.addExtraECV(unitName, version, ecv); - }); - }); - } }; // dependencies - an array of string names of packages (not slices) @@ -394,8 +384,7 @@ ConstraintSolver.PackagesResolver.prototype._getResolverOptions = PackageVersion.versionMagnitude(uv.version) - PackageVersion.versionMagnitude(prev.version); - var isCompatible = - prev.earliestCompatibleVersion === uv.earliestCompatibleVersion; + var isCompatible = prev.majorVersion === uv.majorVersion; if (isRootDep[uv.name]) { // root dependency @@ -468,7 +457,7 @@ ConstraintSolver.PackagesResolver.prototype._getResolverOptions = var earliestMatching = mori.first(alternatives); var isCompatible = - prev.earliestCompatibleVersion === earliestMatching.earliestCompatibleVersion; + prev.majorVersion === earliestMatching.majorVersion; if (! isCompatible) { cost[VMAJOR]++; return; diff --git a/packages/constraint-solver/constraints-list.js b/packages/constraint-solver/constraints-list.js index 4b510dcde7..d20abf6777 100644 --- a/packages/constraint-solver/constraints-list.js +++ b/packages/constraint-solver/constraints-list.js @@ -127,7 +127,7 @@ ConstraintSolver.ConstraintsList.prototype.toString = function (options) { strs.push(c.toString({removeUnibuild: options.removeUnibuild})); }); - strs.sort(); + strs = _.uniq(strs); return ""; }; diff --git a/packages/constraint-solver/package.js b/packages/constraint-solver/package.js index e8f5f1c9e0..e6430fc0e5 100644 --- a/packages/constraint-solver/package.js +++ b/packages/constraint-solver/package.js @@ -21,6 +21,7 @@ Package.on_test(function (api) { // data for big benchmarky tests api.add_files('test-data.js', ['server']); api.add_files('constraint-solver-tests.js', ['server']); + api.add_files('benchmark-tests.js', ['server']); api.add_files('resolver-tests.js', ['server']); api.use('underscore'); }); diff --git a/packages/constraint-solver/resolver-tests.js b/packages/constraint-solver/resolver-tests.js index 7abf3a5667..e0283e32f2 100644 --- a/packages/constraint-solver/resolver-tests.js +++ b/packages/constraint-solver/resolver-tests.js @@ -13,16 +13,15 @@ Tinytest.add("constraint solver - resolver, get exact deps", function (test) { // \ \-> D => E // \-> \-> F var resolver = new ConstraintSolver.Resolver(); - var A100 = new ConstraintSolver.UnitVersion("a", "1.0.0", "1.0.0"); - var B100 = new ConstraintSolver.UnitVersion("b", "1.0.0", "1.0.0"); - var C100 = new ConstraintSolver.UnitVersion("c", "1.0.0", "1.0.0"); - var D110 = new ConstraintSolver.UnitVersion("d", "1.1.0", "1.0.0"); - var E100 = new ConstraintSolver.UnitVersion("e", "1.0.0", "1.0.0"); - var F120 = new ConstraintSolver.UnitVersion("f", "1.2.0", "1.0.0"); - // Ensure that the resolver knows that these versions exist and have ECV = - // 1.0.0. - var F100 = new ConstraintSolver.UnitVersion("f", "1.0.0", "1.0.0"); - var F110 = new ConstraintSolver.UnitVersion("f", "1.1.0", "1.0.0"); + var A100 = new ConstraintSolver.UnitVersion("a", "1.0.0"); + var B100 = new ConstraintSolver.UnitVersion("b", "1.0.0"); + var C100 = new ConstraintSolver.UnitVersion("c", "1.0.0"); + var D110 = new ConstraintSolver.UnitVersion("d", "1.1.0"); + var E100 = new ConstraintSolver.UnitVersion("e", "1.0.0"); + var F120 = new ConstraintSolver.UnitVersion("f", "1.2.0"); + // Ensure that the resolver knows that these versions exist. + var F100 = new ConstraintSolver.UnitVersion("f", "1.0.0"); + var F110 = new ConstraintSolver.UnitVersion("f", "1.1.0"); resolver.addUnitVersion(A100); resolver.addUnitVersion(B100); @@ -61,12 +60,12 @@ Tinytest.add("constraint solver - resolver, get exact deps", function (test) { Tinytest.add("constraint solver - resolver, cost function - pick latest", function (test) { var resolver = new ConstraintSolver.Resolver(); - var A100 = new ConstraintSolver.UnitVersion("a", "1.0.0", "1.0.0"); - var A110 = new ConstraintSolver.UnitVersion("a", "1.1.0", "1.0.0"); - var B100 = new ConstraintSolver.UnitVersion("b", "1.0.0", "1.0.0"); - var C100 = new ConstraintSolver.UnitVersion("c", "1.0.0", "1.0.0"); - var C110 = new ConstraintSolver.UnitVersion("c", "1.1.0", "1.0.0"); - var C120 = new ConstraintSolver.UnitVersion("c", "1.2.0", "1.0.0"); + var A100 = new ConstraintSolver.UnitVersion("a", "1.0.0"); + var A110 = new ConstraintSolver.UnitVersion("a", "1.1.0"); + var B100 = new ConstraintSolver.UnitVersion("b", "1.0.0"); + var C100 = new ConstraintSolver.UnitVersion("c", "1.0.0"); + var C110 = new ConstraintSolver.UnitVersion("c", "1.1.0"); + var C120 = new ConstraintSolver.UnitVersion("c", "1.2.0"); resolver.addUnitVersion(A100); resolver.addUnitVersion(A110); @@ -108,11 +107,11 @@ Tinytest.add("constraint solver - resolver, cost function - pick latest", functi Tinytest.add("constraint solver - resolver, cost function - avoid upgrades", function (test) { var resolver = new ConstraintSolver.Resolver(); - var A100 = new ConstraintSolver.UnitVersion("a", "1.0.0", "1.0.0"); - var A110 = new ConstraintSolver.UnitVersion("a", "1.1.0", "1.0.0"); - var B100 = new ConstraintSolver.UnitVersion("b", "1.0.0", "1.0.0"); - var B110 = new ConstraintSolver.UnitVersion("b", "1.1.0", "1.0.0"); - var C100 = new ConstraintSolver.UnitVersion("c", "1.0.0", "1.0.0"); + var A100 = new ConstraintSolver.UnitVersion("a", "1.0.0"); + var A110 = new ConstraintSolver.UnitVersion("a", "1.1.0"); + var B100 = new ConstraintSolver.UnitVersion("b", "1.0.0"); + var B110 = new ConstraintSolver.UnitVersion("b", "1.1.0"); + var C100 = new ConstraintSolver.UnitVersion("c", "1.0.0"); resolver.addUnitVersion(A100); resolver.addUnitVersion(A110); @@ -148,8 +147,8 @@ Tinytest.add("constraint solver - resolver, cost function - avoid upgrades", fun Tinytest.add("constraint solver - resolver, don't pick rcs", function (test) { var resolver = new ConstraintSolver.Resolver(); - var A100 = new ConstraintSolver.UnitVersion("a", "1.0.0", "1.0.0"); - var A100rc1 = new ConstraintSolver.UnitVersion("a", "1.0.0-rc1", "1.0.0"); + var A100 = new ConstraintSolver.UnitVersion("a", "1.0.0"); + var A100rc1 = new ConstraintSolver.UnitVersion("a", "1.0.0-rc1"); resolver.addUnitVersion(A100rc1); resolver.addUnitVersion(A100); diff --git a/packages/constraint-solver/resolver.js b/packages/constraint-solver/resolver.js index 77d318b727..b6d2f2163e 100644 --- a/packages/constraint-solver/resolver.js +++ b/packages/constraint-solver/resolver.js @@ -26,16 +26,6 @@ ConstraintSolver.Resolver = function (options) { // Refs to all constraints. Mapping String -> instance self._constraints = {}; - - // Let's say that we that package P is available from source at version X.Y.Z. - // Then that's the only version that can actually be chosen by the resolver, - // and so it's the only version included as a UnitVersion. But let's say - // another unit depends on it with a 'compatible-with' dependency "@A.B.C". We - // need to be able to figure out the earliestCompatibleVersion of A.B.C, even - // though A.B.C is not a valid (selectable) UnitVersion. We store them here. - // - // Maps String unitName -> String version -> String earliestCompatibleVersion - self._extraECVs = {}; }; ConstraintSolver.Resolver.prototype.addUnitVersion = function (unitVersion) { @@ -86,36 +76,6 @@ ConstraintSolver.Resolver.prototype.getConstraint = new ConstraintSolver.Constraint(name, versionConstraint); }; -ConstraintSolver.Resolver.prototype.addExtraECV = function ( - unitName, version, earliestCompatibleVersion) { - var self = this; - check(unitName, String); - check(version, String); - check(earliestCompatibleVersion, String); - - if (!_.has(self._extraECVs, unitName)) { - self._extraECVs[unitName] = {}; - } - self._extraECVs[unitName][version] = earliestCompatibleVersion; -}; - -ConstraintSolver.Resolver.prototype.getEarliestCompatibleVersion = function ( - unitName, version) { - var self = this; - - var uv = self.getUnitVersion(unitName, version); - if (uv) { - return uv.earliestCompatibleVersion; - } - if (!_.has(self._extraECVs, unitName)) { - return null; - } - if (!_.has(self._extraECVs[unitName], version)) { - return null; - } - return self._extraECVs[unitName][version]; -}; - // options: Object: // - costFunction: function (state, options) - given a state evaluates its cost // - estimateCostFunction: function (state) - given a state, evaluates the @@ -300,12 +260,11 @@ ConstraintSolver.Resolver.prototype._stateNeighbors = function ( // UnitVersion //////////////////////////////////////////////////////////////////////////////// -ConstraintSolver.UnitVersion = function (name, unitVersion, ecv) { +ConstraintSolver.UnitVersion = function (name, unitVersion) { var self = this; check(name, String); check(unitVersion, String); - check(ecv, String); check(self, ConstraintSolver.UnitVersion); self.name = name; @@ -315,7 +274,7 @@ ConstraintSolver.UnitVersion = function (name, unitVersion, ecv) { self.dependencies = []; self.constraints = new ConstraintSolver.ConstraintsList(); // a string in a form of "1.2.0" - self.earliestCompatibleVersion = ecv; + self.majorVersion = PackageVersion.majorVersion(unitVersion); }; _.extend(ConstraintSolver.UnitVersion.prototype, { @@ -369,7 +328,6 @@ ConstraintSolver.Constraint = function (name, versionString) { removeBuildIDs: true, archesOK: true })); - }; ConstraintSolver.Constraint.prototype.toString = function (options) { @@ -437,19 +395,10 @@ ConstraintSolver.Constraint.prototype.isSatisfied = function ( if (PackageVersion.lessThan(candidateUV.version, currConstraint.version)) return false; - var myECV = resolver.getEarliestCompatibleVersion( - self.name, currConstraint.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 - // 1.2.3! - if (!myECV) - return false; - - // To be compatible, the two versions must have the same - // earliestCompatibleVersion. If the earliestCompatibleVersions haven't been - // overridden from their default, this means that the two versions have the - // same major version number. - return myECV === candidateUV.earliestCompatibleVersion; + // To be compatible, the two versions must have the same major version + // number. + return candidateUV.majorVersion === + PackageVersion.majorVersion(currConstraint.version); }); }; diff --git a/packages/ddp/.npm/package/npm-shrinkwrap.json b/packages/ddp/.npm/package/npm-shrinkwrap.json index c4651eb370..df994535c2 100644 --- a/packages/ddp/.npm/package/npm-shrinkwrap.json +++ b/packages/ddp/.npm/package/npm-shrinkwrap.json @@ -1,21 +1,20 @@ { "dependencies": { - "sockjs": { - "version": "0.3.9", + "faye-websocket": { + "version": "0.8.1", "dependencies": { - "node-uuid": { - "version": "1.3.3" - }, - "faye-websocket": { - "version": "0.7.2" + "websocket-driver": { + "version": "0.4.0" } } }, - "tunnel-agent": { - "version": "0.4.0" - }, - "websocket-driver": { - "version": "0.3.6" + "sockjs": { + "version": "0.3.11", + "dependencies": { + "node-uuid": { + "version": "1.4.1" + } + } } } } diff --git a/packages/ddp/package.js b/packages/ddp/package.js index 282995b0af..0530b01cc5 100644 --- a/packages/ddp/package.js +++ b/packages/ddp/package.js @@ -3,18 +3,17 @@ Package.describe({ version: '1.0.11' }); -// We use Faye's 'websocket-driver' for connections in server-to-server DDP, -// mostly because it's the same library used as a server in sockjs, and it's -// easiest to deal with a single websocket implementation. (Plus, its -// maintainer is easy to work with on pull requests.) +// We use 'faye-websocket' for connections in server-to-server DDP, mostly +// because it's the same library used as a server in sockjs, and it's easiest to +// deal with a single websocket implementation. (Plus, its maintainer is easy +// to work with on pull requests.) // -// (By listing websocket-driver first, it's more likely that npm deduplication -// will prevent a second copy of websocket-driver from being installed inside +// (By listing faye-websocket first, it's more likely that npm deduplication +// will prevent a second copy of faye-websocket from being installed inside // sockjs.) Npm.depends({ - "websocket-driver": "0.3.6", - sockjs: "0.3.9", - "tunnel-agent": "0.4.0" + "faye-websocket": "0.8.1", + sockjs: "0.3.11" }); Package.on_use(function (api) { diff --git a/packages/ddp/stream_client_nodejs.js b/packages/ddp/stream_client_nodejs.js index 93e9919a33..6bd8d72435 100644 --- a/packages/ddp/stream_client_nodejs.js +++ b/packages/ddp/stream_client_nodejs.js @@ -36,7 +36,7 @@ _.extend(LivedataTest.ClientStream.prototype, { send: function (data) { var self = this; if (self.currentStatus.connected) { - self.client.messages.write(data); + self.client.send(data); } }, @@ -111,6 +111,17 @@ _.extend(LivedataTest.ClientStream.prototype, { } }, + _getProxyUrl: function (targetUrl) { + var self = this; + // Similar to code in tools/http-helpers.js. + var proxy = process.env.HTTP_PROXY || process.env.http_proxy || null; + // if we're going to a secure url, try the https_proxy env variable first. + if (targetUrl.match(/^wss:/)) { + proxy = process.env.HTTPS_PROXY || process.env.https_proxy || proxy; + } + return proxy; + }, + _launchConnection: function () { var self = this; self._cleanup(); // cleanup the old socket, if there was one. @@ -118,15 +129,24 @@ _.extend(LivedataTest.ClientStream.prototype, { // Since server-to-server DDP is still an experimental feature, we only // require the module if we actually create a server-to-server // connection. - var websocketDriver = Npm.require('websocket-driver'); + var FayeWebSocket = Npm.require('faye-websocket'); + + var targetUrl = toWebsocketUrl(self.endpoint); + var fayeOptions = { headers: self.headers }; + var proxyUrl = self._getProxyUrl(targetUrl); + if (proxyUrl) { + fayeOptions.proxy = { origin: proxyUrl }; + }; // We would like to specify 'ddp' as the subprotocol here. The npm module we // used to use as a client would fail the handshake if we ask for a // subprotocol and the server doesn't send one back (and sockjs doesn't). // Faye doesn't have that behavior; it's unclear from reading RFC 6455 if // Faye is erroneous or not. So for now, we don't specify protocols. - var wsUrl = toWebsocketUrl(self.endpoint); - var client = self.client = websocketDriver.client(wsUrl); + var subprotocols = []; + + var client = self.client = new FayeWebSocket.Client( + targetUrl, subprotocols, fayeOptions); self._clearConnectionTimer(); self.connectionTimer = Meteor.setTimeout( @@ -136,22 +156,6 @@ _.extend(LivedataTest.ClientStream.prototype, { }, self.CONNECT_TIMEOUT); - var onConnect = function () { - client.start(); - }; - var stream = self._createSocket(wsUrl, onConnect); - - if (!self.client) { - // We hit a connection timeout or other issue while yielding in - // _createSocket. Drop the connection. - stream.end(); - return; - } - - _.each(self.headers, function (header, name) { - client.setHeader(name, header); - }); - self.client.on('open', Meteor.bindEnvironment(function () { return self._onConnect(client); }, "stream connect callback")); @@ -165,131 +169,29 @@ _.extend(LivedataTest.ClientStream.prototype, { }, description)); }; - var finalize = Meteor.bindEnvironment(function () { - if (stream.unpipe) { - stream.unpipe(client.io); - } - stream.on('data', function () { - stream.destroy(); - }); - stream.end(); - if (client === self.client) { - self._lostConnection(); - } - }, "finalizing stream"); - - stream.on('end', finalize); - stream.on('close', finalize); - client.on('close', finalize); - - var onError = function (message) { + clientOnIfCurrent('error', 'stream error callback', function (error) { if (!self.options._dontPrintErrors) - Meteor._debug("driver error", message); + Meteor._debug("stream error", error.message); // Faye's 'error' object is not a JS error (and among other things, // doesn't stringify well). Convert it to one. - self._lostConnection(new DDP.ConnectionError(message)); - }; - - clientOnIfCurrent('error', 'driver error callback', function (error) { - onError(error.message); + self._lostConnection(new DDP.ConnectionError(error.message)); + }); + + + clientOnIfCurrent('close', 'stream close callback', function () { + self._lostConnection(); }); - stream.on('error', Meteor.bindEnvironment(function (error) { - if (client === self.client) { - onError('Network error: ' + wsUrl + ': ' + error.message); - } - stream.end(); - })); clientOnIfCurrent('message', 'stream message callback', function (message) { - // Ignore binary frames, where data is a Buffer + // Ignore binary frames, where message.data is a Buffer if (typeof message.data !== "string") return; + _.each(self.eventCallbacks.message, function (callback) { callback(message.data); }); }); - - stream.pipe(self.client.io); - self.client.io.pipe(stream); - }, - - _createSocket: function (wsUrl, onConnect) { - var self = this; - var urlModule = Npm.require('url'); - var parsedTargetUrl = urlModule.parse(wsUrl); - var targetUrlPort = +parsedTargetUrl.port; - if (!targetUrlPort) { - targetUrlPort = parsedTargetUrl.protocol === 'wss:' ? 443 : 80; - } - - // Corporate proxy tunneling support. - var proxyUrl = self._getProxyUrl(parsedTargetUrl.protocol); - if (proxyUrl) { - var targetProtocol = - (parsedTargetUrl.protocol === 'wss:' ? 'https' : 'http'); - var parsedProxyUrl = urlModule.parse(proxyUrl); - var proxyProtocol = - (parsedProxyUrl.protocol === 'https:' ? 'Https' : 'Http'); - var proxyUrlPort = +parsedProxyUrl.port; - if (!proxyUrlPort) { - proxyUrlPort = parsedProxyUrl.protocol === 'https:' ? 443 : 80; - } - var tunnelFnName = targetProtocol + 'Over' + proxyProtocol; - var tunnelAgent = Npm.require('tunnel-agent'); - var proxyOptions = { - host: parsedProxyUrl.hostname, - port: proxyUrlPort, - headers: { - host: parsedTargetUrl.host + ':' + targetUrlPort - } - }; - if (parsedProxyUrl.auth) { - proxyOptions.proxyAuth = Npm.require('querystring').unescape( - parsedProxyUrl.auth); - } - var tunneler = tunnelAgent[tunnelFnName]({proxy: proxyOptions}); - var events = Npm.require('events'); - var fakeRequest = new events.EventEmitter(); - var Future = Npm.require('fibers/future'); - var fut = new Future; - fakeRequest.on('error', function (e) { - fut.isResolved() || fut.throw(e); - }); - tunneler.createSocket({ - host: parsedTargetUrl.host, - port: targetUrlPort, - request: fakeRequest - }, function (socket) { - socket.on('close', function () { - tunneler.removeSocket(socket); - }); - process.nextTick(onConnect); - fut.return(socket); - }); - return fut.wait(); - } - - if (parsedTargetUrl.protocol === 'wss:') { - return Npm.require('tls').connect( - targetUrlPort, parsedTargetUrl.hostname, onConnect); - } else { - var stream = Npm.require('net').createConnection( - targetUrlPort, parsedTargetUrl.hostname); - stream.on('connect', onConnect); - return stream; - } - }, - - _getProxyUrl: function (protocol) { - var self = this; - // Similar to code in tools/http-helpers.js. - var proxy = process.env.HTTP_PROXY || process.env.http_proxy || null; - // if we're going to a secure url, try the https_proxy env variable first. - if (protocol === 'wss:') { - proxy = process.env.HTTPS_PROXY || process.env.https_proxy || proxy; - } - return proxy; } }); diff --git a/packages/ddp/stream_tests.js b/packages/ddp/stream_tests.js index 0e2df75316..b9168b0bd8 100644 --- a/packages/ddp/stream_tests.js +++ b/packages/ddp/stream_tests.js @@ -148,7 +148,7 @@ testAsyncMulti("stream - /websocket is a websocket endpoint", [ _.each(['/websocket', '/websocket/'], function(path) { HTTP.get(Meteor._relativeToSiteRootUrl(path), expect(function(error, result) { test.isNotNull(error); - test.equal('Can "Upgrade" only to "WebSocket".', result.content); + test.equal('Not a valid websocket request', result.content); })); }); @@ -164,12 +164,12 @@ testAsyncMulti("stream - /websocket is a websocket endpoint", [ test.equal(pageContent, result.content); }); - HTTP.get(Meteor._relativeToSiteRootUrl('/'), expect(function(error, result) { + HTTP.get(Meteor.absoluteUrl('/'), expect(function(error, result) { test.isNull(error); pageContent = result.content; _.each(['/websockets', '/websockets/'], function(path) { - HTTP.get(Meteor._relativeToSiteRootUrl(path), wrappedCallback); + HTTP.get(Meteor.absoluteUrl(path), wrappedCallback); }); })); } diff --git a/packages/package-version-parser/package-version-parser-tests.js b/packages/package-version-parser/package-version-parser-tests.js index 9124914e14..aec7591021 100644 --- a/packages/package-version-parser/package-version-parser-tests.js +++ b/packages/package-version-parser/package-version-parser-tests.js @@ -136,7 +136,7 @@ Tinytest.add("Smart Package version string parsing - or", function (test) { FAIL("foo@1.0.0-rc|1.0.0"); // This is the current implementation, but is arguably not great. - FAIL("foo@1.0.0 "); + FAIL("foo@1.0.0 "); // trailing space }); Tinytest.add( diff --git a/scripts/generate-dev-bundle.sh b/scripts/generate-dev-bundle.sh index 9bfc24adda..b2935035ee 100755 --- a/scripts/generate-dev-bundle.sh +++ b/scripts/generate-dev-bundle.sh @@ -71,6 +71,54 @@ umask 022 mkdir build cd build +TEMP_PREFIX="$DIR/build/prefix" +mkdir -p $TEMP_PREFIX + +# Add $DIR/bin and $TEMP_PREFIX/bin to $PATH so that we can use tools +# installed earlier when building later tools (namely, autoconf and +# automake for watchman, and node and npm for the various NPM packages we +# install below). +export PATH="$DIR/bin:$PATH" +PATH="$TEMP_PREFIX/bin:$PATH" + +# Build reliable versions of m4, autoconf, and automake for watchman and +# potentially other projects. + +M4_VERSION="1.4.17" +curl "http://ftp.gnu.org/gnu/m4/m4-$M4_VERSION.tar.gz" | gzip -d | tar x +pushd "m4-$M4_VERSION" +./configure --prefix="$TEMP_PREFIX" +make install +popd + +AUTOCONF_VERSION="2.69" +curl "http://ftp.gnu.org/gnu/autoconf/autoconf-$AUTOCONF_VERSION.tar.gz" | gzip -d | tar x +pushd "autoconf-$AUTOCONF_VERSION" +./configure --prefix="$TEMP_PREFIX" +make install +popd + +AUTOMAKE_VERSION="1.14" +curl "http://ftp.gnu.org/gnu/automake/automake-$AUTOMAKE_VERSION.tar.gz" | gzip -d | tar x +pushd "automake-$AUTOMAKE_VERSION" +./configure --prefix="$TEMP_PREFIX" +make install +popd + +WATCHMAN_VERSION="3.0.0" +curl "https://codeload.github.com/facebook/watchman/tar.gz/v$WATCHMAN_VERSION" | gzip -d | tar x +pushd "watchman-$WATCHMAN_VERSION" +./autogen.sh +./configure --prefix="$DIR" --without-pcre +make install +strip "$DIR/bin/watchman" +popd + +# Clean up some unnecessary megabytes of docs. +rm -rf "$DIR/share/doc" "$DIR/share/man" + +which watchman + # ios-sim is used to run iPhone simulator from the command-line. Doesn't make # sense to build it for linux. if [ "$OS" == "osx" ]; then @@ -110,9 +158,6 @@ make install PORTABLE=1 # PORTABLE=1 is a node hack to make npm look relative to itself instead # of hard coding the PREFIX. -# export path so we use our new node for later builds -export PATH="$DIR/bin:$PATH" - which node which npm @@ -180,6 +225,8 @@ rm -rf node_modules/browserstack-webdriver/lib/test npm install node-inspector@0.7.4 +npm install sane@1.0.0-rc1 + npm install chalk@0.5.1 npm install sqlite3@3.0.2 diff --git a/tools/builder.js b/tools/builder.js index 620bb37a90..c25cd0a3a2 100644 --- a/tools/builder.js +++ b/tools/builder.js @@ -1,18 +1,10 @@ var path = require('path'); -var files = require(path.join(__dirname, 'files.js')); var watch = require('./watch.js'); var files = require('./files.js'); var NpmDiscards = require('./npm-discards.js'); var fs = require('fs'); var _ = require('underscore'); -var sha1 = function (contents) { - var crypto = require('crypto'); - var hash = crypto.createHash('sha1'); - hash.update(contents); - return hash.digest('hex'); -}; - // Builder encapsulates much of the file-handling logic need to create // "bundles" (directory trees such as site archives, programs, or // packages). It can create a temporary directory in which to build @@ -499,7 +491,4 @@ _.extend(Builder.prototype, { } }); -// static convenience method -Builder.sha1 = sha1; - module.exports = Builder; diff --git a/tools/bundler.js b/tools/bundler.js index 957dcce6b1..4949667e06 100644 --- a/tools/bundler.js +++ b/tools/bundler.js @@ -293,7 +293,7 @@ _.extend(File.prototype, { hash: function () { var self = this; if (! self._hash) - self._hash = Builder.sha1(self.contents()); + self._hash = watch.sha1(self.contents()); return self._hash; }, @@ -1171,7 +1171,7 @@ _.extend(ClientTarget.prototype, { path: dataFile, where: 'internal', type: type, - hash: Builder.sha1(dataBuffer) + hash: watch.sha1(dataBuffer) }); } }); @@ -1449,7 +1449,7 @@ _.extend(JsImage.prototype, { loadItem.assets = {}; _.each(item.assets, function (data, relPath) { - var sha = Builder.sha1(data); + var sha = watch.sha1(data); if (_.has(assetFilesBySha, sha)) { loadItem.assets[relPath] = assetFilesBySha[sha]; } else { diff --git a/tools/catalog-local.js b/tools/catalog-local.js index 1e4e0f2819..22ddbed12d 100644 --- a/tools/catalog-local.js +++ b/tools/catalog-local.js @@ -332,7 +332,6 @@ _.extend(LocalCatalog.prototype, { testName: packageSource.testName, version: version, publishedBy: null, - earliestCompatibleVersion: packageSource.earliestCompatibleVersion, description: packageSource.metadata.summary, dependencies: packageSource.getDependencyMetadata(), source: null, diff --git a/tools/catalog.js b/tools/catalog.js index 94e96c30d8..2c0d8c9ced 100644 --- a/tools/catalog.js +++ b/tools/catalog.js @@ -32,7 +32,7 @@ catalog.Refresh.OnceAtStart.prototype.beforeCommand = function () { if (self.options.ignoreErrors) { Console.debug("Failed to update package catalog, but will continue."); } else { - Console.error(catalog.refreshError); + Console.printError(catalog.refreshError); Console.error("This command requires an up-to-date package catalog. Exiting."); // Avoid circular dependency. throw new (require('./main.js').ExitWithCode)(1); @@ -161,22 +161,6 @@ _.extend(LayeredCatalog.prototype, { return self.otherCatalog[f].apply(self.otherCatalog, splittedArgs); }, - // Returns the map from version to earliestCompatibleVersion for all versions - // overridden by a local package. If there's no local package, returns an - // empty object. - getForgottenECVs: function (packageName) { - var self = this; - if (! self.localCatalog.getPackage(packageName)) - return {}; - var versions = self.otherCatalog.getSortedVersions(packageName); - var forgottenECVs = {}; - _.each(versions, function (v) { - var vr = self.otherCatalog.getVersion(packageName, v); - forgottenECVs[v] = vr.earliestCompatibleVersion; - }); - return forgottenECVs; - }, - // Doesn't download packages. Downloading should be done at the time // that .meteor/versions is updated. getLoadPathForPackage: function (name, version, constraintSolverOpts) { diff --git a/tools/commands-packages.js b/tools/commands-packages.js index de1bc68b7a..0ca9b36710 100644 --- a/tools/commands-packages.js +++ b/tools/commands-packages.js @@ -2714,57 +2714,6 @@ main.registerCommand({ }); -main.registerCommand({ - name: 'admin set-earliest-compatible-version', - minArgs: 2, - maxArgs: 2, - catalogRefresh: new catalog.Refresh.OnceAtStart({ ignoreErrors: false }) -}, function (options) { - - // We want the most recent information. - //refreshOfficialCatalogOrDie(); - var package = options.args[0].split('@'); - var name = package[0]; - var version = package[1]; - if (!version) { - Console.error('\n Must specify release version (track@version)'); - return 1; - } - var ecv = options.args[1]; - - // Now let's get down to business! Fetching the thing. - var record = catalog.official.getPackage(name); - if (!record) { - Console.error('\n There is no package named ' + name); - return 1; - } - - try { - var conn = packageClient.loggedInPackagesConnection(); - } catch (err) { - packageClient.handlePackageServerConnectionError(err); - return 1; - } - - try { - Console.info( - "Setting earliest compatible version on " - + options.args[0] + " to " + ecv + "..."); - var versionInfo = { name : name, - version : version }; - packageClient.callPackageServer(conn, - '_setEarliestCompatibleVersion', versionInfo, ecv); - Console.info("Done!"); - } catch (err) { - packageClient.handlePackageServerConnectionError(err); - return 1; - } - conn.close(); - refreshOfficialCatalogOrDie(); - - return 0; -}); - main.registerCommand({ name: 'admin change-homepage', minArgs: 2, diff --git a/tools/commands.js b/tools/commands.js index 447a8751b7..96c05c505f 100644 --- a/tools/commands.js +++ b/tools/commands.js @@ -727,7 +727,10 @@ var buildCommand = function (options) { var localPath = path.join(options.appDir, '.meteor', 'local'); - var mobilePlatforms = project.getCordovaPlatforms(); + var mobilePlatforms = []; + if (! options._serverOnly) { + mobilePlatforms = project.getCordovaPlatforms(); + } var appName = path.basename(options.appDir); if (! _.isEmpty(mobilePlatforms) && ! options._serverOnly) { @@ -777,27 +780,22 @@ var buildCommand = function (options) { var buildDir = path.join(localPath, 'build_tar'); var outputPath = path.resolve(options.args[0]); // get absolute path - if (! _.isEmpty(mobilePlatforms)) { - // XXX: Create helper function? Maybe fs.resolve to follow symlinks? - var appDir = path.resolve(options.appDir); - if (appDir.substr(-1) !== path.sep) { - appDir += path.sep; - } - var outputDir = path.resolve(outputPath); - if (outputDir.substr(-1) !== path.sep) { - outputDir += path.sep; - } - - if (outputDir.indexOf(appDir) == 0) { + // Unless we're just making a tarball, warn if people try to build inside the + // app directory. + if (options.directory || ! _.isEmpty(mobilePlatforms)) { + var relative = path.relative(options.appDir, outputPath); + // We would like the output path to be outside the app directory, which + // means the first step to getting there is going up a level. + if (relative.substr(0, 3) !== ('..' + path.sep)) { Console.warn(""); Console.warn("Warning: The output directory is under your source tree."); - Console.warn(" This causes issues when building with mobile platforms."); + Console.warn(" Your generated files may get interpreted as source code!"); Console.warn(" Consider building into a different directory instead (" + Console.command("meteor build ../output") + ")"); Console.warn(""); } } - var bundlePath = options['directory'] ? + var bundlePath = options.directory ? (options._serverOnly ? outputPath : path.join(outputPath, 'bundle')) : path.join(buildDir, 'bundle'); @@ -841,7 +839,7 @@ var buildCommand = function (options) { if (! options._serverOnly) files.mkdir_p(outputPath); - if (! options['directory']) { + if (! options.directory) { try { var outputTar = options._serverOnly ? outputPath : path.join(outputPath, appName + '.tar.gz'); diff --git a/tools/compiler.js b/tools/compiler.js index e69d01f702..877e5f9f9b 100644 --- a/tools/compiler.js +++ b/tools/compiler.js @@ -1057,7 +1057,6 @@ compiler.compile = function (packageSource, options) { name: packageSource.name, metadata: packageSource.metadata, version: packageSource.version, - earliestCompatibleVersion: packageSource.earliestCompatibleVersion, isTest: packageSource.isTest, plugins: plugins, pluginWatchSet: pluginWatchSet, diff --git a/tools/console.js b/tools/console.js index c6ad9007b3..9fa07e8a4c 100644 --- a/tools/console.js +++ b/tools/console.js @@ -516,12 +516,42 @@ _.extend(Console.prototype, { setPretty: function (pretty) { var self = this; - if (FORCE_PRETTY === undefined) { - self._pretty = pretty; - } + // If we're being forced, do nothing. + if (FORCE_PRETTY !== undefined) + return; + // If no change, do nothing. + if (self._pretty === pretty) + return; + self._pretty = pretty; self._updateProgressDisplay(); }, + // Runs f with the progress display visible (ie, with progress display enabled + // and pretty). Resets both flags to their original values after f runs. + withProgressDisplayVisible: function (f) { + var self = this; + var originalPretty = self._pretty; + var originalProgressDisplayEnabled = self._progressDisplayEnabled; + + // Turn both flags on. + self._pretty = self._progressDisplayEnabled = true; + + // Update the screen if anything changed. + if (!originalPretty || !originalProgressDisplayEnabled) + self._updateProgressDisplay(); + + try { + return f(); + } finally { + // Reset the flags. + self._pretty = originalPretty; + self._progressDisplayEnabled = originalProgressDisplayEnabled; + // Update the screen if anything changed. + if (!originalPretty || !originalProgressDisplayEnabled) + self._updateProgressDisplay(); + } + }, + setVerbose: function (verbose) { var self = this; self.verbose = verbose; @@ -745,6 +775,9 @@ _.extend(Console.prototype, { enabled = true; } + if (self._progressDisplayEnabled === enabled) + return; + self._progressDisplayEnabled = enabled; self._updateProgressDisplay(); }, diff --git a/tools/isopack.js b/tools/isopack.js index e98b2dd39d..b3a94629b7 100644 --- a/tools/isopack.js +++ b/tools/isopack.js @@ -234,7 +234,6 @@ var Isopack = function () { self.name = null; self.metadata = {}; self.version = null; - self.earliestCompatibleVersion = null; self.isTest = false; self.debugOnly = false; @@ -311,7 +310,6 @@ _.extend(Isopack.prototype, { self.name = options.name; self.metadata = options.metadata; self.version = options.version; - self.earliestCompatibleVersion = options.earliestCompatibleVersion; self.isTest = options.isTest; self.plugins = options.plugins; self.cordovaDependencies = options.cordovaDependencies; @@ -637,7 +635,6 @@ _.extend(Isopack.prototype, { summary: mainJson.summary }; self.version = mainJson.version; - self.earliestCompatibleVersion = mainJson.earliestCompatibleVersion; self.isTest = mainJson.isTest; self.debugOnly = !!mainJson.debugOnly; } @@ -727,8 +724,6 @@ _.extend(Isopack.prototype, { JSON.stringify(resource.type)); }); - self.cordovaDependencies = mainJson.cordovaDependencies || null; - self.unibuilds.push(new Unibuild(self, { name: unibuildMeta.name, arch: unibuildMeta.arch, @@ -738,11 +733,12 @@ _.extend(Isopack.prototype, { nodeModulesPath: nodeModulesPath, prelinkFiles: prelinkFiles, packageVariables: unibuildJson.packageVariables || [], - resources: resources, - cordovaDependencies: unibuildJson.cordovaDependencies + resources: resources })); }); + self.cordovaDependencies = mainJson.cordovaDependencies || null; + _.each(mainJson.tools, function (toolMeta) { toolMeta.rootDir = dir; // XXX check for overlap @@ -775,7 +771,6 @@ _.extend(Isopack.prototype, { name: self.name, summary: self.metadata.summary, version: self.version, - earliestCompatibleVersion: self.earliestCompatibleVersion, isTest: self.isTest, builds: [], plugins: [] @@ -812,8 +807,7 @@ _.extend(Isopack.prototype, { pluginProviderPackages: self.pluginProviderPackageDirs, source: options.buildOfPath || undefined, buildTimeDirectDependencies: buildTimeDirectDeps, - buildTimePluginDependencies: buildTimePluginDeps, - cordovaDependencies: self.cordovaDependencies + buildTimePluginDependencies: buildTimePluginDeps }; } diff --git a/tools/main.js b/tools/main.js index a7f0a09874..cd851d7f55 100644 --- a/tools/main.js +++ b/tools/main.js @@ -371,22 +371,18 @@ var springboard = function (rel, options) { // XXX split better try { - Console.setPretty(true); - Console.enableProgressDisplay(true); - - buildmessage.enterJob({ - title: "Downloading tools package " + toolsPkg + "@" + toolsVersion - }, function () { - tropohouse.default.maybeDownloadPackageForArchitectures({ - packageName: toolsPkg, - version: toolsVersion, - architectures: [archinfo.host()], - definitelyNotLocal: true + Console.withProgressDisplayVisible(function () { + buildmessage.enterJob({ + title: "Downloading tools package " + toolsPkg + "@" + toolsVersion + }, function () { + tropohouse.default.maybeDownloadPackageForArchitectures({ + packageName: toolsPkg, + version: toolsVersion, + architectures: [archinfo.host()], + definitelyNotLocal: true + }); }); }); - - Console.enableProgressDisplay(false); - Console.setPretty(false); } catch (err) { // We have failed to download the tool that we are supposed to springboard // to! That's bad. Let's exit. @@ -795,11 +791,9 @@ Fiber(function () { // Somehow we have a catalog that doesn't have any releases on the // default track. Try syncing, at least. (This is a pretty unlikely // error case, since you should always start with a non-empty catalog.) - Console.setPretty(true); - Console.enableProgressDisplay(true); - alreadyRefreshed = catalog.refreshOrWarn(); - Console.enableProgressDisplay(false); - Console.setPretty(false); + Console.withProgressDisplayVisible(function () { + alreadyRefreshed = catalog.refreshOrWarn(); + }); releaseName = release.latestKnown(); } if (!releaseName) { @@ -855,11 +849,9 @@ Fiber(function () { } // ATTEMPT 3: modern release, troposphere sync needed. - Console.setPretty(true); - Console.enableProgressDisplay(true); - alreadyRefreshed = catalog.refreshOrWarn(); - Console.enableProgressDisplay(false); - Console.setPretty(false); + Console.withProgressDisplayVisible(function () { + alreadyRefreshed = catalog.refreshOrWarn(); + }); // Try to load the release even if the refresh failed, since it might // have failed on a later page than the one we needed. @@ -1296,7 +1288,6 @@ commandName + ": You're not in a Meteor project directory.\n" + require('./profile-require.js').printReport(); Console.setPretty(command.pretty); - Console.enableProgressDisplay(true); // Run the command! diff --git a/tools/package-client.js b/tools/package-client.js index 6e164cd9de..15a62d6759 100644 --- a/tools/package-client.js +++ b/tools/package-client.js @@ -580,7 +580,6 @@ exports.publishPackage = function (packageSource, compileResult, conn, options) version: version, description: packageSource.metadata.summary, git: packageSource.metadata.git, - earliestCompatibleVersion: packageSource.earliestCompatibleVersion, compilerVersion: compiler.BUILT_BY, containsPlugins: packageSource.containsPlugins(), debugOnly: packageSource.debugOnly, diff --git a/tools/package-source.js b/tools/package-source.js index ad2f7ab50a..fd507fee8b 100644 --- a/tools/package-source.js +++ b/tools/package-source.js @@ -223,10 +223,6 @@ var PackageSource = function (catalog) { // with names have versions? certainly the reverse is true self.version = null; - // The earliest version for which this package is supposed to be a - // compatible replacement. Set if and only if version is set. - self.earliestCompatibleVersion = null; - // Available architectures of this package. Array of SourceArch. self.architectures = []; @@ -452,7 +448,7 @@ _.extend(PackageSource.prototype, { var packageJsPath = path.join(self.sourceRoot, 'package.js'); var code = fs.readFileSync(packageJsPath); - var packageJsHash = Builder.sha1(code); + var packageJsHash = watch.sha1(code); var releaseRecords = []; var hasTests = false; @@ -476,7 +472,6 @@ _.extend(PackageSource.prototype, { // Set package metadata. Options: // - summary: for 'meteor list' & package server // - version: package version string - // - earliestCompatibleVersion: version string // There used to be a third option documented here, // 'environments', but it was never implemented and no package // ever used it. @@ -510,8 +505,6 @@ _.extend(PackageSource.prototype, { // XXX validate that version parses -- and that it doesn't // contain a +! self.version = value; - } else if (key === "earliestCompatibleVersion") { - self.earliestCompatibleVersion = value; } else if (key === "name" && !self.isTest) { if (!self.name) { self.name = value; @@ -970,11 +963,6 @@ _.extend(PackageSource.prototype, { } } - if (self.version !== null && ! self.earliestCompatibleVersion) { - self.earliestCompatibleVersion = - packageVersionParser.defaultECV(self.version); - } - // source files used var sources = {}; diff --git a/tools/package-version-parser.js b/tools/package-version-parser.js index 0f0449b729..d22ce475b3 100644 --- a/tools/package-version-parser.js +++ b/tools/package-version-parser.js @@ -90,7 +90,7 @@ var prereleaseIdentifierToFraction = function (prerelease) { if (prerelease.length === 0) return 0; - return _.reduce(prerelease, function (memo, part, index) { + return __.reduce(prerelease, function (memo, part, index) { var digit; if (typeof part === 'number') { digit = part+1; @@ -124,16 +124,18 @@ PV.lessThan = function (versionOne, versionTwo) { return PV.compare(versionOne, versionTwo) < 0; }; -// Given a string version, computes its default ECV (not counting any overrides). +// Given a string version, returns its major version (the first section of the +// semver), as an integer. Two versions are compatible if they have the same +// version number. // // versionString: valid meteor version string. -PV.defaultECV = function (versionString) { +PV.majorVersion = function (versionString) { var version = extractSemverPart(versionString).semver; var parsed = semver.parse(version); if (! parsed) - throwVersionParserError("not a valid version: " + version); - return parsed.major + ".0.0"; -} + throwVersionParserError("not a valid version: " + version); + return parsed.major; +}; // Takes in two meteor versions. Returns 0 if equal, 1 if v1 is greater, -1 if // v2 is greater. diff --git a/tools/project.js b/tools/project.js index 5957f7bb21..bee85601f6 100644 --- a/tools/project.js +++ b/tools/project.js @@ -430,8 +430,9 @@ _.extend(Project.prototype, { if (!oldVersion) { return; } - var oldECV = oldVersion.earliestCompatibleVersion; - if (oldECV !== newRec.earliestCompatibleVersion) { + var oldMajorVersion = packageVersionParser.majorVersion(oldV); + var newMajorVersion = packageVersionParser.majorVersion(newV); + if (oldMajorVersion !== newMajorVersion) { incompatibleUpdates.push({ name: package, description: "(" + oldV + "->" + newV + ") " + newRec.description diff --git a/tools/selftest.js b/tools/selftest.js index 427d35a5b2..ed5a8d1834 100644 --- a/tools/selftest.js +++ b/tools/selftest.js @@ -682,7 +682,6 @@ _.extend(Sandbox.prototype, { stubCatalog.collections.versions.push({ packageName: toolPackageName, version: toolPackage.version, - earliestCompatibleVersion: toolPackage.version, containsPlugins: false, description: toolPackage.metadata.summary, dependencies: {}, @@ -758,7 +757,6 @@ _.extend(Sandbox.prototype, { stubCatalog.collections.versions.push({ packageName: name, version: versionRec.version, - earliestCompatibleVersion: versionRec.earliestCompatibleVersion, containsPlugins: false, description: "warehouse test", dependencies: {}, diff --git a/tools/tropohouse.js b/tools/tropohouse.js index d06a4ccbe2..01ce765da8 100644 --- a/tools/tropohouse.js +++ b/tools/tropohouse.js @@ -57,7 +57,8 @@ _.extend(exports.Tropohouse.prototype, { } var relativePath = path.join(config.getPackagesDirectoryName(), - packageName, version); + utils.escapePackageNameForPath(packageName), + version); return relative ? relativePath : path.join(self.root, relativePath); }, @@ -70,7 +71,7 @@ _.extend(exports.Tropohouse.prototype, { var packageRootDir = path.join(self.root, packagesDirectoryName); try { - var packages = fs.readdirSync(packageRootDir); + var escapedPackages = fs.readdirSync(packageRootDir); } catch (e) { // No packages at all? We're done. if (e.code === 'ENOENT') @@ -80,9 +81,9 @@ _.extend(exports.Tropohouse.prototype, { // We want to be careful not to break the 'meteor' symlink inside the // tropohouse. Hopefully nobody deleted/modified that package! - var latestToolPackage = null; + var latestToolPackageEscaped = null; var latestToolVersion = null; - var currentToolPackage = null; + var currentToolPackageEscaped = null; var currentToolVersion = null; // Warning: we can't examine release.current here, because we might be // currently processing release.load! @@ -91,7 +92,8 @@ _.extend(exports.Tropohouse.prototype, { // /home/user/.meteor/packages/meteor-tool/.1.0.17.ut200e++os.osx.x86_64+web.browser+web.cordova/meteor-tool-os.osx.x86_64 var toolsDir = files.getCurrentToolsDir(); // eg, 'meteor-tool' - currentToolPackage = path.basename(path.dirname(path.dirname(toolsDir))); + currentToolPackageEscaped = + path.basename(path.dirname(path.dirname(toolsDir))); // eg, '.1.0.17-xyz1.2.ut200e++os.osx.x86_64+web.browser+web.cordova' var toolVersionDir = path.basename(path.dirname(toolsDir)); var toolVersionWithDotAndRandomBit = toolVersionDir.split('++')[0]; @@ -104,13 +106,13 @@ _.extend(exports.Tropohouse.prototype, { packagesDirectoryName + path.sep)) { var rest = latestMeteorSymlink.substr(packagesDirectoryName.length + path.sep.length); var pieces = rest.split(path.sep); - latestToolPackage = pieces[0]; + latestToolPackageEscaped = pieces[0]; latestToolVersion = pieces[1]; } } - _.each(packages, function (package) { - var packageDir = path.join(packageRootDir, package); + _.each(packagesEscaped, function (packageEscaped) { + var packageDir = path.join(packageRootDir, packageEscaped); try { var versions = fs.readdirSync(packageDir); } catch (e) { @@ -119,7 +121,7 @@ _.extend(exports.Tropohouse.prototype, { return; throw e; } - _.each(fs.readdirSync(packageDir), function (version) { + _.each(versions, function (version) { // Is this a pre-0.9.0 "warehouse" version with a hash name? if (/^[a-f0-9]{3,}$/.test(version)) return; @@ -127,7 +129,7 @@ _.extend(exports.Tropohouse.prototype, { // Skip the currently-latest tool (ie, don't break top-level meteor // symlink). This includes both the symlink with its name and the thing // it points to. - if (package === latestToolPackage && + if (packageEscaped === latestToolPackageEscaped && (version === latestToolVersion || utils.startsWith(version, '.' + latestToolVersion + '.'))) { return; @@ -135,7 +137,7 @@ _.extend(exports.Tropohouse.prototype, { // Skip the currently-executing tool (ie, don't break the current // operation). - if (package === currentToolPackage && + if (packageEscaped === currentToolPackageEscaped && (version === currentToolVersion || utils.startsWith(version, '.' + currentToolVersion + '.'))) { return; diff --git a/tools/utils.js b/tools/utils.js index 89774ac6d4..51566be336 100644 --- a/tools/utils.js +++ b/tools/utils.js @@ -668,3 +668,11 @@ exports.mobileServerForRun = function (options) { protocol: "http://" }; }; + +exports.escapePackageNameForPath = function (packageName) { + return packageName.replace(":", "_"); +}; + +exports.unescapePackageNameForPath = function (escapedPackageName) { + return escapedPackageName.replace("_", ":"); +}; diff --git a/tools/watch.js b/tools/watch.js index 8fc4627d7e..b806f09926 100644 --- a/tools/watch.js +++ b/tools/watch.js @@ -573,5 +573,6 @@ _.extend(exports, { isUpToDate: isUpToDate, readAndWatchDirectory: readAndWatchDirectory, readAndWatchFile: readAndWatchFile, - readAndWatchFileWithHash: readAndWatchFileWithHash + readAndWatchFileWithHash: readAndWatchFileWithHash, + sha1: sha1 });