From 01d07a3eb61e12897c7fd1d74e27d8bfb2d1fa66 Mon Sep 17 00:00:00 2001 From: James Ide Date: Fri, 10 Jul 2015 00:23:58 -0700 Subject: [PATCH] [io.js] Print a warning message if the user is not on io.js 2.x Summary: Detects if the user is on Node or io.js 1.x and prints a banner explaining how to upgrade. We probably should link to more detailed upgrade docs so this is just a start. I also added a function to format banners that is kind of useful. Addresses part of #1737 ![packager-banner](https://cloud.githubusercontent.com/assets/379606/8447050/ad615402-1f67-11e5-8c02-ece5f7488135.png) Closes https://github.com/facebook/react-native/pull/1824 Github Author: James Ide --- checkNodeVersion.js | 40 ++++++++++++++++ formatBanner.js | 108 ++++++++++++++++++++++++++++++++++++++++++++ package.json | 4 +- packager.js | 25 ++++++---- 4 files changed, 166 insertions(+), 11 deletions(-) create mode 100644 checkNodeVersion.js create mode 100644 formatBanner.js diff --git a/checkNodeVersion.js b/checkNodeVersion.js new file mode 100644 index 00000000..f1a07c03 --- /dev/null +++ b/checkNodeVersion.js @@ -0,0 +1,40 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ +'use strict'; + +var chalk = require('chalk'); +var semver = require('semver'); + +var formatBanner = require('./formatBanner'); + +function checkNodeVersion() { + if (!semver.satisfies(process.version, '>=2.0.0')) { + var engine = semver.lt(process.version, '1.0.0') ? 'Node' : 'io.js'; + var message = 'You are currently running ' + engine + ' ' + + process.version + '.\n' + + '\n' + + 'React Native is moving to io.js 2.x. There are several ways to upgrade' + + 'to io.js depending on your preference.\n' + + '\n' + + 'nvm: nvm install iojs && nvm alias default iojs\n' + + 'Homebrew: brew unlink node; brew install iojs && brew ln iojs --force\n' + + 'Installer: download the Mac .pkg from https://iojs.org/\n' + + '\n' + + 'About io.js: https://iojs.org\n' + + 'Follow along at: https://github.com/facebook/react-native/issues/1737'; + console.log(formatBanner(message, { + chalkFunction: chalk.green, + marginLeft: 1, + marginRight: 1, + paddingBottom: 1, + })); + } +} + +module.exports = checkNodeVersion; diff --git a/formatBanner.js b/formatBanner.js new file mode 100644 index 00000000..f54095b0 --- /dev/null +++ b/formatBanner.js @@ -0,0 +1,108 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ +'use strict'; + +var _ = require('underscore'); +var wordwrap = require('wordwrap'); + +var HORIZONTAL_LINE = '\u2500'; +var VERTICAL_LINE = '\u2502'; +var TOP_LEFT = '\u250c'; +var TOP_RIGHT = '\u2510'; +var BOTTOM_LEFT = '\u2514'; +var BOTTOM_RIGHT = '\u2518'; + +/** + * Prints a banner with a border around it containing the given message. The + * following options are supported: + * + * type Options = { + * // A function to apply to each line of text to decorate it + * chalkFunction: (string: message) => string; + * // The total width (max line length) of the banner, including margin and + * // padding (default = 80) + * width: number; + * // How much leading space to prepend to each line (default = 0) + * marginLeft: number; + * // How much trailing space to append to each line (default = 0) + * marginRight: number; + * // Space between the top banner border and the text (default = 0) + * paddingTop: number; + * // Space between the bottom banner border and the text (default = 0) + * paddingBottom: number; + * // Space between the left banner border and the text (default = 2) + * paddingLeft: number; + * // Space between the right banner border and the text (default = 2) + * paddingRight: number; + * }; + */ +function formatBanner(message, options) { + options = options || {}; + _.defaults(options, { + chalkFunction: _.identity, + width: 80, + marginLeft: 0, + marginRight: 0, + paddingTop: 0, + paddingBottom: 0, + paddingLeft: 2, + paddingRight: 2, + }); + + var width = options.width; + var marginLeft = options.marginLeft; + var marginRight = options.marginRight; + var paddingTop = options.paddingTop; + var paddingBottom = options.paddingBottom; + var paddingLeft = options.paddingLeft; + var paddingRight = options.paddingRight; + + var horizSpacing = marginLeft + paddingLeft + paddingRight + marginRight; + // 2 for the banner borders + var maxLineWidth = width - horizSpacing - 2; + var wrap = wordwrap(maxLineWidth); + var body = wrap(message); + + var left = spaces(marginLeft) + VERTICAL_LINE + spaces(paddingLeft); + var right = spaces(paddingRight) + VERTICAL_LINE + spaces(marginRight); + var bodyLines = _.flatten([ + arrayOf('', paddingTop), + body.split('\n'), + arrayOf('', paddingBottom), + ]).map(function(line) { + var padding = spaces(Math.max(0, maxLineWidth - line.length)); + return left + options.chalkFunction(line) + padding + right; + }); + + var horizontalBorderLine = repeatString( + HORIZONTAL_LINE, + width - marginLeft - marginRight - 2 + ); + var top = spaces(marginLeft) + TOP_LEFT + horizontalBorderLine + TOP_RIGHT + + spaces(marginRight); + var bottom = spaces(marginLeft) + BOTTOM_LEFT + horizontalBorderLine + + BOTTOM_RIGHT + spaces(marginRight); + return _.flatten([top, bodyLines, bottom]).join('\n'); +} + +function spaces(number) { + return repeatString(' ', number); +} + +function repeatString(string, number) { + return new Array(number + 1).join(string); +} + +function arrayOf(value, number) { + return _.range(number).map(function() { + return value; + }); +} + +module.exports = formatBanner; diff --git a/package.json b/package.json index cc3f4fc6..f9927a87 100644 --- a/package.json +++ b/package.json @@ -23,7 +23,9 @@ "lint": "node linter.js Examples/", "start": "./packager/packager.sh" }, - "dependencies": {}, + "dependencies": { + "wordwrap": "^1.0.0" + }, "devDependencies": { "jest-cli": "git://github.com/facebook/jest#0.5.x", "eslint": "0.9.2" diff --git a/packager.js b/packager.js index ff0faa31..fcff7e58 100644 --- a/packager.js +++ b/packager.js @@ -30,6 +30,8 @@ var chalk = require('chalk'); var connect = require('connect'); var ReactPackager = require('./react-packager'); var blacklist = require('./blacklist.js'); +var checkNodeVersion = require('./checkNodeVersion'); +var formatBanner = require('./formatBanner'); var launchEditor = require('./launchEditor.js'); var parseCommandLine = require('./parseCommandLine.js'); var webSocketProxy = require('./webSocketProxy.js'); @@ -108,16 +110,19 @@ if (options.assetRoots) { } } -console.log('\n' + -' ===============================================================\n' + -' | Running packager on port ' + options.port + '. \n' + -' | Keep this packager running while developing on any JS \n' + -' | projects. Feel free to close this tab and run your own \n' + -' | packager instance if you prefer. \n' + -' | \n' + -' | https://github.com/facebook/react-native \n' + -' | \n' + -' ===============================================================\n' +checkNodeVersion(); + +console.log(formatBanner( + 'Running packager on port ' + options.port + '.\n'+ + '\n' + + 'Keep this packager running while developing on any JS projects. Feel free ' + + 'to close this tab and run your own packager instance if you prefer.\n' + + '\n' + + 'https://github.com/facebook/react-native', { + marginLeft: 1, + marginRight: 1, + paddingBottom: 1, + }) ); console.log(