Skip to content

fix(apple): read Gemfile & fallback to globally installed pod #2629

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .yarnrc.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
nodeLinker: node-modules
17 changes: 9 additions & 8 deletions packages/cli-config-apple/src/tools/installPods.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,16 @@ import {
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) {
Expand All @@ -30,8 +32,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.
Expand Down Expand Up @@ -139,12 +143,8 @@ async function installPods(loader?: Ora, options?: PodInstallOptions) {
return;
}

if (fs.existsSync('../Gemfile') && !options?.skipBundleInstall) {
if (options?.useBundler) {
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 {
Expand All @@ -157,10 +157,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 ?? '..');
}
}

Expand Down
49 changes: 35 additions & 14 deletions packages/cli-config-apple/src/tools/pods.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
CLIError,
cacheManager,
getLoader,
logger,
} from '@react-native-community/cli-tools';
import installPods from './installPods';
import {
Expand All @@ -24,6 +25,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'));
Expand Down Expand Up @@ -87,7 +100,6 @@ async function getChecksum(

async function install(
packageJson: Record<string, any>,
cachedDependenciesHash: string | undefined,
currentDependenciesHash: string,
iosFolderPath: string,
platform: string,
Expand All @@ -101,9 +113,24 @@ 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".`,
);
}

await installPods(loader, {
skipBundleInstall: !!cachedDependenciesHash,
useBundler,
iosFolderPath,
root,
});
cacheManager.set(packageJson.name, 'dependencies', currentDependenciesHash);
loader.succeed();
Expand Down Expand Up @@ -161,7 +188,6 @@ export default async function resolvePods(
if (options?.forceInstall) {
await install(
packageJson,
cachedDependenciesHash,
currentDependenciesHash,
platformFolderPath,
platformName,
Expand All @@ -182,17 +208,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`
Expand All @@ -202,9 +225,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',
Expand Down
4 changes: 3 additions & 1 deletion packages/cli-config/src/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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({
Expand Down
8 changes: 6 additions & 2 deletions packages/cli/src/commands/init/init.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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') {
Expand All @@ -312,7 +314,9 @@ async function createFromTemplate({
platform: 'ios',
reactNativePath,
});
await installPods(loader, {});
await installPods(loader, {
useBundler: true,
});
loader.succeed();
setEmptyHashForCachedDependencies(projectName);
}
Expand Down
Loading