From 7cfb4c633474dfd8e64078ee3c22ef06ed860b7b Mon Sep 17 00:00:00 2001 From: szymonrybczak <szymon.rybczak@gmail.com> Date: Sat, 8 Mar 2025 18:19:39 +0100 Subject: [PATCH 1/2] fix: read gemfile & fallback to globally installed `pod` --- .yarnrc.yml | 1 + .../cli-config-apple/src/tools/installPods.ts | 20 +++---- packages/cli-config-apple/src/tools/pods.ts | 52 ++++++++++++++----- packages/cli-config/src/schema.ts | 4 +- packages/cli/src/commands/init/init.ts | 8 ++- 5 files changed, 56 insertions(+), 29 deletions(-) create mode 100644 .yarnrc.yml diff --git a/.yarnrc.yml b/.yarnrc.yml new file mode 100644 index 000000000..3186f3f07 --- /dev/null +++ b/.yarnrc.yml @@ -0,0 +1 @@ +nodeLinker: node-modules diff --git a/packages/cli-config-apple/src/tools/installPods.ts b/packages/cli-config-apple/src/tools/installPods.ts index c9d4d1fa4..c0f991ee2 100644 --- a/packages/cli-config-apple/src/tools/installPods.ts +++ b/packages/cli-config-apple/src/tools/installPods.ts @@ -9,17 +9,18 @@ import { CLIError, runSudo, } from '@react-native-community/cli-tools'; -import runBundleInstall from './runBundleInstall'; interface PodInstallOptions { - skipBundleInstall?: boolean; newArchEnabled?: boolean; iosFolderPath?: string; + useBundler?: boolean; + root?: string; } interface RunPodInstallOptions { shouldHandleRepoUpdate?: boolean; newArchEnabled?: boolean; + useBundler?: boolean; } async function runPodInstall(loader: Ora, options: RunPodInstallOptions) { @@ -30,8 +31,10 @@ async function runPodInstall(loader: Ora, options: RunPodInstallOptions) { options?.newArchEnabled ? 'with New Architecture' : '', )} ${chalk.dim('(this may take a few minutes)')}`, ); + const command = options.useBundler ? 'bundle' : 'pod'; + const args = options.useBundler ? ['exec', 'pod', 'install'] : ['install']; - await execa('bundle', ['exec', 'pod', 'install'], { + await execa(command, args, { env: { RCT_NEW_ARCH_ENABLED: options?.newArchEnabled ? '1' : '0', RCT_IGNORE_PODS_DEPRECATION: '1', // From React Native 0.79 onwards, users shouldn't install CocoaPods manually. @@ -139,14 +142,6 @@ async function installPods(loader?: Ora, options?: PodInstallOptions) { return; } - if (fs.existsSync('../Gemfile') && !options?.skipBundleInstall) { - await runBundleInstall(loader); - } else if (!fs.existsSync('../Gemfile')) { - throw new CLIError( - 'Could not find the Gemfile. Currently the CLI requires to have this file in the root directory of the project to install CocoaPods. If your configuration is different, please install the CocoaPods manually.', - ); - } - try { // Check if "pod" is available and usable. It happens that there are // multiple versions of "pod" command and even though it's there, it exits @@ -157,10 +152,11 @@ async function installPods(loader?: Ora, options?: PodInstallOptions) { await installCocoaPods(loader); } await runPodInstall(loader, { + useBundler: options?.useBundler, newArchEnabled: options?.newArchEnabled, }); } finally { - process.chdir('..'); + process.chdir(options?.root ?? '..'); } } diff --git a/packages/cli-config-apple/src/tools/pods.ts b/packages/cli-config-apple/src/tools/pods.ts index 1ca5693af..eeae83a0f 100644 --- a/packages/cli-config-apple/src/tools/pods.ts +++ b/packages/cli-config-apple/src/tools/pods.ts @@ -6,6 +6,7 @@ import { CLIError, cacheManager, getLoader, + logger, } from '@react-native-community/cli-tools'; import installPods from './installPods'; import { @@ -14,6 +15,7 @@ import { } from '@react-native-community/cli-types'; import {ApplePlatform} from '../types'; import runCodegen from './runCodegen'; +import runBundleInstall from './runBundleInstall'; interface ResolvePodsOptions { forceInstall?: boolean; @@ -24,6 +26,18 @@ interface NativeDependencies { [key: string]: DependencyConfig; } +function checkGemfileForCocoaPods(gemfilePath: string): boolean { + try { + const gemfileContent = fs.readFileSync(gemfilePath, 'utf-8'); + // Check for common CocoaPods gem declarations, because some projects might have Gemfile but for other purposes + return /^\s*gem\s+['"]cocoapods['"]/.test(gemfileContent); + } catch (error) { + logger.debug(`Failed to read Gemfile at: ${gemfilePath}`); + logger.debug(String(error)); + return false; + } +} + function getPackageJson(root: string) { try { return require(path.join(root, 'package.json')); @@ -87,7 +101,6 @@ async function getChecksum( async function install( packageJson: Record<string, any>, - cachedDependenciesHash: string | undefined, currentDependenciesHash: string, iosFolderPath: string, platform: string, @@ -101,9 +114,26 @@ async function install( platform, reactNativePath, }); + const gemfilePath = path.join(root, 'Gemfile'); + let useBundler = checkGemfileForCocoaPods(gemfilePath); + + if (!useBundler) { + logger.debug( + `Could not find the Gemfile at: ${chalk.cyan(gemfilePath)} + The default React Native Template uses Gemfile to leverage Ruby Bundler and we advice the same. + If you use Gemfile, make sure it's ${chalk.bold( + 'in the project root directory', + )}. + Falling back to installing CocoaPods using globally installed "pod".`, + ); + } else { + await runBundleInstall(loader); + } + await installPods(loader, { - skipBundleInstall: !!cachedDependenciesHash, + useBundler, iosFolderPath, + root, }); cacheManager.set(packageJson.name, 'dependencies', currentDependenciesHash); loader.succeed(); @@ -161,7 +191,6 @@ export default async function resolvePods( if (options?.forceInstall) { await install( packageJson, - cachedDependenciesHash, currentDependenciesHash, platformFolderPath, platformName, @@ -182,17 +211,14 @@ export default async function resolvePods( currentPodfileLockChecksum ?? '', ); } else { - const loader = getLoader('Installing CocoaPods...'); try { - await installPods(loader, { - skipBundleInstall: !!cachedDependenciesHash, - newArchEnabled: options?.newArchEnabled, - iosFolderPath: platformFolderPath, - }); - cacheManager.set( - packageJson.name, - 'dependencies', + await install( + packageJson, currentDependenciesHash, + platformFolderPath, + platformName, + root, + reactNativePath, ); cacheManager.set(packageJson.name, 'podfile', currentPodfileHash); // We need to read again the checksum because value changed after running `pod install` @@ -202,9 +228,7 @@ export default async function resolvePods( 'podfileLock', currentPodfileLockChecksum ?? '', ); - loader.succeed(); } catch (error) { - loader.fail(); throw new CLIError( `Something when wrong while installing CocoaPods. Please run ${chalk.bold( 'pod install', diff --git a/packages/cli-config/src/schema.ts b/packages/cli-config/src/schema.ts index 0eb8e5013..cb229bd83 100644 --- a/packages/cli-config/src/schema.ts +++ b/packages/cli-config/src/schema.ts @@ -158,7 +158,9 @@ export const projectConfig = t automaticPodsInstallation: t.bool().default(true), assets: t.array().items(t.string()).default([]), }) - .default({}), + .default({ + automaticPodsInstallation: true, + }), android: t // AndroidProjectParams .object({ diff --git a/packages/cli/src/commands/init/init.ts b/packages/cli/src/commands/init/init.ts index 87c49f890..2441238b3 100644 --- a/packages/cli/src/commands/init/init.ts +++ b/packages/cli/src/commands/init/init.ts @@ -293,7 +293,9 @@ async function createFromTemplate({ platform: 'ios', reactNativePath, }); - await installPods(loader, {}); + await installPods(loader, { + useBundler: true, + }); loader.succeed(); setEmptyHashForCachedDependencies(projectName); } else if (installPodsValue === 'undefined') { @@ -312,7 +314,9 @@ async function createFromTemplate({ platform: 'ios', reactNativePath, }); - await installPods(loader, {}); + await installPods(loader, { + useBundler: true, + }); loader.succeed(); setEmptyHashForCachedDependencies(projectName); } From f35c1211e2a845d8b62343bd8eed73d3814fd86d Mon Sep 17 00:00:00 2001 From: szymonrybczak <szymon.rybczak@gmail.com> Date: Sat, 8 Mar 2025 18:27:38 +0100 Subject: [PATCH 2/2] fix: move run `bundle install` to `installPods` --- packages/cli-config-apple/src/tools/installPods.ts | 5 +++++ packages/cli-config-apple/src/tools/pods.ts | 3 --- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/packages/cli-config-apple/src/tools/installPods.ts b/packages/cli-config-apple/src/tools/installPods.ts index c0f991ee2..cbcbb0bdf 100644 --- a/packages/cli-config-apple/src/tools/installPods.ts +++ b/packages/cli-config-apple/src/tools/installPods.ts @@ -9,6 +9,7 @@ import { CLIError, runSudo, } from '@react-native-community/cli-tools'; +import runBundleInstall from './runBundleInstall'; interface PodInstallOptions { newArchEnabled?: boolean; @@ -142,6 +143,10 @@ async function installPods(loader?: Ora, options?: PodInstallOptions) { return; } + if (options?.useBundler) { + await runBundleInstall(loader); + } + try { // Check if "pod" is available and usable. It happens that there are // multiple versions of "pod" command and even though it's there, it exits diff --git a/packages/cli-config-apple/src/tools/pods.ts b/packages/cli-config-apple/src/tools/pods.ts index eeae83a0f..3cfb407ab 100644 --- a/packages/cli-config-apple/src/tools/pods.ts +++ b/packages/cli-config-apple/src/tools/pods.ts @@ -15,7 +15,6 @@ import { } from '@react-native-community/cli-types'; import {ApplePlatform} from '../types'; import runCodegen from './runCodegen'; -import runBundleInstall from './runBundleInstall'; interface ResolvePodsOptions { forceInstall?: boolean; @@ -126,8 +125,6 @@ async function install( )}. Falling back to installing CocoaPods using globally installed "pod".`, ); - } else { - await runBundleInstall(loader); } await installPods(loader, {