diff --git a/packages/cli/package.json b/packages/cli/package.json index 4feb0411f..9ee5b969a 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -27,6 +27,7 @@ "@react-native-community/cli-platform-ios": "^2.0.0-alpha.17", "@react-native-community/cli-tools": "^2.0.0-alpha.17", "chalk": "^1.1.1", + "command-exists": "^1.2.8", "commander": "^2.19.0", "compression": "^1.7.1", "connect": "^3.6.5", diff --git a/packages/cli/src/commands/init/init.js b/packages/cli/src/commands/init/init.js index c88d4fddf..288214046 100644 --- a/packages/cli/src/commands/init/init.js +++ b/packages/cli/src/commands/init/init.js @@ -2,6 +2,7 @@ import os from 'os'; import path from 'path'; import fs from 'fs-extra'; +import Ora from 'ora'; import minimist from 'minimist'; import semver from 'semver'; import type {ConfigT} from 'types'; @@ -17,6 +18,7 @@ import { } from './template'; import {changePlaceholderInTemplate} from './editTemplate'; import * as PackageManager from '../../tools/packageManager'; +import installPods from '../../tools/installPods'; import {processTemplateName} from './templateName'; import banner from './banner'; import {getLoader} from '../../tools/loader'; @@ -93,9 +95,7 @@ async function createFromTemplate({ loader.succeed(); } - loader.start('Installing all required dependencies'); - await PackageManager.installAll({preferYarn: !npm, silent: true}); - loader.succeed(); + await installDependencies({projectName, npm, loader}); } catch (e) { loader.fail(); throw new Error(e); @@ -104,6 +104,29 @@ async function createFromTemplate({ } } +async function installDependencies({ + projectName, + npm, + loader, +}: { + projectName: string, + npm?: boolean, + loader: typeof Ora, +}) { + loader.start('Installing all required dependencies'); + + await PackageManager.installAll({ + preferYarn: !npm, + silent: true, + }); + + if (process.platform === 'darwin') { + await installPods({projectName, loader}); + } + + loader.succeed(); +} + function createProject(projectName: string, options: Options, version: string) { fs.mkdirSync(projectName); process.chdir(projectName); diff --git a/packages/cli/src/commands/init/printRunInstructions.js b/packages/cli/src/commands/init/printRunInstructions.js index 220c146fe..43258c85a 100644 --- a/packages/cli/src/commands/init/printRunInstructions.js +++ b/packages/cli/src/commands/init/printRunInstructions.js @@ -9,19 +9,22 @@ */ import path from 'path'; +import fs from 'fs'; import chalk from 'chalk'; import {logger} from '@react-native-community/cli-tools'; function printRunInstructions(projectDir: string, projectName: string) { const absoluteProjectDir = path.resolve(projectDir); - const xcodeProjectPath = `${path.resolve( - projectDir, - 'ios', - projectName, - )}.xcodeproj`; + const iosProjectDir = path.resolve(projectDir, 'ios'); + + const iosPodsFile = path.resolve(iosProjectDir, `${projectName}.xcworkspace`); + const isUsingPods = fs.existsSync(iosPodsFile); + const relativeXcodeProjectPath = path.relative( process.cwd(), - xcodeProjectPath, + isUsingPods + ? iosPodsFile + : path.resolve(iosProjectDir, `${projectName}.xcodeproj`), ); logger.log(` diff --git a/packages/cli/src/tools/installPods.js b/packages/cli/src/tools/installPods.js new file mode 100644 index 000000000..d59b7781e --- /dev/null +++ b/packages/cli/src/tools/installPods.js @@ -0,0 +1,83 @@ +// @flow +import fs from 'fs-extra'; +import execa from 'execa'; +import chalk from 'chalk'; +import Ora from 'ora'; +import inquirer from 'inquirer'; +import commandExists from 'command-exists'; +import {logger} from '@react-native-community/cli-tools'; + +async function installPods({ + projectName, + loader, +}: { + projectName: string, + loader: typeof Ora, +}) { + try { + process.chdir('ios'); + + const hasPods = await fs.pathExists('Podfile'); + + if (!hasPods) { + return; + } + + try { + await commandExists('pod'); + } catch (e) { + loader.stop(); + + const {shouldInstallCocoaPods} = await inquirer.prompt([ + { + type: 'confirm', + name: 'shouldInstallCocoaPods', + message: 'CocoaPods is not installed, do you want to install it?', + }, + ]); + + if (shouldInstallCocoaPods) { + try { + // First attempt to install `cocoapods` + await execa('gem', ['install', 'cocoapods']); + } catch (_error) { + try { + // If that doesn't work then try with sudo + await execa('sudo', ['gem', 'install', 'cocoapods']); + } catch (error) { + logger.log(error.stderr); + + throw new Error( + `Error occured while trying to install CocoaPods, which is required by this template.\nPlease try again manually: "sudo gem install cocoapods".\nCocoaPods documentation: ${chalk.dim.underline( + 'https://cocoapods.org/', + )}`, + ); + } + } + + // This only shows when `CocoaPods` is automatically installed, + // if it's already installed then we just show the `Installing dependencies` step + loader.start('Installing CocoaPods dependencies'); + } + } + + try { + await execa('pod', ['install']); + } catch (error) { + // "pod" command outputs errors to stdout (at least some of them) + logger.log(error.stderr || error.stdout); + + throw new Error( + `Failed to install CocoaPods dependencies for iOS project, which is required by this template.\nPlease try again manually: "cd ./${projectName}/ios && pod install".\nCocoaPods documentation: ${chalk.dim.underline( + 'https://cocoapods.org/', + )}`, + ); + } + } catch (error) { + throw error; + } finally { + process.chdir('..'); + } +} + +export default installPods; diff --git a/yarn.lock b/yarn.lock index c3750962c..2b6b68669 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2787,6 +2787,11 @@ combined-stream@^1.0.6, combined-stream@~1.0.6: dependencies: delayed-stream "~1.0.0" +command-exists@^1.2.8: + version "1.2.8" + resolved "https://registry.yarnpkg.com/command-exists/-/command-exists-1.2.8.tgz#715acefdd1223b9c9b37110a149c6392c2852291" + integrity sha512-PM54PkseWbiiD/mMsbvW351/u+dafwTJ0ye2qB60G1aGQP9j3xK2gmMDc+R34L3nDtx4qMCitXT75mkbkGJDLw== + commander@^2.19.0, commander@~2.19.0: version "2.19.0" resolved "https://registry.yarnpkg.com/commander/-/commander-2.19.0.tgz#f6198aa84e5b83c46054b94ddedbfed5ee9ff12a"