From aee56f0523f35fe2ea0eb94d0f8fddce50df1af3 Mon Sep 17 00:00:00 2001 From: Geoff Schmidt Date: Sun, 29 Dec 2013 21:12:14 -0800 Subject: [PATCH] Eliminate context.appDir. Introduce requiresApp. --- tools/commands.js | 119 ++++++++++++++------------- tools/files.js | 2 + tools/main.js | 187 +++++++++++++++++++++++++++++------------- tools/mongo_runner.js | 4 +- tools/run.js | 13 +-- 5 files changed, 202 insertions(+), 123 deletions(-) diff --git a/tools/commands.js b/tools/commands.js index 38b02e3d89..682dbac3d6 100644 --- a/tools/commands.js +++ b/tools/commands.js @@ -53,12 +53,11 @@ var hostedWithGalaxy = function (site) { // // If called from a run that isn't in an app directory, print an error // and kill the process! -var findMongoPort = function (context, cmd) { +var findMongoPort = function (appDir) { var fut = new Future; - main.requireDirInApp(context, cmd); var mongo_runner = require(path.join(__dirname, 'mongo_runner.js')); - mongo_runner.find_mongo_port(context.appDir, function (port) { + mongo_runner.find_mongo_port(appDir, function (port) { fut.return(port); }); @@ -72,7 +71,7 @@ var findMongoPort = function (context, cmd) { // Prints the Meteor architecture name of this host main.registerCommand({ name: '--arch', - maxArgs: 0 + requiresRelease: false }, function (options) { var archinfo = require('./archinfo.js'); console.log(archinfo.host()); @@ -84,7 +83,7 @@ main.registerCommand({ // (making this useful to scripts). main.registerCommand({ name: '--version', - maxArgs: 0 + requiresRelease: false }, function (options) { var context = options.context; @@ -104,7 +103,7 @@ main.registerCommand({ // Internal use only. main.registerCommand({ name: '--built-by', - maxArgs: 0 + requiresRelease: false }, function (options) { var packages = require('./packages.js'); console.log(packages.BUILT_BY); @@ -120,7 +119,7 @@ main.registerCommand({ // manifest and all of the packages in it. main.registerCommand({ name: '--get-ready', - maxArgs: 0 + requiresRelease: false }, function (options) { var context = options.context; @@ -142,6 +141,7 @@ main.registerCommand({ main.registerCommand({ name: 'run', + requiresApp: true, options: { port: { type: Number, short: "p", default: 3000 }, production: { type: Boolean }, @@ -156,7 +156,6 @@ main.registerCommand({ } }, function (options) { var context = options.context; - main.requireDirInApp(context, "run"); if (files.usesWarehouse() && context.appReleaseVersion !== 'none' && @@ -168,7 +167,7 @@ main.registerCommand({ auth.tryRevokeOldTokens({timeout: 1000}); - runner.run(context, { + runner.run(options.appDir, context, { port: options.port, rawLogs: options['raw-logs'], minify: options.production, @@ -278,7 +277,10 @@ main.registerCommand({ options: { // Undocumented flag (used, eg, by upgrade-to-engine.js). 'dont-fetch-latest': { type: Boolean } - } + }, + // We have to be able to work without a release, since 'meteor + // update' is how you fix apps that don't have a release. + requiresRelease: false }, function (options) { var context = options.context; @@ -318,7 +320,7 @@ main.registerCommand({ // If we're not in an app, then we're done (other than maybe printing some // stuff). - if (! context.appDir) { + if (! options.appDir) { if (options["dont-fetch-latest"]) return; if (options.release || didGlobalUpdateWithoutSpringboarding) { @@ -326,6 +328,11 @@ main.registerCommand({ // update (with springboarding, in which case --release is set, or // without springboarding, in which case didGlobalUpdate is set), // print this message. + // + // (Realize that if they specified --release, the release has + // already been installed by virtue of the install/springboard + // process that runs at startup even before command starts + // running.) console.log("Installed. Run 'meteor update' inside of a particular project\n" + "directory to update that project to Meteor %s.", context.releaseVersion); @@ -341,7 +348,7 @@ main.registerCommand({ } // Otherwise, we have to upgrade the app too, if the release changed. - var appRelease = project.getMeteorReleaseVersion(context.appDir); + var appRelease = project.getMeteorReleaseVersion(options.appDir); if (appRelease !== null && appRelease === context.releaseVersion) { if (triedToGloballyUpdateButFailed) { console.log( @@ -357,7 +364,7 @@ main.registerCommand({ } // Write the release to .meteor/release. - project.writeMeteorReleaseVersion(context.appDir, + project.writeMeteorReleaseVersion(options.appDir, context.releaseVersion); // Find upgraders (in order) necessary to upgrade the app for the new @@ -371,7 +378,7 @@ main.registerCommand({ var upgraders = _.difference(context.releaseManifest.upgraders || [], oldManifest.upgraders || []); _.each(upgraders, function (upgrader) { - require("./upgraders.js").runUpgrader(upgrader, context.appDir); + require("./upgraders.js").runUpgrader(upgrader, options.appDir); }); } @@ -379,12 +386,12 @@ main.registerCommand({ // order to update it for the new release . // XXX add app packages to .meteor/packages here for linker upgrade! console.log("%s: updated to Meteor %s.", - path.basename(context.appDir), context.releaseVersion); + path.basename(options.appDir), context.releaseVersion); // Print any notices relevant to this upgrade. // XXX This doesn't include package-specific notices for packages that // are included transitively (eg, packages used by app packages). - var packages = project.get_packages(context.appDir); + var packages = project.get_packages(options.appDir); warehouse.printNotices(appRelease, context.releaseVersion, packages); }); @@ -397,17 +404,15 @@ main.registerCommand({ hidden: true, minArgs: 1, maxArgs: 1, - options: { - } + requiresApp: true }, function (options) { var upgrader = options.args[0]; var context = options.context; - main.requireDirInApp(context, "run-upgrader"); var upgraders = require("./upgraders.js"); console.log("%s: running upgrader %s.", - path.basename(context.appDir), upgrader); - upgraders.runUpgrader(upgrader, context.appDir); + path.basename(options.appDir), upgrader); + upgraders.runUpgrader(upgrader, options.appDir); }); /////////////////////////////////////////////////////////////////////////////// @@ -418,14 +423,13 @@ main.registerCommand({ name: 'add', minArgs: 1, maxArgs: Infinity, + requiresApp: true }, function (options) { var context = options.context; - main.requireDirInApp(context, 'add'); - var all = context.library.list(); var using = {}; - _.each(project.get_packages(context.appDir), function (name) { + _.each(project.get_packages(options.appDir), function (name) { using[name] = true; }); @@ -435,7 +439,7 @@ main.registerCommand({ } else if (name in using) { process.stderr.write(name + ": already using\n"); } else { - project.add_package(context.appDir, name); + project.add_package(options.appDir, name); var note = all[name].metadata.summary || ''; process.stderr.write(name + ": " + note + "\n"); } @@ -450,14 +454,12 @@ main.registerCommand({ name: 'remove', minArgs: 1, maxArgs: Infinity, - options: { - } + requiresApp: true }, function (options) { var context = options.context; - main.requireDirInApp(context, 'remove'); var using = {}; - _.each(project.get_packages(context.appDir), function (name) { + _.each(project.get_packages(options.appDir), function (name) { using[name] = true; }); @@ -465,7 +467,7 @@ main.registerCommand({ if (! (name in using)) { process.stderr.write(name + ": not in project\n"); } else { - project.remove_package(context.appDir, name); + project.remove_package(options.appDir, name); process.stderr.write(name + ": removed\n"); } }); @@ -477,6 +479,7 @@ main.registerCommand({ main.registerCommand({ name: 'list', + requiresApp: true, options: { using: { type: Boolean } } @@ -484,8 +487,7 @@ main.registerCommand({ var context = options.context; if (options.using) { - main.requireDirInApp(context, 'list --using'); - var using = project.get_packages(context.appDir); + var using = project.get_packages(options.appDir); if (using.length) { _.each(using, function (name) { @@ -502,7 +504,6 @@ main.registerCommand({ return; } - main.requireDirInApp(context, 'list'); var list = context.library.list(); var names = _.keys(list); names.sort(); @@ -522,6 +523,7 @@ main.registerCommand({ name: 'bundle', minArgs: 1, maxArgs: 1, + requiresApp: true, options: { debug: { type: Boolean }, // Undocumented @@ -540,13 +542,12 @@ main.registerCommand({ var context = options.context; - main.requireDirInApp(context, "bundle"); - var buildDir = path.join(context.appDir, '.meteor', 'local', 'build_tar'); + var buildDir = path.join(options.appDir, '.meteor', 'local', 'build_tar'); var bundle_path = path.join(buildDir, 'bundle'); var output_path = path.resolve(options.args[0]); // get absolute path var bundler = require(path.join(__dirname, 'bundler.js')); - var bundleResult = bundler.bundle(context.appDir, bundle_path, { + var bundleResult = bundler.bundle(options.appDir, bundle_path, { nodeModulesMode: options['for-deploy'] ? 'skip' : 'copy', minify: ! options.debug, releaseStamp: context.releaseVersion, @@ -576,14 +577,17 @@ main.registerCommand({ maxArgs: 1, options: { url: { type: Boolean, short: 'U' } + }, + requiresApp: function (options) { + return options.args.length === 0; } }, function (options) { var mongoUrl; - if (options.length === 0) { + if (options.args.length === 0) { // localhost mode var fut = new Future; - var mongoPort = findMongoPort(options.context, "mongo"); + var mongoPort = findMongoPort(options.appDir); if (! mongoPort) { process.stdout.write( "mongo: Meteor isn't running.\n" + @@ -625,7 +629,8 @@ main.registerCommand({ name: 'reset', // Doesn't actually take an argument, but we want to print an custom // error message if they try to pass one. - maxArgs: 1 + maxArgs: 1, + requiresApp: true }, function (options) { if (options.args.length !== 0) { process.stderr.write( @@ -638,7 +643,7 @@ main.registerCommand({ return 1; } - var isRunning = !! findMongoPort(options.context, "reset"); + var isRunning = !! findMongoPort(options.appDir); if (isRunning) { process.stderr.write( "reset: Meteor is running.\n" + @@ -648,7 +653,7 @@ main.registerCommand({ return 1; } - var localDir = path.join(options.context.appDir, '.meteor', 'local'); + var localDir = path.join(options.appDir, '.meteor', 'local'); files.rm_recursive(localDir); process.stdout.write("Project reset.\n"); @@ -674,6 +679,9 @@ main.registerCommand({ // application as an admin app, so that it will be available in // Galaxy admin interface. admin: { type: Boolean } + }, + requiresApp: function (options) { + return options.delete || options.star ? false : true; } }, function (options) { var context = options.context; @@ -706,8 +714,9 @@ main.registerCommand({ // We don't need to be in an app if we're not going to run the bundler. var starball = options.star; - if (! starball) - main.requireDirInApp(context, "deploy"); + // XXX I think this is only supported for deploying to Galaxy, so it + // should print an error if you try to pass --starball while + // deploying to Meteor. var settings = undefined; if (options.settings) @@ -727,7 +736,7 @@ main.registerCommand({ var deployGalaxy = require('./deploy-galaxy.js'); deployGalaxy.deploy({ app: site, - appDir: context.appDir, + appDir: options.appDir, settings: settings, context: context, starball: starball, @@ -741,7 +750,7 @@ main.registerCommand({ }); } else { deploy.bundleAndDeploy({ - appDir: context.appDir, + appDir: options.appDir, site: site, settings: settings, bundleOptions: { @@ -914,17 +923,17 @@ main.registerCommand({ // run multiple "test-packages" commands in parallel without them stomping // on each other. // - // Note: context.appDir now is DIFFERENT from + // Note: testRunnerAppDir is DIFFERENT from // bundleOptions.library.appDir: we are bundling the test // runner app, but finding app packages from the current app (if any). - context.appDir = files.mkdtemp('meteor-test-run'); - files.cp_r(path.join(__dirname, 'test-runner-app'), context.appDir); - project.add_package(context.appDir, + var testRunnerAppDir = files.mkdtemp('meteor-test-run'); + files.cp_r(path.join(__dirname, 'test-runner-app'), testRunnerAppDir); + project.add_package(testRunnerAppDir, options['driver-package'] || 'test-in-browser'); if (options.deploy) { deploy.bundleAndDeploy({ - appDir: context.appDir, + appDir: testRunnerAppDir, site: options.deploy, settings: options.settings && runner.getSettings(options.settings), bundleOptions: { @@ -936,7 +945,7 @@ main.registerCommand({ } }); } else { - runner.run(context, { + runner.run(testRunnerAppDir, context, { port: options.port, minify: options.production, once: options.once, @@ -958,11 +967,11 @@ main.registerCommand({ }, function (options) { var context = options.context; - if (context.appDir) { + if (options.appDir) { // The library doesn't know about other programs in your app. Let's blow // away their .build directories if they have them, and not rebuild // them. Sort of hacky, but eh. - var programsDir = path.join(context.appDir, 'programs'); + var programsDir = path.join(options.appDir, 'programs'); try { var programs = fs.readdirSync(programsDir); } catch (e) { @@ -1086,9 +1095,7 @@ main.registerCommand({ /////////////////////////////////////////////////////////////////////////////// main.registerCommand({ - name: 'whoami', - options: { - } + name: 'whoami' }, function (options) { return auth.whoAmICommand(options); }); diff --git a/tools/files.js b/tools/files.js index e14b9a311c..fbf1bebbc3 100644 --- a/tools/files.js +++ b/tools/files.js @@ -124,6 +124,8 @@ _.extend(exports, { return test_dir; }, + // Determine if 'filepath' (a path, or omit for cwd) is within an + // app directory. If so, return the top-level app directory. findAppDir: function (filepath) { return files.find_upwards(files.is_app_dir, filepath); }, diff --git a/tools/main.js b/tools/main.js index 9af9bb4eb7..4408afca30 100644 --- a/tools/main.js +++ b/tools/main.js @@ -19,13 +19,24 @@ var main = exports; /////////////////////////////////////////////////////////////////////////////// var Command = function (options) { - this.name = options.name; - this.minArgs = options.minArgs || 0; - this.maxArgs = this.minArgs || 0; - this.options = options.options || {}; - this.raw = options.raw || false; - this.hidden = options.hidden || false; - this.func = options.func; + options = _.extend({ + minArgs: 0, + options: {}, + requiresApp: false, + requiresRelease: true, + raw: false, + hidden: false + }, options); + + if (! _.has(options, 'maxArgs')) + options.maxArgs = options.minArgs; + + _.each(["name", "func"], function (key) { + if (! _.has(options, key)) + throw new Error("command missing '" + key + "'?"); + }); + + _.extend(this, options); _.each(this.options, function (value, key) { if (! _.has(value, 'type')) @@ -71,6 +82,35 @@ main.ShowUsage = function () {}; // - short: single character short alias (eg, 'p' for 'port', to do -p 3000) // - default: value to use if none supplied // - required: true if required (incompatible with 'default') +// - requiresApp: does this command work with an app? possible values: +// - true if an app is required, and command must be run inside an +// app. The command will be run using the app's Meteor release +// (unless overridden by --release or a checkout). An 'appDir' +// option will be passed with the absolute path to the app's +// top-level directory, and an error will be printed if the +// command isn't run from inside an app. +// - false if an app is not required. But if the command does happen +// to have been run from an app, 'appDir' will be +// provided. Moreover, in that case, we will still use the version +// of this program that goes with the Meteor release of the +// app. This is not ideal but is necessary for 'meteor help' to +// behave in a sane way in our current system. (XXX In the future +// we should separate the build system out into a package that is +// versioned with the release, and then take the CLI tool out of +// the release and always use the latest available version.) +// - function: some apps determine whether they use an app based on +// their arguments (eg, 'deploy' versus 'deploy --delete'). for +// these, set usesApp to a function that takes 'options' (same as +// would be received by the actual command function) and returns +// true or false. +// - requiresRelease: defaults to true. Set to false if this command +// doesn't need a functioning Meteor release to be available (that +// is, if the command does not need the ability to resolve +// packages). There is only one case where this comes up: if you +// create an app with a checkout (so that it has no release), and +// then run that app with released Meteor. Normally this just prints +// an error saying that you have to pick a release, but you can +// disable that by setting this flag to false. // - raw: if true, option parsing is completely skipped (including // --release and --help). To be activated the command will need to be // literally the first argument, and it will need to do its own option @@ -190,9 +230,6 @@ var setReleaseVersion = function (context, version) { // // Keys in context: // -// - appDir: if 'meteor' was run from inside a project (a project has a file -// .meteor/packages), the absolute path to the top-level project directory -// // - releaseVersion: the actual Meteor release that we are now // using. if running from a checkout, "none". else we have a // release, either from --release on the command line, the release @@ -239,9 +276,10 @@ var setReleaseVersion = function (context, version) { // - authToken // // Arguments to calculateContext: +// - appDir: if non-null, the app // - releaseOverride: if non-null, the --release the user asked for on // the command line -var calculateContext = function (releaseOverride) { +var calculateContext = function (appDir, releaseOverride) { var context = {}; var calculateReleaseVersion = function () { @@ -264,13 +302,11 @@ var calculateContext = function (releaseOverride) { warehouse.latestRelease(); }; - var appDir = files.findAppDir(); - context.appDir = appDir && path.resolve(appDir); context.globalReleaseVersion = calculateReleaseVersion(); - if (context.appDir) { + if (appDir) { context.appReleaseVersion = - project.getMeteorReleaseVersion(context.appDir) || + project.getMeteorReleaseVersion(appDir) || (files.usesWarehouse() ? warehouse.latestRelease() : 'none'); } context.userReleaseOverride = !!releaseOverride; @@ -284,14 +320,14 @@ var calculateContext = function (releaseOverride) { // Prints a message if $METEOR_TOOLS_DEBUG is set. // XXX We really should have a better logging system. -// XXX XXX there is only one call anywhere to this (in toolsSpringboard) +// XXX XXX there are only two calls anywhere to this (they're here in this file) var toolsDebugMessage = function (msg) { if (process.env.METEOR_TOOLS_DEBUG) console.log("[TOOLS DEBUG] " + msg); }; // As the first step of running the Meteor CLI, check which Meteor -// release we should be running against. Then, check whether the +// release we shouldb e running against. Then, check whether the // tools corresponding to that release is the same as the one // we're running. If not, springboard to the right tools (after // having fetched it to the local warehouse) @@ -403,47 +439,6 @@ var longHelp = function (commandName) { // XXX XXX XXX stuff that should go away /////////////////////////////////////////////////////////////////////////////// -// XXX refactor/remove -// -// If we're not in an app directory, die with an error message. -// -// @param cmd {String} The command that was run. Used when printing -// error message. -main.requireDirInApp = function (context, cmd) { - if (context.appDir) { - // XXX this is an inelegant place to put these checks, but it is pretty - // accurate for now: "all the commands that need an app and don't do - // something special with releases" (ie, everything but create, update, - // help, logs, mongo SITE, test-packages, and deploy -D). - if (!files.usesWarehouse() && context.appReleaseVersion !== 'none') { - console.log( - "=> Running Meteor from a checkout -- overrides project version (%s)", - context.appReleaseVersion); - console.log(); - } - if (files.usesWarehouse() && context.releaseVersion === 'none') { - logging.die( - "You must specify a Meteor version with --release when you work with this\n" + - "project. It was created from an unreleased Meteor checkout and doesn't\n" + - "have a version associated with it.\n" + - "\n" + - "You can permanently set a release for this project with 'meteor update'."); - } - return; - } - // This is where you end up if you type 'meteor' with no args. Be gentle to - // the noobs.. - logging.die(cmd + ": You're not in a Meteor project directory.\n" + - "\n" + - "To create a new Meteor project:\n" + - " meteor create \n" + - "For example:\n" + - " meteor create myapp\n" + - "\n" + - "For more help, see 'meteor --help'."); -}; - - // XXX refactor/remove // called by the update command - we need to find another way to do this main.hackContextForUpdateMaybeSpringboard = function (context) { @@ -604,7 +599,35 @@ Fiber(function () { delete parsed.release; } - var context = calculateContext(releaseOverride); + var appDir = files.findAppDir(); + if (appDir) + appDir = path.resolve(appDir); + var context = calculateContext(appDir, releaseOverride); + + // (NB: At this point, we might be in an inconsistent state where we + // have context.releaseVersion === 'none' and no manifest, as if we + // were in a checkout; yet we are not in a checkout, and thus we + // can't resolve packages. This happens if you create a project with + // a checkout and then run it with a release. We'll check for this + // in a moment.) + + if (files.usesWarehouse() && context.releaseVersion === 'none') { + // We are in an app that was created with a checkout and has not + // been given a proper release, but we're not running from a + // checkout anymore, so we don't know what release to use. The + // user needs to tell us either with --release or by 'meteor + // update'ing the project to a release. + // + // We used to allow this for commands that had requiresApp false. + + logging.die( + "You must specify a Meteor version with --release when you work with this\n" + + "project. It was created from an unreleased Meteor checkout and doesn't\n" + + "have a version associated with it.\n" + + "\n" + + "You can permanently set a release for this project with 'meteor update'."); + } + // If we're not running the correct tools, fetch it and // re-run. Do *not* do this if we are in a checkout, or if @@ -815,6 +838,52 @@ longHelp(commandName) + "\n"); process.exit(1); } + // We know we have a valid command and options. Now check to see if + // the command can only be run from an app dir, and add the appDir + // option if running from an app. + var requiresApp = command.requiresApp; + if (typeof requiresApp === "function") + requiresApp = requiresApp(options); + + if (appDir) + options.appDir = appDir; + + if (requiresApp && ! options.appDir) { + // This is where you end up if you type 'meteor' with no args, + // since you'll default to the 'run' command which requires an + // app. Be welcoming to our new developers! + process.stderr.write( +commandName + ": You're not in a Meteor project directory.\n" + +"\n" + +"To create a new Meteor project:\n" + +" meteor create \n" + +"For example:\n" + +" meteor create myapp\n" + +"\n" + +"For more help, see 'meteor --help'.\n"); + process.exit(1); + } + + if (options.requiresRelease && + (files.usesWarehouse() && context.releaseVersion === 'none')) { + process.stderr.write( +"You must specify a Meteor version with --release when you work with this\n" + +"project. It was created from an unreleased Meteor checkout and doesn't\n" + +"have a version associated with it.\n" + +"\n" + +"You can permanently set a release for this project with 'meteor update'.\n"); + process.exit(1); + } + + if (options.requiresApp && + (! files.usesWarehouse() && context.appReleaseVersion !== 'none')) { + // For commands that work with apps, if we have overridden the + // app's usual release by using a checkout, print a reminder banner. + process.stdout.write( +"=> Running Meteor from a checkout -- overrides project version (%s)\n\n", + context.appReleaseVersion); + } + // Now that we're ready to start executing the command, if we are in // startup time profiling mode, print the profile. if (showRequireProfile) diff --git a/tools/mongo_runner.js b/tools/mongo_runner.js index 40d0a39bf8..ed7d953237 100644 --- a/tools/mongo_runner.js +++ b/tools/mongo_runner.js @@ -147,10 +147,10 @@ exports.launchMongo = function (options) { 'mongod'); // store data in app_dir - var dbPath = path.join(options.context.appDir, '.meteor', 'local', 'db'); + var dbPath = path.join(options.appDir, '.meteor', 'local', 'db'); files.mkdir_p(dbPath, 0755); // add .gitignore if needed. - files.add_to_gitignore(path.join(options.context.appDir, '.meteor'), 'local'); + files.add_to_gitignore(path.join(options.appDir, '.meteor'), 'local'); find_mongo_and_kill_it_dead(options.port, function (err) { Fiber(function (){ diff --git a/tools/run.js b/tools/run.js index 8cc0b34922..789a6eb935 100644 --- a/tools/run.js +++ b/tools/run.js @@ -405,13 +405,13 @@ exports.getSettings = function (filename, watchSet) { // // // banner can be used to replace the application path that is normally -// printed on startup (context.appDir) with an arbitrary string, for +// printed on startup (appDir) with an arbitrary string, for // example if you autogenerated an app in a temp file to run tests -exports.run = function (context, options) { +exports.run = function (appDir, context, options) { var outerPort = options.port || 3000; var innerPort = outerPort + 1; var mongoPort = outerPort + 2; - var bundlePath = path.join(context.appDir, '.meteor', 'local', 'build'); + var bundlePath = path.join(appDir, '.meteor', 'local', 'build'); // Allow override and use of external mongo. Matches code in launch_mongo. var mongoUrl = process.env.MONGO_URL || ("mongodb://127.0.0.1:" + mongoPort + "/meteor"); @@ -515,7 +515,7 @@ exports.run = function (context, options) { // though; there's not a real app to update there!) if (files.usesWarehouse() && !context.userReleaseOverride && !options.testPackages) { - var newAppRelease = project.getMeteorReleaseVersion(context.appDir) || + var newAppRelease = project.getMeteorReleaseVersion(appDir) || warehouse.latestRelease(); if (newAppRelease !== context.appReleaseVersion) { console.error("Your app has been updated to Meteor %s from " + @@ -529,7 +529,7 @@ exports.run = function (context, options) { serverLog = []; // Bundle up the app - var bundleResult = bundler.bundle(context.appDir, bundlePath, bundleOpts); + var bundleResult = bundler.bundle(appDir, bundlePath, bundleOpts); var watchSet = bundleResult.watchSet; if (bundleResult.errors) { logToClients({stdout: "=> Errors prevented startup:\n\n" + @@ -614,6 +614,7 @@ exports.run = function (context, options) { Fiber(function () { Status.mongoHandle = mongo_runner.launchMongo({ context: context, + appDir: appDir, port: mongoPort, onListen: function () { // On Mongo startup complete // don't print mongo startup is slow warning. @@ -672,7 +673,7 @@ exports.run = function (context, options) { }; startProxy(outerPort, innerPort, function () { - var banner = options.banner || files.pretty_path(context.appDir); + var banner = options.banner || files.pretty_path(appDir); process.stdout.write("[[[[[ " + banner + " ]]]]]\n\n"); mongoStartupPrintTimer = setTimeout(function () {