Don't write bundle dependencies (files to monitor) to disk. Just plumb them through in memory from the bundler to the runner.

This commit is contained in:
Geoff Schmidt
2013-04-03 17:40:36 -07:00
committed by David Glasser
parent 57db17dde0
commit 1266e5278e
6 changed files with 217 additions and 230 deletions

View File

@@ -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)]
};
}
};

View File

@@ -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);
}

View File

@@ -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);
}

View File

@@ -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 <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);

View File

@@ -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.

View File

@@ -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(),