import fs from 'fs' ; import execa from 'execa' ; import chalk from 'chalk' ; import ora from 'ora' ; import prompts from 'prompts' ; import { logger } from '@react-native-community/cli-tools' ; import { NoopLoader } from './loader' ; import sudo from 'sudo-prompt' ; import { brewInstall } from './brewInstall' ; type PromptCocoaPodsInstallation = { installMethod : 'gem' | 'homebrew' ; promptQuestion : string ; } ; async function runPodInstall ( loader , directory , shouldHandleRepoUpdate = true ) { try { loader . start ( `Installing CocoaPods dependencies ${ chalk . dim ( '(this may take a few minutes)' ) }` ) ; await execa ( 'pod' , [ 'install' ] ) ; } catch ( error ) { const stderr = error . stderr || error . stdout ; /**
         * If CocoaPods failed due to repo being out of date, it will
         * include the update command in the error message.
         *
         * `shouldHandleRepoUpdate` will be set to `false` to
         * prevent infinite loop (unlikely scenario)
         */ if ( stderr . includes ( 'pod repo update' ) && shouldHandleRepoUpdate ) { await runPodUpdate ( loader ) ; await runPodInstall ( loader , directory , false ) ; } else { loader . fail ( ) ; throw new Error ( `Failed to install CocoaPods dependencies for iOS project, which is required by this template.\nPlease try again manually: "cd ./${ directory }/ios && pod install".\nCocoaPods documentation: ${ chalk . dim . underline ( 'https://cocoapods.org/' ) }` ) ; } } } async function runPodUpdate ( loader ) { try { loader . start ( `Updating CocoaPods repositories ${ chalk . dim ( '(this may take a few minutes)' ) }` ) ; await execa ( 'pod' , [ 'repo' , 'update' ] ) ; } catch ( error ) { logger . log ( error . stderr || error . stdout ) ; loader . fail ( ) ; throw new Error ( `Failed to update CocoaPods repositories for iOS project.\nPlease try again manually: "pod repo update".\nCocoaPods documentation: ${ chalk . dim . underline ( 'https://cocoapods.org/' ) }` ) ; } } function runSudo ( command ) { return new Promise ( ( resolve , reject ) => { sudo . exec ( command , { name : 'React Native CLI' } , ( error ) => { if ( error ) { reject ( error ) ; } resolve ( ) ; } ) ; } ) ; } async function promptCocoaPodsInstallationQuestion ( ) { const promptQuestion = `CocoaPods ${ chalk . dim . underline ( '(https://cocoapods.org/)' ) } ${ chalk . reset . bold ( 'is not installed. CocoaPods is necessary for the iOS project to run correctly. Do you want to install it?' ) }` ; const installWithGem = 'Yes, with gem (may require sudo)' ; const installWithHomebrew = 'Yes, with Homebrew' ; const { installMethod } = await prompts ( [ { type : 'select' , name : 'installMethod' , message : promptQuestion , choices : [ { title : installWithGem , value : 'gem' } , { title : installWithHomebrew , value : 'homebrew' } , ] , } , ] ) ; return { installMethod , promptQuestion : `? ${ promptQuestion } ${ installMethod === 'gem' ? installWithGem : installWithHomebrew }` , } ; } async function installCocoaPodsWithGem ( ) { const options = [ 'install' , 'cocoapods' , '--no-document' ] ; try { await execa ( 'gem' , options ) ; } catch ( _error ) { await runSudo ( `gem ${ options . join ( ' ' ) }` ) ; } } async function installCocoaPods ( loader ) { loader . stop ( ) ; const { installMethod } = await promptCocoaPodsInstallationQuestion ( ) ; if ( installMethod === 'gem' ) { loader . start ( 'Installing CocoaPods' ) ; try { await installCocoaPodsWithGem ( ) ; return loader . succeed ( ) ; } catch ( error ) { loader . fail ( ) ; logger . error ( error . stderr ) ; throw new Error ( `An 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/' ) }` ) ; } } if ( installMethod === 'homebrew' ) { return await brewInstall ( { pkg : 'cocoapods' , label : 'Installing CocoaPods' , loader , } ) ; } } async function installPods ( { directory , loader , } ) { loader = loader || new NoopLoader ( ) ; try { if ( ! fs . existsSync ( 'ios' ) ) { return ; } process . chdir ( 'ios' ) ; const hasPods = fs . existsSync ( 'Podfile' ) ; if ( ! hasPods ) { return ; } try { await execa ( 'pod' , [ '--version' ] ) ; } catch ( e ) { loader . info ( ) ; await installCocoaPods ( loader ) ; } await runPodInstall ( loader , directory ) ; } catch ( error ) { throw error ; } finally { process . chdir ( '..' ) ; } } export { promptCocoaPodsInstallationQuestion , runSudo , installCocoaPods } ; export default installPods ;