From 02e39719c2097643fdadf2a03beae7a024dc3d05 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mart=C3=ADn=20Bigio?= Date: Tue, 20 Oct 2015 11:46:37 -0700 Subject: [PATCH] Move `run-android` to `private-cli` Reviewed By: mkonicek Differential Revision: D2544567 fb-gh-sync-id: 3c62f6c30b5be7f480d8f44a48fb551fc30d477e --- local-cli/cli.js | 12 +- private-cli/src/runAndroid/runAndroid.js | 145 ++++++++++++++++++++++ private-cli/src/util/isPackagerRunning.js | 31 +++++ 3 files changed, 184 insertions(+), 4 deletions(-) create mode 100644 private-cli/src/runAndroid/runAndroid.js create mode 100644 private-cli/src/util/isPackagerRunning.js diff --git a/local-cli/cli.js b/local-cli/cli.js index aa229df34..58de6edf4 100644 --- a/local-cli/cli.js +++ b/local-cli/cli.js @@ -14,14 +14,15 @@ var fs = require('fs'); var generate = require('../private-cli/src/generate/generate'); var init = require('./init.js'); var library = require('../private-cli/src/library/library'); -var runAndroid = require('./run-android.js'); -var runPackager = require('./run-packager.js'); +var runAndroid = require('../private-cli/src/runAndroid/runAndroid'); var server = require('../private-cli/src/server/server'); // TODO: remove once we fully roll out the `private-cli` based cli // var bundle_DEPRECATED = require('./bundle.js'); // var generateAndroid_DEPRECATED = require('./generate-android.js'); // var newLibrary_DEPRECATED = require('./new-library.js'); +// var runPackager_DEPRECATED = require('./run-packager.js'); +// var runAndroid_DEPRECATED = require('./run-android.js'); function printUsage() { console.log([ @@ -52,9 +53,11 @@ function run() { } var config = Config.get(__dirname); + switch (args[0]) { case 'start': - runPackager(false); + server(args, config).done(); + // runPackager_DEPRECATED(); break; case 'bundle': bundle(args, config).done(); @@ -84,7 +87,8 @@ function run() { // ); break; case 'run-android': - runAndroid(); + runAndroid(args, config).done(); + // runAndroid_DEPRECATED(); default: break; case 'help': printUsage(); diff --git a/private-cli/src/runAndroid/runAndroid.js b/private-cli/src/runAndroid/runAndroid.js new file mode 100644 index 000000000..7b8af5f69 --- /dev/null +++ b/private-cli/src/runAndroid/runAndroid.js @@ -0,0 +1,145 @@ +/** + * 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'; + +const chalk = require('chalk'); +const child_process = require('child_process'); +const fs = require('fs'); +const path = require('path'); +const parseCommandLine = require('../../../packager/parseCommandLine'); +const isPackagerRunning = require('../util/isPackagerRunning'); +const Promise = require('promise'); + +/** + * Starts the app on the Android simulator. + */ +function runAndroid(argv, config) { + return new Promise((resolve, reject) => { + _runAndroid(argv, config, resolve, reject); + }); +} + +function _runAndroid(argv, config, resolve, reject) { + const args = parseCommandLine([{ + command: 'install-debug', + type: 'string', + required: false, + }], argv); + + if (!checkAndroid()) { + console.log(chalk.red('Android project not found. Maybe run react-native android first?')); + return; + } + + resolve(isPackagerRunning().then(result => { + if (result === 'running') { + console.log(chalk.bold('JS server already running.')); + } else if (result === 'unrecognized') { + console.warn(chalk.yellow('JS server not recognized, continuing with build...')); + } else { + // result == 'not_running' + console.log(chalk.bold('Starting JS server...')); + startServerInNewWindow(); + } + buildAndRun(args); + })); +} + +// Verifies this is an Android project +function checkAndroid() { + return fs.existsSync('android/gradlew'); +} + +// Builds the app and runs it on a connected emulator / device. +function buildAndRun(args, reject) { + process.chdir('android'); + try { + const cmd = process.platform.startsWith('win') + ? 'gradlew.bat' + : './gradlew'; + + const gradleArgs = ['installDebug']; + if (args['install-debug']) { + gradleArgs.push(args['install-debug']); + } + + console.log(chalk.bold( + 'Building and installing the app on the device (cd android && ' + cmd + + ' ' + gradleArgs.join(' ') + ')...' + )); + + child_process.execFileSync(cmd, gradleArgs, { + stdio: [process.stdin, process.stdout, process.stderr], + }); + } catch (e) { + console.log(chalk.red( + 'Could not install the app on the device, see the error above.' + )); + // stderr is automatically piped from the gradle process, so the user + // should see the error already, there is no need to do + // `console.log(e.stderr)` + reject(); + return; + } + + try { + const packageName = fs.readFileSync( + 'app/src/main/AndroidManifest.xml', + 'utf8' + ).match(/package="(.+?)"/)[1]; + + const adbPath = process.env.ANDROID_HOME + ? process.env.ANDROID_HOME + '/platform-tools/adb' + : 'adb'; + + const adbArgs = [ + 'shell', 'am', 'start', '-n', packageName + '/.MainActivity' + ]; + + console.log(chalk.bold( + 'Starting the app (' + adbPath + ' ' + adbArgs.join(' ') + ')...' + )); + + child_process.spawnSync(adbPath, adbArgs, {stdio: 'inherit'}); + } catch (e) { + console.log(chalk.red( + 'adb invocation failed. Do you have adb in your PATH?' + )); + // stderr is automatically piped from the gradle process, so the user + // should see the error already, there is no need to do + // `console.log(e.stderr)` + reject(); + return; + } +} + +function startServerInNewWindow() { + const launchPackagerScript = path.resolve( + __dirname, '..', '..', '..', 'packager', 'launchPackager.command' + ); + + if (process.platform === 'darwin') { + child_process.spawnSync('open', [launchPackagerScript]); + } else if (process.platform === 'linux') { + child_process.spawn( + 'xterm', + ['-e', 'sh', launchPackagerScript], + {detached: true} + ); + } else { + console.error(chalk.yellow( + 'Starting packager in new window is not supported on Windows yet. ' + + 'See https://github.com/facebook/react-native/issues/3469 on how to ' + + 'start it manually.' + )); + throw new Error('Windows is not yet supported'); + } +} + +module.exports = runAndroid; diff --git a/private-cli/src/util/isPackagerRunning.js b/private-cli/src/util/isPackagerRunning.js new file mode 100644 index 000000000..ae8950a8b --- /dev/null +++ b/private-cli/src/util/isPackagerRunning.js @@ -0,0 +1,31 @@ +/** + * 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'; + +const fetch = require('node-fetch'); + +/** + * Indicates whether or not the packager is running. It ruturns a promise that + * when fulfilled can returns one out of these possible values: + * - `running`: the packager is running + * - `not_running`: the packager nor any process is running on the expected + * port. + * - `unrecognized`: one other process is running on the port ew expect the + * packager to be running. + */ +function isPackagerRunning() { + return fetch('http://localhost:8081/status').then( + res => res.text().then(body => + body === 'packager-status:running' ? 'running' : 'unrecognized' + ), + () => 'not_running' + ); +} + +module.exports = isPackagerRunning;