From 1266e5278eb0deaf804dcb5ed5aeb8b67bb03ef2 Mon Sep 17 00:00:00 2001 From: Geoff Schmidt Date: Wed, 3 Apr 2013 17:40:36 -0700 Subject: [PATCH] Don't write bundle dependencies (files to monitor) to disk. Just plumb them through in memory from the bundler to the runner. --- tools/bundler.js | 68 +++--- tools/deploy.js | 7 +- tools/meteor.js | 7 +- tools/run.js | 311 +++++++++++++--------------- tools/tests/test_bundler_npm.js | 34 +-- tools/tests/test_bundler_options.js | 20 +- 6 files changed, 217 insertions(+), 230 deletions(-) diff --git a/tools/bundler.js b/tools/bundler.js index 50c2d08c15..dc9c7d3fbf 100644 --- a/tools/bundler.js +++ b/tools/bundler.js @@ -133,8 +133,9 @@ var Bundle = function (options) { self.head = []; self.body = []; - // list of errors encountered while bundling. array of string. - self.errors = []; + // Files and paths used by the bundle, in the format returned by + // bundle().dependencyInfo. + self.dependencyInfo = null; }; _.extend(Bundle.prototype, { @@ -437,15 +438,17 @@ _.extend(Bundle.prototype, { }, // nodeModulesMode should be "skip", "symlink", or "copy" + // computes self.dependencyInfo write_to_directory: function (output_path, project_dir, nodeModulesMode) { var self = this; var app_json = {}; - var dependencies_json = {core: [], app: [], packages: {}, hashes: {}}; var is_app = files.is_app_dir(project_dir); + self.dependencyInfo = {core: [], app: [], packages: {}, hashes: {}}; + if (is_app) { - dependencies_json.app.push(path.join('.meteor', 'packages')); - dependencies_json.app.push(path.join('.meteor', 'release')); + self.dependencyInfo.app.push(path.join('.meteor', 'packages')); + self.dependencyInfo.app.push(path.join('.meteor', 'release')); } // --- Set up build area --- @@ -464,7 +467,7 @@ _.extend(Bundle.prototype, { files.cp_r(path.join(__dirname, 'server'), path.join(build_path, 'server'), {ignore: ignore_files}); // XXX we don't do content-based dependency watching for these files - dependencies_json.core.push('server'); + self.dependencyInfo.core.push('server'); // --- Third party dependencies --- @@ -514,13 +517,13 @@ _.extend(Bundle.prototype, { var filepath = path.join(build_path, 'static', fs_relative_path); var contents = fs.readFileSync(filepath); var hash = sha1(contents); - dependencies_json.hashes[ + self.dependencyInfo.hashes[ path.join(project_dir, 'public', fs_relative_path)] = hash; addClientFileToManifest(fs_relative_path, contents, 'static', false, undefined, hash); }); } - dependencies_json.app.push('public'); + self.dependencyInfo.app.push('public'); } // Add cache busting query param if needed, and @@ -600,7 +603,7 @@ _.extend(Bundle.prototype, { where: 'internal', hash: sha1(app_html) }); - dependencies_json.core.push(path.join('tools', 'app.html.in')); + self.dependencyInfo.core.push(path.join('tools', 'app.html.in')); // --- Documentation, and running from the command line --- @@ -627,22 +630,22 @@ _.extend(Bundle.prototype, { app_json.manifest = self.manifest; - dependencies_json.extensions = self._app_extensions(); - dependencies_json.exclude = _.pluck(ignore_files, 'source'); - dependencies_json.packages = {}; + self.dependencyInfo.extensions = self._app_extensions(); + self.dependencyInfo.exclude = _.pluck(ignore_files, 'source'); + self.dependencyInfo.packages = {}; _.each(_.values(self.slices), function (slice) { // Data for the mtime dependency watcher. We only record data here for // packages, not apps, since apps watch the whole directory for added // files. if (slice.pkg.name) { - dependencies_json.packages[slice.pkg.name] = _.union( - dependencies_json.packages[slice.pkg.name] || [], + self.dependencyInfo.packages[slice.pkg.name] = _.union( + self.dependencyInfo.packages[slice.pkg.name] || [], _.keys(slice.pkg.dependencyFileShas) ); } // Data for the contents dependency watcher check. _.each(slice.pkg.dependencyFileShas, function (sha, relPath) { - dependencies_json.hashes[ + self.dependencyInfo.hashes[ path.join(slice.pkg.source_root, relPath)] = sha; }); }); @@ -652,8 +655,6 @@ _.extend(Bundle.prototype, { fs.writeFileSync(path.join(build_path, 'app.json'), JSON.stringify(app_json, null, 2)); - fs.writeFileSync(path.join(build_path, 'dependencies.json'), - JSON.stringify(dependencies_json, null, 2)); // --- Move into place --- @@ -675,11 +676,23 @@ _.extend(Bundle.prototype, { * version is *not* read from the app's .meteor/release file. Instead, * it must be passed in as an option. * - * Returns undefined on success. On failure, returns an array of - * strings, the error messages. On failure, a bundle will still be - * written to output_path. It is probably broken, but it is supposed - * to contain correct dependency information, so you can tell when to - * try bundling again. + * Returns an object with keys: + * - errors: An array of strings, or falsy if bundling succeeded. + * - dependencyInfo: Information about files and paths that were + * inputs into the bundle and that we may wish to monitor for + * changes if we are developing interactively. + * - extensions: list of extensions registered for user code, with dots] + * - packages: map from package name to list of paths relative to the package + * - core: paths relative to 'app' in meteor tree + * - app: paths relative to top of app tree + * - exclude: list of regexps for files to ignore (everywhere) + * (for 'core' and 'apps', if a directory is given, you should + * monitor everything in the subtree under it minus the stuff that + * matches exclude, and if it doesn't exist yet, you should watch + * for it to appear) + * + * On failure ('errors' is truthy), no bundle will be output (in fact, + * output_path will have been removed if it existed.) * * options include: * - minify : minify the CSS and JS assets @@ -749,9 +762,14 @@ exports.bundle = function (app_dir, output_path, options) { // Write to disk bundle.write_to_directory(output_path, app_dir, options.nodeModulesMode); - if (bundle.errors.length) - return bundle.errors; + return { + errors: false, + dependencyInfo: bundle.dependencyInfo + }; } catch (err) { - return ["Exception while bundling application:\n" + (err.stack || err)]; + files.rm_recursive(output_path); + return { + errors: ["Exception while bundling application:\n" + (err.stack || err)] + }; } }; diff --git a/tools/deploy.js b/tools/deploy.js index 9ab8cb6a67..429b0f7c0d 100644 --- a/tools/deploy.js +++ b/tools/deploy.js @@ -92,13 +92,12 @@ var deployToServer = function (app_dir, bundleOptions, deployOptions) { process.stdout.write('Deploying to ' + site + '. Bundling...\n'); var bundler = require('./bundler.js'); - var errors = bundler.bundle(app_dir, bundle_path, bundleOptions); - if (errors) { + var bundleResult = bundler.bundle(app_dir, bundle_path, bundleOptions); + if (bundleResult.errors) { process.stdout.write("\n\nErrors prevented deploying:\n"); - _.each(errors, function (e) { + _.each(bundleResult.errors, function (e) { process.stdout.write(e + "\n"); }); - files.rm_recursive(build_dir); process.exit(1); } diff --git a/tools/meteor.js b/tools/meteor.js index 70975b549d..2933361fda 100644 --- a/tools/meteor.js +++ b/tools/meteor.js @@ -606,18 +606,17 @@ Fiber(function () { var output_path = path.resolve(argv._[0]); // get absolute path var bundler = require(path.join(__dirname, 'bundler.js')); - var errors = bundler.bundle(context.appDir, bundle_path, { + var bundleResult = bundler.bundle(context.appDir, bundle_path, { nodeModulesMode: 'copy', minify: true, // XXX allow --debug releaseStamp: context.releaseVersion, library: context.library }); - if (errors) { + if (bundleResult.errors) { process.stdout.write("Errors prevented bundling:\n"); - _.each(errors, function (e) { + _.each(bundleResult.errors, function (e) { process.stdout.write(e + "\n"); }); - files.rm_recursive(buildDir); process.exit(1); } diff --git a/tools/run.js b/tools/run.js index 11a9e49632..927664ac4a 100644 --- a/tools/run.js +++ b/tools/run.js @@ -23,7 +23,7 @@ var Future = require('fibers/future'); //XXX: Refactor to not have globals anymore? // list of log objects from the child process. -var server_log = []; +var serverLog = []; var Status = { running: false, // is server running now? @@ -36,7 +36,7 @@ var Status = { exitNow: function () { var self = this; - log_to_clients({'exit': "Your application is exiting."}); + logToClients({'exit': "Your application is exiting."}); self.shuttingDown = true; self.mongoHandle && self.mongoHandle.stop(function (err) { @@ -50,17 +50,17 @@ var Status = { this.counter = 0; }, - hard_crashed: function () { + hardCrashed: function () { var self = this; if (!self.shouldRestart) { self.exitNow(); return; } - log_to_clients({'exit': "=> Your application is crashing. Waiting for file change."}); + logToClients({'exit': "=> Your application is crashing. Waiting for file change."}); this.crashing = true; }, - soft_crashed: function () { + softCrashed: function () { var self = this; if (!self.shouldRestart) { self.exitNow(); @@ -74,7 +74,7 @@ var Status = { this.counter++; if (this.counter > 2) { - Status.hard_crashed(); + Status.hardCrashed(); } } }; @@ -93,14 +93,14 @@ var getNodeOptionsFromEnvironment = function () { // List of queued requests. Each item in the list is a function to run // when the inner app is ready to receive connections. -var request_queue = []; +var requestQueue = []; ////////// Outer Proxy Server ////////// // // calls callback once proxy is actively listening on outer and // proxying to inner. -var start_proxy = function (outer_port, inner_port, callback) { +var startProxy = function (outerPort, innerPort, callback) { callback = callback || function () {}; var p = httpProxy.createServer(function (req, res, proxy) { @@ -111,7 +111,7 @@ var start_proxy = function (outer_port, inner_port, callback) { res.write("Your app is crashing. Here's the latest log.\n\n"); - _.each(server_log, function(log) { + _.each(serverLog, function(log) { _.each(log, function(val, key) { if (val) res.write(val); @@ -125,14 +125,14 @@ var start_proxy = function (outer_port, inner_port, callback) { } else if (Status.listening) { // server is listening. things are hunky dory! proxy.proxyRequest(req, res, { - host: '127.0.0.1', port: inner_port + host: '127.0.0.1', port: innerPort }); } else { // Not listening yet. Queue up request. var buffer = httpProxy.buffer(req); - request_queue.push(function () { + requestQueue.push(function () { proxy.proxyRequest(req, res, { - host: '127.0.0.1', port: inner_port, + host: '127.0.0.1', port: innerPort, buffer: buffer }); }); @@ -144,14 +144,14 @@ var start_proxy = function (outer_port, inner_port, callback) { if (Status.listening) { // server is listening. things are hunky dory! p.proxy.proxyWebSocketRequest(req, socket, head, { - host: '127.0.0.1', port: inner_port + host: '127.0.0.1', port: innerPort }); } else { // Not listening yet. Queue up request. var buffer = httpProxy.buffer(req); - request_queue.push(function () { + requestQueue.push(function () { p.proxy.proxyWebSocketRequest(req, socket, head, { - host: '127.0.0.1', port: inner_port, + host: '127.0.0.1', port: innerPort, buffer: buffer }); }); @@ -160,11 +160,11 @@ var start_proxy = function (outer_port, inner_port, callback) { p.on('error', function (err) { if (err.code == 'EADDRINUSE') { - process.stderr.write("Can't listen on port " + outer_port + process.stderr.write("Can't listen on port " + outerPort + ". Perhaps another Meteor is running?\n"); process.stderr.write("\n"); process.stderr.write("Running two copies of Meteor in the same application directory\n"); - process.stderr.write("will not work. If something else is using port " + outer_port + ", you can\n"); + process.stderr.write("will not work. If something else is using port " + outerPort + ", you can\n"); process.stderr.write("specify an alternative port with --port .\n"); } else { process.stderr.write(err + "\n"); @@ -183,15 +183,15 @@ var start_proxy = function (outer_port, inner_port, callback) { res.end('Unexpected error.'); }); - p.listen(outer_port, callback); + p.listen(outerPort, callback); }; ////////// MongoDB ////////// -var log_to_clients = function (msg) { - server_log.push(msg); - if (server_log.length > 100) { - server_log.shift(); +var logToClients = function (msg) { + serverLog.push(msg); + if (serverLog.length > 100) { + serverLog.shift(); } // log to console @@ -214,13 +214,13 @@ var log_to_clients = function (msg) { // bundlePath // outerPort // innerPort -// mongoURL +// mongoUrl // onExit // [onListen] // [nodeOptions] // [settingsFile] -var start_server = function (options) { +var startServer = function (options) { // environment options = _.extend({ nodeOptions: [] @@ -231,10 +231,10 @@ var start_server = function (options) { env[k] = process.env[k]; env.PORT = options.innerPort; - env.MONGO_URL = options.mongoURL; + env.MONGO_URL = options.mongoUrl; env.ROOT_URL = env.ROOT_URL || ('http://localhost:' + options.outerPort); if (options.settingsFile) { - // Re-read the settings file each time we call start_server. + // Re-read the settings file each time we call startServer. var settings = exports.getSettings(options.settingsFile); if (settings) env.METEOR_SETTINGS = settings; @@ -260,22 +260,22 @@ var start_server = function (options) { if (data.length != originalLength) options.onListen && options.onListen(); if (data) { - log_to_clients({stdout: data}); + logToClients({stdout: data}); } }); proc.stderr.setEncoding('utf8'); proc.stderr.on('data', function (data) { if (data) { - log_to_clients({stderr: data}); + logToClients({stderr: data}); } }); proc.on('exit', function (code, signal) { if (signal) { - log_to_clients({'exit': '=> Exited from signal: ' + signal}); + logToClients({'exit': '=> Exited from signal: ' + signal}); } else { - log_to_clients({'exit': '=> Exited with code: ' + code}); + logToClients({'exit': '=> Exited with code: ' + code}); } options.onExit(code); @@ -303,7 +303,7 @@ var start_server = function (options) { }; }; -var kill_server = function (handle) { +var killServer = function (handle) { if (handle.proc.pid) { handle.proc.removeAllListeners('exit'); handle.proc.kill(); @@ -314,41 +314,41 @@ var kill_server = function (handle) { ////////// Watching dependencies ////////// // deps is the data from dependencies.json in the bundle -// app_dir is the root of the app +// appDir is the root of the app // relativeFiles are any other files to watch, relative to the current // directory (eg, the --settings file) -// on_change is only fired once +// onChange is only fired once var DependencyWatcher = function ( - deps, app_dir, relativeFiles, library, on_change) { + deps, appDir, relativeFiles, library, onChange) { var self = this; - self.app_dir = app_dir; - self.on_change = on_change; + self.appDir = appDir; + self.onChange = onChange; self.watches = {}; // path => unwatch function with no arguments - self.last_contents = {}; // path => last contents (array of filenames) + self.lastContents = {}; // path => last contents (array of filenames) self.mtimes = {}; // path => last seen mtime - // If a file is under a source_dir, and has one of the - // source_extensions, then it's interesting. - self.source_dirs = [self.app_dir]; - self.source_extensions = deps.extensions || []; + // If a file is under a sourceDir, and has one of the + // sourceExtensions, then it's interesting. + self.sourceDirs = [self.appDir]; + self.sourceExtensions = deps.extensions || []; - // Any file under a bulk_dir is interesting. (bulk_dirs may also + // Any file under a bulkDir is interesting. (bulkDirs may also // contain individual files) - self.bulk_dirs = []; + self.bulkDirs = []; // If we're running from a git checkout, we reload when "core" files like // server.js change. if (!files.usesWarehouse()) { _.each(deps.core || [], function (filepath) { - self.bulk_dirs.push(path.join(files.getCurrentToolsDir(), filepath)); + self.bulkDirs.push(path.join(files.getCurrentToolsDir(), filepath)); }); } _.each(deps.app || [], function (filepath) { - self.bulk_dirs.push(path.join(self.app_dir, filepath)); + self.bulkDirs.push(path.join(self.appDir, filepath)); }); // Additional list of specific files that are interesting. - self.specific_files = {}; + self.specificFiles = {}; for (var pkg in (deps.packages || {})) { // We only watch for changes in local packages, rather than ones in the // warehouse, since only changes to local ones need to cause an app to @@ -357,28 +357,28 @@ var DependencyWatcher = function ( var localPackageDir = library.directoryForLocalPackage(pkg); if (localPackageDir) { _.each(deps.packages[pkg], function (file) { - self.specific_files[path.join(localPackageDir, file)] = true; + self.specificFiles[path.join(localPackageDir, file)] = true; }); } }; _.each(relativeFiles, function (file) { - self.specific_files[file] = true; + self.specificFiles[file] = true; }); // Things that are never interesting. - self.exclude_patterns = _.map((deps.exclude || []), function (pattern) { + self.excludePatterns = _.map((deps.exclude || []), function (pattern) { return new RegExp(pattern); }); - self.exclude_paths = [ - path.join(app_dir, '.meteor', 'local'), + self.excludePaths = [ + path.join(appDir, '.meteor', 'local'), // For app packages, we only watch files explicitly used by the package (in - // specific_files) - path.join(app_dir, 'packages') + // specificFiles) + path.join(appDir, 'packages') ]; // Start monitoring - _.each(_.union(self.source_dirs, self.bulk_dirs, _.keys(self.specific_files)), + _.each(_.union(self.sourceDirs, self.bulkDirs, _.keys(self.specificFiles)), _.bind(self._scan, self, true)); // mtime scans are great and relatively efficient, but they have a couple of @@ -410,7 +410,7 @@ _.extend(DependencyWatcher.prototype, { // stop monitoring destroy: function () { var self = this; - self.on_change = null; + self.onChange = null; for (var filepath in self.watches) self.watches[filepath](); // unwatch self.watches = {}; @@ -418,9 +418,9 @@ _.extend(DependencyWatcher.prototype, { _fire: function () { var self = this; - if (self.on_change) { - var f = self.on_change; - self.on_change = null; + if (self.onChange) { + var f = self.onChange; + self.onChange = null; f(); self.destroy(); } @@ -430,7 +430,7 @@ _.extend(DependencyWatcher.prototype, { _scan: function (initial, filepath) { var self = this; - if (self._is_excluded(filepath)) + if (self._isExcluded(filepath)) return false; try { @@ -447,8 +447,8 @@ _.extend(DependencyWatcher.prototype, { return; // If an interesting file has changed, fire! - var is_interesting = self._is_interesting(filepath); - if (!initial && is_interesting) { + var isInteresting = self._isInteresting(filepath); + if (!initial && isInteresting) { self._fire(); return; } @@ -458,7 +458,7 @@ _.extend(DependencyWatcher.prototype, { var unwatch = self.watches[filepath]; unwatch && unwatch(); delete self.watches[filepath]; - delete self.last_contents[filepath]; + delete self.lastContents[filepath]; delete self.mtimes[filepath]; return; } @@ -466,7 +466,7 @@ _.extend(DependencyWatcher.prototype, { // If we're seeing this file or directory for the first time, // monitor it if necessary if (!(filepath in self.watches) && - (is_interesting || stats.isDirectory())) { + (isInteresting || stats.isDirectory())) { if (!stats.isDirectory()) { // Intentionally not using fs.watch since it doesn't play well with // vim (https://github.com/joyent/node/issues/3172) @@ -486,11 +486,11 @@ _.extend(DependencyWatcher.prototype, { // don't need to check for removed files here, since if we care // about a file, we'll already be monitoring it) if (stats.isDirectory()) { - var old_contents = self.last_contents[filepath] || []; - var new_contents = fs.readdirSync(filepath); - var added = _.difference(new_contents, old_contents); + var oldContents = self.lastContents[filepath] || []; + var newContents = fs.readdirSync(filepath); + var added = _.difference(newContents, oldContents); - self.last_contents[filepath] = new_contents; + self.lastContents[filepath] = newContents; _.each(added, function (child) { self._scan(initial, path.join(filepath, child)); }); @@ -498,50 +498,50 @@ _.extend(DependencyWatcher.prototype, { }, // Should we even bother to scan/recurse into this file? - _is_excluded: function (filepath) { + _isExcluded: function (filepath) { var self = this; // Files we're specifically being asked to scan are never excluded. For // example, files from app packages (that are actually pulled in by their // package.js) are not excluded, but the app packages directory itself is // (so that other files in package directories aren't watched). - if (filepath in self.specific_files) + if (filepath in self.specificFiles) return false; - if (_.indexOf(self.exclude_paths, filepath) !== -1) + if (_.indexOf(self.excludePaths, filepath) !== -1) return true; - var excluded_by_pattern = _.any(self.exclude_patterns, function (regexp) { + var excludedByPattern = _.any(self.excludePatterns, function (regexp) { return path.basename(filepath).match(regexp); }); - return excluded_by_pattern; + return excludedByPattern; }, // Should we fire if this file changes? - _is_interesting: function (filepath) { + _isInteresting: function (filepath) { var self = this; - if (self._is_excluded(filepath)) + if (self._isExcluded(filepath)) return false; - var in_any_dir = function (dirs) { + var inAnyDir = function (dirs) { return _.any(dirs, function (dir) { return filepath.slice(0, dir.length) === dir; }); }; // Specific, individual files that we want to monitor - if (filepath in self.specific_files) + if (filepath in self.specificFiles) return true; // Source files - if (in_any_dir(self.source_dirs) && - files.findExtension(self.source_extensions, filepath)) + if (inAnyDir(self.sourceDirs) && + files.findExtension(self.sourceExtensions, filepath)) return true; // Other directories and files that are included - if (in_any_dir(self.bulk_dirs)) + if (inAnyDir(self.bulkDirs)) return true; return false; @@ -581,19 +581,16 @@ exports.getSettings = function (filename) { // context is as created in meteor.js. // options include: port, minify, once, settingsFile, testPackages exports.run = function (context, options) { - var outer_port = options.port || 3000; - var inner_port = outer_port + 1; - var mongo_port = outer_port + 2; - var bundle_path = path.join(context.appDir, '.meteor', 'local', 'build'); + var outerPort = options.port || 3000; + var innerPort = outerPort + 1; + var mongoPort = outerPort + 2; + var bundlePath = path.join(context.appDir, '.meteor', 'local', 'build'); // Allow override and use of external mongo. Matches code in launch_mongo. - var mongo_url = process.env.MONGO_URL || - ("mongodb://127.0.0.1:" + mongo_port + "/meteor"); + var mongoUrl = process.env.MONGO_URL || + ("mongodb://127.0.0.1:" + mongoPort + "/meteor"); var firstRun = true; - var deps_info = null; - var warned_about_no_deps_info = false; - - var server_handle; + var serverHandle; var watcher; var lastThingThatPrintedWasRestartMessage = false; @@ -636,36 +633,36 @@ exports.run = function (context, options) { library: context.library }; - var start_watching = function () { + var startWatching = function (dependencyInfo) { if (!Status.shouldRestart) return; - if (deps_info) { - if (watcher) - watcher.destroy(); - var relativeFiles; - if (options.settingsFile) { - relativeFiles = [options.settingsFile]; - } + if (watcher) + watcher.destroy(); - watcher = new DependencyWatcher(deps_info, context.appDir, relativeFiles, - context.library, - function () { - if (Status.crashing) - log_to_clients({'system': "=> Modified -- restarting."}); - Status.reset(); - restart_server(); - }); + var relativeFiles; + if (options.settingsFile) { + relativeFiles = [options.settingsFile]; } + + var onChange = function () { + if (Status.crashing) + logToClients({'system': "=> Modified -- restarting."}); + Status.reset(); + restartServer(); + }; + + watcher = new DependencyWatcher(dependencyInfo, context.appDir, + relativeFiles, context.library, onChange); }; // Using `inFiber` since bundling can yield when loading a manifest // file from warehouse.meteor.com. - var restart_server = inFiber(function () { + var restartServer = inFiber(function () { Status.running = false; Status.listening = false; - if (server_handle) - kill_server(server_handle); + if (serverHandle) + killServer(serverHandle); // If the user did not specify a --release on the command line, and // simultaneously runs `meteor update` during this run, just exit and let @@ -688,54 +685,28 @@ exports.run = function (context, options) { } } - server_log = []; + serverLog = []; // Make the library reload packages, in case they've changed context.library.flush(); - var errors = bundler.bundle(context.appDir, bundle_path, bundleOpts); + var bundleResult = bundler.bundle(context.appDir, bundlePath, bundleOpts); + startWatching(bundleResult.dependencyInfo); - var deps_raw; - try { - deps_raw = - fs.readFileSync(path.join(bundle_path, 'dependencies.json'), 'utf8'); - } catch (e) { - if (!warned_about_no_deps_info) { - process.stdout.write("No dependency info in bundle. " + - "Filesystem monitoring disabled.\n"); - warned_about_no_deps_info = true; - } - } - - if (deps_raw) - deps_info = JSON.parse(deps_raw.toString()); - - if (errors) { - log_to_clients({stdout: "=> Errors prevented startup:\n"}); - _.each(errors, function (e) { - log_to_clients({stdout: e + "\n"}); + if (bundleResult.errors) { + logToClients({stdout: "=> Errors prevented startup:\n"}); + _.each(bundleResult.errors, function (e) { + logToClients({stdout: e + "\n"}); }); - if (!deps_info) { - // We don't know what files to watch for changes, so we have to exit. - process.stdout.write("\nPlease fix the problem and restart.\n"); - - // XXX calling process.exit like this leaves mongod running! - // One solution would be to try to kill mongo in this case. Or - // we could try to bundle before we launch mongo, so in this case - // mongo would never have been started. - process.exit(1); - } - start_watching(); - Status.hard_crashed(); + Status.hardCrashed(); return; } - start_watching(); Status.running = true; if (firstRun) { - process.stdout.write("=> Meteor server running on: http://localhost:" + outer_port + "/\n"); + process.stdout.write("=> Meteor server running on: http://localhost:" + outerPort + "/\n"); firstRun = false; lastThingThatPrintedWasRestartMessage = false; } else { @@ -753,45 +724,45 @@ exports.run = function (context, options) { lastThingThatPrintedWasRestartMessage = true; } - server_handle = start_server({ - bundlePath: bundle_path, - outerPort: outer_port, - innerPort: inner_port, - mongoURL: mongo_url, + serverHandle = startServer({ + bundlePath: bundlePath, + outerPort: outerPort, + innerPort: innerPort, + mongoUrl: mongoUrl, onExit: function (code) { // on server exit Status.running = false; Status.listening = false; Status.code = code; - Status.soft_crashed(); + Status.softCrashed(); if (!Status.crashing) - restart_server(); + restartServer(); }, onListen: function () { // on listen Status.listening = true; - _.each(request_queue, function (f) { f(); }); - request_queue = []; + _.each(requestQueue, function (f) { f(); }); + requestQueue = []; }, nodeOptions: getNodeOptionsFromEnvironment(), settingsFile: options.settingsFile }); }); - var mongo_err_count = 0; - var mongo_err_timer; - var mongo_startup_print_timer; + var mongoErrorCount = 0; + var mongoErrorTimer; + var mongoStartupPrintTimer; var launch = function () { Status.mongoHandle = mongo_runner.launch_mongo( context.appDir, - mongo_port, + mongoPort, function () { // On Mongo startup complete // don't print mongo startup is slow warning. - if (mongo_startup_print_timer) { - clearTimeout(mongo_startup_print_timer); - mongo_startup_print_timer = null; + if (mongoStartupPrintTimer) { + clearTimeout(mongoStartupPrintTimer); + mongoStartupPrintTimer = null; } - restart_server(); + restartServer(); }, function (code, signal) { // On Mongo dead if (Status.shuttingDown) { @@ -801,22 +772,22 @@ exports.run = function (context, options) { // if mongo dies 3 times with less than 5 seconds between each, // declare it failed and die. - mongo_err_count += 1; - if (mongo_err_count >= 3) { + mongoErrorCount += 1; + if (mongoErrorCount >= 3) { var explanation = mongoExitCodes.Codes[code]; console.log("Can't start mongod\n"); if (explanation) console.log(explanation.longText); if (explanation === mongoExitCodes.EXIT_NET_ERROR) - console.log("\nCheck for other processes listening on port " + mongo_port + + console.log("\nCheck for other processes listening on port " + mongoPort + "\nor other meteors running in the same project."); process.exit(1); } - if (mongo_err_timer) - clearTimeout(mongo_err_timer); - mongo_err_timer = setTimeout(function () { - mongo_err_count = 0; - mongo_err_timer = null; + if (mongoErrorTimer) + clearTimeout(mongoErrorTimer); + mongoErrorTimer = setTimeout(function () { + mongoErrorCount = 0; + mongoErrorTimer = null; }, 5000); // Wait a sec to restart. @@ -824,10 +795,10 @@ exports.run = function (context, options) { }); }; - start_proxy(outer_port, inner_port, function () { + startProxy(outerPort, innerPort, function () { process.stdout.write("[[[[[ " + files.pretty_path(context.appDir) + " ]]]]]\n\n"); - mongo_startup_print_timer = setTimeout(function () { + mongoStartupPrintTimer = setTimeout(function () { process.stdout.write("Initializing mongo database... this may take a moment.\n"); }, 3000); diff --git a/tools/tests/test_bundler_npm.js b/tools/tests/test_bundler_npm.js index 466088c736..7635a9ee88 100644 --- a/tools/tests/test_bundler_npm.js +++ b/tools/tests/test_bundler_npm.js @@ -133,8 +133,8 @@ console.log("app that uses gcd - clean run"); assert.doesNotThrow(function () { updateTestPackage({gcd: '0.0.0'}); var tmpOutputDir = tmpDir(); - var errors = bundler.bundle(appWithPackageDir, tmpOutputDir, {nodeModulesMode: 'skip', releaseStamp: 'none', library: library}); - assert.strictEqual(errors, undefined, errors && errors[0]); + var result = bundler.bundle(appWithPackageDir, tmpOutputDir, {nodeModulesMode: 'skip', releaseStamp: 'none', library: library}); + assert.strictEqual(result.errors, false, errors && errors[0]); _assertCorrectPackageNpmDir({gcd: '0.0.0'}); _assertCorrectBundleNpmContents(tmpOutputDir, {gcd: '0.0.0'}); }); @@ -142,8 +142,8 @@ assert.doesNotThrow(function () { console.log("app that uses gcd - no changes, running again"); assert.doesNotThrow(function () { var tmpOutputDir = tmpDir(); - var errors = bundler.bundle(appWithPackageDir, tmpOutputDir, {nodeModulesMode: 'skip', releaseStamp: 'none', library: library}); - assert.strictEqual(errors, undefined, errors && errors[0]); + var result = bundler.bundle(appWithPackageDir, tmpOutputDir, {nodeModulesMode: 'skip', releaseStamp: 'none', library: library}); + assert.strictEqual(result.errors, false, errors && errors[0]); _assertCorrectPackageNpmDir({gcd: '0.0.0'}); _assertCorrectBundleNpmContents(tmpOutputDir, {gcd: '0.0.0'}); }); @@ -169,10 +169,10 @@ assert.doesNotThrow(function () { assert.fail("shouldn't be installing specific npm packages: " + args[1]); return bareExecFileSync(file, args, opts); }; - var errors = bundler.bundle(appWithPackageDir, tmpOutputDir, {nodeModulesMode: 'skip', releaseStamp: 'none', library: library}); + var result = bundler.bundle(appWithPackageDir, tmpOutputDir, {nodeModulesMode: 'skip', releaseStamp: 'none', library: library}); meteorNpm._execFileSync = bareExecFileSync; - assert.strictEqual(errors, undefined, errors && errors[0]); + assert.strictEqual(result.errors, false, errors && errors[0]); _assertCorrectPackageNpmDir({gcd: '0.0.0'}); _assertCorrectBundleNpmContents(tmpOutputDir, {gcd: '0.0.0'}); }); @@ -182,8 +182,8 @@ console.log("app that uses gcd - add mime and semver"); assert.doesNotThrow(function () { updateTestPackage({gcd: '0.0.0', mime: '1.2.7', semver: '1.1.0'}); var tmpOutputDir = tmpDir(); - var errors = bundler.bundle(appWithPackageDir, tmpOutputDir, {nodeModulesMode: 'skip', releaseStamp: 'none', library: library}); - assert.strictEqual(errors, undefined, errors && errors[0]); + var result = bundler.bundle(appWithPackageDir, tmpOutputDir, {nodeModulesMode: 'skip', releaseStamp: 'none', library: library}); + assert.strictEqual(result.errors, false, errors && errors[0]); _assertCorrectPackageNpmDir({gcd: '0.0.0', mime: '1.2.7', semver: '1.1.0'}); _assertCorrectBundleNpmContents(tmpOutputDir, {gcd: '0.0.0', mime: '1.2.7', semver: '1.1.0'}); }); @@ -198,8 +198,8 @@ assert.doesNotThrow(function () { files.rm_recursive(nodeModulesMimeDir); assert(!fs.existsSync(path.join(nodeModulesMimeDir))); - var errors = bundler.bundle(appWithPackageDir, tmpOutputDir, {nodeModulesMode: 'skip', releaseStamp: 'none', library: library}); - assert.strictEqual(errors, undefined, errors && errors[0]); + var result = bundler.bundle(appWithPackageDir, tmpOutputDir, {nodeModulesMode: 'skip', releaseStamp: 'none', library: library}); + assert.strictEqual(result.errors, false, errors && errors[0]); _assertCorrectPackageNpmDir({gcd: '0.0.0', mime: '1.2.7', semver: '1.1.0'}); _assertCorrectBundleNpmContents(tmpOutputDir, {gcd: '0.0.0', mime: '1.2.7', semver: '1.1.0'}); }); @@ -208,8 +208,8 @@ console.log("app that uses gcd - upgrade mime, remove semver"); assert.doesNotThrow(function () { updateTestPackage({gcd: '0.0.0', mime: '1.2.8'}); var tmpOutputDir = tmpDir(); - var errors = bundler.bundle(appWithPackageDir, tmpOutputDir, {nodeModulesMode: 'skip', releaseStamp: 'none', library: library}); - assert.strictEqual(errors, undefined, errors && errors[0]); + var result = bundler.bundle(appWithPackageDir, tmpOutputDir, {nodeModulesMode: 'skip', releaseStamp: 'none', library: library}); + assert.strictEqual(result.errors, false, errors && errors[0]); _assertCorrectPackageNpmDir({gcd: '0.0.0', mime: '1.2.8'}); _assertCorrectBundleNpmContents(tmpOutputDir, {gcd: '0.0.0', mime: '1.2.8'}); }); @@ -218,7 +218,7 @@ console.log("app that uses gcd - try downgrading mime to non-existant version"); assert.doesNotThrow(function () { updateTestPackage({gcd: '0.0.0', mime: '0.1.2'}); var tmpOutputDir = tmpDir(); - var errors = bundler.bundle(appWithPackageDir, tmpOutputDir, {nodeModulesMode: 'skip', releaseStamp: 'none', library: library}); + var result = bundler.bundle(appWithPackageDir, tmpOutputDir, {nodeModulesMode: 'skip', releaseStamp: 'none', library: library}); assert.strictEqual(errors.length, 1); assert(/version not found/.test(errors[0])); _assertCorrectPackageNpmDir({gcd: '0.0.0', mime: '1.2.8'}); // shouldn't've changed @@ -228,8 +228,8 @@ console.log("app that uses gcd - downgrade mime to an existant version"); assert.doesNotThrow(function () { updateTestPackage({gcd: '0.0.0', mime: '1.2.7'}); var tmpOutputDir = tmpDir(); - var errors = bundler.bundle(appWithPackageDir, tmpOutputDir, {nodeModulesMode: 'skip', releaseStamp: 'none', library: library}); - assert.strictEqual(errors, undefined, errors && errors[0]); + var result = bundler.bundle(appWithPackageDir, tmpOutputDir, {nodeModulesMode: 'skip', releaseStamp: 'none', library: library}); + assert.strictEqual(result.errors, false, errors && errors[0]); _assertCorrectPackageNpmDir({gcd: '0.0.0', mime: '1.2.7'}); _assertCorrectBundleNpmContents(tmpOutputDir, {gcd: '0.0.0', mime: '1.2.7'}); @@ -241,8 +241,8 @@ assert.doesNotThrow(function () { var deps = {gzippo: 'https://github.com/meteor/gzippo/tarball/1e4b955439abc643879ae264b28a761521818f3b'}; updateTestPackage(deps); var tmpOutputDir = tmpDir(); - var errors = bundler.bundle(appWithPackageDir, tmpOutputDir, {nodeModulesMode: 'skip', releaseStamp: 'none', library: library}); - assert.strictEqual(errors, undefined, errors && errors[0]); + var result = bundler.bundle(appWithPackageDir, tmpOutputDir, {nodeModulesMode: 'skip', releaseStamp: 'none', library: library}); + assert.strictEqual(result.errors, false, errors && errors[0]); _assertCorrectPackageNpmDir(deps); _assertCorrectBundleNpmContents(tmpOutputDir, deps); // Check that a string introduced by our fork is in the source. diff --git a/tools/tests/test_bundler_options.js b/tools/tests/test_bundler_options.js index 88886f0d82..c876368cba 100644 --- a/tools/tests/test_bundler_options.js +++ b/tools/tests/test_bundler_options.js @@ -15,8 +15,8 @@ var library = new library.Library(); console.log("nodeModules: 'skip'"); assert.doesNotThrow(function () { var tmpOutputDir = tmpDir(); - var errors = bundler.bundle(emptyAppDir, tmpOutputDir, {nodeModulesMode: 'skip', releaseStamp: 'none', minify: true, library: library}); - assert.strictEqual(errors, undefined, errors && errors[0]); + var result = bundler.bundle(emptyAppDir, tmpOutputDir, {nodeModulesMode: 'skip', releaseStamp: 'none', minify: true, library: library}); + assert.strictEqual(result.errors, false, errors && errors[0]); // sanity check -- main.js has expected contents. assert.strictEqual(fs.readFileSync(path.join(tmpOutputDir, "main.js"), "utf8").trim(), @@ -37,8 +37,8 @@ assert.doesNotThrow(function () { console.log("nodeModules: 'skip', no minify"); assert.doesNotThrow(function () { var tmpOutputDir = tmpDir(); - var errors = bundler.bundle(emptyAppDir, tmpOutputDir, {nodeModulesMode: 'skip', minify: false, releaseStamp: 'none', library: library}); - assert.strictEqual(errors, undefined); + var result = bundler.bundle(emptyAppDir, tmpOutputDir, {nodeModulesMode: 'skip', minify: false, releaseStamp: 'none', library: library}); + assert.strictEqual(result.errors, false); // sanity check -- main.js has expected contents. assert.strictEqual(fs.readFileSync(path.join(tmpOutputDir, "main.js"), "utf8").trim(), @@ -55,9 +55,9 @@ assert.doesNotThrow(function () { console.log("nodeModules: 'skip', no minify, testPackages: ['meteor']"); assert.doesNotThrow(function () { var tmpOutputDir = tmpDir(); - var errors = bundler.bundle( + var result = bundler.bundle( emptyAppDir, tmpOutputDir, {nodeModulesMode: 'skip', minify: false, testPackages: ['meteor'], releaseStamp: 'none', library: library}); - assert.strictEqual(errors, undefined); + assert.strictEqual(result.errors, false); // sanity check -- main.js has expected contents. assert.strictEqual(fs.readFileSync(path.join(tmpOutputDir, "main.js"), "utf8").trim(), @@ -70,8 +70,8 @@ assert.doesNotThrow(function () { console.log("nodeModules: 'copy'"); assert.doesNotThrow(function () { var tmpOutputDir = tmpDir(); - var errors = bundler.bundle(emptyAppDir, tmpOutputDir, {nodeModulesMode: 'copy', releaseStamp: 'none', library: library}); - assert.strictEqual(errors, undefined); + var result = bundler.bundle(emptyAppDir, tmpOutputDir, {nodeModulesMode: 'copy', releaseStamp: 'none', library: library}); + assert.strictEqual(result.errors, false); // sanity check -- main.js has expected contents. assert.strictEqual(fs.readFileSync(path.join(tmpOutputDir, "main.js"), "utf8").trim(), @@ -85,8 +85,8 @@ assert.doesNotThrow(function () { console.log("nodeModules: 'symlink'"); assert.doesNotThrow(function () { var tmpOutputDir = tmpDir(); - var errors = bundler.bundle(emptyAppDir, tmpOutputDir, {nodeModulesMode: 'symlink', releaseStamp: 'none', library: library}); - assert.strictEqual(errors, undefined); + var result = bundler.bundle(emptyAppDir, tmpOutputDir, {nodeModulesMode: 'symlink', releaseStamp: 'none', library: library}); + assert.strictEqual(result.errors, false); // sanity check -- main.js has expected contents. assert.strictEqual(fs.readFileSync(path.join(tmpOutputDir, "main.js"), "utf8").trim(),