You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
192 lines
6.6 KiB
192 lines
6.6 KiB
require_relative 'constants'
|
|
require_relative 'package'
|
|
|
|
# Require extensions to CocoaPods' classes
|
|
require_relative 'cocoapods/pod_target'
|
|
require_relative 'cocoapods/sandbox'
|
|
require_relative 'cocoapods/target_definition'
|
|
require_relative 'cocoapods/umbrella_header_generator'
|
|
require_relative 'cocoapods/user_project_integrator'
|
|
|
|
module Expo
|
|
class AutolinkingManager
|
|
require 'colored2'
|
|
include Pod
|
|
|
|
public def initialize(podfile, target_definition, options)
|
|
@podfile = podfile
|
|
@target_definition = target_definition
|
|
@options = options
|
|
@packages = resolve()['modules'].map { |json_package| Package.new(json_package) }
|
|
end
|
|
|
|
public def use_expo_modules!
|
|
if has_packages?
|
|
return
|
|
end
|
|
|
|
global_flags = @options.fetch(:flags, {})
|
|
tests_only = @options.fetch(:testsOnly, false)
|
|
include_tests = @options.fetch(:includeTests, false)
|
|
|
|
project_directory = Pod::Config.instance.project_root
|
|
|
|
UI.section 'Using Expo modules' do
|
|
@packages.each { |package|
|
|
package.pods.each { |pod|
|
|
# The module can already be added to the target, in which case we can just skip it.
|
|
# This allows us to add a pod before `use_expo_modules` to provide custom flags.
|
|
if @target_definition.dependencies.any? { |dependency| dependency.name == pod.pod_name }
|
|
UI.message '— ' << package.name.green << ' is already added to the target'.yellow
|
|
next
|
|
end
|
|
|
|
podspec_dir_path = Pathname.new(pod.podspec_dir).relative_path_from(project_directory).to_path
|
|
|
|
# Ensure that the dependencies of packages with Swift code use modular headers, otherwise
|
|
# `pod install` may fail if there is no `use_modular_headers!` declaration or
|
|
# `:modular_headers => true` is not used for this particular dependency.
|
|
# The latter require adding transitive dependencies to user's Podfile that we'd rather like to avoid.
|
|
if package.has_swift_modules_to_link?
|
|
podspec = get_podspec_for_pod(pod)
|
|
use_modular_headers_for_dependencies(podspec.all_dependencies)
|
|
end
|
|
|
|
pod_options = {
|
|
:path => podspec_dir_path,
|
|
:configuration => package.debugOnly ? ['Debug'] : [] # An empty array means all configurations
|
|
}.merge(global_flags, package.flags)
|
|
|
|
if tests_only || include_tests
|
|
podspec = podspec || get_podspec_for_pod(pod)
|
|
test_specs_names = podspec.test_specs.map { |test_spec|
|
|
test_spec.name.delete_prefix(podspec.name + "/")
|
|
}
|
|
|
|
# Jump to the next package when it doesn't have any test specs (except interfaces, they're required)
|
|
# TODO: Can remove interface check once we move all the interfaces into the core.
|
|
next if tests_only && test_specs_names.empty? && !pod.pod_name.end_with?('Interface')
|
|
|
|
pod_options[:testspecs] = test_specs_names
|
|
end
|
|
|
|
# Install the pod.
|
|
@podfile.pod(pod.pod_name, pod_options)
|
|
|
|
# TODO: Can remove this once we move all the interfaces into the core.
|
|
next if pod.pod_name.end_with?('Interface')
|
|
|
|
UI.message "— #{package.name.green} (#{package.version})"
|
|
}
|
|
}
|
|
end
|
|
self
|
|
end
|
|
|
|
# Spawns `expo-module-autolinking generate-package-list` command.
|
|
public def generate_package_list(target_name, target_path)
|
|
Process.wait IO.popen(generate_package_list_command_args(target_path)).pid
|
|
end
|
|
|
|
# If there is any package to autolink.
|
|
public def has_packages?
|
|
@packages.empty?
|
|
end
|
|
|
|
# Filters only these packages that needs to be included in the generated modules provider.
|
|
public def packages_to_generate
|
|
@packages.select { |package| package.modules.any? }
|
|
end
|
|
|
|
# Returns the provider name which is also a name of the generated file
|
|
public def modules_provider_name
|
|
@options.fetch(:providerName, Constants::MODULES_PROVIDER_FILE_NAME)
|
|
end
|
|
|
|
# For now there is no need to generate the modules provider for testing.
|
|
public def should_generate_modules_provider?
|
|
return !@options.fetch(:testsOnly, false)
|
|
end
|
|
|
|
# privates
|
|
|
|
private def resolve
|
|
json = []
|
|
|
|
IO.popen(resolve_command_args) do |data|
|
|
while line = data.gets
|
|
json << line
|
|
end
|
|
end
|
|
|
|
begin
|
|
JSON.parse(json.join())
|
|
rescue => error
|
|
raise "Couldn't parse JSON coming from `expo-modules-autolinking` command:\n#{error}"
|
|
end
|
|
end
|
|
|
|
private def node_command_args(command_name)
|
|
search_paths = @options.fetch(:searchPaths, @options.fetch(:modules_paths, nil))
|
|
ignore_paths = @options.fetch(:ignorePaths, nil)
|
|
exclude = @options.fetch(:exclude, [])
|
|
|
|
args = [
|
|
'node',
|
|
'--eval',
|
|
'require(\'expo-modules-autolinking\')(process.argv.slice(1))',
|
|
command_name,
|
|
'--platform',
|
|
'ios'
|
|
]
|
|
|
|
if !search_paths.nil? && !search_paths.empty?
|
|
args.concat(search_paths)
|
|
end
|
|
|
|
if !ignore_paths.nil? && !ignore_paths.empty?
|
|
args.concat(['--ignore-paths'], ignore_paths)
|
|
end
|
|
|
|
if !exclude.nil? && !exclude.empty?
|
|
args.concat(['--exclude'], exclude)
|
|
end
|
|
|
|
args
|
|
end
|
|
|
|
private def resolve_command_args
|
|
node_command_args('resolve').concat(['--json'])
|
|
end
|
|
|
|
private def generate_package_list_command_args(target_path)
|
|
node_command_args('generate-package-list').concat([
|
|
'--target',
|
|
target_path
|
|
])
|
|
end
|
|
|
|
private def get_podspec_for_pod(pod)
|
|
podspec_file_path = File.join(pod.podspec_dir, pod.pod_name + ".podspec")
|
|
return Pod::Specification.from_file(podspec_file_path)
|
|
end
|
|
|
|
private def use_modular_headers_for_dependencies(dependencies)
|
|
dependencies.each { |dependency|
|
|
# The dependency name might be a subspec like `ReactCommon/turbomodule/core`,
|
|
# but the modular headers need to be enabled for the entire `ReactCommon` spec anyway,
|
|
# so we're stripping the subspec path from the dependency name.
|
|
root_spec_name = dependency.name.partition('/').first
|
|
|
|
unless @target_definition.build_pod_as_module?(root_spec_name)
|
|
UI.info "[Expo] ".blue << "Enabling modular headers for pod #{root_spec_name.green}"
|
|
|
|
# This is an equivalent to setting `:modular_headers => true` for the specific dependency.
|
|
@target_definition.set_use_modular_headers_for_pod(root_spec_name, true)
|
|
end
|
|
}
|
|
end
|
|
|
|
end # class AutolinkingManager
|
|
end # module Expo
|