From a6881695e47021ab0cddf36c057c098e89c85b67 Mon Sep 17 00:00:00 2001 From: Riccardo Cipolleschi Date: Wed, 6 Apr 2022 02:13:43 -0700 Subject: [PATCH] Introduce .xcode.env configuration file to source `node` (#33546) Summary: Pull Request resolved: https://github.com/facebook/react-native/pull/33546 This Diff does 2 things: 1. Removes all the remnant of the `find-node.sh` script. This allows React Native to stay agnostic from any other node manager 2. Introduces a way for the developers to specify which `node` executable they want to use, through a simple `.env` file. ## Changelog [iOS][Changed] - This PR removes the `find-node.sh` scripts and replaces it with an `.xcode.env` file that is sourced by the script phases that needs it. The `.xcode.env` file is versioned: to customize a local environment, an unversioned `.xcode.local.env` can be used. Differential Revision: D35317070 fbshipit-source-id: d368fa95bab7e39fcdccec4962df337fb33a48c9 --- .circleci/config.yml | 6 --- .gitignore | 1 + package.json | 1 + packages/rn-tester/.xcode.env | 11 +++++ .../RNTesterPods.xcodeproj/project.pbxproj | 4 +- scripts/react-native-xcode.sh | 4 -- scripts/react_native_pods.rb | 4 +- .../react_native_pods_utils/script_phases.rb | 4 +- .../react_native_pods_utils/script_phases.sh | 7 ++- scripts/xcode/with-environment.sh | 47 +++++++++++++++++++ template/_gitignore | 1 + .../ios/HelloWorld.xcodeproj/project.pbxproj | 4 +- template/ios/_xcode.env | 11 +++++ 13 files changed, 86 insertions(+), 19 deletions(-) create mode 100644 packages/rn-tester/.xcode.env create mode 100755 scripts/xcode/with-environment.sh create mode 100644 template/ios/_xcode.env diff --git a/.circleci/config.yml b/.circleci/config.yml index 6323c4fc6cc7..2d7b313eafce 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -468,12 +468,6 @@ jobs: - brew_install: package: applesimutils - - run: - name: Configure Node - # Sourcing find-node.sh will ensure nvm is set up. - # It also helps future invocation of find-node.sh prevent permission issue with nvm.sh. - command: source scripts/find-node-for-xcode.sh && nvm install 16 && nvm alias default 16 - - run: name: Configure Watchman command: echo "{}" > .watchmanconfig diff --git a/.gitignore b/.gitignore index 35da812e0543..18328754723b 100644 --- a/.gitignore +++ b/.gitignore @@ -20,6 +20,7 @@ DerivedData *.ipa *.xcuserstate project.xcworkspace +**/.xcode.env.local # Gradle /build/ diff --git a/package.json b/package.json index 6d1420b88965..41b61bee46d6 100644 --- a/package.json +++ b/package.json @@ -43,6 +43,7 @@ "scripts/generate-provider-cli.js", "scripts/generate-specs-cli.js", "scripts/ios-configure-glog.sh", + "scripts/xcode/with-environment.sh", "scripts/launchPackager.bat", "scripts/launchPackager.command", "scripts/node-binary.sh", diff --git a/packages/rn-tester/.xcode.env b/packages/rn-tester/.xcode.env new file mode 100644 index 000000000000..3d5782c71568 --- /dev/null +++ b/packages/rn-tester/.xcode.env @@ -0,0 +1,11 @@ +# This `.xcode.env` file is versioned and is used to source the environment +# used when running script phases inside Xcode. +# To customize your local environment, you can create an `.xcode.env.local` +# file that is not versioned. + +# NODE_BINARY variable contains the PATH to the node executable. +# +# Customize the NODE_BINARY variable here. +# For example, to use nvm with brew, add the following line +# . "$(brew --prefix nvm)/nvm.sh" --no-use +export NODE_BINARY=$(command -v node) diff --git a/packages/rn-tester/RNTesterPods.xcodeproj/project.pbxproj b/packages/rn-tester/RNTesterPods.xcodeproj/project.pbxproj index a562a0e62796..4a0f2a6ece4f 100644 --- a/packages/rn-tester/RNTesterPods.xcodeproj/project.pbxproj +++ b/packages/rn-tester/RNTesterPods.xcodeproj/project.pbxproj @@ -633,13 +633,15 @@ files = ( ); inputPaths = ( + "$(SRCROOT)/.xcode.env.local", + "$(SRCROOT)/.xcode.env", ); name = "Build JS Bundle"; outputPaths = ( ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "set -e\n\nexport NODE_BINARY=node\nexport PROJECT_ROOT=\"$SRCROOT/../../\"\nexport ENTRY_FILE=\"$SRCROOT/js/RNTesterApp.ios.js\"\nexport SOURCEMAP_FILE=../sourcemap.ios.map\n# export FORCE_BUNDLING=true\n\"$SRCROOT/../../scripts/react-native-xcode.sh\"\n"; + shellScript = "set -e\n\nexport PROJECT_ROOT=\"$SRCROOT/../../\"\nexport ENTRY_FILE=\"$SRCROOT/js/RNTesterApp.ios.js\"\nexport SOURCEMAP_FILE=../sourcemap.ios.map\n# export FORCE_BUNDLING=true \n\nWITH_ENVIRONMENT=\"../../scripts/xcode/with-environment.sh\"\nREACT_NATIVE_XCODE=\"../../scripts/react-native-xcode.sh\"\n\n/bin/sh -c \"$WITH_ENVIRONMENT $REACT_NATIVE_XCODE\"\n"; }; 98E057AC8860597818FB485A /* [CP] Copy Pods Resources */ = { isa = PBXShellScriptBuildPhase; diff --git a/scripts/react-native-xcode.sh b/scripts/react-native-xcode.sh index de52d215473e..6f95a2953c12 100755 --- a/scripts/react-native-xcode.sh +++ b/scripts/react-native-xcode.sh @@ -79,10 +79,6 @@ if [[ $DEV != true && ! -f "$ENTRY_FILE" ]]; then exit 2 fi -# Find path to Node -# shellcheck source=/dev/null -source "$REACT_NATIVE_DIR/scripts/find-node-for-xcode.sh" - # check and assign NODE_BINARY env # shellcheck source=/dev/null source "$REACT_NATIVE_DIR/scripts/node-binary.sh" diff --git a/scripts/react_native_pods.rb b/scripts/react_native_pods.rb index 36431eb9d4a5..c3aa0557e0d5 100644 --- a/scripts/react_native_pods.rb +++ b/scripts/react_native_pods.rb @@ -630,9 +630,11 @@ def use_react_native_codegen!(spec, options={}) system(prepare_command) # Always run prepare_command when a podspec uses the codegen, as CocoaPods may skip invoking this command in certain scenarios. Replace with pre_integrate_hook after updating to CocoaPods 1.11 spec.prepare_command = prepare_command + env_files = ["$PODS_ROOT/../.xcode.env.local", "$PODS_ROOT/../.xcode.env"] + spec.script_phase = { :name => 'Generate Specs', - :input_files => input_files, # This also needs to be relative to Xcode + :input_files => input_files + env_files, # This also needs to be relative to Xcode :output_files => ["${DERIVED_FILE_DIR}/codegen-#{library_name}.log"].concat(generated_files.map { |filename| "${PODS_TARGET_SRCROOT}/#{filename}"} ), # The final generated files will be created when this script is invoked at Xcode build time. :script => get_script_phases_no_codegen_discovery( diff --git a/scripts/react_native_pods_utils/script_phases.rb b/scripts/react_native_pods_utils/script_phases.rb index a91b1a9b2a0a..4520da175597 100644 --- a/scripts/react_native_pods_utils/script_phases.rb +++ b/scripts/react_native_pods_utils/script_phases.rb @@ -45,9 +45,9 @@ def get_script_template(react_native_path, export_vars={}) <% end %> SCRIPT_PHASES_SCRIPT="$RCT_SCRIPT_RN_DIR/scripts/react_native_pods_utils/script_phases.sh" - /bin/sh -c "$SCRIPT_PHASES_SCRIPT" + WITH_ENVIRONMENT="$RCT_SCRIPT_RN_DIR/scripts/xcode/with-environment.sh" + /bin/sh -c "$WITH_ENVIRONMENT $SCRIPT_PHASES_SCRIPT" EOS result = ERB.new(template, 0, '->').result(binding) - # puts result return result end diff --git a/scripts/react_native_pods_utils/script_phases.sh b/scripts/react_native_pods_utils/script_phases.sh index 4cb38b7b2d88..afd41d829392 100755 --- a/scripts/react_native_pods_utils/script_phases.sh +++ b/scripts/react_native_pods_utils/script_phases.sh @@ -33,12 +33,11 @@ else fi find_node () { - # shellcheck disable=SC1091 - source "$RCT_SCRIPT_RN_DIR/scripts/find-node-for-xcode.sh" - NODE_BINARY="${NODE_BINARY:-$(command -v node || true)}" if [ -z "$NODE_BINARY" ]; then - error "error: Could not find node. Make sure it is in bash PATH or set the NODE_BINARY environment variable." + error "[Error] Could not find node. It looks like that the .xcode.env or .xcode.env.local " \ +"files are misconfigured. Please check that they are exporting a valid NODE_BINARY " \ +"variable, pointing to a node executable." fi } diff --git a/scripts/xcode/with-environment.sh b/scripts/xcode/with-environment.sh new file mode 100755 index 000000000000..938ded3f153a --- /dev/null +++ b/scripts/xcode/with-environment.sh @@ -0,0 +1,47 @@ +#!/bin/bash +# Copyright (c) Meta Platforms, Inc. and affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +# This script is used to source in Xcode the environment settings required to run properly. +# The script first sources the base `.xcode.env` file. +# Then it sources the `.xcode.env.local` file if present, to override some local config +# Finally, it will execute the command passed i input if any. +# +# USAGE: +# ./with-environment.sh command + +# Start with a default +NODE_BINARY=$(command -v node) +export NODE_BINARY + +# Override the default with the global environment +ENV_PATH="$PODS_ROOT/../.xcode.env" +if [ -f "$ENV_PATH" ]; then + source "$ENV_PATH" +fi + +# Override the global with the local environment +LOCAL_ENV_PATH="${ENV_PATH}.local" +if [ -f "$LOCAL_ENV_PATH" ]; then + source "$LOCAL_ENV_PATH" +fi + +# Check whether NODE_BINARY has been properly set, otherwise help the users with a meaningful error. +if [ -n "$NODE_BINARY" ]; then + echo "Node found at: ${NODE_BINARY}" +else + echo "[Warning] You need to configure your node path in the `'.xcode.env' file` environment. " \ + "You can set it up quickly by running: " \ + "echo 'export NODE_BINARY=$(command -v node)' > .xcode.env " \ + "in the ios folder. This is needed by React Native to work correctly. " \ + "We fallback to the DEPRECATED behavior of finding `node`. This will be REMOVED in a future version. " \ + "You can read more about this here: " >&2 + source "../find-node-for-xcode.sh" +fi + +# Execute argument, if present +if [ -n "$1" ]; then + $1 +fi diff --git a/template/_gitignore b/template/_gitignore index e8b2d63f70a5..344481b211f2 100644 --- a/template/_gitignore +++ b/template/_gitignore @@ -20,6 +20,7 @@ DerivedData *.hmap *.ipa *.xcuserstate +ios/.xcode.env.local # Android/IntelliJ # diff --git a/template/ios/HelloWorld.xcodeproj/project.pbxproj b/template/ios/HelloWorld.xcodeproj/project.pbxproj index 8cfb8881a102..70234ff08ade 100644 --- a/template/ios/HelloWorld.xcodeproj/project.pbxproj +++ b/template/ios/HelloWorld.xcodeproj/project.pbxproj @@ -256,13 +256,15 @@ files = ( ); inputPaths = ( + "$(SRCROOT)/.xcode.env.local", + "$(SRCROOT)/.xcode.env", ); name = "Bundle React Native code and images"; outputPaths = ( ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "set -e\n\nexport NODE_BINARY=node\n../node_modules/react-native/scripts/react-native-xcode.sh\n"; + shellScript = "set -e\n\nWITH_ENVIRONMENT=\"../node_modules/react-native/scripts/xcode/with-environment.sh\"\nREACT_NATIVE_XCODE=\"../node_modules/react-native/scripts/react-native-xcode.sh\"\n\n/bin/sh -c \"$WITH_ENVIRONMENT $REACT_NATIVE_XCODE\"\n"; }; 00EEFC60759A1932668264C0 /* [CP] Embed Pods Frameworks */ = { isa = PBXShellScriptBuildPhase; diff --git a/template/ios/_xcode.env b/template/ios/_xcode.env new file mode 100644 index 000000000000..3d5782c71568 --- /dev/null +++ b/template/ios/_xcode.env @@ -0,0 +1,11 @@ +# This `.xcode.env` file is versioned and is used to source the environment +# used when running script phases inside Xcode. +# To customize your local environment, you can create an `.xcode.env.local` +# file that is not versioned. + +# NODE_BINARY variable contains the PATH to the node executable. +# +# Customize the NODE_BINARY variable here. +# For example, to use nvm with brew, add the following line +# . "$(brew --prefix nvm)/nvm.sh" --no-use +export NODE_BINARY=$(command -v node)