Skip to content

Commit

Permalink
Move cocoapods utilities to utils.rb - Part 1 (#33978)
Browse files Browse the repository at this point in the history
Summary:
Pull Request resolved: #33978

This Diff moves 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

Reviewed By: cortinico

Differential Revision: D37004347

fbshipit-source-id: a5156f7c199d082d5d895a58af80948556c51c2a
  • Loading branch information
Riccardo Cipolleschi authored and facebook-github-bot committed Jun 10, 2022
1 parent 780fe80 commit 7a27044
Show file tree
Hide file tree
Showing 11 changed files with 349 additions and 51 deletions.
5 changes: 1 addition & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -55,10 +55,7 @@
"scripts/react_native_pods_utils/script_phases.rb",
"scripts/react_native_pods_utils/script_phases.sh",
"scripts/react_native_pods.rb",
"scripts/cocoapods/codegen.rb",
"scripts/cocoapods/fabric.rb",
"scripts/cocoapods/flipper.rb",
"scripts/cocoapods/new_architecture.rb",
"scripts/cocoapods",
"scripts/react-native-xcode.sh",
"sdks/.hermesversion",
"sdks/hermes-engine",
Expand Down
2 changes: 2 additions & 0 deletions scripts/.npmignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# Make sure we never publish __test__ folders (Gradle output)
**/__tests__/
21 changes: 21 additions & 0 deletions scripts/cocoapods/__tests__/test_utils/EnvironmentMock.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# 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.

# Mock object for the Environment
class Environment
@@RUBY_PLATFORM = "arm64-darwin21"

def ruby_platform
return @@RUBY_PLATFORM
end

def self.set_ruby_platform(newPlatform)
@@RUBY_PLATFORM = newPlatform
end

def self.reset()
@@RUBY_PLATFORM = "arm64-darwin21"
end
end
15 changes: 14 additions & 1 deletion scripts/cocoapods/__tests__/test_utils/InstallerMock.rb
Original file line number Diff line number Diff line change
Expand Up @@ -54,9 +54,22 @@ def target_with_name(name)

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

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

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

def save()
end
end

Expand Down
10 changes: 10 additions & 0 deletions scripts/cocoapods/__tests__/test_utils/PodMock.rb
Original file line number Diff line number Diff line change
Expand Up @@ -41,17 +41,27 @@ def relative_path_from(path)
class UI

@@collected_messages = []
@@collected_warns = []

def self.puts(message)
@@collected_messages.push(message)
end

def self.warn(warn)
@@collected_warns.push(warn)
end

def self.collected_messages()
return @@collected_messages
end

def self.collected_warns()
return @@collected_warns
end

def self.reset()
@@collected_messages = []
@@collected_warns = []
end
end

Expand Down
21 changes: 21 additions & 0 deletions scripts/cocoapods/__tests__/test_utils/SysctlCheckerMock.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# 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.

# Mock object for SysctlChecker
class SysctlChecker
@@call_sysctl_arm64_return_value = 1

def call_sysctl_arm64
return @@call_sysctl_arm64_return_value
end

def self.set_call_sysctl_arm64_return_value(newValue)
@@call_sysctl_arm64_return_value = newValue
end

def self.reset()
@@call_sysctl_arm64_return_value = 1
end
end
189 changes: 189 additions & 0 deletions scripts/cocoapods/__tests__/utils-test.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,189 @@
# 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.

require "test/unit"
require_relative "../utils.rb"
require_relative "../flipper.rb"
require_relative "./test_utils/PodMock.rb"
require_relative "./test_utils/InstallerMock.rb"
require_relative "./test_utils/EnvironmentMock.rb"
require_relative "./test_utils/SysctlCheckerMock.rb"

class UtilsTests < Test::Unit::TestCase
def teardown
Pod::UI.reset()
SysctlChecker.reset()
Environment.reset()
ENV['RCT_NEW_ARCH_ENABLED'] = '0'
ENV['USE_HERMES'] = '0'
end

# ======================= #
# TEST - warnIfNotOnArm64 #
# ======================= #

def test_warnIfNotOnArm64_whenSysctlReturnsNot1_printsNothing
# Arrange
SysctlChecker.set_call_sysctl_arm64_return_value(23)
Environment.set_ruby_platform("something")

# Act
ReactNativePodsUtils.warn_if_not_on_arm64()

# Assert
assert_equal(Pod::UI.collected_messages, [])
assert_equal(Pod::UI.collected_warns, [])

end

def test_warnIfNotOnArm64_whenSysctlReturns1AndRubyIncludeArm64_printsNothing
# Arrange
SysctlChecker.set_call_sysctl_arm64_return_value(1)
Environment.set_ruby_platform("arm64-darwin21")

# Act
ReactNativePodsUtils.warn_if_not_on_arm64()

# Assert
assert_equal(Pod::UI.collected_messages, [])
assert_equal(Pod::UI.collected_warns, [])
end

def test_warnIfNotOnArm64_whenSysctlReturns1AndRubyNotIncludeArm64_warns
# Arrange
SysctlChecker.set_call_sysctl_arm64_return_value(1)
Environment.set_ruby_platform("something else")

# Act
ReactNativePodsUtils.warn_if_not_on_arm64()

# Assert
assert_equal(Pod::UI.collected_messages, [])
assert_equal(Pod::UI.collected_warns, [
'Do not use "pod install" from inside Rosetta2 (x86_64 emulation on arm64).',
' - Emulated x86_64 is slower than native arm64',
' - May result in mixed architectures in rubygems (eg: ffi_c.bundle files may be x86_64 with an arm64 interpreter)',
'Run "env /usr/bin/arch -arm64 /bin/bash --login" then try again.',
])
end

# ====================== #
# TEST - getDefaultFlags #
# ====================== #
def test_getDefaultFlag_whenOldArchitecture()
# Arrange
ENV['RCT_NEW_ARCH_ENABLED'] = '0'
ENV['USE_HERMES'] = '0'
# Act
flags = ReactNativePodsUtils.get_default_flags()

# Assert
assert_equal(flags, {
:fabric_enabled => false,
:hermes_enabled => false,
:flipper_configuration => FlipperConfiguration.disabled
})
end

def test_getDefaultFlag_whenOldArchitectureButHermesEnabled()
# Arrange
ENV['RCT_NEW_ARCH_ENABLED'] = '0'
ENV['USE_HERMES'] = '1'

# Act
flags = ReactNativePodsUtils.get_default_flags()

# Assert
assert_equal(flags, {
:fabric_enabled => false,
:hermes_enabled => true,
:flipper_configuration => FlipperConfiguration.disabled
})
end

def test_getDefaultFlag_whenNewArchitecture()
# Arrange
ENV['RCT_NEW_ARCH_ENABLED'] = '1'

# Act
flags = ReactNativePodsUtils.get_default_flags()

# Assert
assert_equal(flags, {
:fabric_enabled => true,
:hermes_enabled => true,
:flipper_configuration => FlipperConfiguration.disabled
})
end

# ============== #
# TEST - has_pod #
# ============== #
def test_hasPod_whenInstallerDoesNotHavePod_returnFalse
# Arrange
installer = InstallerMock.new(PodsProjectMock.new([], {"other_pod" => {}}))

# Act
result = ReactNativePodsUtils.has_pod(installer, "some_pod")

# Assert
assert_equal(result, false)

end

def test_hasPod_whenInstallerHasPod_returnTrue
# Arrange
installer = InstallerMock.new(PodsProjectMock.new([], {"some_pod" => {}}))

# Act
result = ReactNativePodsUtils.has_pod(installer, "some_pod")

# Assert
assert_equal(result, true)
end

# ============================ #
# Test - Exclude Architectures #
# ============================ #
def test_excludeArchitectures_whenHermesEngineIsNotIncluded_excludeNothing
# Arrange
user_project_mock = UserProjectMock.new("a/path", [
BuildConfigurationMock.new("Debug"),
BuildConfigurationMock.new("Release"),
])
installer = InstallerMock.new(PodsProjectMock.new(), [
AggregatedProjectMock.new(user_project_mock)
])

# Act
ReactNativePodsUtils.exclude_i386_architecture_while_using_hermes(installer)

# Assert
user_project_mock.build_configurations.each do |config|
assert_equal(config.build_settings["EXCLUDED_ARCHS[sdk=iphonesimulator*]"], "")
end

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" => {}}), [
AggregatedProjectMock.new(user_project_mock)
])

# Act
ReactNativePodsUtils.exclude_i386_architecture_while_using_hermes(installer)

# Assert
user_project_mock.build_configurations.each do |config|
assert_equal(config.build_settings["EXCLUDED_ARCHS[sdk=iphonesimulator*]"], "i386")
end
end

end
6 changes: 6 additions & 0 deletions scripts/cocoapods/flipper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -109,4 +109,10 @@ def self.enabled(configurations = ["Debug"], versions = {})
def self.disabled
FlipperConfiguration.new(false, [], {})
end

def == (other)
return @flipper_enabled == other.flipper_enabled &&
@configurations == other.configurations &&
@versions == other.versions
end
end
20 changes: 20 additions & 0 deletions scripts/cocoapods/helpers.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# 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.

# Helper object to wrap the invocation of sysctl
# This makes it easier to mock the behaviour in tests
class SysctlChecker
def call_sysctl_arm64
return `/usr/sbin/sysctl -n hw.optional.arm64 2>&1`.to_i
end
end

# Helper object to wrap system properties like RUBY_PLATFORM
# This makes it easier to mock the behaviour in tests
class Environment
def ruby_platform
return RUBY_PLATFORM
end
end
60 changes: 60 additions & 0 deletions scripts/cocoapods/utils.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
# 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.

require_relative "./helpers.rb"

# Utilities class for React Native Cocoapods
class ReactNativePodsUtils
def self.warn_if_not_on_arm64
if SysctlChecker.new().call_sysctl_arm64() == 1 && !Environment.new().ruby_platform().include?('arm64')
Pod::UI.warn 'Do not use "pod install" from inside Rosetta2 (x86_64 emulation on arm64).'
Pod::UI.warn ' - Emulated x86_64 is slower than native arm64'
Pod::UI.warn ' - May result in mixed architectures in rubygems (eg: ffi_c.bundle files may be x86_64 with an arm64 interpreter)'
Pod::UI.warn 'Run "env /usr/bin/arch -arm64 /bin/bash --login" then try again.'
end
end

def self.get_default_flags
flags = {
:fabric_enabled => false,
:hermes_enabled => false,
:flipper_configuration => FlipperConfiguration.disabled
}

if ENV['RCT_NEW_ARCH_ENABLED'] == '1'
flags[:fabric_enabled] = true
flags[:hermes_enabled] = true
end

if ENV['USE_HERMES'] == '1'
flags[:hermes_enabled] = true
end

return flags
end

def self.has_pod(installer, name)
installer.pods_project.pod_group(name) != nil
end

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


# Hermes does not support `i386` architecture
excluded_archs_default = ReactNativePodsUtils.has_pod(installer, 'hermes-engine') ? "i386" : ""

projects.each do |project|
project.build_configurations.each do |config|
config.build_settings["EXCLUDED_ARCHS[sdk=iphonesimulator*]"] = excluded_archs_default
end

project.save()
end
end
end
Loading

0 comments on commit 7a27044

Please sign in to comment.