Merge pull request #3232 from meteor/word-wrap-final

Automatically line-wrap output
This commit is contained in:
ekatek
2014-12-09 12:23:30 -08:00
25 changed files with 1409 additions and 940 deletions

2
meteor
View File

@@ -1,6 +1,6 @@
#!/bin/bash
BUNDLE_VERSION=0.3.72 # 0.3.63 on the Windows branch
BUNDLE_VERSION=0.3.74
# OS Check. Put here because here is where we download the precompiled
# bundles that are arch specific.

View File

@@ -33,6 +33,7 @@ var packageJson = {
netroute: "0.2.5",
phantomjs: "1.9.12",
"http-proxy": "1.6.0",
"wordwrap": "0.0.2",
// XXX We ought to be able to get this from the copy in js-analyze rather
// than in the dev bundle.)
esprima: "1.2.2",

View File

@@ -117,7 +117,6 @@ npm install
npm dedupe
cp -R node_modules/* "${DIR}/lib/node_modules/"
cd "${DIR}/lib"
# TODO Move this into dev-bundle-tool-package.js when it can be safely
@@ -142,6 +141,7 @@ delete browserstack-webdriver/docs
delete browserstack-webdriver/lib/test
delete sqlite3/deps
delete wordwrap/test
# dedupe isn't good enough to eliminate 3 copies of esprima, sigh.
find . -path '*/esprima/test' | xargs rm -rf

View File

@@ -58,9 +58,10 @@ exports.loggedInConnection = function (url, domain, sessionType) {
if (! auth.isLoggedIn()) {
// XXX we should have a better account signup page.
Console.stderr.write(
"Please log in with your Meteor developer account. If you don't have one,\n" +
"you can quickly create one at www.meteor.com.\n");
Console.error(
"Please log in with your Meteor developer account.",
"If you don't have one,",
"you can quickly create one at www.meteor.com.");
auth.doUsernamePasswordLogin({ retry: true });
}
@@ -78,10 +79,10 @@ exports.loggedInConnection = function (url, domain, sessionType) {
if (err.message === "access-denied") {
// Maybe we thought we were logged in, but our token had been
// revoked.
Console.stderr.write(
"It looks like you have been logged out! Please log in with your Meteor\n" +
"developer account. If you don't have one, you can quickly create one\n" +
"at www.meteor.com.\n");
Console.error(
"It looks like you have been logged out!",
"Please log in with your Meteor developer account. If you don't have",
"one, you can quickly create one at www.meteor.com.");
auth.doUsernamePasswordLogin({ retry: true });
auth.loginWithTokenOrOAuth(
conn,

View File

@@ -336,11 +336,10 @@ var tryRevokeOldTokens = function (options) {
var logoutFailWarning = function (domain) {
if (! warned) {
// This isn't ideal but is probably better that saying nothing at all
process.stderr.write("warning: " +
(options.firstTry ?
"couldn't" : "still trying to") +
" confirm logout with " + domain +
"\n");
Console.error("warning: " +
(options.firstTry ?
"couldn't" : "still trying to") +
" confirm logout with " + domain);
warned = true;
}
};
@@ -603,7 +602,7 @@ var doInteractivePasswordLogin = function (options) {
var loginFailed = function () {
if (! options.suppressErrorMessage) {
process.stderr.write("Login failed.\n");
Console.error("Login failed.");
}
};
@@ -634,7 +633,7 @@ var doInteractivePasswordLogin = function (options) {
} else {
loginFailed();
if (options.retry) {
process.stderr.write("\n");
Console.error();
continue;
} else {
maybeCloseConnection();
@@ -715,17 +714,18 @@ exports.loginCommand = withAccountsConnection(function (options,
var galaxyLoginResult = logInToGalaxy(galaxy);
if (galaxyLoginResult.error) {
// XXX add human readable error messages
process.stderr.write('\nLogin to ' + galaxy + ' failed. ');
var failedLoginMsg = "\nLogin to ' + galaxy + ' failed. ";
if (galaxyLoginResult.error === 'unauthorized') {
process.stderr.write('You are not authorized for this galaxy.\n');
Console.error(
failedLoginMsg + 'You are not authorized for this galaxy.');
} else if (galaxyLoginResult.error === 'no_oauth_server') {
process.stderr.write('The galaxy could not ' +
'contact Meteor Accounts.\n');
Console.error(
failedLoginMsg + 'The galaxy could not contact Meteor Accounts.');
} else if (galaxyLoginResult.error === 'no_identity') {
process.stderr.write('Your login information could not be found.\n');
Console.error(
failedLoginMsg + 'Your login information could not be found.');
} else {
process.stderr.write('Error: ' + galaxyLoginResult.error + '\n');
Console.error(failedLoginMsg + 'Error: ' + galaxyLoginResult.error );
}
return 1;
@@ -741,10 +741,11 @@ exports.loginCommand = withAccountsConnection(function (options,
tryRevokeOldTokens({ firstTry: true, connection: connection });
data = readSessionData();
process.stderr.write("\nLogged in" + (galaxy ? " to " + galaxy : "") +
(currentUsername(data) ?
" as " + currentUsername(data) : "") + ".\n" +
"Thanks for being a Meteor developer!\n");
Console.error();
Console.error("Logged in" + (galaxy ? " to " + galaxy : "") +
(currentUsername(data) ?
" as " + currentUsername(data) : "") + "." +
"Thanks for being a Meteor developer!");
return 0;
});
@@ -759,11 +760,11 @@ exports.logoutCommand = function (options) {
tryRevokeOldTokens({ firstTry: true });
if (wasLoggedIn)
process.stderr.write("Logged out.\n");
Console.error("Logged out.");
else
// We called logOutAllSessions/writeSessionData anyway, out of an
// abundance of caution.
process.stderr.write("Not logged in.\n");
Console.error("Not logged in.");
};
// If this is fully set up account (with a username and password), or
@@ -845,25 +846,25 @@ exports.whoAmICommand = function (options) {
var data = readSessionData();
if (! loggedIn(data)) {
process.stderr.write("Not logged in. 'meteor login' to log in.\n");
Console.error(
"Not logged in. " + Console.command("'meteor login'") + " to log in.");
return 1;
}
var username = currentUsername(data);
if (username) {
process.stdout.write(username + "\n");
Console.rawInfo(username + "\n");
return 0;
}
var url = getSession(data, config.getAccountsDomain()).registrationUrl;
if (url) {
process.stderr.write(
"You haven't chosen your username yet. To pick it, go here:\n" +
"\n" +
url + "\n");
Console.error("You haven't chosen your username yet. To pick it, go here:");
Console.error();
Console.error(Console.url(url));
} else {
// Won't happen in normal operation
process.stderr.write("You haven't chosen your username yet.\n");
Console.error("You haven't chosen your username yet.");
}
return 1;
@@ -893,11 +894,13 @@ exports.registerOrLogIn = withAccountsConnection(function (connection) {
break;
} catch (err) {
if (err.error === 400 && ! utils.validEmail(email)) {
if (email.trim().length)
process.stderr.write("Please double-check that address.\n\n");
if (email.trim().length) {
Console.error("Please double-check that address.");
Console.error();
}
} else {
process.stderr.write("\nCouldn't connect to server. " +
"Check your internet connection.\n");
Console.error("\nCouldn't connect to server. " +
"Check your internet connection.");
return false;
}
}
@@ -917,10 +920,11 @@ exports.registerOrLogIn = withAccountsConnection(function (connection) {
writeSessionData(data);
return true;
} else if (result.alreadyExisted && result.sentRegistrationEmail) {
process.stderr.write(
"\n" +
"You need to pick a password for your account so that you can log in.\n" +
"An email has been sent to you with the link.\n\n");
Console.error();
Console.error(
"You need to pick a password for your account so that you can log in.",
"An email has been sent to you with the link.");
Console.error();
var animationFrame = 0;
var lastLinePrinted = "";
@@ -928,12 +932,12 @@ exports.registerOrLogIn = withAccountsConnection(function (connection) {
var spinner = ['-', '\\', '|', '/'];
lastLinePrinted = "Waiting for you to register on the web... " +
spinner[animationFrame];
process.stderr.write(lastLinePrinted + "\r");
Console.rawError(lastLinePrinted + "\r");
animationFrame = (animationFrame + 1) % spinner.length;
}, 200);
var stopSpinner = function () {
process.stderr.write(new Array(lastLinePrinted.length + 1).join(' ') +
"\r");
Console.rawError(new Array(lastLinePrinted.length + 1).join(' ') +
"\r");
clearInterval(timer);
};
@@ -946,14 +950,14 @@ exports.registerOrLogIn = withAccountsConnection(function (connection) {
stopSpinner();
if (e.errorType !== "Meteor.Error")
throw e;
process.stderr.write(
"When you've picked your password, run 'meteor login' to log in.\n")
Console.error(
"When you've picked your password, run " +
Console.command("'meteor login'") + " to log in.");
return false;
}
stopSpinner();
process.stderr.write("Username: " +
waitForRegistrationResult.username + "\n");
Console.error("Username: " + waitForRegistrationResult.username);
loginResult = doInteractivePasswordLogin({
username: waitForRegistrationResult.username,
retry: true,
@@ -961,7 +965,7 @@ exports.registerOrLogIn = withAccountsConnection(function (connection) {
});
return loginResult;
} else if (result.alreadyExisted && result.username) {
process.stderr.write("\nLogging in as " + result.username + ".\n");
Console.error("\nLogging in as " + Console.command(result.username) + ".");
loginResult = doInteractivePasswordLogin({
username: result.username,
@@ -971,8 +975,9 @@ exports.registerOrLogIn = withAccountsConnection(function (connection) {
return loginResult;
} else {
// Hmm, got an email we don't understand.
process.stderr.write(
"\nThere was a problem. Please log in with 'meteor login'.\n");
Console.error(
"\nThere was a problem. Please log in with " +
Console.command("'meteor login'") + ".");
return false;
}
});
@@ -989,26 +994,29 @@ exports.maybePrintRegistrationLink = function (options) {
if (session.userId && ! session.username && session.registrationUrl) {
if (options.leadingNewline)
process.stderr.write("\n");
Console.error();
if (options.onlyAllowIfRegistered) {
// A stronger message: we're going to not allow whatever they were trying
// to do!
process.stderr.write(
"You need to claim a username and set a password on your Meteor developer\n" +
"account to run this command. It takes about a minute at:\n" +
" " + session.registrationUrl + "\n");
Console.error(
"You need to claim a username and set a password on your Meteor",
"developer account to run this command. It takes about a minute at:",
session.registrationUrl);
Console.error();
} else if (! options.firstTime) {
// If they've already been prompted to set a password then this
// is more of a friendly reminder, so we word it slightly
// differently than the first time they're being shown a
// registration url.
process.stderr.write(
"You should set a password on your Meteor developer account. It takes\n" +
"about a minute at: " + session.registrationUrl + "\n\n");
Console.error(
"You should set a password on your Meteor developer account.",
"It takes about a minute at:", session.registrationUrl);
Console.error();
} else {
process.stderr.write(
"You can set a password on your account or change your email address at:\n" +
session.registrationUrl + "\n\n");
Console.error(
"You can set a password on your account or change your email",
"address at:" + session.registrationUrl);
Console.error();
}
return true;
}

View File

@@ -90,17 +90,17 @@ cordova.buildTargets = function (projectContext, targets, options) {
if (! inProject) {
if (! supported) {
Console.warn(Console.fail(MESSAGE_IOS_ONLY_ON_MAC));
Console.failWarn(MESSAGE_IOS_ONLY_ON_MAC);
} else {
Console.warn("Please add the " + displayPlatform +
" platform to your project first.");
if (! hasSdk) {
Console.info("First install the SDK by running: " +
Console.bold("meteor install-sdk " + platform));
Console.command("meteor install-sdk " + platform));
Console.info("Then run: " +
Console.bold("meteor add-platform " + platform));
Console.command("meteor add-platform " + platform));
} else {
Console.info("Run: " + Console.bold("meteor add-platform " + platform));
Console.info("Run: " + Console.command("meteor add-platform " + platform));
}
}
throw new main.ExitWithCode(2);
@@ -115,9 +115,9 @@ cordova.buildTargets = function (projectContext, targets, options) {
if (supported)
Console.warn("The " + displayPlatform + " platform is not installed;" +
" please run: " +
Console.bold("meteor install-sdk " + platform));
Console.command("meteor install-sdk " + platform));
else
Console.warn(Console.fail(MESSAGE_IOS_ONLY_ON_MAC));
Console.failWarn(MESSAGE_IOS_ONLY_ON_MAC);
throw new main.ExitWithCode(2);
}
@@ -184,7 +184,7 @@ var setVerboseness = cordova.setVerboseness = function (v) {
};
var verboseLog = cordova.verboseLog = function (/* args */) {
if (verboseness)
Console.stderr.write('%% ' + util.format.apply(null, arguments) + '\n');
Console.rawError('%% ' + util.format.apply(null, arguments) + "\n");
};
@@ -374,8 +374,8 @@ var ensureCordovaProject = function (projectContext, appName) {
if (err instanceof main.ExitWithCode) {
process.exit(err.code);
}
Console.stderr.write("Error creating Cordova project: " +
err.message + "\n" + err.stack + "\n");
Console.error("Error creating Cordova prject: " + err.message);
Console.rawError(err.stack + "\n");
}
}
};
@@ -904,14 +904,16 @@ var CordovaRunner = function (projectContext, platformName, options) {
// projectContext being asynchronously reset.)
if (self.platformName !== "ios" &&
self.projectContext.packageMap.getInfo('oauth2')) {
Console.warn(
"\n" +
"WARNING: It looks like you are using OAuth2 login in your app.\n" +
" Meteor's OAuth2 implementation does not currently work with\n" +
" mobile apps in local development mode, except in the iOS\n" +
" simulator. You can run the iOS simulator with 'meteor run ios'.\n" +
" For additional workarounds, see\n" +
" https://github.com/meteor/meteor/wiki/OAuth-for-mobile-Meteor-clients.\n");
Console.warn();
Console.labelWarn(
"It looks like you are using OAuth2 login in your app. " +
"Meteor's OAuth2 implementation does not currently work with " +
"mobile apps in local development mode, except in the iOS " +
"simulator. You can run the iOS simulator with 'meteor run ios'. " +
"For additional workarounds, see " +
Console.url(
"https://github.com/meteor/meteor/wiki/" +
"OAuth-for-mobile-Meteor-clients."));
}
};
@@ -1030,30 +1032,29 @@ var execCordovaOnPlatform = function (projectContext, platformName, options) {
try {
execFileSyncOrThrow('sh', args);
} catch (err) {
Console.stderr.write([
"",
chalk.green("Could not open your project in Xcode."),
chalk.green("Try running again with the --verbose option."),
chalk.green("Instructions for running your app on an iOS device:"),
chalk.cyan("https://github.com/meteor/meteor/wiki/How-to-run-your-app-on-an-iOS-device"),
""
].join("\n"));
Console.error();
Console.error(chalk.green("Could not open your project in Xcode."));
Console.error(chalk.green("Try running again with the --verbose option."));
Console.error(
chalk.green("Instructions for running your app on an iOS device: ") +
Console.url(
"https://github.com/meteor/meteor/wiki/" +
"How-to-run-your-app-on-an-iOS-device")
);
Console.error();
process.exit(2);
}
Console.stdout.write([
"",
chalk.green([
"Your project has been opened in Xcode so that you can run your app on ",
"an iOS device. For further instructions, visit this wiki page:",
].join("\n")),
chalk.cyan(
"https://github.com/meteor/meteor/wiki/How-to-run-your-app-on-an-iOS-device"
),
""
].join("\n"));
Console.info();
Console.info(
chalk.green(
"Your project has been opened in Xcode so that you can run your " +
"app on an iOS device. For further instructions, visit this " +
"wiki page: ") +
Console.url(
"https://github.com/meteor/meteor/wiki/" +
"How-to-run-your-app-on-an-iOS-device"
));
Console.info();
} else {
verboseLog('Running emulator:', localCordova, args);
var emulatorOptions = { verbose: options.verbose, cwd: cordovaPath };
@@ -1068,35 +1069,31 @@ var execCordovaOnPlatform = function (projectContext, platformName, options) {
localCordova, args, emulatorOptions,
function(err, code) {
if (err && platform === "android" && isDevice) {
Console.stderr.write([
"",
chalk.green("Could not start the app on your device. Is it plugged in?"),
chalk.green("Try running again with the --verbose option."),
chalk.green("Instructions for running your app on an Android device:"),
chalk.cyan("https://github.com/meteor/meteor/wiki/How-to-run-your-app-on-an-Android-device"),
""
].join("\n"));
Console.error();
Console.error(
chalk.green("Could not start the app on your device. Is it plugged in?"));
Console.error("Try running again with the --verbose option.");
Console.error(
chalk.green("Instructions for running your app on an Android device: ") +
Console.url(
"https://github.com/meteor/meteor/wiki/" +
"How-to-run-your-app-on-an-Android-device"));
Console.error();
} else if (err && platform === "android") {
Console.stderr.write([
"",
chalk.green("Could not start the app in the Android emulator."),
chalk.green("Try running again with the --verbose option."),
""
].join("\n"));
Console.error();
Console.error(chalk.green("Could not start the app in the Android emulator."));
Console.error(chalk.green("Try running again with the --verbose option."));
Console.error();
} else if (err && platform === "ios") {
Console.stderr.write([
"",
chalk.green("Could not start the app in the iOS simulator."),
chalk.green("Try running again with the --verbose option."),
""
].join("\n"));
Console.error();
Console.error(chalk.green("Could not start the app in the iOS simulator."));
Console.error(chalk.green("Try running again with the --verbose option."));
Console.error();
} else if (err) {
Console.stderr.write([
"",
chalk.green("Could not start your app."),
chalk.green("Try running again with the --verbose option."),
""
].join("\n"));
Console.error();
Console.error(chalk.green("Could not start your app."));
Console.error(chalk.green("Try running again with the --verbose option."));
Console.error();
}
// Don't throw an error or print the stack trace, but still exit the
@@ -1292,9 +1289,12 @@ var checkAgreePlatformTerms = function (platform, name) {
return true;
}
Console.stdout.write("The following terms apply to " + name + ":\n\n");
Console.stdout.write(terms + "\n\n");
Console.stdout.write("You must agree to the terms to proceed.\n");
Console.info("The following terms apply to " + name + ":");
Console.info();
Console.info(terms);
Console.info();
Console.info("You must agree to the terms to proceed.");
Console.info();
var agreed = false;
@@ -1312,7 +1312,8 @@ var checkAgreePlatformTerms = function (platform, name) {
};
var checkPlatformRequirements = function (platform, options) {
options = _.extend({log: false, fix: false, fixConsole: false, fixSilent: false}, options);
options = _.extend(
{ log: false, fix: false, fixConsole: false, fixSilent: false }, options);
if (platform == 'android') {
return Android.checkRequirements(options);
} else if (platform == 'ios') {
@@ -1327,7 +1328,9 @@ var requirePlatformReady = function (platform) {
try {
var installed = checkPlatformRequirements(platform);
if (!installed.acceptable) {
Console.warn("The " + platformToHuman(platform) + " platform is not installed; please run: " + Console.bold("meteor install-sdk " + platform));
Console.warn(
"The " + platformToHuman(platform) + " platform is not installed;",
"please run: " + Console.command("meteor install-sdk " + platform));
throw new main.ExitWithCode(2);
}
} catch (err) {
@@ -1336,7 +1339,8 @@ var requirePlatformReady = function (platform) {
} else if (err instanceof main.ExitWithCode) {
throw err;
} else {
Console.warn("Unexpected error while checking platform requirements: ", err);
Console.warn(
"Unexpected error while checking platform requirements: ", err);
}
throw new main.ExitWithCode(2);
}
@@ -1787,7 +1791,9 @@ _.extend(IOS.prototype, {
}
buildmessage.enterJob({title: 'Installing Xcode'}, function () {
//Console.info("Launching Xcode installer; please choose 'Get Xcode' to install Xcode");
//Console.info(
// "Launching Xcode installer;",
// "please choose 'Get Xcode' to install Xcode");
//files.run('/usr/bin/xcodebuild', '--install');
// XXX: Any way to open direct in AppStore (rather than in browser)?
@@ -1832,7 +1838,9 @@ _.extend(IOS.prototype, {
var fix = !!options.fix;
if (!Host.isMac()) {
log && Console.info("You are not running on OSX; we won't be able to install Xcode for local iOS development");
log && Console.info(
"You are not running on OSX;",
"we won't be able to install Xcode for local iOS development");
return { acceptable: false, missing: [ "ios" ] };
}
@@ -1840,14 +1848,14 @@ _.extend(IOS.prototype, {
var okay = true;
if (self.hasXcode()) {
log && Console.info(Console.success("Xcode is installed"));
log && Console.success("Xcode is installed");
} else {
if (fix) {
log && Console.info("Installing Xcode");
self.installXcode();
} else {
log && Console.info(Console.fail("Xcode is not installed"));
log && Console.failInfo("Xcode is not installed");
result.missing.push("xcode");
result.acceptable = false;
@@ -1864,7 +1872,7 @@ _.extend(IOS.prototype, {
if (self.hasXcode()) {
if (self.hasAgreedXcodeLicense()) {
log && Console.info(Console.success("Xcode license agreed"));
log && Console.success("Xcode license agreed");
} else {
if (fix) {
log && Console.info("Please accept the Xcode license");
@@ -1873,7 +1881,7 @@ _.extend(IOS.prototype, {
// XXX: Wait?
} else {
log && Console.info(Console.fail("You must accept the Xcode license"));
log && Console.failInfo("You must accept the Xcode license");
result.missing.push("xcode-license");
result.acceptable = false;
@@ -1882,14 +1890,17 @@ _.extend(IOS.prototype, {
}
_.each(['5.0', '5.0.1', '5.1', '6.0', '6.1'], function (version) {
if (self.isSdkInstalled(version)) {
log && Console.warn("An old version of the iPhone SDK is installed (" + version + "); you should");
log && Console.warn("probably delete it. With SDK versions prior to 7.0 installed, your apps");
log && Console.warn("can't be published to the App Store. Moreover, some Cordova plugins are");
log && Console.warn("incompatible with this SDK.");
log && Console.info("You can remove it by deleting this directory: ");
log && Console.info(" " + self.getDirectoryForSdk(version));
if (self.isSdkInstalled(version) && log) {
Console.warn(
"An old version of the iPhone SDK is installed",
Console.noWrap("(" + version + ")") + ";",
"you should probably delete it. With SDK versions prior to 7.0",
"installed, your apps can't be published to the App Store.",
"Moreover, some Cordova plugins are incompatible with this SDK.",
"You can remove it by deleting this directory: ");
Console.warn(
Console.path(self.getDirectoryForSdk(version)),
Console.options({ indent: 4 }));
// Not really a failure; just warn...
}
});
@@ -1935,7 +1946,9 @@ _.extend(Android.prototype, {
return stat != null;
}
Console.info("Can't determine acceleration for unknown host: ", archinfo.host());
Console.info(
"Can't determine acceleration for unknown host: ",
Console.noWrap(archinfo.host()));
return undefined;
},
@@ -1956,7 +1969,9 @@ _.extend(Android.prototype, {
files.mkdir_p(dir);
fs.writeFileSync(filepath, mpkg);
Console.info("Launching HAXM installer; we recommend allocating 1024MB of RAM (or more)");
Console.info(
"Launching HAXM installer;",
"we recommend allocating 1024MB of RAM (or more)");
files.run('open', filepath);
return;
@@ -1969,7 +1984,8 @@ _.extend(Android.prototype, {
return;
}
throw new Error("Can't install acceleration for unknown host: " + archinfo.host());
throw new Error(
"Can't install acceleration for unknown host: " + archinfo.host());
},
useGlobalAdk: function () {
@@ -1998,7 +2014,8 @@ _.extend(Android.prototype, {
}
if (!optional && !androidSdkPath) {
throw new Error("Cannot find Android SDK; be sure the 'android' tool is on your path");
throw new Error(
"Cannot find Android SDK; be sure the 'android' tool is on your path");
}
Console.debug("Using (global) Android SDK at", androidSdkPath);
@@ -2054,9 +2071,10 @@ _.extend(Android.prototype, {
}
if (execution.exitCode !== 0) {
Console.warn("Unexpected exit code from android process: " + execution.exitCode);
Console.warn("stdout: " + execution.stdout);
Console.warn("stderr: " + execution.stderr);
Console.warn(
"Unexpected exit code from android process: " + execution.exitCode);
Console.rawWarn("stdout: " + execution.stdout + "\n");
Console.rawWarn("stderr: " + execution.stderr + "\n");
throw new Error("Error running android tool: exit code " + execution.exitCode);
}
@@ -2175,9 +2193,9 @@ _.extend(Android.prototype, {
if (execution.exitCode !== 0) {
Console.debug("Unable to run aapt." +
" (This is normal if 32 bit libraries are not found)");
Console.debug(" exit code: " + execution.exitCode);
Console.debug(" stdout: " + execution.stdout);
Console.debug(" stderr: " + execution.stderr);
Console.rawDebug(" exit code: " + execution.exitCode + "\n");
Console.rawDebug(" stdout: " + execution.stdout + "\n");
Console.rawDebug(" stderr: " + execution.stderr + "\n");
return false;
}
@@ -2376,25 +2394,38 @@ _.extend(Android.prototype, {
if (Host.hasAptGet()) {
Console.info("You can install the JDK using:");
Console.info(" sudo apt-get install --yes openjdk-7-jdk");
Console.info(
Console.comand("sudo apt-get install --yes openjdk-7-jdk"),
Console.options({ indent: 2 }));
// XXX: Technically, these are for Android, not installing Java
if (processor == "x86_64") {
Console.info("You will also need some 32-bit libraries:");
Console.info(" sudo apt-get install --yes lib32z1 lib32stdc++6");
Console.info(
Console.command("sudo apt-get install --yes lib32z1 lib32stdc++6"),
Console.options({ indent: 2 }));
}
} else if (Host.hasYum()) {
Console.info("You can install the JDK using:");
Console.info(" sudo yum install -y java-1.7.0-openjdk-devel");
Console.info(
Console.command("sudo yum install -y java-1.7.0-openjdk-devel"),
Console.options({ indent: 2 }));
// XXX: Technically, these are for Android, not installing Java
if (processor == "x86_64") {
Console.info("You will also need some 32-bit libraries:");
Console.info(" sudo yum install -y glibc.i686 zlib.i686 libstdc++.i686 ncurses-libs.i686");
Console.info(
Console.command(
"sudo yum install -y glibc.i686 zlib.i686 " +
"libstdc++.i686 ncurses-libs.i686"),
Console.options({ indent: 2 }));
}
} else {
Console.warn("You should install the JDK; we don't have instructions for your distribution (sorry!)");
Console.info("Please do submit the instructions so we can include them.")
Console.warn(
"You should install the JDK; we don't have instructions",
"for your distribution (sorry!)");
Console.info(
"Please do submit the instructions so we can include them.");
}
return;
@@ -2463,9 +2494,10 @@ _.extend(Android.prototype, {
}
if (execution.exitCode != 0) {
Console.warn("Unexpected exit code from script: " + execution.exitCode);
Console.warn("stdout: " + execution.stdout);
Console.warn("stderr: " + execution.stderr);
Console.warn(
"Unexpected exit code from script: " + execution.exitCode);
Console.rawWarn("stdout: " + execution.stdout + "\n");
Console.rawWarn("stderr: " + execution.stderr + "\n");
throw new Error('Could not download Android bundle');
}
});
@@ -2484,8 +2516,12 @@ _.extend(Android.prototype, {
// Boost timeout if not running HAXM/KVM
if (self.hasAcceleration() === false) {
Console.warn("Android emulator acceleration was not installed; the emulator will be very slow.");
Console.info("You can run '" + Console.command("meteor install-sdk android") + "' for help.")
Console.warn(
"Android emulator acceleration was not installed;",
"the emulator will be very slow.");
Console.info(
"You can run '" +
Console.command("meteor install-sdk android") + "' for help.");
timeLimit *= 4;
}
@@ -2503,11 +2539,15 @@ _.extend(Android.prototype, {
Console.error("The emulator did not start in the expected time.");
if (self.hasAcceleration() === false) {
if (Host.isLinux()) {
Console.info("We highly recommend enabling KVM to speed up the emulator.");
Console.info(
"We highly recommend enabling KVM to speed up the emulator.");
} else {
Console.info("We highly recommend installing HAXM to speed up the emulator.");
Console.info(
"We highly recommend installing HAXM to speed up the emulator.");
}
Console.info("You can run '" + Console.command("meteor install-sdk android") + "' for help.")
Console.info(
"You can run '" +
Console.command("meteor install-sdk android") + "' for help.");
}
throw new main.ExitWithCode(1);
@@ -2552,7 +2592,7 @@ _.extend(Android.prototype, {
device[kv[0]] = kv[1];
}
devices.push(device);
Console.debug("Found device", JSON.stringify(device));
Console.rawDebug("Found device", JSON.stringify(device) + "\n");
});
return devices;
},
@@ -2581,7 +2621,7 @@ _.extend(Android.prototype, {
var hasAndroid = false;
if (!self.useGlobalAdk()) {
if (self.hasAndroidBundle()) {
log && Console.info(Console.success("Found Android bundle"));
log && Console.success("Found Android bundle");
hasAndroid = true;
} else {
if (fixConsole) {
@@ -2590,7 +2630,7 @@ _.extend(Android.prototype, {
self.installAndroidBundle();
hasAndroid = true;
} else {
log && Console.info(Console.fail("Android bundle not found"));
log && Console.failInfo("Android bundle not found");
result.missing.push("android-bundle");
result.acceptable = false;
@@ -2601,14 +2641,14 @@ _.extend(Android.prototype, {
if (self.useGlobalAdk()) {
var androidSdk = self.findAndroidSdk(true);
if (androidSdk) {
log && Console.info(Console.success("Found Android SDK"));
log && Console.success("Found Android SDK");
// XXX: Verify
hasAndroid = true;
} else {
log && Console.info(Console.fail("Android SDK not found"));
log && Console.info("If you set USE_GLOBAL_ADK, the 'android' tool must be on your path");
log && Console.failInfo("Android SDK not found");
log && Console.info(
"If you set USE_GLOBAL_ADK, the 'android' tool must be on your path");
result.missing.push("android-global-sdk");
result.acceptable = false;
@@ -2616,9 +2656,9 @@ _.extend(Android.prototype, {
var hasAnt = !!Host.which("ant");
if (hasAnt) {
log && Console.info(Console.success("Found ant on PATH"));
log && Console.success("Found ant on PATH");
} else {
log && Console.info(Console.fail("Ant not found on PATH"));
log && Console.failInfo("Ant not found on PATH");
result.missing.push("apache-ant");
result.acceptable = false;
@@ -2627,7 +2667,7 @@ _.extend(Android.prototype, {
var hasJava = false;
if (self.hasJdk()) {
log && Console.info(Console.success("A JDK is installed"));
log && Console.success("A JDK is installed");
hasJava = true;
} else {
if (fix) {
@@ -2636,7 +2676,7 @@ _.extend(Android.prototype, {
self.installJdk();
hasJava = true;
} else {
log && Console.info(Console.fail("A JDK is not installed"));
log && Console.failInfo("A JDK is not installed");
result.missing.push("jdk");
result.acceptable = false;
@@ -2645,16 +2685,16 @@ _.extend(Android.prototype, {
if (hasAndroid && hasJava) {
if (self.isPlatformToolsInstalled()) {
log && Console.info(Console.success("Found Android Platform tools"));
log && Console.success("Found Android Platform tools");
} else {
if (fixSilent) {
log && Console.info("Installing Android Platform tools");
self.installTarget('platform-tools', function () {
return self.isPlatformToolsInstalled();
});
log && Console.info(Console.success("Installed Android Platform tools"));
log && Console.success("Installed Android Platform tools");
} else {
log && Console.info(Console.fail("Android Platform tools not found"));
log && Console.failInfo("Android Platform tools not found");
result.missing.push("android-platform-tools");
result.acceptable = false;
@@ -2663,7 +2703,7 @@ _.extend(Android.prototype, {
var hasBuildToolsVersion;
if (self.isBuildToolsInstalled('21.0.0')) {
log && Console.info(Console.success("Found Android Build Tools"));
log && Console.success("Found Android Build Tools");
hasBuildToolsVersion = '21.0.0';
} else {
if (fixSilent) {
@@ -2671,10 +2711,10 @@ _.extend(Android.prototype, {
self.installTarget('build-tools-21.0.0', function () {
return self.isBuildToolsInstalled('21.0.0');
});
log && Console.info(Console.success("Installed Android Build Tools"));
log && Console.success("Installed Android Build Tools");
hasBuildToolsVersion = '21.0.0';
} else {
log && Console.info(Console.fail("Android Build Tools not found"));
log && Console.failInfo("Android Build Tools not found");
result.missing.push("android-build-tools");
result.acceptable = false;
@@ -2685,7 +2725,7 @@ _.extend(Android.prototype, {
// Check that we can actually run aapt - on 64 bit, we need 32 bit libs
// We need aapt to be installed to do this!
if (!self.canRunAapt(hasBuildToolsVersion)) {
log && Console.info(Console.fail("32-bit libraries not found"));
log && Console.failInfo("32-bit libraries not found");
result.missing.push("libs32");
result.acceptable = false;
@@ -2693,31 +2733,33 @@ _.extend(Android.prototype, {
}
if (self.isPlatformInstalled('android-19')) {
log && Console.info(Console.success("Found Android 19 API"));
log && Console.success("Found Android 19 API");
} else {
if (fixSilent) {
log && Console.info("Installing Android 19 API");
self.installTarget('android-19', function () {
return self.isPlatformInstalled('android-19');
});
log && Console.info(Console.success("Installed Android 19 API"));
log && Console.success("Installed Android 19 API");
} else {
log && Console.info(Console.fail("Android API 19 not found"));
log && Console.failInfo("Android API 19 not found");
result.missing.push("android-api");
result.acceptable = false;
}
}
// (We could alternatively check for {SDK}/system-images/android-19/default/x86/build.prop)
// (We could alternatively check for
// {SDK}/system-images/android-19/default/x86/build.prop)
if (self.hasTarget('19', 'default/x86')) {
log && Console.info(Console.success("Found suitable Android x86 image"));
log && Console.success("Found suitable Android x86 image");
} else {
if (fixSilent) {
// The x86 image will fail to install if dependencies aren't there;
// we've checked the others by version,but we should double-check
// platform-tools as we don't check versions there
log && Console.info("Making sure Android Platform tools are up to date");
log && Console.info(
"Making sure Android Platform tools are up to date");
self.installTarget('platform-tools', function () {
return self.isPlatformToolsInstalled();
});
@@ -2726,9 +2768,9 @@ _.extend(Android.prototype, {
self.installTarget('sys-img-x86-android-19', function () {
return self.hasTarget('19', 'default/x86');
});
log && Console.info(Console.success("Installed Android x86 image"));
log && Console.success("Installed Android x86 image");
} else {
log && Console.info(Console.fail("Suitable Android x86 image not found"));
log && Console.failInfo("Suitable Android x86 image not found");
result.missing.push("android-sys-img");
result.acceptable = false;
@@ -2737,21 +2779,26 @@ _.extend(Android.prototype, {
var avdName = self.getAvdName();
if (self.hasAvd(avdName)) {
log && Console.info(Console.success("'" + avdName + "' android virtual device (AVD) found"));
log && Console.success(
"'" + avdName + "' android virtual device (AVD) found");
} else {
var isDefaultAvd = avdName === DEFAULT_AVD_NAME;
if (fixSilent && isDefaultAvd) {
log && Console.info("Creating android virtual device (AVD): " + avdName);
log && Console.info(
"Creating android virtual device (AVD): " + avdName);
var avdOptions = {};
self.createAvd(avdName, avdOptions);
log && Console.info(Console.success("'" + avdName + "' android virtual device (AVD) created"));
log && Console.success(
"'" + avdName + "' android virtual device (AVD) created");
} else {
log && Console.info(Console.fail("'" + avdName + "' android virtual device (AVD) not found"));
log && Console.failInfo(
"'" + avdName + "' android virtual device (AVD) not found");
if (!isDefaultAvd) {
log && Console.info("(Because you specified a custom AVD, we don't create it automatically)");
log && Console.info(
"(Because you specified a custom AVD, we don't create it",
"automatically)");
}
result.missing.push("android-avd");
@@ -2766,18 +2813,21 @@ _.extend(Android.prototype, {
if (fix) {
self.installAcceleration();
} else {
log && Console.info(Console.fail("Android emulator acceleration is not installed"));
log && Console.info(" (The Android emulator will be very slow without acceleration)");
log && Console.failInfo(
"Android emulator acceleration is not installed");
log && Console.info(
"(The Android emulator will be very slow without acceleration)",
Console.options({ indent: 2 }));
result.missing.push("haxm");
// Not all systems can install the accelerator, so don't block
// XXX: Maybe we should block the emulator (only); it is unusable without it
//result.acceptable = false
// XXX: Maybe we should block the emulator (only); it is unusable
//without it result.acceptable = false
}
} else if (hasAcceleration === true) {
// (can be undefined)
log && Console.info(Console.success("Android emulator acceleration is installed"));
log && Console.success("Android emulator acceleration is installed");
}
return result;
@@ -2886,19 +2936,19 @@ main.registerCommand({
// explain why we can't remove server or browser platforms
if (_.contains(projectContextModule.PlatformList.DEFAULT_PLATFORMS,
platform)) {
Console.stdout.write(platform + ": cannot remove platform " +
"in this version of Meteor\n");
Console.warn(
platform + ": cannot remove platform in this version of Meteor");
return;
}
if (_.contains(platforms, platform)) {
Console.stdout.write(platform + ": removed platform\n");
Console.info(platform + ": removed platform");
platforms = _.without(platforms, platform);
changed = true;
return;
}
Console.stdout.write(platform + ": platform is not in this project\n");
Console.error(platform + ": platform is not in this project");
});
if (! changed) {
@@ -2927,7 +2977,7 @@ main.registerCommand({
var platforms = projectContext.platformList.getPlatforms();
Console.stdout.write(platforms.join("\n"));
Console.rawInfo(platforms.join("\n") + "\n");
});
main.registerCommand({
@@ -2978,7 +3028,9 @@ main.registerCommand({
if (!Android.hasAvd(avd)) {
Console.error("'" + avd + "' android virtual device (AVD) does not exist");
Console.info("The default AVD is called meteor, and will be created automatically for you");
Console.info(
"The default AVD is called meteor, and will be created",
"automatically for you");
return 1;
}
@@ -3023,7 +3075,7 @@ main.registerCommand({
var installed = checkPlatformRequirements(platform, { log:true, fix: false, fixConsole: true, fixSilent: true } );
if (!_.isEmpty(installed.missing)) {
if (Host.isLinux() && platform === "ios") {
Console.warn(Console.fail(MESSAGE_IOS_ONLY_ON_MAC));
Console.failWarn(MESSAGE_IOS_ONLY_ON_MAC);
return 1;
}
@@ -3043,7 +3095,8 @@ main.registerCommand({
url += "#" + anchor;
}
openUrl(url);
Console.info("Please follow the instructions here:\n" + Console.bold(url) + "\n");
Console.info(
"Please follow the instructions here:\n" + Console.url(url) + "\n");
} else {
Console.info("We don't have installation instructions for your platform");
}

View File

@@ -27,7 +27,8 @@ var Console = require('./console.js').Console;
var projectContextModule = require('./project-context.js');
var packageVersionParser = require('./package-version-parser.js');
// On some informational actions, we only refresh the package catalog if it is > 15 minutes old
// On some informational actions, we only refresh the package catalog if it is >
// 15 minutes old
var DEFAULT_MAX_AGE_MS = 15 * 60 * 1000;
// Returns an object with keys:
@@ -153,7 +154,6 @@ main.registerCommand({
// not actually in the app!
// XXX Maybe we should do a first pass that only builds packages actually in
// the app and does display the PackageMapDelta?
return 0;
});
@@ -260,9 +260,9 @@ main.registerCommand({
// weird. Let's not allow this.
Console.error(
"The package you are in appears to be inside a Meteor app but is not " +
"in its packages directory. You may only publish packages that are " +
"entirely outside of a project or that are loaded by the project " +
"that they are inside.");
"in its packages directory. You may only publish packages that are " +
"entirely outside of a project or that are loaded by the project " +
"that they are inside.");
return 1;
}
var packageName = localVersionRecord.packageName;
@@ -290,10 +290,10 @@ main.registerCommand({
if (!options['top-level'] && !packageName.match(/:/)) {
Console.error(
"Only administrators can create top-level packages without an account prefix.\n" +
"(To confirm that you wish to create a top-level package with no account\n" +
"prefix, please run this command again with the --top-level option.)");
"Only administrators can create top-level packages without an",
"account prefix. (To confirm that you wish to create a top-level",
"package with no account prefix, please run this command again",
"with the --top-level option.)");
// You actually shouldn't be able to get here without being logged in, but
// it seems poor form to assume anything like that for the point of a
// brief error message.
@@ -360,28 +360,41 @@ main.registerCommand({
// This is an undocumented command that you are not supposed to run! We
// assume that you know what you are doing, if you ran it, and are OK with
// overrwriting normal compatibilities.
Console.warn("\nWARNING: Your package contains binary code.");
Console.warn();
Console.labelWarn("Your package contains binary code.");
} else if (binary) {
// Normal publish flow. Tell the user nicely.
Console.warn();
Console.warn(
"\nThis package contains binary code and must be built on multiple architectures.\n");
"This package contains binary code and must be built on",
"multiple architectures.");
Console.warn();
Console.info(
"You can access Meteor provided build machines, pre-configured to support\n" +
"older versions of MacOS and Linux, by running:\n");
_.each(["os.osx.x86_64", "os.linux.x86_64", "os.linux.x86_32"], function (a) {
Console.info(" meteor admin get-machine", a);
"You can access Meteor provided build machines, pre-configured to",
"support older versions of MacOS and Linux, by running:");
_.each(["os.osx.x86_64", "os.linux.x86_64", "os.linux.x86_32"],
function (a) {
Console.info(
Console.command("meteor admin get-machine " + a),
Console.options({ indent: 2 }));
});
Console.info("\nOn each machine, run:\n");
Console.info(" meteor",
"publish-for-arch",
packageSource.name + "@" + packageSource.version);
Console.info("\nFor more information on binary ABIs and consistent builds, see:");
Console.info(" https://github.com/meteor/meteor/wiki/Build-Machines\n");
Console.info();
Console.info("On each machine, run:");
Console.info();
Console.info(
Console.command(
"meteor publish-for-arch " +
packageSource.name + "@" + packageSource.version),
Console.options({ indent: 2 }));
Console.info();
Console.info(
"For more information on binary ABIs and consistent builds, see:");
Console.info(
Console.url("https://github.com/meteor/meteor/wiki/Build-Machines"),
Console.options({ indent: 2 })
);
Console.info();
}
// Refresh, so that we actually learn about the thing we just published.
@@ -411,26 +424,36 @@ main.registerCommand({
var packageInfo = catalog.official.getPackage(name);
if (! packageInfo) {
Console.error(
"You can't call `meteor publish-for-arch` on package '" + name + "' without\n" +
"publishing it first.\n\n" +
"To publish the package, run `meteor publish --create` from the package directory.\n");
"You can't call " + Console.command("`meteor publish-for-arch`") +
"on package '" + name + "' without " +" publishing it first."
);
Console.error();
Console.error(
"To publish the package, run " +
Console.command("`meteor publish --create` ") +
"from the package directory.");
Console.error();
return 1;
}
var pkgVersion = catalog.official.getVersion(name, versionString);
if (! pkgVersion) {
Console.error(
"You can't call `meteor publish-for-arch` on version " + versionString + " of\n" +
"package '" + name + "' without publishing it first.\n\n" +
"To publish the version, run `meteor publish` from the package directory.\n\n");
"You can't call", Console.command("`meteor publish-for-arch`"),
"on version " + versionString + " of " + "package '" + name +
"' without publishing it first.");
Console.error();
Console.error(
"To publish the package, run " + Console.command("`meteor publish ` ") +
"from the package directory.");
Console.error();
return 1;
}
if (! pkgVersion.source || ! pkgVersion.source.url) {
Console.error('There is no source uploaded for ' +
name + '@' + versionString);
Console.error(
"There is no source uploaded for",
name + '@' + versionString);
return 1;
}
@@ -439,30 +462,33 @@ main.registerCommand({
// further springboarding based on reading a nested json file.
if (! _.has(pkgVersion, 'releaseName')) {
if (files.inCheckout()) {
process.stderr.write(
"This package was published from an old version of meteor," +
"but you are running from checkout!\nConsider running " +
"`meteor --release 1.0`, so we can springboard correctly.\n");
process.stderr.exit(1);
Console.error(
"This package was published from an old version of meteor, " +
"but you are running from checkout! Consider running " +
Console.command("`meteor --release 1.0`"),
"so we can springboard correctly.");
process.exit(1);
}
throw new main.SpringboardToSpecificRelease("METEOR@1.0");
}
if (pkgVersion.releaseName === null) {
if (! files.inCheckout()) {
process.stderr.write(
"This package was published from a checkout of meteor! The tool cannot replicate\n" +
"that environment and will not even try. Please check out meteor at the \n" +
"corresponding git commit and try again.\n");
Console.error(
"This package was published from a checkout of meteor!",
"The tool cannot replicate that environment and will not even try.",
"Please check out meteor at the " +
"corresponding git commit and try again.");
process.exit(1);
}
} else if (files.inCheckout()) {
process.stderr.write(
"This package was published from a built version of meteor," +
"but you are running from checkout!\nConsider running from a " +
"proper Meteor release with `meteor --release " +
pkgVersion.releaseName + "` so we can springboard correctly.\n");
process.stderr.exit(1);
Console.error(
"This package was published from a built version of meteor, " +
"but you are running from checkout! Consider running from a " +
"proper Meteor release with " +
Console.command("`meteor --release " + pkgVersion.releaseName + "`"),
"so we can springboard correctly.");
process.exit(1);
} else if (pkgVersion.releaseName !== release.current.name) {
// We are in a built release, and so is the package, but it's a different
// one. Springboard!
@@ -496,10 +522,11 @@ main.registerCommand({
// Copy over a version lock file from the source tarball.
var versionsFile = path.join(packageDir, '.versions');
if (! fs.existsSync(versionsFile)) {
process.stderr.write(
"This package has no valid version lock file: are you trying to use publish-for-arch on\n" +
"a core package? Publish-for-arch cannot guarantee safety. Please use\n" +
"publish --existing-version instead.\n");
Console.error(
"This package has no valid version lock file: are you trying to use " +
"publish-for-arch on a core package? Publish-for-arch cannot " +
"guarantee safety. Please use",
Console.command("'meteor publish --existing-version'"), "instead.");
process.exit(1);
}
files.copyFile(path.join(packageDir, '.versions'),
@@ -640,9 +667,9 @@ main.registerCommand({
if (start === "0.8." || start === "0.7." ||
start === "0.6." || start === "0.5.") {
buildmessage.error(
"It looks like you are trying to publish a pre-package-server meteor release.\n" +
"Doing this through the package server is going to cause a lot of confusion.\n" +
"Please use the old release process.");
"It looks like you are trying to publish a pre-package-server " +
"meteor release. Doing this through the package server is going " +
"to cause a lot of confusion. Please use the old release process.");
}
}
}
@@ -656,7 +683,7 @@ main.registerCommand({
if (!trackRecord) {
Console.error(
'There is no release track named ' + relConf.track +
'. If you are creating a new track, use the --create-track flag.');
'. If you are creating a new track, use the --create-track flag.');
return 1;
}
@@ -696,9 +723,9 @@ main.registerCommand({
// these by accident. So, we will disallow it for now.
if (relConf.packages || relConf.tool) {
Console.error(
"Setting the --from-checkout option will use the tool and packages in your meteor " +
"checkout.\n" +
"Your release configuration file should not contain that information.");
"Setting the --from-checkout option will use the tool and packages " +
"in your meteor checkout. " +
"Your release configuration file should not contain that information.");
return 1;
}
@@ -924,13 +951,17 @@ main.registerCommand({
Console.error(
"Failed to push git tag. Please push git tag manually!");
Console.error(
"If you are publishing a non-prerelease version, then the readme will show up " +
"in atmosphere. To make sure that happens, after pushing the git tag, please " +
"run the following:");
"If you are publishing a non-prerelease version, then the readme " +
"should show up in Atmosphere. To make sure that happens, after " +
"pushing the git tag, please run the following:");
_.each(toPublish, function (name) {
Console.info("meteor admin set-latest-readme " + name + " --tag " + gitTag);
Console.info(
Console.command(
"meteor admin set-latest-readme " + name + " --tag " + gitTag));
});
Console.error("If you are publishing an experimental version, don't worry about it.");
Console.error(
"If you are publishing an experimental version, ",
"don't worry about it.");
fail = true;
}
if (! fail) {
@@ -938,14 +969,15 @@ main.registerCommand({
var isopk = projectContext.isopackCache.getIsopack(name);
if (! isopk)
throw Error("no isopack for " + name);
var url = "https://raw.githubusercontent.com/meteor/meteor/" + gitTag +
var url =
"https://raw.githubusercontent.com/meteor/meteor/" + gitTag +
"/packages/" +
name + "/README.md";
var version = isopk.version;
packageClient.callPackageServer(
conn, '_changeReadmeURL', name, version, url);
Console.info("Setting the readme of", name + "@" + version, "to", url);
Console.info(
"Setting the readme of", name + "@" + version, "to", Console.url(url));
});
}
}
@@ -954,12 +986,13 @@ main.registerCommand({
// packages. Unlike publish, this is advanced functionality, so the user
// should be familiar with the concept.
if (! _.isEmpty(unfinishedBuilds)) {
Console.warning();
Console.warning(
"WARNING: Some packages contain binary dependencies.");
Console.warning("Builds have not been published for the following packages:");
Console.warn();
Console.labelWarn(
"Some packages contain binary dependencies.");
Console.warn(
"Builds have not been published for the following packages:");
_.each(unfinishedBuilds, function (version, name) {
Console.warning(name + "@" + version);
Console.warn(name + "@" + version);
});
// Note: we don't actually enforce the proper build machine thing. You
// can't use publish-for-arch for meteor-tool, for example, you need to
@@ -969,7 +1002,7 @@ main.registerCommand({
// --existing-version: presumably you don't care about compatibility
// etc. If it is an official release, you ought to use a build machine
// though.
Console.warning(
Console.warn(
"Please publish the builds separately, from a proper build machine.");
}
}
@@ -997,6 +1030,7 @@ main.registerCommand({
var versionVisible = function (record) {
return options['show-old'] || !record.unmigrated;
};
var INDENT = 6;
var full = options.args[0].split('@');
var name = full[0];
@@ -1097,20 +1131,25 @@ main.registerCommand({
if (v.buildArchitectures) {
var buildArchitectures = v.buildArchitectures.split(' ');
Console.info(" Architectures: ", formatAsList(buildArchitectures, { formatter: formatArchitecture }));
Console.info(
"Architectures: ",
formatAsList(
buildArchitectures, { formatter: formatArchitecture }),
Console.options({ indent: INDENT }));
}
// XXX: else show "no architectures"?
if (v.packages) {
Console.info(" tool: " + v.tool);
Console.info(" packages:");
Console.info("tool: " + v.tool, Console.options({ indent: INDENT }));
Console.info("packages:", Console.options({ indent: INDENT }));
_.each(v.packages, function(pv, pn) {
Console.info(" " + pn + "@" + pv);
Console.info(pn + "@" + pv, Console.options({ indent: INDENT }));
});
}
});
Console.info("\n");
Console.info();
Console.info();
} else {
// Non-detailed list of versions
@@ -1126,7 +1165,7 @@ main.registerCommand({
rows.push(row);
});
utils.printTwoColumns(rows);
Console.printTwoColumns(rows);
}
}
@@ -1136,7 +1175,8 @@ main.registerCommand({
var myMaintainerString = "";
var myMaintainers = _.pluck(record.maintainers, 'username');
if (myMaintainers.length === 0) {
Console.debug("No maintainer records found: ", JSON.stringify(record));
Console.rawDebug(
"No maintainer records found: ", JSON.stringify(record), "\n");
} else if (myMaintainers.length === 1) {
myMaintainerString = myMaintainers[0];
} else {
@@ -1180,7 +1220,8 @@ main.registerCommand({
catalogRefresh: new catalog.Refresh.OnceAtStart({ maxAge: DEFAULT_MAX_AGE_MS, ignoreErrors: true })
}, function (options) {
if (options.args.length === 0) {
Console.info("To show all packages, do", Console.command("meteor search ."));
Console.info(
"To show all packages, do", Console.command("meteor search ."));
return 1;
}
@@ -1310,7 +1351,8 @@ main.registerCommand({
explainIfRefreshFailed();
} else {
Console.info(
"To get more information on a specific item, use", Console.command("meteor show"));
"To get more information on a specific item, use",
Console.command("meteor show"));
}
});
@@ -1405,21 +1447,26 @@ main.registerCommand({
utils.printPackageList(items);
if (newVersionsAvailable) {
Console.info("\n" +
"* New versions of these packages are available! Run 'meteor update' to try\n" +
" to update those packages to their latest versions. If your packages cannot be\n" +
" updated further, try typing meteor add <package>@<newVersion> to see more\n" +
" information.");
Console.info();
Console.info(
"New versions of these packages are available! Run",
Console.command("'meteor update'"), "to try to update those",
"packages to their latest versions. If your packages cannot be",
"updated further, try typing",
Console.command("`meteor add <package>@<newVersion>`"),
"to see more information.",
Console.options({ bulletPoint: "* " }));
}
if (anyBuiltLocally) {
Console.info("\n" +
"+ These packages are built locally from source.");
Console.info();
Console.info(
"These packages are built locally from source.",
Console.options({ bulletPoint: "+ " }));
}
return 0;
});
///////////////////////////////////////////////////////////////////////////////
// update
///////////////////////////////////////////////////////////////////////////////
@@ -1437,8 +1484,8 @@ var maybeUpdateRelease = function (options) {
// We are running from checkout, so we are not updating the release.
if (release.current && release.current.isCheckout()) {
Console.error(
"You are running Meteor from a checkout, so we cannot update the Meteor release.\n" +
"Checking to see if we can update your packages.");
"You are running Meteor from a checkout, so we cannot update",
"the Meteor release. Checking to see if we can update your packages.");
return 0;
}
@@ -1508,18 +1555,18 @@ var maybeUpdateRelease = function (options) {
// command even ran. They could equivalently have run 'meteor
// help --release xyz'.
Console.info(
"Installed. Run 'meteor update' inside of a particular project\n" +
"directory to update that project to " +
release.current.getDisplayName() + ".");
"Installed. Run " + Console.command("'meteor update' ") +
"inside of a particular project directory to update that project to " +
release.current.getDisplayName() + ".");
} else {
// We get here if the user ran 'meteor update' and we didn't
// find a new version.
Console.info(
"The latest version of Meteor, " + release.current.getReleaseVersion() +
", is already installed on this\n" +
"computer. Run 'meteor update' inside of a particular project\n" +
"directory to update that project to " +
release.current.getDisplayName());
", is already installed on this computer. Run " +
Console.command("'meteor update'") + " inside of a particular " +
"project directory to update that project to " +
release.current.getDisplayName());
}
return 0;
}
@@ -1544,7 +1591,7 @@ var maybeUpdateRelease = function (options) {
var maybeTheLatestRelease = release.explicit ? "" : ", the latest release";
Console.info(
"This project is already at " +
release.current.getDisplayName() + maybeTheLatestRelease + ".");
release.current.getDisplayName() + maybeTheLatestRelease + ".");
return 0;
}
@@ -1590,8 +1637,7 @@ var maybeUpdateRelease = function (options) {
// not try to patch you to an unfriendly release. So, either way, as far
// as we are concerned you are at the 'latest patch version'
if (!patchRecord || !patchRecord.recommended ) {
Console.error(
"You are at the latest patch version.");
Console.error("You are at the latest patch version.");
return 0;
}
// Great, we found a patch version. You can only have one latest patch for
@@ -1616,9 +1662,9 @@ var maybeUpdateRelease = function (options) {
// We could not find any releases newer than the one that we are on, on
// that track, so we are done.
Console.info(
"This project is already at " + projectContext.releaseFile.displayReleaseName +
", which is newer\n" +
"than the latest release.");
"This project is already at " +
Console.noWrap(projectContext.releaseFile.displayReleaseName) +
", which is newer than the latest release.");
return 0;
}
}
@@ -1639,7 +1685,8 @@ var maybeUpdateRelease = function (options) {
// Nope, this release didn't work.
Console.debug(
"Update to release", releaseTrack + "@" + versionToTry,
"is impossible:\n" + messages.formatMessages());
"is impossible:");
Console.debug(messages.formatMessages());
return false;
}
@@ -1651,8 +1698,8 @@ var maybeUpdateRelease = function (options) {
var newerAvailable = false;
if (! solutionReleaseVersion) {
Console.info(
"This project is at the latest release which is compatible with your\n" +
"current package constraints.");
"This project is at the latest release which is compatible with your " +
"current package constraints.");
return 0;
} else if (solutionReleaseVersion !== releaseVersionsToTry[0]) {
newerAvailable = true;
@@ -1689,8 +1736,8 @@ var maybeUpdateRelease = function (options) {
projectContext.releaseFile.displayReleaseName + ".");
if (newerAvailable) {
Console.info(
"(Newer releases are available but are not compatible with your\n" +
"current package constraints.)");
"(Newer releases are available but are not compatible with your " +
"current package constraints.)");
}
// Now run the upgraders.
@@ -2001,7 +2048,7 @@ main.registerCommand({
});
});
if (messages.hasMessages()) {
Console.error("=> Errors while parsing arguments:");
Console.arrowError("Errors while parsing arguments:", 1);
Console.printMessages(messages);
explainIfRefreshFailed(); // this is why we're not using captureAndExit
return 1;
@@ -2014,7 +2061,7 @@ main.registerCommand({
projectContext.prepareProjectForBuild();
});
if (messages.hasMessages()) {
Console.error("=> Errors while adding packages:");
Console.arrowError("Errors while adding packages:", 1);
Console.printMessages(messages);
explainIfRefreshFailed(); // this is why we're not using captureAndExit
return 1;
@@ -2026,12 +2073,12 @@ main.registerCommand({
projectContext.packageMapDelta.displayOnConsole();
// Show descriptions of directly added packages.
Console.stdout.write("\n");
Console.info();
_.each(constraintsToAdd, function (constraint) {
var version = projectContext.packageMap.getInfo(constraint.name).version;
var versionRecord = projectContext.projectCatalog.getVersion(
constraint.name, version);
Console.stdout.write(
Console.info(
constraint.name +
(versionRecord.description ? (": " + versionRecord.description) : ""));
});
@@ -2178,7 +2225,8 @@ main.registerCommand({
}
if ((options.add || options.remove) && options.list) {
Console.error(
"Sorry, you can't change the users at the same time as you're listing them.");
"Sorry, you can't change the users at the same time as you're",
"listing them.");
return 1;
}
@@ -2213,7 +2261,7 @@ main.registerCommand({
packageClient.callPackageServer(
conn, 'removeMaintainer', name, options.remove);
}
Console.info(" Done!");
Console.info("Success.");
}
} catch (err) {
packageClient.handlePackageServerConnectionError(err);
@@ -2230,16 +2278,18 @@ main.registerCommand({
if (!record) {
Console.info(
"Could not get list of maintainers: package " + name + " does not exist.");
"Could not get list of maintainers:",
"package " + name + " does not exist.");
return 1;
}
Console.info("\nThe maintainers for " + name + " are:");
Console.info();
Console.info("The maintainers for " + name + " are:");
_.each(record.maintainers, function (user) {
if (! user || !user.username)
Console.info("<unknown>");
Console.rawInfo("<unknown>" + "\n");
else
Console.info(user.username + "");
Console.rawInfo(user.username + "\n");
});
return 0;
});
@@ -2284,11 +2334,11 @@ main.registerCommand({
toolPackage, toolVersion);
if (!toolPkgBuilds) {
// XXX this could also mean package unknown.
Console.error('Tool version unknown: ' + release.tool + '');
Console.error('Tool version unknown: ' + release.tool);
return 1;
}
if (!toolPkgBuilds.length) {
Console.error('Tool version has no builds: ' + release.tool + '');
Console.error('Tool version has no builds: ' + release.tool);
return 1;
}
@@ -2308,8 +2358,8 @@ main.registerCommand({
});
Console.error(
'Building bootstrap tarballs for architectures ' +
osArches.join(', ') + '');
'Building bootstrap tarballs for architectures ' + osArches.join(', '));
// Before downloading anything, check that the catalog contains everything we
// need for the OSes that the tool is built for.
var messages = buildmessage.capture(function () {
@@ -2328,7 +2378,7 @@ main.registerCommand({
});
if (messages.hasMessages()) {
Console.error("\n" + messages.formatMessages());
Console.printMessages(messages);
return 1;
};
@@ -2432,8 +2482,7 @@ main.registerCommand({
var bannersData = fs.readFileSync(bannersFile, 'utf8');
bannersData = JSON.parse(bannersData);
} catch (e) {
Console.error("Could not parse banners file: ");
Console.error(e.message + "");
Console.error("Could not parse banners file: " + e.message);
return 1;
}
if (!bannersData.track) {
@@ -2482,14 +2531,15 @@ main.registerCommand({
var name = release[0];
var version = release[1];
if (!version) {
Console.error('\n Must specify release version (track@version)');
Console.error('Must specify release version (track@version)');
return 1;
}
// Now let's get down to business! Fetching the thing.
var record = catalog.official.getReleaseTrack(name);
if (!record) {
Console.error('\n There is no release track named ' + name);
Console.error();
Console.error('There is no release track named ' + name);
return 1;
}
@@ -2503,14 +2553,15 @@ main.registerCommand({
try {
if (options.unrecommend) {
Console.info("Unrecommending " + name + "@" + version + "...");
packageClient.callPackageServer(conn, 'unrecommendVersion', name, version);
Console.info("Done!\n " + name + "@" + version +
" is no longer a recommended release");
packageClient.callPackageServer(
conn, 'unrecommendVersion', name, version);
Console.info("Success.");
Console.info(name + "@" + version, "is no longer a recommended release");
} else {
Console.info("Recommending " + options.args[0] + "...");
packageClient.callPackageServer(conn, 'recommendVersion', name, version);
Console.info("Done!\n " + name + "@" + version +
" is now a recommended release");
Console.info("Success.");
Console.info(name + "@" + version, "is now a recommended release");
}
} catch (err) {
packageClient.handlePackageServerConnectionError(err);
@@ -2538,7 +2589,8 @@ main.registerCommand({
// Now let's get down to business! Fetching the thing.
var record = catalog.official.getPackage(name);
if (!record) {
Console.error('\n There is no package named ' + name);
Console.error();
Console.error('There is no package named ' + name);
return 1;
}
@@ -2550,12 +2602,12 @@ main.registerCommand({
}
try {
Console.info(
"Changing homepage on "
Console.rawInfo(
"Changing homepage on "
+ name + " to " + url + "...");
packageClient.callPackageServer(conn,
'_changePackageHomepage', name, url);
Console.info("Done!");
Console.info(" done");
} catch (err) {
packageClient.handlePackageServerConnectionError(err);
return 1;
@@ -2601,16 +2653,16 @@ main.registerCommand({
try {
var status = options.success ? "successfully" : "unsuccessfully";
// XXX: This should probably use progress bars instead.
_.each(versions, function (version) {
process.stdout.write(
"Setting "
+ name + "@" + version + " as " +
status + " migrated ...");
Console.rawInfo(
"Setting " + name + "@" + version + " as " +
status + " migrated ... ");
packageClient.callPackageServer(
conn,
'_changeVersionMigrationStatus',
name, version, !options.success);
process.stdout.write(" done!\n");
Console.info("done.");
});
} catch (err) {
packageClient.handlePackageServerConnectionError(err);
@@ -2656,14 +2708,13 @@ main.registerCommand({
}
try {
Console.info(
"Setting README of "
+ name + "@" + version + " to " + url);
packageClient.callPackageServer(
conn,
'_changeReadmeURL',
name, version, url);
Console.info(" done!\n");
// XXX: This output should probably use progress bars instead!
Console.rawInfo("Setting README of " + name + "@" + version + " to " + url + " ... ");
packageClient.callPackageServer(
conn,
'_changeReadmeURL',
name, version, url);
Console.info("done.");
} catch (err) {
packageClient.handlePackageServerConnectionError(err);
return 1;

View File

@@ -70,7 +70,9 @@ var showInvalidArchMsg = function (arch) {
Console.info("Invalid architecture: " + arch);
Console.info("The following are valid Meteor architectures:");
_.each(_.keys(VALID_ARCHITECTURES), function (va) {
Console.info(" " + va);
Console.info(
Console.command(va),
Console.options({ indent: 2 }));
});
};
@@ -85,7 +87,7 @@ main.registerCommand({
catalogRefresh: new catalog.Refresh.Never()
}, function (options) {
var archinfo = require('./archinfo.js');
console.log(archinfo.host());
Console.rawInfo(archinfo.host() + "\n");
});
// Prints the current release in use. Note that if there is not
@@ -101,15 +103,16 @@ main.registerCommand({
if (release.current === null) {
if (! options.appDir)
throw new Error("missing release, but not in an app?");
Console.stderr.write(
"This project was created with a checkout of Meteor, rather than an\n" +
"official release, and doesn't have a release number associated with\n" +
"it. You can set its release with 'meteor update'.\n");
Console.error(
"This project was created with a checkout of Meteor, rather than an " +
"official release, and doesn't have a release number associated with " +
"it. You can set its release with " +
Console.command("'meteor update'") + ".");
return 1;
}
if (release.current.isCheckout()) {
Console.stderr.write("Unreleased (running from a checkout)\n");
Console.error("Unreleased (running from a checkout).");
return 1;
}
@@ -123,15 +126,15 @@ main.registerCommand({
catalogRefresh: new catalog.Refresh.Never()
}, function (options) {
if (files.inCheckout()) {
Console.stderr.write("checkout\n");
Console.error("checkout");
return 1;
} else if (release.current === null) {
// .meteor/release says "none" but not in a checkout.
Console.stderr.write("none\n");
Console.error("none");
return 1;
} else {
Console.stdout.write(release.current.name + "\n");
Console.stdout.write(files.getToolsVersion() + "\n");
Console.rawInfo(release.current.name + "\n");
Console.rawInfo(files.getToolsVersion() + "\n");
return 0;
}
});
@@ -193,16 +196,16 @@ function doRunCommand (options) {
var parsedUrl = utils.parseUrl(options.port);
} catch (err) {
if (options.verbose) {
Console.stderr.write('Error while parsing --port option: '
+ err.stack + '\n');
Console.rawError(
"Error while parsing --port option: " + err.stack + "\n");
} else {
Console.stderr.write(err.message + '\n');
Console.error(err.message);
}
return 1;
}
if (! parsedUrl.port) {
Console.stderr.write("--port must include a port.\n");
Console.error("--port must include a port.");
return 1;
}
@@ -210,10 +213,10 @@ function doRunCommand (options) {
var parsedMobileServer = utils.mobileServerForRun(options);
} catch (err) {
if (options.verbose) {
Console.stderr.write('Error while parsing --mobile-server option: '
+ err.stack + '\n');
Console.rawError(
"Error while parsing --mobile-server option: " + err.stack + "\n");
} else {
Console.stderr.write(err.message + '\n');
Console.error(err.message);
}
return 1;
}
@@ -289,14 +292,13 @@ function doRunCommand (options) {
// If we are targeting the remote devices, warn about ports and same network
if (utils.runOnDevice(options)) {
cordova.verboseLog('A run on a device requested');
var warning = [
"WARNING: You are testing your app on a remote device.",
" For the mobile app to be able to connect to the local server, make",
" sure your device is on the same network, and that the network",
" configuration allows clients to talk to each other",
" (no client isolation)."];
Console.stderr.write(warning.join("\n"));
var warning =
"You are testing your app on a remote device." +
"For the mobile app to be able to connect to the local server, make " +
"sure your device is on the same network, and that the network " +
"configuration allows clients to talk to each other " +
"(no client isolation).";
Console.labelWarn(warning);
}
@@ -304,9 +306,10 @@ function doRunCommand (options) {
if (options['app-port']) {
var appPortMatch = options['app-port'].match(/^(?:(.+):)?([0-9]+)?$/);
if (!appPortMatch) {
Console.stderr.write(
"run: --app-port must be a number or be of the form 'host:port' where\n" +
"port is a number. Try 'meteor help run' for help.\n");
Console.error(
"run: --app-port must be a number or be of the form 'host:port' ",
"where port is a number. Try",
Console.command("'meteor help run'") + " for help.");
return 1;
}
appHost = appPortMatch[1] || null;
@@ -378,8 +381,9 @@ main.registerCommand({
catalogRefresh: new catalog.Refresh.Never()
}, function (options) {
if (!options.appDir) {
Console.stderr.write(
"The 'meteor shell' command must be run in a Meteor app directory."
Console.error(
"The " + Console.command("'meteor shell'") + " command must be run",
"in a Meteor app directory."
);
} else {
require('./server/shell.js').connect(options.appDir);
@@ -411,12 +415,13 @@ main.registerCommand({
// No package examples exist yet.
if (options.list && options.example) {
Console.stderr.write("No package examples exist at this time.\n\n");
Console.error("No package examples exist at this time.");
Console.error();
throw new main.ShowUsage;
}
if (!packageName) {
Console.stderr.write("Please specify the name of the package. \n");
Console.error("Please specify the name of the package.");
throw new main.ShowUsage;
}
@@ -429,7 +434,7 @@ main.registerCommand({
var inYourApp = options.appDir ? " in your app" : "";
if (fs.existsSync(packageDir)) {
Console.stderr.write(packageName + ": Already exists" + inYourApp + "\n");
Console.error(packageName + ": Already exists" + inYourApp);
return 1;
}
@@ -468,11 +473,11 @@ main.registerCommand({
ignore: [/^local$/]
});
} catch (err) {
Console.stderr.write("Could not create package: " + err.message + "\n");
Console.error("Could not create package: " + err.message);
return 1;
}
Console.stdout.write(packageName + ": created" + inYourApp + "\n");
Console.info(packageName + ": created" + inYourApp);
return 0;
}
@@ -498,12 +503,16 @@ main.registerCommand({
});
if (options.list) {
Console.stdout.write("Available examples:\n");
Console.info("Available examples:");
_.each(examples, function (e) {
Console.stdout.write(" " + e + "\n");
Console.info(
Console.command(e),
Console.options({ indent: 2 }));
});
Console.stdout.write("\n" +
"Create a project from an example with 'meteor create --example <name>'.\n");
Console.info();
Console.info(
"Create a project from an example with " +
Console.command("'meteor create --example <name>'") + ".");
return 0;
};
@@ -517,13 +526,13 @@ main.registerCommand({
var appPath = path.resolve(appPathAsEntered);
if (fs.existsSync(appPath)) {
Console.stderr.write(appPath + ": Already exists\n");
Console.error(appPath + ": Already exists");
return 1;
}
if (files.findAppDir(appPath)) {
Console.stderr.write(
"You can't create a Meteor project inside another Meteor project.\n");
Console.error(
"You can't create a Meteor project inside another Meteor project.");
return 1;
}
@@ -533,8 +542,11 @@ main.registerCommand({
if (options.example) {
if (examples.indexOf(options.example) === -1) {
Console.stderr.write(options.example + ": no such example\n\n");
Console.stderr.write("List available applications with 'meteor create --list'.\n");
Console.error(options.example + ": no such example.");
Console.error();
Console.error(
"List available applications with",
Console.command("'meteor create --list'") + ".");
return 1;
} else {
files.cp_r(path.join(exampleDir, options.example), appPath, {
@@ -597,10 +609,12 @@ main.registerCommand({
Console.info(message);
}
Console.stdout.write(
"To run your new app:\n" +
" cd " + appPathAsEntered + "\n" +
" meteor\n");
Console.info("To run your new app:");
Console.info(
Console.command("cd " + appPathAsEntered), Console.options({ indent: 2 }));
Console.info(
Console.command("meteor"), Console.options({ indent: 2 }));
});
///////////////////////////////////////////////////////////////////////////////
@@ -638,11 +652,13 @@ main.registerCommand(_.extend({ name: 'bundle', hidden: true
}, buildCommands),
function (options) {
Console.stderr.write(
"This command has been deprecated in favor of 'meteor build', which allows you to\n" +
"build for multiple platforms and outputs a directory instead of a single\n" +
"tarball. See 'meteor help build' for more information.\n\n");
Console.error(
"This command has been deprecated in favor of " +
Console.command("'meteor build'") + ", which allows you to " +
"build for multiple platforms and outputs a directory instead of " +
"a single tarball. See " + Console.command("'meteor help build'") +
"for more information.");
Console.error();
return buildCommand(_.extend(options, { _serverOnly: true }));
});
@@ -697,20 +713,20 @@ var buildCommand = function (options) {
var parsedMobileServer = utils.parseUrl(
mobileServer, { protocol: "http://" });
} catch (err) {
Console.stderr.write(err.message);
Console.error(err.message);
return 1;
}
if (! parsedMobileServer.host) {
Console.stderr.write("--server must include a hostname.\n");
Console.error("--server must include a hostname.");
return 1;
}
} else {
// For Cordova builds, require '--server'.
// XXX better error message?
Console.stderr.write(
"Supply the server hostname and port in the --server option\n" +
"for mobile app builds.\n");
Console.error(
"Supply the server hostname and port in the --server option " +
"for mobile app builds.");
return 1;
}
var cordovaSettings = {};
@@ -742,11 +758,14 @@ var buildCommand = function (options) {
// We would like the output path to be outside the app directory, which
// means the first step to getting there is going up a level.
if (relative.substr(0, 3) !== ('..' + path.sep)) {
Console.warn("");
Console.warn("Warning: The output directory is under your source tree.");
Console.warn(" Your generated files may get interpreted as source code!");
Console.warn(" Consider building into a different directory instead (" + Console.command("meteor build ../output") + ")");
Console.warn("");
Console.warn();
Console.labelWarn(
"The output directory is under your source tree.",
"Your generated files may get interpreted as source code!",
"Consider building into a different directory instead (" +
Console.command("meteor build ../output") + ")",
Console.options({ indent: 2 }));
Console.warn();
}
}
@@ -775,8 +794,8 @@ var buildCommand = function (options) {
}
});
if (bundleResult.errors) {
Console.stderr.write("Errors prevented bundling:\n");
Console.stderr.write(bundleResult.errors.formatMessages());
Console.error("Errors prevented bundling:");
Console.error(bundleResult.errors.formatMessages());
return 1;
}
@@ -790,8 +809,8 @@ var buildCommand = function (options) {
files.createTarball(path.join(buildDir, 'bundle'), outputTar);
} catch (err) {
Console.stderr.write("Errors during tarball creation:\n");
Console.stderr.write(err.message);
Console.error("Errors during tarball creation:");
Console.error(err.message);
files.rm_recursive(buildDir);
return 1;
}
@@ -868,17 +887,18 @@ main.registerCommand({
// specified?
if (! mongoPort) {
Console.stdout.write(
"mongo: Meteor isn't running a local MongoDB server.\n" +
"\n" +
"This command only works while Meteor is running your application\n" +
"locally. Start your application first. (This error will also occur if\n" +
"you asked Meteor to use a different MongoDB server with $MONGO_URL when\n" +
"you ran your application.)\n" +
"\n" +
"If you're trying to connect to the database of an app you deployed\n" +
"with 'meteor deploy', specify your site's name with this command.\n"
);
Console.info("mongo: Meteor isn't running a local MongoDB server.");
Console.info();
Console.info(
"This command only works while Meteor is running your application " +
"locally. Start your application first. (This error will also occur " +
"if you asked Meteor to use a different MongoDB server with " +
"$MONGO_URL when you ran your application.)");
Console.info();
Console.info(
"If you're trying to connect to the database of an app you deployed " +
"with " + Console.command("'meteor deploy'") +
", specify your site's name with this command.");
return 1;
}
mongoUrl = "mongodb://127.0.0.1:" + mongoPort + "/meteor";
@@ -925,13 +945,14 @@ main.registerCommand({
catalogRefresh: new catalog.Refresh.Never()
}, function (options) {
if (options.args.length !== 0) {
Console.stderr.write(
"meteor reset only affects the locally stored database.\n" +
"\n" +
"To reset a deployed application use\n" +
" meteor deploy --delete appname\n" +
"followed by\n" +
" meteor deploy appname\n");
Console.error("meteor reset only affects the locally stored database.");
Console.error();
Console.error("To reset a deployed application use");
Console.error(
Console.command("meteor deploy --delete appname"), Console.options({ indent: 2 }));
Console.error("followed by");
Console.error(
Console.command("meteor deploy appname"), Console.options({ indent: 2 }));
return 1;
}
@@ -942,18 +963,18 @@ main.registerCommand({
require(path.join(__dirname, 'run-mongo.js')).findMongoPort;
var isRunning = !! findMongoPort(options.appDir);
if (isRunning) {
Console.stderr.write(
"reset: Meteor is running.\n" +
"\n" +
"This command does not work while Meteor is running your application.\n" +
"Exit the running Meteor development server.\n");
Console.error("reset: Meteor is running.");
Console.error();
Console.error(
"This command does not work while Meteor is running your application.",
"Exit the running Meteor development server.");
return 1;
}
var localDir = path.join(options.appDir, '.meteor', 'local');
files.rm_recursive(localDir);
Console.stdout.write("Project reset.\n");
Console.info("Project reset.");
});
///////////////////////////////////////////////////////////////////////////////
@@ -1004,13 +1025,14 @@ main.registerCommand({
if (options.password) {
if (useGalaxy) {
Console.stderr.write("Galaxy does not support --password.\n");
Console.error("Galaxy does not support --password.");
} else {
Console.stderr.write(
"Setting passwords on apps is no longer supported. Now there are\n" +
"user accounts and your apps are associated with your account so that\n" +
"only you (and people you designate) can access them. See the\n" +
"'meteor claim' and 'meteor authorized' commands.\n");
Console.error(
"Setting passwords on apps is no longer supported. Now there are " +
"user accounts and your apps are associated with your account so " +
"that only you (and people you designate) can access them. See the " +
Console.command("'meteor claim'") + " and " +
Console.command("'meteor authorized'") + " commands.");
}
return 1;
}
@@ -1018,18 +1040,16 @@ main.registerCommand({
var starball = options.star;
if (starball && ! useGalaxy) {
// XXX it would be nice to support this for non-Galaxy deploys too
Console.stderr.write(
"--star: only supported when deploying to Galaxy.\n");
Console.error("--star: only supported when deploying to Galaxy.");
return 1;
}
var loggedIn = auth.isLoggedIn();
if (! loggedIn) {
Console.stderr.write(
"To instantly deploy your app on a free testing server, just enter your\n" +
"email address!\n" +
"\n");
Console.error(
"To instantly deploy your app on a free testing server,",
"just enter your email address!");
Console.error();
if (! auth.registerOrLogIn())
return 1;
}
@@ -1037,10 +1057,11 @@ main.registerCommand({
// Override architecture iff applicable.
var buildArch = DEPLOY_ARCH;
if (options['override-architecture-with-local']) {
Console.stdout.write(
"\n => WARNING: OVERRIDING DEPLOY ARCHITECTURE WITH LOCAL ARCHITECTURE\n");
Console.stdout.write(
" => If your app contains binary code, it may break terribly and you will be sad.\n\n");
Console.warn();
Console.labelWarn(
"OVERRIDING DEPLOY ARCHITECTURE WITH LOCAL ARCHITECTURE.",
"If your app contains binary code, it may break in unexpected " +
"and terrible ways.");
buildArch = archinfo.host();
}
@@ -1142,14 +1163,15 @@ main.registerCommand({
}, function (options) {
if (options.add && options.remove) {
Console.stderr.write(
"Sorry, you can only add or remove one user at a time.\n");
Console.error(
"Sorry, you can only add or remove one user at a time.");
return 1;
}
if ((options.add || options.remove) && options.list) {
Console.stderr.write(
"Sorry, you can't change the users at the same time as you're listing them.\n");
Console.error(
"Sorry, you can't change the users at the same time as",
"you're listing them.");
return 1;
}
@@ -1158,16 +1180,17 @@ main.registerCommand({
var site = qualifySitename(options.args[0]);
if (hostedWithGalaxy(site)) {
Console.stderr.write(
"Sites hosted on Galaxy do not have an authorized user list.\n" +
"Instead, go to your Galaxy dashboard to change the authorized users\n" +
"of your Galaxy.\n");
Console.error(
"Sites hosted on Galaxy do not have an authorized user list. " +
"Instead, go to your Galaxy dashboard to change the authorized users " +
"of your Galaxy.\n");
return 1;
}
if (! auth.isLoggedIn()) {
Console.stderr.write(
"You must be logged in for that. Try 'meteor login'.\n");
Console.error(
"You must be logged in for that. Try " +
Console.command("'meteor login'"));
return 1;
}
@@ -1194,16 +1217,19 @@ main.registerCommand({
var site = qualifySitename(options.args[0]);
if (! auth.isLoggedIn()) {
Console.stderr.write(
"You must be logged in to claim sites. Use 'meteor login' to log in.\n" +
"If you don't have a Meteor developer account yet, create one by clicking\n" +
"'Sign in' and then 'Create account' at www.meteor.com.\n\n");
Console.error(
"You must be logged in to claim sites. Use " +
Console.command("'meteor login'") + " to log in. If you don't have a " +
"Meteor developer account yet, create one by clicking " +
Console.command("'Sign in'") + " and then " +
Console.command("'Create account'") + " at www.meteor.com.");
Console.error();
return 1;
}
if (hostedWithGalaxy(site)) {
Console.stderr.write(
"Sorry, you can't claim sites that are hosted on Galaxy.\n");
Console.error(
"Sorry, you can't claim sites that are hosted on Galaxy.");
return 1;
}
@@ -1270,19 +1296,19 @@ main.registerCommand({
try {
var parsedUrl = utils.parseUrl(options.port);
} catch (err) {
Console.stderr.write(err.message);
Console.error(err.message);
return 1;
}
if (! parsedUrl.port) {
Console.stderr.write("--port must include a port.\n");
Console.error("--port must include a port.");
return 1;
}
try {
var parsedMobileServer = utils.mobileServerForRun(options);
} catch (err) {
Console.stderr.write(err.message);
Console.error(err.message);
return 1;
}
@@ -1583,18 +1609,18 @@ main.registerCommand({
var loggedInAccountsConnectionOrPrompt = function (action) {
var token = auth.getSessionToken(config.getAccountsDomain());
if (! token) {
Console.stderr.write("You must be logged in to " + action + ".\n");
Console.error("You must be logged in to " + action + ".");
auth.doUsernamePasswordLogin({ retry: true });
Console.stdout.write("\n");
Console.info();
}
token = auth.getSessionToken(config.getAccountsDomain());
var conn = auth.loggedInAccountsConnection(token);
if (conn === null) {
// Server rejected our token.
Console.stderr.write("You must be logged in to " + action + ".\n");
Console.error("You must be logged in to " + action + ".");
auth.doUsernamePasswordLogin({ retry: true });
Console.stdout.write("\n");
Console.info();
token = auth.getSessionToken(config.getAccountsDomain());
conn = auth.loggedInAccountsConnection(token);
}
@@ -1612,9 +1638,9 @@ main.registerCommand({
var token = auth.getSessionToken(config.getAccountsDomain());
if (! token) {
Console.stderr.write("You must be logged in to list your organizations.\n");
Console.error("You must be logged in to list your organizations.");
auth.doUsernamePasswordLogin({ retry: true });
Console.stdout.write("\n");
Console.info();
}
var url = config.getAccountsApiUrl() + "/organizations";
@@ -1627,13 +1653,13 @@ main.registerCommand({
});
var body = JSON.parse(result.body);
} catch (err) {
Console.stderr.write("Error listing organizations.\n");
Console.error("Error listing organizations.");
return 1;
}
if (result.response.statusCode === 401 &&
body && body.error === "invalid_credential") {
Console.stderr.write("You must be logged in to list your organizations.\n");
Console.error("You must be logged in to list your organizations.");
// XXX It would be nice to do a username/password prompt here like
// we do for the other orgs commands.
return 1;
@@ -1641,14 +1667,14 @@ main.registerCommand({
if (result.response.statusCode !== 200 ||
! body || ! body.organizations) {
Console.stderr.write("Error listing organizations.\n");
Console.error("Error listing organizations.");
return 1;
}
if (body.organizations.length === 0) {
Console.stdout.write("You are not a member of any organizations.\n");
Console.info("You are not a member of any organizations.");
} else {
Console.stdout.write(_.pluck(body.organizations, "name").join("\n") + "\n");
Console.rawInfo(_.pluck(body.organizations, "name").join("\n") + "\n");
}
return 0;
});
@@ -1666,8 +1692,8 @@ main.registerCommand({
}, function (options) {
if (options.add && options.remove) {
Console.stderr.write(
"Sorry, you can only add or remove one member at a time.\n");
Console.error(
"Sorry, you can only add or remove one member at a time.");
throw new main.ShowUsage;
}
@@ -1685,28 +1711,26 @@ main.registerCommand({
options.add ? "addOrganizationMember": "removeOrganizationMember",
options.args[0], username);
} catch (err) {
Console.stderr.write("Error " +
(options.add ? "adding" : "removing") +
" member: " + err.reason + "\n");
Console.error("Error " +
(options.add ? "adding" : "removing") +
" member: " + err.reason);
return 1;
}
Console.stdout.write(username + " " +
Console.info(username + " " +
(options.add ? "added to" : "removed from") +
" organization " + options.args[0] + ".\n");
" organization " + options.args[0] + ".");
} else {
// Showing the members of an org
try {
var result = conn.call("showOrganization", options.args[0]);
} catch (err) {
Console.stderr.write("Error showing organization: " +
err.reason + "\n");
Console.error("Error showing organization: " + err.reason);
return 1;
}
var members = _.pluck(result, "username");
Console.stdout.write(members.join("\n") + "\n");
Console.rawInfo(members.join("\n") + "\n");
}
return 0;
@@ -1755,7 +1779,7 @@ main.registerCommand({
} catch (e) {
if (!(e instanceof SyntaxError))
throw e;
Console.stderr.write("Bad regular expression: " + str + "\n");
Console.error("Bad regular expression: " + str);
return null;
}
};
@@ -1818,8 +1842,9 @@ main.registerCommand({
}, function (options) {
auth.pollForRegistrationCompletion();
if (! auth.isLoggedIn()) {
Console.stderr.write(
"You must be logged in for that. Try 'meteor login'.\n");
Console.error(
"You must be logged in for that. Try " +
Console.command("'meteor login'") + ".");
return 1;
}
@@ -1898,7 +1923,7 @@ main.registerCommand({
'key' : ret.sshKey,
'hostKey' : ret.hostKey
};
Console.info(JSON.stringify(retJson, null, 2));
Console.rawInfo(JSON.stringify(retJson, null, 2) + "\n");
return 0;
}
@@ -1926,7 +1951,7 @@ main.registerCommand({
maybeVerbose];
var printOptions = connOptions.join(' ');
maybeLog("Connecting: ssh " + printOptions);
maybeLog("Connecting: " + Console.command("ssh " + printOptions));
var child_process = require('child_process');
var future = new Future;
@@ -1978,10 +2003,10 @@ main.registerCommand({
return 'none';
};
Console.stdout.write(p('email') + " " + p('port') + " " + p('changed') +
" " + p('args') + "\n");
Console.info(p('email') + " " + p('port') + " " + p('changed') +
" " + p('args'));
if (options.url)
Console.stdout.write('url\n');
Console.info('url');
if (options['delete'])
Console.stdout.write('delete\n');
Console.info('delete');
});

View File

@@ -1,17 +1,17 @@
///
/// utility functions for formatting output to the screen
/// A set of utility functions for formatting output sent to the screen.
///
/// Console offers several pieces of functionality:
/// debug / info / warn messages:
/// Outputs to the screen, optionally with colors (when pretty == true)
/// 'legacy' functions: Console.stdout.write & Console.stderr.write
/// Make porting code a lot easier (just a regex from process -> Console)
/// Progress bar support
/// Displays a progress bar on the screen, but hides it around log messages
/// (The need to hide it is why we have this class)
/// - debug / info / warn messages: Output to the screen, optionally with
/// colors (when pretty == true). Wrap the output to the width of the user's
/// terminal, making sure to not split the same word over multiple
/// lines. (Also provides 'rawInfo', 'rawDebug' (etc) for when you DON'T want
/// to pre-process the output.)
/// - Progress bar support
/// Display a progress bar on the screen, but hide it around log messages.
///
/// In future, we might do things like move all support for verbose mode in here,
/// and also integrate the buildmessage functionality into here
/// In future, we might do things like move all support for verbose mode in
/// here, and also integrate the buildmessage functionality into here
///
var _ = require('underscore');
@@ -24,6 +24,7 @@ var buildmessage = require('./buildmessage.js');
var chalk = require('chalk');
var cleanup = require('./cleanup.js');
var utils = require('./utils.js');
var wordwrap = require('wordwrap');
var PROGRESS_DEBUG = !!process.env.METEOR_PROGRESS_DEBUG;
var FORCE_PRETTY=undefined;
@@ -31,11 +32,10 @@ if (process.env.METEOR_PRETTY_OUTPUT) {
FORCE_PRETTY = process.env.METEOR_PRETTY_OUTPUT != '0';
}
if (!process.env.METEOR_COLOR) {
if (! process.env.METEOR_COLOR) {
chalk.enabled = false;
}
var STATUSLINE_MAX_LENGTH = 60; // XXX unused?
var STATUS_MAX_LENGTH = 40;
@@ -49,6 +49,18 @@ var STATUS_INTERVAL_MS = 500;
// XXX: ? FALLBACK_STATUS = 'Pondering';
var FALLBACK_STATUS = '';
// If there is a part of the larger text, and we really want to make sure that
// it doesn't get split up, we will replace the space with a utf character that
// we are not likely to use anywhere else. This one looks like the a BLACK SUN
// WITH RAYS. We intentionally want to NOT use a space-like character: it should
// be obvious that something has gone wrong if this ever gets printed.
var SPACE_REPLACEMENT = '\u2600';
// In Javascript, replace only replaces the first occurance and this is the
// proposed alternative.
var replaceAll = function (str, search, replace) {
return str.split(search).join(replace);
};
var spacesArray = new Array(200).join(' ');
var spacesString = function (length) {
if (length > spacesArray.length) {
@@ -56,6 +68,8 @@ var spacesString = function (length) {
}
return spacesArray.substring(0, length);
};
var ARROW = "=> ";
var toFixedLength = function (text, length) {
text = text || "";
@@ -72,7 +86,8 @@ var toFixedLength = function (text, length) {
return text;
};
// No-op progress display, that means we don't have to handle the 'no progress display' case
// No-op progress display, that means we don't have to handle the 'no progress
// display' case
var ProgressDisplayNone = function () {
};
@@ -217,7 +232,7 @@ _.extend(ProgressBarRenderer.prototype, {
.replace(':current', self.curr)
.replace(':total', self.total)
.replace(':elapsed', isNaN(elapsed) ? '0.0' : (elapsed / 1000).toFixed(1))
.replace(':eta', (isNaN(eta) || !isFinite(eta)) ? '0.0' : (eta / 1000).toFixed(1))
.replace(':eta', (isNaN(eta) || ! isFinite(eta)) ? '0.0' : (eta / 1000).toFixed(1))
.replace(':percent', percent.toFixed(0) + '%');
/* compute the available space (non-zero) for the bar */
@@ -312,7 +327,7 @@ _.extend(ProgressDisplayFull.prototype, {
var streamColumns = this._stream.columns;
var statusColumns;
var progressColumns;
if (!streamColumns) {
if (! streamColumns) {
statusColumns = STATUS_MAX_LENGTH;
progressColumns = 0;
} else {
@@ -377,7 +392,7 @@ _.extend(StatusPoller.prototype, {
}
self._pollFiber = Fiber(function () {
while (!self._stop) {
while (! self._stop) {
utils.sleepMs(100);
self.statusPoll();
@@ -414,7 +429,7 @@ _.extend(StatusPoller.prototype, {
} else {
var fraction = state.done ? 1.0 : (state.current / state.end);
if (!isNaN(fraction) && fraction >= 0) {
if (! isNaN(fraction) && fraction >= 0) {
progressDisplay.updateProgress(fraction, startTime);
} else {
progressDisplay.updateProgress(0, startTime);
@@ -471,12 +486,6 @@ var Console = function (options) {
// Legacy helpers
self.stdout = {};
self.stderr = {};
self.stdout.write = function (msg) {
self._legacyWrite(LEVEL_INFO, msg);
};
self.stderr.write = function (msg) {
self._legacyWrite(LEVEL_WARN, msg);
};
self._stream = process.stdout;
@@ -497,7 +506,6 @@ var Console = function (options) {
});
};
var LEVEL_CODE_ERROR = 4;
var LEVEL_CODE_WARN = 3;
var LEVEL_CODE_INFO = 2;
@@ -508,6 +516,15 @@ var LEVEL_WARN = { code: LEVEL_CODE_WARN };
var LEVEL_INFO = { code: LEVEL_CODE_INFO };
var LEVEL_DEBUG = { code: LEVEL_CODE_DEBUG };
// We use a special class to represent the options that we send to the Console
// because it allows us to call 'instance of' on the last argument of variadic
// functions. This allows us to keep the signature of our custom output
// functions (ex: info) roughly the same as the originals.
var ConsoleOptions = function (o) {
var self = this;
self.options = o;
}
_.extend(Console.prototype, {
LEVEL_ERROR: LEVEL_ERROR,
LEVEL_WARN: LEVEL_WARN,
@@ -537,7 +554,7 @@ _.extend(Console.prototype, {
self._pretty = self._progressDisplayEnabled = true;
// Update the screen if anything changed.
if (!originalPretty || !originalProgressDisplayEnabled)
if (! originalPretty || ! originalProgressDisplayEnabled)
self._updateProgressDisplay();
try {
@@ -547,7 +564,7 @@ _.extend(Console.prototype, {
self._pretty = originalPretty;
self._progressDisplayEnabled = originalProgressDisplayEnabled;
// Update the screen if anything changed.
if (!originalPretty || !originalProgressDisplayEnabled)
if (! originalPretty || ! originalProgressDisplayEnabled)
self._updateProgressDisplay();
}
},
@@ -557,6 +574,16 @@ _.extend(Console.prototype, {
self.verbose = verbose;
},
// Get the current width of the Console.
width: function () {
var width = 80;
var stream = process.stdout;
if (stream && stream.isTTY && stream.columns) {
width = stream.columns;
}
return width;
},
// This can be called during long lived operations; it will keep the spinner spinning.
// (This code used to be in Patience.nudge)
//
@@ -583,6 +610,38 @@ _.extend(Console.prototype, {
}
},
// Initializes and returns a new ConsoleOptions object. This allows us to call
// 'instance of' on the ConsoleOptions in parseVariadicInput, by ensuring that
// the object created with Console.options is, in fact, a new object.
options: function (o) {
return new ConsoleOptions(o);
},
// Deal with the arguments to a variadic print function that also takes an
// optional ConsoleOptions argument at the end.
//
// Returns an object with keys:
// - options: The options that were passed in, or an empty object.
// - message: Arguments to the original function, parsed as a string.
//
_parseVariadicInput: function (args) {
var self = this;
var msgArgs;
var options;
// If the last argument is an instance of ConsoleOptions, then we should
// separate it out, and only send the first N-1 arguments to be parsed as a
// message.
if (_.last(args) instanceof ConsoleOptions) {
msgArgs = _.initial(args);
options = _.last(args).options;
} else {
msgArgs = args;
options = {};
}
var message = self._format(msgArgs);
return { message: message, options: options };
},
isLevelEnabled: function (levelCode) {
return (this.verbose || this._logThreshold <= levelCode);
},
@@ -591,9 +650,12 @@ _.extend(Console.prototype, {
return this.isLevelEnabled(LEVEL_CODE_DEBUG);
},
debug: function(/*arguments*/) {
// Don't pretty-fy this output by trying to, for example, line-wrap it. Just
// print it to the screen as it is.
rawDebug: function(/*arguments*/) {
var self = this;
if (!self.isDebugEnabled()) {
if (! self.isDebugEnabled()) {
return;
}
@@ -601,13 +663,32 @@ _.extend(Console.prototype, {
self._print(LEVEL_DEBUG, message);
},
// By default, Console.debug automatically line wraps the output.
//
// Takes in an optional Console.options({}) argument at the end, with the
// following keys:
// - bulletPoint: start the first line with a given string, then offset the
// subsequent lines by the length of that string. See _wrap for more details.
// - indent: offset the entire string by a specific number of
// characters. See _wrap for more details.
//
debug: function(/*arguments*/) {
var self = this;
if (! self.isDebugEnabled()) { return; }
var message = self._prettifyMessage(arguments);
self._print(LEVEL_DEBUG, message);
},
isInfoEnabled: function () {
return this.isLevelEnabled(LEVEL_CODE_INFO);
},
info: function(/*arguments*/) {
// Don't pretty-fy this output by trying to, for example, line-wrap it. Just
// print it to the screen as it is.
rawInfo: function(/*arguments*/) {
var self = this;
if (!self.isInfoEnabled()) {
if (! self.isInfoEnabled()) {
return;
}
@@ -615,13 +696,24 @@ _.extend(Console.prototype, {
self._print(LEVEL_INFO, message);
},
// Generally, we want to process the output for legibility, for example, by
// wrapping it. For raw output (ex: stack traces, user logs, etc), use the
// rawInfo function. For more information about options, see: debug.
info: function(/*arguments*/) {
var self = this;
if (! self.isInfoEnabled()) { return; }
var message = self._prettifyMessage(arguments);
self._print(LEVEL_INFO, message);
},
isWarnEnabled: function () {
return this.isLevelEnabled(LEVEL_CODE_WARN);
},
warn: function(/*arguments*/) {
rawWarn: function(/*arguments*/) {
var self = this;
if (!self.isWarnEnabled()) {
if (! self.isWarnEnabled()) {
return;
}
@@ -629,19 +721,45 @@ _.extend(Console.prototype, {
self._print(LEVEL_WARN, message);
},
error: function(/*arguments*/) {
// Generally, we want to process the output for legibility, for example, by
// wrapping it. For raw output (ex: stack traces, user logs, etc), use the
// rawWarn function. For more information about options, see: debug.
warn: function(/* arguments */) {
var self = this;
if (! self.isWarnEnabled()) { return; }
var message = self._prettifyMessage(arguments);
self._print(LEVEL_WARN, message);
},
rawError: function(/*arguments*/) {
var self = this;
var message = self._format(arguments);
self._print(LEVEL_ERROR, message);
},
_legacyWrite: function (level, message) {
// Generally, we want to process the output for legibility, for example, by
// wrapping it. For raw output (ex: stack traces, user logs, etc), use the
// rawError function. For more information about options, see: debug.
error: function(/*arguments*/) {
var self = this;
if(message.substr && message.substr(-1) == '\n') {
message = message.substr(0, message.length - 1);
}
self._print(level, message);
var message = self._prettifyMessage(arguments);
self._print(LEVEL_ERROR, message);
},
_prettifyMessage: function (msgArguments) {
var self = this;
var parsedArgs = self._parseVariadicInput(msgArguments);
var wrapOpts = {
indent: parsedArgs.options.indent,
bulletPoint: parsedArgs.options.bulletPoint
};
var wrappedMessage = self._wrapText(parsedArgs.message, wrapOpts);
wrappedMessage += "\n";
return wrappedMessage;
},
_print: function(level, message) {
@@ -679,69 +797,95 @@ _.extend(Console.prototype, {
}
if (style) {
dest.write(style(message + '\n'));
dest.write(style(message));
} else {
dest.write(message + '\n');
dest.write(message);
}
// XXX: Pause before showing the progress display, to prevent flicker/spewing messages
// XXX: Pause before showing the progress display, to prevent
// flicker/spewing messages
// Repaint the progress display
progressDisplay.repaint();
},
// A wrapper around Console.info. Prints the message out in green (if pretty),
// with the CHECKMARK as the bullet point in front of it.
success: function (message) {
var self = this;
if (!self._pretty) {
return message;
if (! self._pretty) {
return self.info(message);
}
return chalk.green('\u2713 ' + message); // CHECK MARK
var checkmark = chalk.green('\u2713'); // CHECKMARK
return self.info(
chalk.green(message),
self.options({ bulletPoint: checkmark + " "}));
},
fail: function (message) {
// Wrapper around Console.info. Prints the message out in red (if pretty)
// with the BALLOT X as the bullet point in front of it.
failInfo: function (message) {
var self = this;
return self._fail(message, "info");
},
// Wrapper around Console.warn. Prints the message out in red (if pretty)
// with the ascii x as the bullet point in front of it.
failWarn: function (message) {
var self = this;
return self._fail(message, "warn");
},
// Print the message in red (if pretty) with an x bullet point in front of it.
_fail: function (message, printFn) {
var self = this;
if (!self._pretty) {
return message;
if (! self._pretty) {
return printFn(message);
}
return chalk.red('\u2717 ' + message); // BALLOT X
var xmark = chalk.red('\u2717');
return self[printFn](
chalk.red(message),
self.options({ bulletPoint: xmark + " " }));
},
command: function (message) {
return this.bold(message);
},
url: function (message) {
return this.underline(message);
},
underline: function (message) {
// Wrapper around Console.warn that prints a large "WARNING" label in front.
labelWarn: function (message) {
var self = this;
if (!self._pretty) {
return message;
}
return chalk.underline(message);
return self.warn(message, self.options({ bulletPoint: "WARNING: " }));
},
bold: function (message) {
// Wrappers around Console functions to prints an "=> " in front. Optional
// indent to indent the arrow.
arrowError: function (message, indent) {
var self = this;
if (!self._pretty) {
return message;
}
return chalk.bold(message);
},
_format: function (logArguments) {
return util.format.apply(util, logArguments);
return self._arrowPrint("error", message, indent);
},
arrowWarn: function (message, indent) {
var self = this;
return self._arrowPrint("warn", message, indent);
},
arrowInfo: function (message, indent) {
var self = this;
return self._arrowPrint("info", message, indent);
},
_arrowPrint: function(printFn, message, indent) {
var self = this;
indent = indent || 0;
return self[printFn](
message,
self.options({ bulletPoint: ARROW, indent: indent }));
},
// A wrapper around console.error. Given an error and some background
// information, print out the correct set of messages depending on verbose
// level, etc.
printError: function (err, info) {
var self = this;
var message = err.message;
if (!message) {
if (! message) {
message = "Unexpected error";
if (self.verbose) {
message += " (" + err.toString() + ")";
@@ -754,18 +898,187 @@ _.extend(Console.prototype, {
self.error(message);
if (self.verbose && err.stack) {
self.info(err.stack);
self.rawInfo(err.stack + "\n");
}
},
// A wrapper to print out buildmessage errors.
printMessages: function (messages) {
var self = this;
if (messages.hasMessages()) {
self._print(LEVEL_ERROR, "\n" + messages.formatMessages());
self.error("\n" + messages.formatMessages());
}
},
// Wrap commands in this function -- it ensures that commands don't get line
// wrapped (ie: print 'meteor' at the end of the line, and 'create --example'
// at the beginning of the next one).
//
// To use, wrap commands that you send into print functions with this
// function, like so: Console.info(text + Console.command("meteor create
// --example leaderboard") + moretext).
//
// If pretty print is on, this will also bold the commands.
command: function (message) {
var self = this;
var unwrapped = self.noWrap(message);
return self.bold(unwrapped);
},
// Underline the URLs (if pretty print is on).
url: function (message) {
var self = this;
// If we are going to print URLs with spaces, we should turn spaces into
// things browsers understand.
var unspaced =
replaceAll(message, ' ', '%20');
// There is no need to call noWrap here, since that only handles spaces (and
// we have done that). If it ever handles things other than spaces, we
// should make sure to call it here.
return self.underline(unspaced);
},
// Format a filepath to not wrap. This does NOT automatically escape spaces
// (ie: add a slash in front so the user could copy paste the file path into a
// terminal).
path: function (message) {
var self = this;
// Make sure that we don't wrap this.
var unwrapped = self.noWrap(message);
return self.bold(unwrapped);
},
// Do not wrap this substring when you send it into a non-raw print function.
// DO NOT print the result of this call with a raw function.
noWrap: function (message) {
var noBlanks = replaceAll(message, ' ', SPACE_REPLACEMENT);
return noBlanks;
},
// A wrapper around the underline functionality of chalk.
underline: function (message) {
var self = this;
if (! self._pretty) {
return message;
}
return chalk.underline(message);
},
// A wrapper around the bold functionality of chalk.
bold: function (message) {
var self = this;
if (! self._pretty) {
return message;
}
return chalk.bold(message);
},
// Prints a two column table in a nice format:
// The first column is printed entirely, the second only as space permits
printTwoColumns : function (rows, options) {
var self = this;
options = options || {};
var longest = '';
_.each(rows, function (row) {
var col0 = row[0] || '';
if (col0.length > longest.length)
longest = col0;
});
var pad = longest.replace(/./g, ' ');
var width = self.width();
var out = '';
_.each(rows, function (row) {
var col0 = row[0] || '';
var col1 = row[1] || '';
var line = self.bold(col0) + pad.substr(col0.length);
line += " " + col1;
if (line.length > width) {
line = line.substr(0, width - 3) + '...';
}
out += line + "\n";
});
var level = options.level || self.LEVEL_INFO;
out += "\n";
self._print(level, out);
return out;
},
// Format logs according to the spec in utils.
_format: function (logArguments) {
return util.format.apply(util, logArguments);
},
// Wraps long strings to the length of user's terminal. Inserts linebreaks
// between words when nearing the end of the line. Returns the wrapped string
// and takes the following arguments:
//
// text: the text to wrap
// options:
// - bulletPoint: start the first line with a given string, then offset the
// subsequent lines by the length of that string. For example, if the
// bulletpoint is " => ", we would get:
// " => some long message starts here
// and then continues here."
// - indent: offset the entire string by a specific number of
// characters. For example:
// " This entire message is indented
// by two characters."
//
// Passing in both options will offset the bulletPoint by the indentation,
// like so:
// " this message is indented by two."
// " => this mesage indented by two and
// and also starts with an arrow."
//
// When printing commands in-line, it is best to wrap commands in with Console.command
// to make sure that they don't get line-wrapped. See Console.command for more details.
_wrapText: function (text, options) {
var self = this;
options = options || {};
// Compute the maximum offset on the bulk of the message.
var maxIndent = 0;
if (options.indent && options.indent > 0) {
maxIndent = maxIndent + options.indent;
}
if (options.bulletPoint) {
maxIndent = maxIndent + options.bulletPoint.length;
}
// Get the maximum width, or if we are not running in a terminal (self-test,
// for example), default to 80 columns.
var max = self.width();
// Wrap the text using the npm wordwrap library.
var wrappedText = wordwrap(maxIndent, max)(text);
// Insert the start string, if applicable.
if (options.bulletPoint) {
// Save the initial indent level.
var initIndent = options.indent ?
wrappedText.substring(0, options.indent) : "";
// Add together the initial indent (if any), the bullet point and the
// remainder of the message.
wrappedText = initIndent + options.bulletPoint +
wrappedText.substring(maxIndent);
}
// If we have previously replaces any spaces, now is the time to bring them
// back.
wrappedText = replaceAll(wrappedText, SPACE_REPLACEMENT, ' ');
return wrappedText;
},
// Enables the progress bar, or disables it when called with (false)
enableProgressDisplay: function (enabled) {
var self = this;
@@ -789,12 +1102,12 @@ _.extend(Console.prototype, {
var newProgressDisplay;
if (!self._progressDisplayEnabled) {
if (! self._progressDisplayEnabled) {
newProgressDisplay = new ProgressDisplayNone();
} else if ((!self._stream.isTTY) || (!self._pretty)) {
} else if ((! self._stream.isTTY) || (! self._pretty)) {
// No progress bar if not in pretty / on TTY.
newProgressDisplay = new ProgressDisplayNone(self);
} else if (self._stream.isTTY && !self._stream.columns) {
} else if (self._stream.isTTY && ! self._stream.columns) {
// We might be in a pseudo-TTY that doesn't support
// clearLine() and cursorTo(...).
// It's important that we only enter status message mode
@@ -809,7 +1122,7 @@ _.extend(Console.prototype, {
// Start/stop the status poller, so we never block exit
if (self._progressDisplayEnabled) {
if (!self._statusPoller) {
if (! self._statusPoller) {
self._statusPoller = new StatusPoller(self);
}
} else {
@@ -834,8 +1147,6 @@ _.extend(Console.prototype, {
}
});
Console.prototype.warning = Console.prototype.warn;
// options:
// - echo (boolean): defaults to true
// - prompt (string)

View File

@@ -13,6 +13,7 @@ var _ = require('underscore');
var buildmessage = require('./buildmessage.js');
var ServiceConnection = require('./service-connection.js');
var stats = require('./stats.js');
var Console = require('./console.js').Console;
// If 'error' is an exception that we know how to report in a
// user-friendly way, print an approprite message to stderr and return
@@ -27,9 +28,9 @@ var handleError = function (error, galaxyName, messages) {
if (error.errorType === "Meteor.Error") {
var msg = messages[error.error];
if (msg)
process.stderr.write(msg + "\n");
Console.error(msg);
else if (error.message)
process.stderr.write("Denied: " + error.message + "\n");
Console.error("Denied: " + error.message);
return 1;
} else if (error.errorType === "DDP.ConnectionError") {
// If we have an http/https URL for a galaxyName instead of a
@@ -39,7 +40,7 @@ var handleError = function (error, galaxyName, messages) {
if (m)
galaxyName = m[1];
process.stderr.write(galaxyName + ": connection failed\n");
Console.error(galaxyName + ": connection failed");
return 1;
} else {
throw error;
@@ -147,7 +148,7 @@ exports.deleteApp = function (app) {
try {
conn.call("destroyApp", app);
process.stdout.write("Deleted.\n");
Console.info("Deleted.");
} catch (e) {
return handleError(e, galaxy);
} finally {
@@ -193,7 +194,7 @@ exports.deploy = function (options) {
// concurrent with bundling.
if (! options.starball && ! messages.hasMessages()) {
process.stdout.write('Deploying ' + options.app + '. Bundling...\n');
Console.info('Deploying ' + options.app + '. Bundling...');
var bundleResult = bundler.bundle({
projectContext: options.projectContext,
outputPath: bundlePath,
@@ -230,12 +231,12 @@ exports.deploy = function (options) {
}
if (messages.hasMessages()) {
process.stdout.write("\nErrors prevented deploying:\n");
process.stdout.write(messages.formatMessages());
Console.info("\nErrors prevented deploying:");
Console.info(messages.formatMessages());
return 1;
}
process.stdout.write('Uploading...\n');
Console.info('Uploading...');
var galaxy = exports.discoverGalaxy(options.app);
conn = galaxyServiceConnection(galaxy, "ultraworld");
@@ -289,11 +290,11 @@ exports.deploy = function (options) {
if (error || ((response.statusCode !== 200)
&& (response.statusCode !== 201))) {
if (error && error.message)
process.stderr.write("Upload failed: " + error.message + "\n");
Console.error("Upload failed: " + error.message);
else
process.stderr.write("Upload failed" +
(response.statusCode ?
" (" + response.statusCode + ")\n" : "\n"));
Console.error("Upload failed" +
(response.statusCode ?
" (" + response.statusCode + ")" : ""));
future['return'](false);
} else
future['return'](true);
@@ -313,10 +314,10 @@ exports.deploy = function (options) {
}
if (created)
process.stderr.write(options.app + ": created app\n");
Console.error(options.app + ": created app\n");
process.stderr.write(options.app + ": " +
"pushed revision " + result.serial + "\n");
Console.error(options.app + ": " +
"pushed revision " + result.serial);
return 0;
} finally {
// Close the connection to Galaxy (otherwise Node will continue running).

View File

@@ -256,12 +256,15 @@ var authedRpc = function (options) {
// password-protected app, instruct them to claim it with 'meteor
// claim'.
var printLegacyPasswordMessage = function (site) {
Console.stderr.write(
"\nThis site was deployed with an old version of Meteor that used\n" +
"site passwords instead of user accounts. Now we have a much better\n" +
"system, Meteor developer accounts.\n\n" +
"If this is your site, please claim it into your account with\n" +
" meteor claim " + site + "\n");
Console.error(
"\nThis site was deployed with an old version of Meteor that used " +
"site passwords instead of user accounts. Now we have a much better " +
"system, Meteor developer accounts.");
Console.error();
Console.error("If this is your site, please claim it into your account with");
Console.error(
Console.command("meteor claim " + site),
Console.options({ indent: 2 }));
};
// When the user is trying to do something with an app that they are not
@@ -269,12 +272,16 @@ var printLegacyPasswordMessage = function (site) {
// --add' or switch accounts.
var printUnauthorizedMessage = function () {
var username = auth.loggedInUsername();
Console.stderr.write(
"Sorry, that site belongs to a different user.\n" +
(username ? "You are currently logged in as " + username + ".\n" : "") +
"\nEither have the site owner use 'meteor authorized --add' to add you\n" +
"as an authorized developer for the site, or switch to an authorized\n" +
"account with 'meteor login'.\n");
Console.error("Sorry, that site belongs to a different user.");
if (username) {
Console.error("You are currently logged in as " + username + ".");
}
Console.error();
Console.error(
"Either have the site owner use " +
Console.command("'meteor authorized --add'") + " to add you as an " +
"authorized developer for the site, or switch to an authorized account " +
"with " + Console.command("'meteor login'") + ".");
};
// Take a proposed sitename for deploying to. If it looks
@@ -290,10 +297,10 @@ var canonicalizeSite = function (site) {
// characters (url.parse will do something very strange if a component is
// larger than 63, which is the maximum legal length).
if (site.length > 63) {
Console.stdout.write(
"The maximum hostname length currently supported is 63 characters.\n" +
site + " is too long.\n" +
"Please try again with a shorter URL for your site.\n");
Console.error(
"The maximum hostname length currently supported is 63 characters: " +
site + " is too long. " +
"Please try again with a shorter URL for your site.");
return false;
}
@@ -304,16 +311,16 @@ site + " is too long.\n" +
var parsed = require('url').parse(url);
if (! parsed.hostname) {
Console.stdout.write(
"Please specify a domain to connect to, such as www.example.com or\n" +
"http://www.example.com/\n");
Console.info(
"Please specify a domain to connect to, such as www.example.com or " +
"http://www.example.com/");
return false;
}
if (parsed.pathname != '/' || parsed.hash || parsed.query) {
Console.stdout.write(
"Sorry, Meteor does not yet support specific path URLs, such as\n" +
"http://www.example.com/blog . Please specify the root of a domain.\n");
Console.info(
"Sorry, Meteor does not yet support specific path URLs, such as " +
Console.url("http://www.example.com/blog") + " . Please specify the root of a domain.");
return false;
}
@@ -364,14 +371,13 @@ var bundleAndDeploy = function (options) {
});
if (preflight.errorMessage) {
Console.stderr.write("\nError deploying application: " +
preflight.errorMessage + "\n");
Console.error("Error deploying application: " + preflight.errorMessage);
return 1;
}
if (preflight.protection === "password") {
printLegacyPasswordMessage(site);
Console.stderr.write("If it's not your site, please try a different name!\n");
Console.error("If it's not your site, please try a different name!");
return 1;
} else if (preflight.protection === "account" &&
@@ -383,7 +389,7 @@ var bundleAndDeploy = function (options) {
var buildDir = options.projectContext.getProjectLocalDirectory('build_tar');
var bundlePath = path.join(buildDir, 'bundle');
Console.stdout.write('Deploying to ' + site + '.\n');
Console.info('Deploying to ' + site + '.');
var settings = null;
var messages = buildmessage.capture({
@@ -408,8 +414,8 @@ var bundleAndDeploy = function (options) {
}
if (messages.hasMessages()) {
Console.stdout.write("\nErrors prevented deploying:\n");
Console.stdout.write(messages.formatMessages());
Console.info("\nErrors prevented deploying:");
Console.info(messages.formatMessages());
return 1;
}
@@ -435,15 +441,14 @@ var bundleAndDeploy = function (options) {
if (result.errorMessage) {
Console.stderr.write("\nError deploying application: " +
result.errorMessage + "\n");
Console.error("\nError deploying application: " + result.errorMessage);
return 1;
}
var deployedAt = require('url').parse(result.payload.url);
var hostname = deployedAt.hostname;
Console.stdout.write('Now serving at http://' + hostname + '\n');
Console.info('Now serving at http://' + hostname);
files.rm_recursive(buildDir);
if (! hostname.match(/meteor\.com$/)) {
@@ -452,11 +457,12 @@ var bundleAndDeploy = function (options) {
if (err || cnames[0] !== 'origin.meteor.com') {
dns.resolve(hostname, 'A', function (err, addresses) {
if (err || addresses[0] !== '107.22.210.133') {
Console.stdout.write('-------------\n');
Console.stdout.write("You've deployed to a custom domain.\n");
Console.stdout.write("Please be sure to CNAME your hostname to origin.meteor.com,\n");
Console.stdout.write("or set an A record to 107.22.210.133.\n");
Console.stdout.write('-------------\n');
Console.info('-------------');
Console.info(
"You've deployed to a custom domain.",
"Please be sure to CNAME your hostname",
"to origin.meteor.com, or set an A record to 107.22.210.133.");
Console.info('-------------');
}
});
}
@@ -479,12 +485,11 @@ var deleteApp = function (site) {
});
if (result.errorMessage) {
Console.stderr.write("Couldn't delete application: " +
result.errorMessage + "\n");
Console.error("Couldn't delete application: " + result.errorMessage);
return 1;
}
Console.stdout.write("Deleted.\n");
Console.info("Deleted.");
return 0;
};
@@ -505,8 +510,7 @@ var checkAuthThenSendRpc = function (site, operation, what) {
});
if (preflight.errorMessage) {
Console.stderr.write("Couldn't " + what + ": " +
preflight.errorMessage + "\n");
Console.error("Couldn't " + what + ": " + preflight.errorMessage);
return null;
}
@@ -530,15 +534,17 @@ var checkAuthThenSendRpc = function (site, operation, what) {
} else {
// Shouldn't ever get here because we set the retry flag on the
// login, but just in case.
Console.stderr.write(
"\nYou must be logged in to " + what + " for this app. Use 'meteor login'\n" +
"to log in.\n\n" +
"If you don't have a Meteor developer account yet, you can quickly\n" +
"create one at www.meteor.com.\n");
Console.error(
"\nYou must be logged in to " + what + " for this app. Use " +
Console.command("'meteor login'") + "to log in.");
Console.error();
Console.error(
"If you don't have a Meteor developer account yet, you can quickly " +
"create one at www.meteor.com.");
return null;
}
} else { // User is logged in but not authorized for this app
Console.stderr.write("\n");
Console.error();
printUnauthorizedMessage();
return null;
}
@@ -554,8 +560,7 @@ var checkAuthThenSendRpc = function (site, operation, what) {
});
if (result.errorMessage) {
Console.stderr.write("Couldn't " + what + ": " +
result.errorMessage + "\n");
Console.error("Couldn't " + what + ": " + result.errorMessage);
return null;
}
@@ -590,7 +595,7 @@ var logs = function (site) {
if (result === null) {
return 1;
} else {
Console.stdout.write(result.message);
Console.info(result.message);
auth.maybePrintRegistrationLink({ leadingNewline: true });
return 0;
}
@@ -607,33 +612,35 @@ var listAuthorized = function (site) {
expectPayload: []
});
if (result.errorMessage) {
Console.stderr.write("Couldn't get authorized users list: " +
result.errorMessage + "\n");
Console.error("Couldn't get authorized users list: " + result.errorMessage);
return 1;
}
var info = result.payload;
if (! _.has(info, 'protection')) {
Console.stdout.write("<anyone>\n");
Console.info("<anyone>");
return 0;
}
if (info.protection === "password") {
Console.stdout.write("<password>\n");
Console.info("<password>");
return 0;
}
if (info.protection === "account") {
if (! _.has(info, 'authorized')) {
Console.stderr.write("Couldn't get authorized users list: " +
"You are not authorized\n");
Console.error("Couldn't get authorized users list: " +
"You are not authorized");
return 1;
}
Console.stdout.write((auth.loggedInUsername() || "<you>") + "\n");
Console.info((auth.loggedInUsername() || "<you>"));
_.each(info.authorized, function (username) {
if (username)
Console.stdout.write(username + "\n");
// Current username rules don't let you register anything that we might
// want to split over multiple lines (ex: containing a space), but we
// don't want confusion if we ever change some implementation detail.
Console.rawInfo(username + "\n");
});
return 0;
}
@@ -655,14 +662,13 @@ var changeAuthorized = function (site, action, username) {
});
if (result.errorMessage) {
Console.stderr.write("Couldn't change authorized users: " +
result.errorMessage + "\n");
Console.error("Couldn't change authorized users: " + result.errorMessage);
return 1;
}
Console.stdout.write(site + ": " +
(action === "add" ? "added " : "removed ")
+ username + "\n");
Console.info(site + ": " +
(action === "add" ? "added " : "removed ")
+ username);
return 0;
};
@@ -679,27 +685,28 @@ var claim = function (site) {
operation: 'info',
site: site
});
if (infoResult.statusCode === 404) {
Console.stderr.write(
"There isn't a site deployed at that address. Use 'meteor deploy' if\n" +
"you'd like to deploy your app here.\n");
Console.error(
"There isn't a site deployed at that address. Use " +
Console.command("'meteor deploy'") + " " +
"if you'd like to deploy your app here.");
return 1;
}
if (infoResult.payload && infoResult.payload.protection === "account") {
if (infoResult.payload.authorized)
Console.stderr.write("That site already belongs to you.\n");
Console.error("That site already belongs to you.\n");
else
Console.stderr.write("Sorry, that site belongs to someone else.\n");
Console.error("Sorry, that site belongs to someone else.\n");
return 1;
}
if (infoResult.payload &&
infoResult.payload.protection === "password") {
Console.stdout.write(
"To claim this site and transfer it to your account, enter the\n" +
"site password one last time.\n\n");
Console.info(
"To claim this site and transfer it to your account, enter the",
"site password one last time.");
Console.info();
}
var result = authedRpc({
@@ -713,29 +720,34 @@ var claim = function (site) {
auth.pollForRegistrationCompletion();
if (! auth.loggedInUsername() &&
auth.registrationUrl()) {
Console.stderr.write(
"You need to set a password on your Meteor developer account before\n" +
"you can claim sites. You can do that here in under a minute:\n\n" +
auth.registrationUrl() + "\n\n");
Console.error(
"You need to set a password on your Meteor developer account before",
"you can claim sites. You can do that here in under a minute:");
Console.error(Console.url(auth.registrationUrl()));
Console.error();
} else {
Console.stderr.write("Couldn't claim site: " +
result.errorMessage + "\n");
Console.error("Couldn't claim site: " + result.errorMessage);
}
return 1;
}
Console.stdout.write(
site + ": " + "successfully transferred to your account.\n" +
"\n" +
"Show authorized users with:\n" +
" meteor authorized " + site + "\n" +
"\n" +
"Add authorized users with:\n" +
" meteor authorized " + site + " --add <username>\n" +
"\n" +
"Remove authorized users with:\n" +
" meteor authorized " + site + " --remove <user>\n" +
"\n");
Console.info(site + ": " + "successfully transferred to your account.");
Console.info();
Console.info("Show authorized users with:");
Console.info(
Console.command("meteor authorized " + site),
Console.options({ indent: 2 }));
Console.info();
Console.info("Add authorized users with:");
Console.info(
Console.command("meteor authorized " + site + " --add <username>"),
Console.options({ indent: 2 }));
Console.info();
Console.info("Remove authorized users with:");
Console.info(
Console.command("meteor authorized " + site + " --remove <username>"),
Console.options({ indent: 2 }));
Console.info();
return 0;
};
@@ -748,19 +760,18 @@ var listSites = function () {
});
if (result.errorMessage) {
Console.stderr.write("Couldn't list sites: " +
result.errorMessage + "\n");
Console.error("Couldn't list sites: " + result.errorMessage);
return 1;
}
if (! result.payload ||
! result.payload.sites ||
! result.payload.sites.length) {
Console.stdout.write("You don't have any sites yet.\n");
Console.info("You don't have any sites yet.");
} else {
result.payload.sites.sort();
_.each(result.payload.sites, function (site) {
Console.stdout.write(site + "\n");
Console.info(site);
});
}
return 0;

View File

@@ -14,6 +14,7 @@ var isopackets = require("./isopackets.js");
var isopackCacheModule = require('./isopack-cache.js');
var packageMapModule = require('./package-map.js');
var Future = require('fibers/future');
var Console = require('./console.js').Console;
var rejectBadPath = function (p) {
if (p.match(/\.\./))
@@ -1090,8 +1091,8 @@ _.extend(Isopack.prototype, {
// and similar to a isopacket load failure, it can just crash the app
// instead of being handled nicely.
if (messages.hasMessages()) {
process.stderr.write("Errors prevented tool build:\n");
process.stderr.write(messages.formatMessages());
Console.error("Errors prevented tool build:");
Console.error(messages.formatMessages());
throw new Error("tool build failed?");
}

View File

@@ -218,7 +218,7 @@ var newIsopacketBuildingCatalog = function () {
});
});
if (messages.hasMessages()) {
Console.error("=> Errors while scanning core packages:");
Console.arrowError("Errors while scanning core packages:");
Console.printMessages(messages);
throw new Error("isopacket scan failed?");
}

View File

@@ -401,13 +401,13 @@ var springboard = function (rel, options) {
// to! That's bad. Let's exit.
if (options.fromApp) {
Console.error(
"Sorry, this project uses " + rel.getDisplayName() + ", which is not\n" +
"installed and could not be downloaded. Please check to make sure that you\n" +
"are online.");
"Sorry, this project uses " + rel.getDisplayName() + ", which is not",
"installed and could not be downloaded. Please check to make sure",
"that you are online.");
} else {
Console.error(
"Sorry, " + rel.getDisplayName() + " is not installed and could not be\n" +
"downloaded. Please check to make sure that you are online.");
"Sorry, " + rel.getDisplayName() + " is not installed and could not",
"be downloaded. Please check to make sure that you are online.");
}
process.exit(1);
}
@@ -712,8 +712,8 @@ Fiber(function () {
if (_.has(rawOptions, '--release')) {
if (rawOptions['--release'].length > 1) {
Console.error(
"--release should only be passed once.\n" +
"Try 'meteor help' for help.");
"--release should only be passed once. " +
"Try 'meteor help' for help.");
process.exit(1);
}
releaseOverride = rawOptions['--release'][0];
@@ -721,8 +721,8 @@ Fiber(function () {
releaseExplicit = true;
if (! releaseOverride) {
Console.error(
"The --release option needs a value.\n" +
"Try 'meteor help' for help.");
"The --release option needs a value. " +
"Try 'meteor help' for help.");
process.exit(1);
}
delete rawOptions['--release'];
@@ -748,19 +748,21 @@ Fiber(function () {
// shouldn't happen unless the user did it manually.
if (appReleaseFile.noReleaseSpecified()) {
Console.error(
"Problem! This project has a .meteor/release file which is empty.\n" +
"The file should either contain the release of Meteor that you want to use,\n" +
"or the word 'none' if you will only use the project with unreleased\n" +
"checkouts of Meteor. Please edit the .meteor/release file in the project\n" +
"and change it to a valid Meteor release or 'none'.");
"Problem! This project has a .meteor/release file which is empty.",
"The file should either contain the release of Meteor that you want",
"to use, or the word 'none' if you will only use the project with",
"unreleased checkouts of Meteor. Please edit the .meteor/release",
"file in the project and change it to a valid Meteor release or",
"'none'.");
process.exit(1);
} else if (appReleaseFile.fileMissing()) {
Console.error(
"Problem! This project does not have a .meteor/release file.\n" +
"The file should either contain the release of Meteor that you want to use,\n" +
"or the word 'none' if you will only use the project with unreleased\n" +
"checkouts of Meteor. Please edit the .meteor/release file in the project\n" +
"and change it to a valid Meteor release or 'none'.");
"Problem! This project does not have a .meteor/release file.",
"The file should either contain the release of Meteor that you",
"want to use, or the word 'none' if you will only use the project",
"with unreleased checkouts of Meteor. Please edit the",
".meteor/release file in the project and change it to a valid Meteor",
"release or 'none'.");
process.exit(1);
}
}
@@ -805,11 +807,12 @@ Fiber(function () {
if (!releaseName) {
if (catalog.refreshFailed) {
Console.error(
"The package catalog has no information about any Meteor releases, and we\n" +
"had trouble connecting to the package server.");
"The package catalog has no information about any Meteor",
"releases, and we had trouble connecting to the package server.");
} else {
Console.error(
"The package catalog has no information about any Meteor releases.");
"The package catalog has no information about",
"any Meteor releases.");
}
process.exit(1);
}
@@ -883,7 +886,8 @@ Fiber(function () {
} else if (e instanceof files.OfflineError) {
if (!catalog.refreshFailed) {
// Warn if we didn't already warn.
Console.warn("Unable to contact release server (are you offline?)");
Console.warn(
"Unable to contact release server (are you offline?)");
}
// Treat this like a failure to refresh the catalog
// (map the old world to the new world)
@@ -918,17 +922,18 @@ Fiber(function () {
}
if (catalog.refreshFailed) {
Console.error(
"This project says that it uses " + displayRelease + ", but\n" +
"you don't have that version of Meteor installed, and we were unable to\n" +
"contact Meteor's update servers to find out about it. Please edit the\n" +
".meteor/release file in the project and change it to a valid Meteor\n" +
"release, or go online.");
"This project says that it uses " + displayRelease + ", but",
"you don't have that version of Meteor installed, and we were",
"unable to contact Meteor's update servers to find out about it.",
"Please edit the .meteor/release file in the project and change",
"it to a valid Meteor release, or go online.");
} else {
Console.error(
"This project says that it uses " + displayRelease + ", but you don't have\n" +
"that version of Meteor installed and the Meteor update servers\n" +
"don't have it either. Please edit the .meteor/release file in\n" +
"the project and change it to a valid Meteor release.");
"This project says that it uses " + displayRelease + ", but you",
"don't have that version of Meteor installed and the Meteor",
"update servers don't have it either. Please edit the",
".meteor/release file in the project and change it to a valid",
"Meteor release.");
}
} else {
throw new Error("can't load latest release?");
@@ -971,12 +976,12 @@ Fiber(function () {
if (rawOptions[fullName]) {
if (rawOptions[fullName].length > 1) {
Console.error("It doesn't make sense to pass " +
fullName + " more than once.");
fullName + " more than once.");
process.exit(1);
}
if (_.size(rawOptions) > 1 || rawArgs.length !== 0 || command) {
Console.error("Can't pass anything else along with " +
value.name + ".");
value.name + ".");
process.exit(1);
}
command = value;
@@ -1017,7 +1022,9 @@ Fiber(function () {
if (! _.has(walk, word)) {
Console.error(
"'" + commandName + "' is not a Meteor command. See 'meteor --help'.");
Console.command("'" + commandName + "'") +
" is not a Meteor command. See " +
Console.command("'meteor --help'")+ ".");
process.exit(1);
}
@@ -1036,7 +1043,8 @@ Fiber(function () {
// They typed something like 'meteor admin' (when they were
// supposed to type 'meteor admin grant' or something).
Console.error(
"Try 'meteor " + commandName + " help' for available commands.");
"Try " + Console.command("'meteor " + commandName + " help'") + " " +
"for available commands.");
process.exit(1);
}
@@ -1048,7 +1056,9 @@ Fiber(function () {
// which case showHelp will be true and command will be null
if (showHelp) {
Console.stdout.write(longHelp(commandName) + "\n");
// XXX: Until we rewrite the longHelp function to cope with the new output
// format, let's go with the static, painstakingly-formatted version.
Console.rawInfo(longHelp(commandName) + "\n");
process.exit(0);
}
@@ -1061,13 +1071,16 @@ Fiber(function () {
var presentLong = _.has(rawOptions, "--" + optionName);
var presentShort = _.has(optionInfo, 'short') &&
_.has(rawOptions, "-" + optionInfo.short);
var tryHelpMessage =
"Try " + Console.command("'meteor help " + commandName + "'") + " " +
"for help.";
if (presentShort && presentLong) {
// this would get caught below, but give a clearer error message
Console.error(
commandName + ": can't pass both -" + optionInfo.short + " and --" +
optionName + ".\n" +
"Try 'meteor help " + commandName + "' for help.");
commandName + ": can't pass both -" + optionInfo.short + " and --" +
optionName + ". " + tryHelpMessage);
process.exit(1);
}
var helpfulOptionName = "--" + optionName +
@@ -1086,8 +1099,10 @@ commandName + ": can't pass both -" + optionInfo.short + " and --" +
// in the future, we could support multiple values, but we don't
// for now since no command needs it
Console.error(
commandName + ": can only take one " + helpfulOptionName + " option.\n" +
"Try 'meteor help " + commandName + "' for help.");
Console.command(commandName) + ": can only take one " +
Console.command(helpfulOptionName) + " option.");
Console.error(tryHelpMessage);
process.exit(1);
} else if (values.length === 1) {
// OK, they provided exactly one value. Check its type and add
@@ -1097,22 +1112,27 @@ commandName + ": can only take one " + helpfulOptionName + " option.\n" +
// This option requires a value and they didn't give it one
// (it was the last word on the command line).
Console.error(
commandName + ": the " + helpfulOptionName + " option needs a value.\n" +
"Try 'meteor help " + commandName + "' for help.");
Console.command(commandName) + ": the " +
Console.command(helpfulOptionName) + " option needs a value.");
Console.error(tryHelpMessage);
process.exit(1);
} else if (optionInfo.type === Number) {
if (! value.match(/^[0-9]+$/)) {
Console.error(
commandName + ": " + helpfulOptionName + " must be a number.\n" +
"Try 'meteor help " + commandName + "' for help.");
Console.command(commandName) + ": " +
Console.command(helpfulOptionName) + " must be a number.");
Console.error(tryHelpMessage);
process.exit(1);
}
value = parseInt(value);
} else if (optionInfo.type === Boolean) {
if (!value) {
Console.error(
commandName + ": the " + helpfulOptionName + " option does not need a value.\n" +
"Try 'meteor help " + commandName + "' for help.");
Console.command(commandName) + ": the " +
Console.command(helpfulOptionName) + " " +
"option does not need a value.");
Console.error(tryHelpMessage);
process.exit(1);
}
value = true;
@@ -1137,8 +1157,9 @@ commandName + ": the " + helpfulOptionName + " option does not need a value.\n"
options[optionName] = optionInfo.default;
} else if (optionInfo.required) {
Console.error(
commandName + ": the --" + optionName + " option is required.\n" +
longHelp(commandName));
Console.command(commandName) + ": the --" +
Console.command(optionName) + " option is required.");
Console.rawError(longHelp(commandName));
process.exit(1);
}
}
@@ -1147,23 +1168,26 @@ longHelp(commandName));
// Check for unrecognized options.
if (_.keys(rawOptions).length > 0) {
Console.error(
_.keys(rawOptions)[0] + ": unknown option.\n" +
longHelp(commandName));
Console.command(_.keys(rawOptions)[0]) + ": unknown option.");
Console.rawError(
longHelp(commandName));
process.exit(1);
}
// Check argument count.
if (options.args.length < command.minArgs) {
Console.error(
commandName + ": not enough arguments.\n" +
longHelp(commandName));
Console.command(commandName) + ": not enough arguments.");
Console.rawError(
longHelp(commandName));
process.exit(1);
}
if (options.args.length > command.maxArgs) {
Console.error(
commandName + ": too many arguments.\n" +
longHelp(commandName));
Console.command(commandName) + ": too many arguments.");
Console.rawError(
longHelp(commandName));
process.exit(1);
}
@@ -1183,14 +1207,20 @@ longHelp(commandName));
// since you'll default to the 'run' command which requires an
// app. Be welcoming to our new developers!
Console.error(
commandName + ": You're not in a Meteor project directory.\n" +
"\n" +
"To create a new Meteor project:\n" +
" meteor create <project name>\n" +
"For example:\n" +
" meteor create myapp\n" +
"\n" +
"For more help, see 'meteor --help'.");
Console.command(commandName) +
": You're not in a Meteor project directory.");
Console.error();
Console.error("To create a new Meteor project:");
Console.error(
Console.command("meteor create <project name>"),
Console.options({ indent: 2 }));
Console.error("For example:");
Console.error(
Console.command("meteor create myapp"),
Console.options({ indent: 2 }));
Console.error();
Console.error(
"For more help, see " + Console.command("'meteor --help'") + ".");
process.exit(1);
}
@@ -1211,18 +1241,20 @@ commandName + ": You're not in a Meteor project directory.\n" +
if (! options.packageDir) {
Console.error(
commandName + ": You're not in a Meteor package directory.");
Console.command(commandName) +
": You're not in a Meteor package directory.");
process.exit(1);
}
}
if (command.requiresRelease && ! release.current) {
Console.error(
"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'.");
"You must specify a Meteor version with --release when you work with",
"this project. It was created from an unreleased Meteor checkout and",
"doesn't have a version associated with it.");
Console.error(
"You can permanently set a release for this project with " +
Console.command("'meteor update'") + ".");
process.exit(1);
}
@@ -1230,9 +1262,9 @@ commandName + ": You're not in a Meteor project directory.\n" +
appReleaseFile && ! appReleaseFile.isCheckout()) {
// For commands that work with apps, if we have overridden the
// app's usual release by using a checkout, print a reminder banner.
Console.warn(
"=> Running Meteor from a checkout -- overrides project version (" +
appReleaseFile.displayReleaseName + ")");
Console.arrowWarn(
"Running Meteor from a checkout -- overrides project version " +
Console.noWrap("(" + appReleaseFile.displayReleaseName + ")"));
}
// Now that we're ready to start executing the command, if we are in
@@ -1264,7 +1296,7 @@ commandName + ": You're not in a Meteor project directory.\n" +
throw new Error(
"you meant 'throw new main.Foo', not 'throw main.Foo'");
} else if (e instanceof main.ShowUsage) {
Console.error(longHelp(commandName));
Console.rawError(longHelp(commandName) + "\n");
process.exit(1);
} else if (e instanceof main.SpringboardToLatestRelease) {
// Load the metadata for the latest release (or at least, the latest

View File

@@ -69,7 +69,7 @@ _.extend(RunCommand.prototype, {
self.process.stdout.on('data', function (data) {
self.stdout = self.stdout + data;
if (self.options.pipeOutput) {
Console.stdout.write(data);
Console.rawInfo(data);
}
if (self.options.onStdout) {
self.options.onStdout(data);
@@ -79,7 +79,7 @@ _.extend(RunCommand.prototype, {
self.process.stderr.on('data', function (data) {
self.stderr = self.stderr + data;
if (self.options.pipeOutput) {
Console.stderr.write(data);
Console.rawError(data);
}
if (self.options.onStderr) {
self.options.onStderr(data);
@@ -121,4 +121,3 @@ _.extend(RunCommand.prototype, {
});
exports.RunCommand = RunCommand;

View File

@@ -129,7 +129,7 @@ _.extend(Runner.prototype, {
// print the banner only once we've successfully bound the port
if (! self.quiet && ! self.stopped) {
runLog.log("[[[[[ " + self.banner + " ]]]]]\n");
runLog.log("=> Started proxy.");
runLog.log("Started proxy.", { arrow: true });
}
self._startMongoAsync();
@@ -142,7 +142,7 @@ _.extend(Runner.prototype, {
if (! self.stopped && self.httpProxy) {
self.httpProxy.start();
if (! self.quiet) {
runLog.log("=> Started http proxy.");
runLog.log("Started http proxy.", { arrow: true });
}
}
@@ -153,7 +153,7 @@ _.extend(Runner.prototype, {
extraRunner.start();
});
if (! self.quiet && ! self.stopped)
runLog.log("=> Started " + title + ".");
runLog.log("Started " + title + ".", { arrow: true });
}
});
@@ -162,18 +162,20 @@ _.extend(Runner.prototype, {
self.appRunner.start();
});
if (! self.quiet && ! self.stopped)
runLog.log("=> Started your app.");
runLog.log("Started your app.", { arrow: true });
}
if (! self.stopped && ! self.quiet)
runLog.log("\n=> App running at: " + self.rootUrl);
if (! self.stopped && ! self.quiet) {
runLog.log("");
runLog.log("App running at: " + self.rootUrl, { arrow: true });
}
if (self.selenium && ! self.stopped) {
buildmessage.enterJob({ title: "Starting Selenium" }, function () {
self.selenium.start();
});
if (! self.quiet && ! self.stopped)
runLog.log("=> Started Selenium.");
runLog.log("Started Selenium.", { arrow: true });
}
// XXX It'd be nice to (cosmetically) handle failure better. Right
@@ -191,7 +193,7 @@ _.extend(Runner.prototype, {
_startMongoFuture: function () {
this.mongoRunner.start();
if (! this.stopped && ! this.quiet) {
runLog.log("=> Started MongoDB.");
runLog.log("Started MongoDB.", { arrow: true });
}
}.future(),
@@ -321,25 +323,24 @@ exports.run = function (options) {
runner.stop();
if (result.outcome === "conflicting-versions") {
process.stderr.write(
"The constraint solver could not find a set of package versions to use that would\n" +
"satisfy the constraints of .meteor/versions and .meteor/packages. This could be\n" +
"caused by conflicts in .meteor/versions, conflicts in .meteor/packages, and/or\n" +
"inconsistent changes to the dependencies in local packages.");
Console.error(
"The constraint solver could not find a set of package versions to",
"use that would satisfy the constraints of .meteor/versions and",
".meteor/packages. This could be caused by conflicts in",
".meteor/versions, conflicts in .meteor/packages, and/or",
"inconsistent changes to the dependencies in local packages.");
return 254;
}
if (result.outcome === "outdated-cordova-plugins") {
process.stderr.write(
"Your app's Cordova plugins have changed.\n" +
"Restart meteor to use the new set of plugins.\n");
Console.error("Your app's Cordova plugins have changed.");
Console.error("Restart meteor to use the new set of plugins.");
return 254;
}
if (result.outcome === "outdated-cordova-platforms") {
process.stderr.write(
"Your app's platforms have changed.\n" +
"Restart meteor to use the new set of platforms.\n");
Console.error("Your app's platforms have changed.");
Console.error("Restart meteor to use the new set of platforms.");
return 254;
}
@@ -357,10 +358,9 @@ exports.run = function (options) {
// this (which prevents weird errors) is a start.)
var from = release.current.getDisplayName();
var to = result.displayReleaseNeeded;
process.stderr.write(
"Your app has been updated to " + to + " from " + from +
".\n" +
"Restart meteor to use the new release.\n");
Console.error(
"Your app has been updated to " + to + " from " + from + ".",
"Restart meteor to use the new release.");
return 254;
}
@@ -373,14 +373,14 @@ exports.run = function (options) {
}
if (once && result.outcome === "bundle-fail") {
process.stderr.write("=> Build failed:\n\n" +
result.errors.formatMessages() + "\n");
Console.arrowError("Build failed:\n\n" +
result.errors.formatMessages());
return 254;
}
if (once && result.outcome === "terminated") {
if (result.signal) {
process.stderr.write("Killed (" + result.signal + ")\n");
Console.error("Killed (" + result.signal + ")");
return 255;
} else if (typeof result.code === "number") {
// We used to print 'Your application is exiting' here, but that

View File

@@ -112,7 +112,7 @@ _.extend(AppProcess.prototype, {
}));
self.proc.on('error', fiberHelpers.inBareFiber(function (err) {
runLog.log("=> Couldn't spawn process: " + err.message);
runLog.log("Couldn't spawn process: " + err.message, { arrow: true });
// node docs say that it might make both an 'error' and a
// 'close' callback, so we use a guard to make sure we only call
@@ -770,11 +770,11 @@ _.extend(AppRunner.prototype, {
}
else if (runResult.outcome === "bundle-fail") {
runLog.log("=> Errors prevented startup:\n\n" +
runResult.errors.formatMessages());
runLog.log("Errors prevented startup:\n\n" +
runResult.errors.formatMessages(), { arrow: true });
if (self.watchForChanges) {
runLog.log("=> Your application has errors. " +
"Waiting for file change.");
runLog.log("Your application has errors. " +
"Waiting for file change.", { arrow: true });
Console.enableProgressDisplay(false);
}
}
@@ -784,9 +784,9 @@ _.extend(AppRunner.prototype, {
else if (runResult.outcome === "terminated") {
if (runResult.signal) {
runLog.log('=> Exited from signal: ' + runResult.signal);
runLog.log('Exited from signal: ' + runResult.signal, { arrow: true });
} else if (runResult.code !== undefined) {
runLog.log('=> Exited with code: ' + runResult.code);
runLog.log('Exited with code: ' + runResult.code, { arrow: true });
} else {
// explanation should already have been logged
}
@@ -796,8 +796,9 @@ _.extend(AppRunner.prototype, {
continue;
if (self.watchForChanges) {
runLog.log("=> Your application is crashing. " +
"Waiting for file change.");
runLog.log("Your application is crashing. " +
"Waiting for file change.",
{ arrow: true });
Console.enableProgressDisplay(false);
}
}
@@ -824,7 +825,7 @@ _.extend(AppRunner.prototype, {
// While we were waiting, did somebody stop() us?
if (self.exitFuture)
break;
runLog.log("=> Modified -- restarting.");
runLog.log("Modified -- restarting.", { arrow: true });
Console.enableProgressDisplay(true);
continue;
}

View File

@@ -62,12 +62,12 @@ _.extend(RunLog.prototype, {
if (self.consecutiveRestartMessages) {
self.consecutiveRestartMessages = null;
Console.stdout.write("\n");
Console.info();
}
if (self.consecutiveClientRestartMessages) {
self.consecutiveClientRestartMessages = null;
Console.stdout.write("\n");
Console.info();
}
if (self.temporaryMessageLength) {
@@ -93,16 +93,20 @@ _.extend(RunLog.prototype, {
self._clearSpecial();
if (self.rawLogs)
Console[isStderr ? "stderr" : "stdout"].write(line + "\n");
Console[isStderr ? "rawError" : "rawInfo"](line + "\n");
else
Console.stdout.write(Log.format(obj, { color: true }) + "\n");
Console.rawInfo(Log.format(obj, { color: true }) + "\n");
// XXX deal with test server logging differently?!
},
log: function (msg) {
// Log the message.
// msg: message
// options:
// - arrow: if true, preface with => and wrap accordingly.
log: function (msg, options) {
var self = this;
options = options || {};
var obj = {
time: new Date,
message: msg
@@ -113,7 +117,11 @@ _.extend(RunLog.prototype, {
self._record(obj);
self._clearSpecial();
Console.stdout.write(msg + "\n");
// Process the options. By default, we want to wordwrap the message with
// Console.info. If we ask for raw output, then we don't want to do that. If
// we ask for an arrow, we want to wrap around with => as the bulletPoint.
Console[options.arrow ? 'arrowInfo' : 'info'](msg);
},
// Write a message to the terminal that will get overwritten by the

View File

@@ -30,8 +30,8 @@ var runVelocity = function (url) {
ddpConnection.subscribe("VelocityTestReports", {
onError: function () {
Console.stderr.write("failed to subscribe to VelocityTestReports "
+ "subscription");
Console.error("failed to subscribe to VelocityTestReports " +
"subscription");
// XXX tell user to add velocity:core
// XXX these also fire if the user turns on autopublish
}, onReady: function () {
@@ -65,8 +65,8 @@ var runVelocity = function (url) {
var isFinished = false;
ddpConnection.subscribe("VelocityAggregateReports", {
onError: function () {
Console.stderr.write("failed to subscribe to " +
"VelocityAggregateReports subscription");
Console.error("failed to subscribe to " +
"VelocityAggregateReports subscription");
}, onReady: function () {
this.connection.registerStore("velocityAggregateReports", {
update: function (msg) {
@@ -113,8 +113,8 @@ var runVelocity = function (url) {
ddpConnection.subscribe("VelocityMirrors", {
onError: function (err) {
Console.stderr.write("failed to subscribe to VelocityMirrors " +
"subscription", err);
Console.error("failed to subscribe to VelocityMirrors " +
"subscription", err);
}, onReady: function () {
this.connection.registerStore("velocityMirrors", {
update: function (msg) {

View File

@@ -171,7 +171,7 @@ var newSelfTestCatalog = function () {
});
});
if (messages.hasMessages()) {
Console.error("=> Errors while scanning core packages:");
Console.arrowError("Errors while scanning core packages:");
Console.printMessages(messages);
throw new Error("scan failed?");
}
@@ -240,7 +240,7 @@ _.extend(Matcher.prototype, {
var self = this;
if (self.buf.length > 0) {
console.log("Extra junk is ", self.buf);
Console.info("Extra junk is :", self.buf);
throw new TestFailure('junk-at-end', { run: self.run });
}
},
@@ -1639,22 +1639,22 @@ var listTests = function (options) {
var testList = getFilteredTests(options);
if (! testList.allTests.length) {
Console.stderr.write("No tests defined.\n");
Console.error("No tests defined.\n");
return;
}
_.each(_.groupBy(testList.filteredTests, 'file'), function (tests, file) {
Console.stdout.write(file + ':\n');
Console.rawInfo(file + ':\n');
_.each(tests, function (test) {
Console.stdout.write(' - ' + test.name +
(test.tags.length ? ' [' + test.tags.join(' ') + ']'
: ''));
Console.rawInfo(' - ' + test.name +
(test.tags.length ? ' [' + test.tags.join(' ') + ']'
: ''));
});
});
Console.stderr.write('\n');
Console.stderr.write(testList.filteredTests.length + " tests listed.");
Console.stderr.write(testList.generateSkipReport());
Console.error();
Console.error(testList.filteredTests.length + " tests listed.");
Console.error(testList.generateSkipReport());
};
///////////////////////////////////////////////////////////////////////////////
@@ -1669,7 +1669,7 @@ var runTests = function (options) {
var testList = getFilteredTests(options);
if (! testList.allTests.length) {
Console.stderr.write("No tests defined.\n");
Console.error("No tests defined.");
return 0;
}
@@ -1689,7 +1689,7 @@ var runTests = function (options) {
if (e instanceof TestFailure) {
failure = e;
} else {
Console.stderr.write("exception\n\n");
Console.error("exception\n");
throw e;
}
} finally {
@@ -1698,84 +1698,85 @@ var runTests = function (options) {
}
if (failure) {
Console.stderr.write("fail!\n");
Console.error("fail!");
failedTests.push(test);
testList.notifyFailed(test);
var frames = parseStack.parse(failure);
var relpath = path.relative(files.getCurrentToolsDir(),
frames[0].file);
Console.stderr.write(" => " + failure.reason + " at " +
relpath + ":" + frames[0].line + "\n");
Console.rawError(" => " + failure.reason + " at " +
relpath + ":" + frames[0].line + "\n");
if (failure.reason === 'no-match') {
Console.stderr.write(" => Pattern: " + failure.details.pattern + "\n");
Console.arrowError("Pattern: " + failure.details.pattern, 2);
}
if (failure.reason === "wrong-exit-code") {
var s = function (status) {
return status.signal || ('' + status.code) || "???";
};
Console.stderr.write(" => Expected: " + s(failure.details.expected) +
"; actual: " + s(failure.details.actual) + "\n");
Console.rawError(" => " + "Expected: " + s(failure.details.expected) +
"; actual: " + s(failure.details.actual) + "\n");
}
if (failure.reason === 'expected-exception') {
}
if (failure.reason === 'not-equal') {
Console.stderr.write(
" => Expected: " + JSON.stringify(failure.details.expected) +
"; actual: " + JSON.stringify(failure.details.actual) + "\n");
Console.rawError(
" => " + "Expected: " + JSON.stringify(failure.details.expected) +
"; actual: " + JSON.stringify(failure.details.actual) + "\n");
}
if (failure.details.run) {
failure.details.run.outputLog.end();
var lines = failure.details.run.outputLog.get();
if (! lines.length) {
Console.stderr.write(" => No output\n");
Console.arrowError("No output", 2);
} else {
var historyLines = options.historyLines || 100;
Console.stderr.write(" => Last " + historyLines + " lines:\n");
Console.arrowError("Last " + historyLines + " lines:", 2
);
_.each(lines.slice(-historyLines), function (line) {
Console.stderr.write(" " +
(line.channel === "stderr" ? "2| " : "1| ") +
line.text +
(line.bare ? "%" : "") + "\n");
Console.rawError(" " +
(line.channel === "stderr" ? "2| " : "1| ") +
line.text +
(line.bare ? "%" : "") + "\n");
});
}
}
if (failure.details.messages) {
Console.stderr.write(" => Errors while building:\n");
Console.stderr.write(failure.details.messages.formatMessages());
Console.arrowError("Errors while building:", 2);
Console.rawError(failure.details.messages.formatMessages() + "\n");
}
} else {
var durationMs = +(new Date) - startTime;
Console.stderr.write("ok (" + durationMs + " ms)\n");
Console.error("ok (" + durationMs + " ms)");
}
});
testList.saveTestState();
if (totalRun > 0)
Console.stderr.write("\n");
Console.error();
Console.stderr.write(testList.generateSkipReport());
Console.error(testList.generateSkipReport());
if (testList.filteredTests.length === 0) {
Console.stderr.write("No tests run.\n");
Console.error("No tests run.");
return 0;
} else if (failedTests.length === 0) {
var disclaimers = '';
if (testList.filteredTests.length < testList.allTests.length)
disclaimers += " other";
Console.stderr.write("All" + disclaimers + " tests passed.\n");
Console.error("All" + disclaimers + " tests passed.");
return 0;
} else {
var failureCount = failedTests.length;
Console.stderr.write(failureCount + " failure" +
(failureCount > 1 ? "s" : "") + ":\n");
Console.error(failureCount + " failure" +
(failureCount > 1 ? "s" : "") + ":");
_.each(failedTests, function (test) {
Console.stderr.write(" - " + test.file + ": " + test.name);
Console.rawError(" - " + test.file + ": " + test.name + "\n");
});
return 1;
}

View File

@@ -118,11 +118,14 @@ var recordPackages = function (options) {
var logErrorIfInCheckout = function (err) {
if (files.inCheckout() || process.env.METEOR_PACKAGE_STATS_TEST_OUTPUT) {
Console.stderr.write("Failed to record package usage.\n");
Console.stderr.write(
"(This error is hidden when you are not running Meteor from a checkout.)\n");
Console.stderr.write(err.stack || err);
Console.stderr.write("\n\n");
Console.warn("Failed to record package usage.");
Console.warn(
"(This error is hidden when you are not running Meteor from a",
"checkout.)");
var printErr = err.stack || err;
Console.rawWarn(printErr + "\n");
Console.warn();
Console.warn();
}
};

View File

@@ -35,7 +35,7 @@ selftest.define("add cordova platforms", function () {
run.match("added");
run = s.run("remove-platform", "foo");
run.match("foo: platform is not");
run.matchErr("foo: platform is not");
run = s.run("remove-platform", "android");
run.match("removed");

View File

@@ -872,7 +872,7 @@ selftest.define("add package with no builds", ["net"], function () {
var run = s.run("add", "glasser:binary-package-with-no-builds");
run.waitSecs(10);
run.matchErr("No compatible build found for " +
run.matchErr("No compatible build found for\n" +
"glasser:binary-package-with-no-builds@1.0.0");
run.expectExit(1);
});

View File

@@ -79,7 +79,8 @@ selftest.define("springboard", ['checkout', 'net'], function () {
run = s.run();
run.matchErr("offline");
run.matchErr("it uses Meteor strange");
run.matchErr("don't have that version of Meteor installed");
run.matchErr("don't have that version");
run.matchErr("of Meteor installed");
run.matchErr("update servers");
run.expectExit(1);
@@ -186,7 +187,8 @@ selftest.define("checkout", ['checkout'], function () {
s.write(".meteor/release", "something");
run = s.run("list");
run.readErr("=> Running Meteor from a checkout");
run.matchErr("project version (Meteor something)\n");
run.matchErr("project version");
run.matchErr("(Meteor something)\n");
run.expectExit(0);
});
});

View File

@@ -112,49 +112,8 @@ exports.printPackageList = function (items, options) {
};
rows = _.sortBy(rows, alphaSort);
return utils.printTwoColumns(rows, options);
};
// XXX: Move to e.g. formatters.js?
// Prints a two column table in a nice format:
// The first column is printed entirely, the second only as space permits
exports.printTwoColumns = function (rows, options) {
options = options || {};
var longest = '';
_.each(rows, function (row) {
var col0 = row[0] || '';
if (col0.length > longest.length)
longest = col0;
});
var pad = longest.replace(/./g, ' ');
var width = 80;
var stream = process.stdout;
if (stream && stream.isTTY && stream.columns) {
width = stream.columns;
}
var Console = require("./console.js").Console;
var out = '';
_.each(rows, function (row) {
var col0 = row[0] || '';
var col1 = row[1] || '';
var line = Console.bold(col0) + pad.substr(col0.length);
line += " " + col1;
if (line.length > width) {
line = line.substr(0, width - 3) + '...';
}
out += line + "\n";
});
// XXX: Naughty call to 'private' function
var level = options.level || Console.LEVEL_INFO;
Console._print(level, out);
return out;
var Console = require('./console.js').Console;
return Console.printTwoColumns(rows, options);
};
// Determine a human-readable hostname for this computer. Prefer names
@@ -300,7 +259,8 @@ exports.validatePackageNameOrExit = function (packageName, options) {
} catch (e) {
if (!e.versionParserError)
throw e;
process.stderr.write("Error: " + e.message + "\n");
var Console = require('./console.js').Console;
Console.error(e.message, Console.options({ bulletPoint: "Error: " }));
// lazy-load main: old bundler tests fail if you add a circular require to
// this file
var main = require('./main.js');