Skip to content

Commit

Permalink
Move utilities out of react_native_pods - Part 2 (facebook#33982)
Browse files Browse the repository at this point in the history
Summary:
Pull Request resolved: facebook#33982

This Diff moves another part of the utilities from the `react_native_pods` file to a specific `utils.rb` file.

It adds tests for these utils and improve our test mocks.

The goal is to simplify the `react_native_pods.rb` so it's easier to work with it.

I decided to split this diff in 2 because it was becoming quite big.

## Changelog

[iOS][Changed] - Refactoring part of the react_native_pods.rb script

Differential Revision: https://www.internalfb.com/diff/D37006265?entry_point=27

fbshipit-source-id: 204470a68d5a5da137c1f698f413fd9c66618076
  • Loading branch information
Riccardo Cipolleschi authored and facebook-github-bot committed Jun 10, 2022
1 parent 902bcda commit f77af20
Show file tree
Hide file tree
Showing 4 changed files with 244 additions and 65 deletions.
16 changes: 14 additions & 2 deletions scripts/cocoapods/__tests__/test_utils/InstallerMock.rb
Original file line number Diff line number Diff line change
Expand Up @@ -54,22 +54,27 @@ def target_with_name(name)

class PodsProjectMock
attr_reader :targets
attr_reader :native_targets
attr_reader :path
attr_reader :build_configurations
@pod_group
attr_reader :save_invocation_count

def initialize(targets = [], pod_group = {}, path = "test/path-pod.xcodeproj", build_configurations = [])
def initialize(targets = [], pod_group = {}, path = "test/path-pod.xcodeproj", build_configurations = [], native_targets: [])
@targets = targets
@pod_group = pod_group
@path = path
@build_configurations = build_configurations
@save_invocation_count = 0
@native_targets = native_targets
end

def pod_group(name)
return @pod_group[name]
end

def save()
@save_invocation_count += 1
end
end

Expand All @@ -84,13 +89,20 @@ def initialize(user_project = UserProjectMock.new)
class UserProjectMock
attr_reader :path
attr_reader :build_configurations
attr_reader :native_targets

def initialize(path = "/test/path.xcproj", build_configurations = [])
attr_reader :save_invocation_count


def initialize(path = "/test/path.xcproj", build_configurations = [], native_targets: [])
@path = path
@build_configurations = build_configurations
@native_targets = native_targets
@save_invocation_count = 0
end

def save()
@save_invocation_count += 1
end
end

Expand Down
180 changes: 170 additions & 10 deletions scripts/cocoapods/__tests__/utils-test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -149,10 +149,8 @@ def test_hasPod_whenInstallerHasPod_returnTrue
# ============================ #
def test_excludeArchitectures_whenHermesEngineIsNotIncluded_excludeNothing
# Arrange
user_project_mock = UserProjectMock.new("a/path", [
BuildConfigurationMock.new("Debug"),
BuildConfigurationMock.new("Release"),
])
user_project_mock = prepare_empty_user_project_mock()
pods_projects_mock = PodsProjectMock.new()
installer = InstallerMock.new(PodsProjectMock.new(), [
AggregatedProjectMock.new(user_project_mock)
])
Expand All @@ -164,16 +162,15 @@ def test_excludeArchitectures_whenHermesEngineIsNotIncluded_excludeNothing
user_project_mock.build_configurations.each do |config|
assert_equal(config.build_settings["EXCLUDED_ARCHS[sdk=iphonesimulator*]"], "")
end

assert_equal(user_project_mock.save_invocation_count, 1)
assert_equal(pods_projects_mock.save_invocation_count, 0)
end

def test_excludeArchitectures_whenHermesEngineIsIncluded_excludeI386
# Arrange
user_project_mock = UserProjectMock.new("a/path", [
BuildConfigurationMock.new("Debug"),
BuildConfigurationMock.new("Release"),
])
installer = InstallerMock.new(PodsProjectMock.new([], {"hermes-engine" => {}}), [
user_project_mock = prepare_empty_user_project_mock()
pods_projects_mock = PodsProjectMock.new([], {"hermes-engine" => {}})
installer = InstallerMock.new(pods_projects_mock, [
AggregatedProjectMock.new(user_project_mock)
])

Expand All @@ -184,6 +181,169 @@ def test_excludeArchitectures_whenHermesEngineIsIncluded_excludeI386
user_project_mock.build_configurations.each do |config|
assert_equal(config.build_settings["EXCLUDED_ARCHS[sdk=iphonesimulator*]"], "i386")
end

assert_equal(user_project_mock.save_invocation_count, 1)
assert_equal(pods_projects_mock.save_invocation_count, 1)
end

# ================= #
# Test - Fix Config #
# ================= #

def test_fixLibrarySearchPath_whenThereIsNoSearchPaths_doNothing
# Arrange
buildConfig = BuildConfigurationMock.new("Debug")

# Act
ReactNativePodsUtils.fix_library_search_path(buildConfig)

# Assert
assert_nil(buildConfig.build_settings["LIBRARY_SEARCH_PATHS"])
end

def test_fixLibrarySearchPath_whenThereAreSearchPathsAndSwiftUnescaped_removesSwift5_5
# Arrange
buildConfig = BuildConfigurationMock.new("Debug", {"LIBRARY_SEARCH_PATHS" => [
"$(TOOLCHAIN_DIR)/usr/lib/swift-5.0/$(PLATFORM_NAME)",
"\"$(TOOLCHAIN_DIR)/usr/lib/swift-5.0/$(PLATFORM_NAME)\"",
"$(SDKROOT)/usr/lib/swift"
]})

# Act
ReactNativePodsUtils.fix_library_search_path(buildConfig)

# Assert
assert_equal(buildConfig.build_settings["LIBRARY_SEARCH_PATHS"], ["$(SDKROOT)/usr/lib/swift"])
end

def test_fixLibrarySearchPath_whenThereAreSearchPathsAndSwiftEscaped_removesSwift5_5
# Arrange
buildConfig = BuildConfigurationMock.new("Debug", {"LIBRARY_SEARCH_PATHS" => [
"$(TOOLCHAIN_DIR)/usr/lib/swift-5.0/$(PLATFORM_NAME)",
"\"$(TOOLCHAIN_DIR)/usr/lib/swift-5.0/$(PLATFORM_NAME)\"",
"another/path",
"\"$(SDKROOT)/usr/lib/swift\""
]})

# Act
ReactNativePodsUtils.fix_library_search_path(buildConfig)

# Assert
assert_equal(buildConfig.build_settings["LIBRARY_SEARCH_PATHS"], ["another/path", "\"$(SDKROOT)/usr/lib/swift\""])
end

def test_fixLibrarySearchPath_whenThereAreSearchPathsAndNoSwift_removesSwift5_5AndAddsSwiftAsFirst
# Arrange
buildConfig = BuildConfigurationMock.new("Debug", {"LIBRARY_SEARCH_PATHS" => [
"another/path"
]})

# Act
ReactNativePodsUtils.fix_library_search_path(buildConfig)

# Assert
assert_equal(buildConfig.build_settings["LIBRARY_SEARCH_PATHS"], ["$(SDKROOT)/usr/lib/swift", "another/path"])
end

# ============================== #
# Test - Fix Library Search Path #
# ============================== #

def test_fixLibrarySearchPaths_correctlySetsTheSearchPathsForAllProjects
firstTarget = prepare_target("FirstTarget")
secondTarget = prepare_target("SecondTarget")
thirdTarget = prepare_target("ThirdTarget")
user_project_mock = UserProjectMock.new("a/path", [
prepare_config("Debug"),
prepare_config("Release"),
],
:native_targets => [
firstTarget,
secondTarget
]
)
pods_projects_mock = PodsProjectMock.new([], {"hermes-engine" => {}}, :native_targets => [
thirdTarget
])
installer = InstallerMock.new(pods_projects_mock, [
AggregatedProjectMock.new(user_project_mock)
])

# Act
ReactNativePodsUtils.fix_library_search_paths(installer)

# Assert
user_project_mock.build_configurations.each do |config|
assert_equal(config.build_settings["LIBRARY_SEARCH_PATHS"], [
"$(SDKROOT)/usr/lib/swift", "another/path"
])
end

user_project_mock.native_targets.each do |target|
target.build_configurations.each do |config|
assert_equal(config.build_settings["LIBRARY_SEARCH_PATHS"], [
"$(SDKROOT)/usr/lib/swift", "another/path"
])
end
end

pods_projects_mock.native_targets.each do |target|
target.build_configurations.each do |config|
assert_equal(config.build_settings["LIBRARY_SEARCH_PATHS"], [
"$(SDKROOT)/usr/lib/swift", "another/path"
])
end
end

assert_equal(user_project_mock.save_invocation_count, 1)
assert_equal(pods_projects_mock.save_invocation_count, 1)
end

# ==================================== #
# Test - Set Node_Modules User Setting #
# ==================================== #

def test_setNodeModulesUserSettings_addTheUserSetting
# Arrange
react_native_path = "react_native/node_modules"
user_project_mock = prepare_empty_user_project_mock()
pods_projects_mock = PodsProjectMock.new([], {"hermes-engine" => {}})
installer = InstallerMock.new(pods_projects_mock, [
AggregatedProjectMock.new(user_project_mock)
])

# Act
ReactNativePodsUtils.set_node_modules_user_settings(installer, react_native_path)

# Assert
user_project_mock.build_configurations.each do |config|
assert_equal(config.build_settings["REACT_NATIVE_PATH"], "${PODS_ROOT}/../#{react_native_path}")
end

assert_equal(user_project_mock.save_invocation_count, 1)
assert_equal(pods_projects_mock.save_invocation_count, 1)
assert_equal(Pod::UI.collected_messages, ["Setting REACT_NATIVE build settings"])
end
end

def prepare_empty_user_project_mock
return UserProjectMock.new("a/path", [
BuildConfigurationMock.new("Debug"),
BuildConfigurationMock.new("Release"),
])
end

def prepare_config(config_name)
return BuildConfigurationMock.new(config_name, {"LIBRARY_SEARCH_PATHS" => [
"$(TOOLCHAIN_DIR)/usr/lib/swift-5.0/$(PLATFORM_NAME)",
"\"$(TOOLCHAIN_DIR)/usr/lib/swift-5.0/$(PLATFORM_NAME)\"",
"another/path",
]})
end

def prepare_target(name)
return TargetMock.new(name, [
prepare_config("Debug"),
prepare_config("Release")
])
end
58 changes: 58 additions & 0 deletions scripts/cocoapods/utils.rb
Original file line number Diff line number Diff line change
Expand Up @@ -57,4 +57,62 @@ def self.exclude_i386_architecture_while_using_hermes(installer)
project.save()
end
end

def self.set_node_modules_user_settings(installer, react_native_path)
Pod::UI.puts("Setting REACT_NATIVE build settings")
projects = installer.aggregate_targets
.map{ |t| t.user_project }
.uniq{ |p| p.path }
.push(installer.pods_project)

projects.each do |project|
project.build_configurations.each do |config|
config.build_settings["REACT_NATIVE_PATH"] = File.join("${PODS_ROOT}", "..", react_native_path)
end

project.save()
end
end

def self.fix_library_search_paths(installer)
projects = installer.aggregate_targets
.map{ |t| t.user_project }
.uniq{ |p| p.path }
.push(installer.pods_project)

projects.each do |project|
project.build_configurations.each do |config|
ReactNativePodsUtils.fix_library_search_path(config)
end
project.native_targets.each do |target|
target.build_configurations.each do |config|
ReactNativePodsUtils.fix_library_search_path(config)
end
end
project.save()
end
end

private

def self.fix_library_search_path(config)
lib_search_paths = config.build_settings["LIBRARY_SEARCH_PATHS"]

if lib_search_paths == nil
# No search paths defined, return immediately
return
end

# $(TOOLCHAIN_DIR)/usr/lib/swift-5.0/$(PLATFORM_NAME) causes problem with Xcode 12.5 + arm64 (Apple M1)
# since the libraries there are only built for x86_64 and i386.
lib_search_paths.delete("$(TOOLCHAIN_DIR)/usr/lib/swift-5.0/$(PLATFORM_NAME)")
lib_search_paths.delete("\"$(TOOLCHAIN_DIR)/usr/lib/swift-5.0/$(PLATFORM_NAME)\"")

if !(lib_search_paths.include?("$(SDKROOT)/usr/lib/swift") || lib_search_paths.include?("\"$(SDKROOT)/usr/lib/swift\""))
# however, $(SDKROOT)/usr/lib/swift is required, at least if user is not running CocoaPods 1.11
lib_search_paths.insert(0, "$(SDKROOT)/usr/lib/swift")
end
end


end
55 changes: 2 additions & 53 deletions scripts/react_native_pods.rb
Original file line number Diff line number Diff line change
Expand Up @@ -141,72 +141,21 @@ def use_flipper!(versions = {}, configurations: ['Debug'])
use_flipper_pods(versions, :configurations => configurations)
end

def fix_library_search_paths(installer)
def fix_config(config)
lib_search_paths = config.build_settings["LIBRARY_SEARCH_PATHS"]
if lib_search_paths
if lib_search_paths.include?("$(TOOLCHAIN_DIR)/usr/lib/swift-5.0/$(PLATFORM_NAME)") || lib_search_paths.include?("\"$(TOOLCHAIN_DIR)/usr/lib/swift-5.0/$(PLATFORM_NAME)\"")
# $(TOOLCHAIN_DIR)/usr/lib/swift-5.0/$(PLATFORM_NAME) causes problem with Xcode 12.5 + arm64 (Apple M1)
# since the libraries there are only built for x86_64 and i386.
lib_search_paths.delete("$(TOOLCHAIN_DIR)/usr/lib/swift-5.0/$(PLATFORM_NAME)")
lib_search_paths.delete("\"$(TOOLCHAIN_DIR)/usr/lib/swift-5.0/$(PLATFORM_NAME)\"")
if !(lib_search_paths.include?("$(SDKROOT)/usr/lib/swift") || lib_search_paths.include?("\"$(SDKROOT)/usr/lib/swift\""))
# however, $(SDKROOT)/usr/lib/swift is required, at least if user is not running CocoaPods 1.11
lib_search_paths.insert(0, "$(SDKROOT)/usr/lib/swift")
end
end
end
end

projects = installer.aggregate_targets
.map{ |t| t.user_project }
.uniq{ |p| p.path }
.push(installer.pods_project)

projects.each do |project|
project.build_configurations.each do |config|
fix_config(config)
end
project.native_targets.each do |target|
target.build_configurations.each do |config|
fix_config(config)
end
end
project.save()
end
end

def set_node_modules_user_settings(installer, react_native_path)
puts "Setting REACT_NATIVE build settings"
projects = installer.aggregate_targets
.map{ |t| t.user_project }
.uniq{ |p| p.path }
.push(installer.pods_project)

projects.each do |project|
project.build_configurations.each do |config|
config.build_settings["REACT_NATIVE_PATH"] = File.join("${PODS_ROOT}", "..", react_native_path)
end

project.save()
end
end

def react_native_post_install(installer, react_native_path = "../node_modules/react-native")
if ReactNativePodsUtils.has_pod(installer, 'Flipper')
flipper_post_install(installer)
end

ReactNativePodsUtils.exclude_i386_architecture_while_using_hermes(installer)
fix_library_search_paths(installer)
ReactNativePodsUtils.fix_library_search_paths(installer)

cpp_flags = DEFAULT_OTHER_CPLUSPLUSFLAGS
if ENV['RCT_NEW_ARCH_ENABLED'] == '1'
cpp_flags = NEW_ARCH_OTHER_CPLUSPLUSFLAGS
end
modify_flags_for_new_architecture(installer, cpp_flags)

set_node_modules_user_settings(installer, react_native_path)
ReactNativePodsUtils.set_node_modules_user_settings(installer, react_native_path)

puts "Pod install took #{Time.now.to_i - $START_TIME} [s] to run"
end
Expand Down

0 comments on commit f77af20

Please sign in to comment.