From 5140d6438d3f3fa7152a503a581925c0c09d759c Mon Sep 17 00:00:00 2001 From: Riccardo Cipolleschi Date: Wed, 9 Aug 2023 08:38:22 -0700 Subject: [PATCH] Generate .xcode.env.local at pod install time (#38879) Summary: Pull Request resolved: https://github.com/facebook/react-native/pull/38879 When creating a new app for iOS, you need to have Node installed properly and in the right paths in order for Xcode to pick it up. Xcode, by default, looks into the following folders for executables: - /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin - /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/appleinternal/bin: - /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/local/bin: - /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/libexec - /Applications/Xcodefb.app/Contents/Developer/Platforms/iPhoneSimulator.platform/usr/bin - /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/usr/appleinternal/bin - /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/usr/local/bin - /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/usr/bin - /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/usr/local/bin - /Applications/Xcode.app/Contents/Developer/usr/bin - /Applications/Xcode.app/Contents/Developer/usr/local/bin - /usr/local/bin - /usr/bin - /bin - /usr/sbin - /sbin If `node` is not in one of them, our JS codegen scripts will fail to run. However, as soon as we run some scripts in Xcode, it is too late to properly look for node. We already had a cocoapod step, running before the build phase, which was creating the `.xode.env` file, setting `NODE_BINARY` to `$(command -v node)`. Unfortunately, when executed by Xcode, that's too late too. This change creates an `.xcode.env.local` file with the `$(command -v node)` command expanded, so I user can start working locally and quickly. We had multiple reports and issues related to this configuration online. For example: - https://www.reddit.com/r/reactnative/comments/15jpj0a/is_there_a_react_native_version_that_just_works/?utm_source=share&utm_medium=web2x&context=3 Note: we cannot automatically create simlinks to node in `/usr/local/bin` as it requires `sudo`. ## Changelog: [Internal] - Generate `.xcode.env.local` to simplify the creation of an app. Reviewed By: rshest Differential Revision: D48111724 fbshipit-source-id: 49cc6375bd80458d69adbc343ead6c4408805eee --- .../scripts/cocoapods/__tests__/utils-test.rb | 14 +++++++++----- packages/react-native/scripts/cocoapods/utils.rb | 10 +++++++--- 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/packages/react-native/scripts/cocoapods/__tests__/utils-test.rb b/packages/react-native/scripts/cocoapods/__tests__/utils-test.rb index 690145b6144..4e4aa2ef4e6 100644 --- a/packages/react-native/scripts/cocoapods/__tests__/utils-test.rb +++ b/packages/react-native/scripts/cocoapods/__tests__/utils-test.rb @@ -560,24 +560,28 @@ class UtilsTests < Test::Unit::TestCase # =================================== # # Test - Prepare React Native Project # # =================================== # - def test_createXcodeEnvIfMissing_whenItIsPresent_doNothing + def test_createXcodeEnvIfMissing_whenTheyArePresent_doNothing # Arrange FileMock.mocked_existing_files("/.xcode.env") + FileMock.mocked_existing_files("/.xcode.env.local") # Act ReactNativePodsUtils.create_xcode_env_if_missing(file_manager: FileMock) # Assert - assert_equal(FileMock.exist_invocation_params, ["/.xcode.env"]) + assert_equal(FileMock.exist_invocation_params, ["/.xcode.env", "/.xcode.env.local"]) assert_equal($collected_commands, []) end - def test_createXcodeEnvIfMissing_whenItIsNotPresent_createsIt + def test_createXcodeEnvIfMissing_whenTheyAreNotPresent_createsThem # Arrange # Act ReactNativePodsUtils.create_xcode_env_if_missing(file_manager: FileMock) # Assert - assert_equal(FileMock.exist_invocation_params, ["/.xcode.env"]) - assert_equal($collected_commands, ["echo 'export NODE_BINARY=$(command -v node)' > /.xcode.env"]) + assert_equal(FileMock.exist_invocation_params, ["/.xcode.env", "/.xcode.env.local"]) + assert_equal($collected_commands[0], "echo 'export NODE_BINARY=$(command -v node)' > /.xcode.env") + + assert_true($collected_commands[1].start_with? "echo 'export NODE_BINARY=") + assert_true($collected_commands[1].end_with? "' > /.xcode.env.local") end # ============================ # diff --git a/packages/react-native/scripts/cocoapods/utils.rb b/packages/react-native/scripts/cocoapods/utils.rb index 2f66018339b..e26f0cf1b2a 100644 --- a/packages/react-native/scripts/cocoapods/utils.rb +++ b/packages/react-native/scripts/cocoapods/utils.rb @@ -186,11 +186,15 @@ class ReactNativePodsUtils def self.create_xcode_env_if_missing(file_manager: File) relative_path = Pod::Config.instance.installation_root.relative_path_from(Pathname.pwd) file_path = file_manager.join(relative_path, '.xcode.env') - if file_manager.exist?(file_path) - return + + if !file_manager.exist?(file_path) + system("echo 'export NODE_BINARY=$(command -v node)' > #{file_path}") end - system("echo 'export NODE_BINARY=$(command -v node)' > #{file_path}") + if !file_manager.exist?("#{file_path}.local") + node_binary = `command -v node` + system("echo 'export NODE_BINARY=#{node_binary}' > #{file_path}.local") + end end # It examines the target_definition property and sets the appropriate value for