Unverified Commit 0cf463ee authored by Dimitris Koutsogiorgas's avatar Dimitris Koutsogiorgas Committed by GitHub

Merge pull request #7610 from dnkoutso/remove_native_target

Remove all PBX state from targets, improve project generation performance
parents 15df291f 41e52c16
...@@ -8,6 +8,10 @@ To install release candidates run `[sudo] gem install cocoapods --pre` ...@@ -8,6 +8,10 @@ To install release candidates run `[sudo] gem install cocoapods --pre`
##### Enhancements ##### Enhancements
* Remove all PBX state from targets, improve project generation performance
[Dimitris Koutsogiorgas](https://github.com/dnkoutso)
[#7610](https://github.com/CocoaPods/CocoaPods/pull/7610)
* Improve performance of the dependency resolver by removing duplicates for dependency nodes. * Improve performance of the dependency resolver by removing duplicates for dependency nodes.
[Jacek Suliga](https://github.com/jmkk) [Jacek Suliga](https://github.com/jmkk)
......
...@@ -173,14 +173,14 @@ module Pod ...@@ -173,14 +173,14 @@ module Pod
private private
def create_generator def create_generator
Xcode::PodsProjectGenerator.new(aggregate_targets, sandbox, pod_targets, analysis_result, installation_options, config) Xcode::PodsProjectGenerator.new(sandbox, aggregate_targets, pod_targets, analysis_result, installation_options, config)
end end
# Generate the 'Pods/Pods.xcodeproj' project. # Generate the 'Pods/Pods.xcodeproj' project.
# #
def generate_pods_project(generator = create_generator) def generate_pods_project(generator = create_generator)
UI.section 'Generating Pods project' do UI.section 'Generating Pods project' do
generator.generate! @target_installation_results = generator.generate!
@pods_project = generator.project @pods_project = generator.project
run_podfile_post_install_hooks run_podfile_post_install_hooks
generator.write generator.write
...@@ -200,6 +200,11 @@ module Pod ...@@ -200,6 +200,11 @@ module Pod
# #
attr_reader :analysis_result attr_reader :analysis_result
# @return [Array<Hash{String, TargetInstallationResult}>] the installation results produced by the pods project
# generator
#
attr_reader :target_installation_results
# @return [Pod::Project] the `Pods/Pods.xcodeproj` project. # @return [Pod::Project] the `Pods/Pods.xcodeproj` project.
# #
attr_reader :pods_project attr_reader :pods_project
......
...@@ -6,10 +6,15 @@ module Pod ...@@ -6,10 +6,15 @@ module Pod
class PodsProjectGenerator class PodsProjectGenerator
require 'cocoapods/installer/xcode/pods_project_generator/pod_target_integrator' require 'cocoapods/installer/xcode/pods_project_generator/pod_target_integrator'
require 'cocoapods/installer/xcode/pods_project_generator/target_installer' require 'cocoapods/installer/xcode/pods_project_generator/target_installer'
require 'cocoapods/installer/xcode/pods_project_generator/target_installation_result'
require 'cocoapods/installer/xcode/pods_project_generator/pod_target_installer' require 'cocoapods/installer/xcode/pods_project_generator/pod_target_installer'
require 'cocoapods/installer/xcode/pods_project_generator/file_references_installer' require 'cocoapods/installer/xcode/pods_project_generator/file_references_installer'
require 'cocoapods/installer/xcode/pods_project_generator/aggregate_target_installer' require 'cocoapods/installer/xcode/pods_project_generator/aggregate_target_installer'
# @return [Sandbox] The sandbox where the Pods should be installed.
#
attr_reader :sandbox
# @return [Pod::Project] the `Pods/Pods.xcodeproj` project. # @return [Pod::Project] the `Pods/Pods.xcodeproj` project.
# #
attr_reader :project attr_reader :project
...@@ -20,10 +25,6 @@ module Pod ...@@ -20,10 +25,6 @@ module Pod
# #
attr_reader :aggregate_targets attr_reader :aggregate_targets
# @return [Sandbox] The sandbox where the Pods should be installed.
#
attr_reader :sandbox
# @return [Array<PodTarget>] The model representations of pod targets. # @return [Array<PodTarget>] The model representations of pod targets.
# #
attr_reader :pod_targets attr_reader :pod_targets
...@@ -43,16 +44,16 @@ module Pod ...@@ -43,16 +44,16 @@ module Pod
# Initialize a new instance # Initialize a new instance
# #
# @param [Array<AggregateTarget>] aggregate_targets @see #aggregate_targets
# @param [Sandbox] sandbox @see #sandbox # @param [Sandbox] sandbox @see #sandbox
# @param [Array<AggregateTarget>] aggregate_targets @see #aggregate_targets
# @param [Array<PodTarget>] pod_targets @see #pod_targets # @param [Array<PodTarget>] pod_targets @see #pod_targets
# @param [Analyzer] analysis_result @see #analysis_result # @param [Analyzer] analysis_result @see #analysis_result
# @param [InstallationOptions] installation_options @see #installation_options # @param [InstallationOptions] installation_options @see #installation_options
# @param [Config] config @see #config # @param [Config] config @see #config
# #
def initialize(aggregate_targets, sandbox, pod_targets, analysis_result, installation_options, config) def initialize(sandbox, aggregate_targets, pod_targets, analysis_result, installation_options, config)
@aggregate_targets = aggregate_targets
@sandbox = sandbox @sandbox = sandbox
@aggregate_targets = aggregate_targets
@pod_targets = pod_targets @pod_targets = pod_targets
@analysis_result = analysis_result @analysis_result = analysis_result
@installation_options = installation_options @installation_options = installation_options
...@@ -62,9 +63,10 @@ module Pod ...@@ -62,9 +63,10 @@ module Pod
def generate! def generate!
prepare prepare
install_file_references install_file_references
install_libraries @target_installation_results = install_libraries
integrate_targets integrate_targets(@target_installation_results.pod_target_installation_results)
set_target_dependencies wire_target_dependencies(@target_installation_results)
@target_installation_results
end end
def write def write
...@@ -76,11 +78,16 @@ module Pod ...@@ -76,11 +78,16 @@ module Pod
UI.message('- Generating deterministic UUIDs') { project.predictabilize_uuids } UI.message('- Generating deterministic UUIDs') { project.predictabilize_uuids }
end end
library_product_types = [:framework, :dynamic_library, :static_library] library_product_types = [:framework, :dynamic_library, :static_library]
pod_target_installation_results = @target_installation_results.pod_target_installation_results.values
project.recreate_user_schemes(false) do |scheme, target| project.recreate_user_schemes(false) do |scheme, target|
next unless target.respond_to?(:symbol_type)
next unless library_product_types.include? target.symbol_type next unless library_product_types.include? target.symbol_type
pod_target = pod_targets.find { |pt| pt.native_target == target } pod_target_installation_results.each do |pod_target_installation_result|
next if pod_target.nil? || pod_target.test_native_targets.empty? next unless pod_target_installation_result.native_target == target
pod_target.test_native_targets.each { |test_native_target| scheme.add_test_target(test_native_target) } pod_target_installation_result.test_native_targets.each do |test_native_target|
scheme.add_test_target(test_native_target)
end
end
end end
project.save project.save
end end
...@@ -104,6 +111,8 @@ module Pod ...@@ -104,6 +111,8 @@ module Pod
private private
InstallationResults = Struct.new(:pod_target_installation_results, :aggregate_target_installation_results)
def create_project def create_project
if object_version = aggregate_targets.map(&:user_project).compact.map { |p| p.object_version.to_i }.min if object_version = aggregate_targets.map(&:user_project).compact.map { |p| p.object_version.to_i }.min
Pod::Project.new(sandbox.project_path, false, object_version) Pod::Project.new(sandbox.project_path, false, object_version)
...@@ -170,41 +179,50 @@ module Pod ...@@ -170,41 +179,50 @@ module Pod
pod_target.umbrella_header_path pod_target.umbrella_header_path
end.compact.group_by(&:dirname) end.compact.group_by(&:dirname)
pod_targets.sort_by(&:name).each do |pod_target| pod_target_installation_results = Hash[pod_targets.sort_by(&:name).map do |pod_target|
target_installer = PodTargetInstaller.new(sandbox, project, pod_target, umbrella_headers_by_dir) target_installer = PodTargetInstaller.new(sandbox, @project, pod_target, umbrella_headers_by_dir)
target_installer.install! [pod_target.name, target_installer.install!]
end end]
aggregate_targets.sort_by(&:name).each do |target| # Hook up system framework dependencies for the pod targets that were just installed.
target_installer = AggregateTargetInstaller.new(sandbox, project, target) pod_target_installation_result_values = pod_target_installation_results.values.compact
target_installer.install! unless pod_target_installation_result_values.empty?
add_system_framework_dependencies(pod_target_installation_result_values)
end end
add_system_framework_dependencies aggregate_target_installation_results = Hash[aggregate_targets.sort_by(&:name).map do |target|
target_installer = AggregateTargetInstaller.new(sandbox, @project, target)
[target.name, target_installer.install!]
end]
InstallationResults.new(pod_target_installation_results, aggregate_target_installation_results)
end end
end end
def integrate_targets def integrate_targets(pod_target_installation_results)
pod_targets_to_integrate = pod_targets.select { |pt| !pt.test_native_targets.empty? || pt.contains_script_phases? } pod_installations_to_integrate = pod_target_installation_results.values.select do |pod_target_installation_result|
unless pod_targets_to_integrate.empty? pod_target = pod_target_installation_result.target
!pod_target_installation_result.test_native_targets.empty? || pod_target.contains_script_phases?
end
unless pod_installations_to_integrate.empty?
UI.message '- Integrating targets' do UI.message '- Integrating targets' do
pod_targets_to_integrate.each do |pod_target| pod_installations_to_integrate.each do |pod_target_installation_result|
PodTargetIntegrator.new(pod_target).integrate! PodTargetIntegrator.new(pod_target_installation_result).integrate!
end end
end end
end end
end end
def add_system_framework_dependencies def add_system_framework_dependencies(pod_target_installation_results)
# @TODO: Add Specs sorted_installation_results = pod_target_installation_results.sort_by do |pod_target_installation_result|
pod_targets.select(&:should_build?).sort_by(&:name).each do |pod_target| pod_target_installation_result.target.name
test_file_accessors, file_accessors = pod_target.file_accessors.partition { |fa| fa.spec.test_specification? } end
file_accessors.each do |file_accessor| sorted_installation_results.each do |target_installation_result|
add_system_frameworks_to_native_target(file_accessor, pod_target.native_target) pod_target = target_installation_result.target
end next unless pod_target.should_build?
test_file_accessors.each do |test_file_accessor| pod_target.file_accessors.each do |file_accessor|
native_target = pod_target.native_target_for_spec(test_file_accessor.spec) native_target = target_installation_result.native_target_for_spec(file_accessor.spec)
add_system_frameworks_to_native_target(test_file_accessor, native_target) add_system_frameworks_to_native_target(native_target, file_accessor)
end end
end end
end end
...@@ -212,67 +230,73 @@ module Pod ...@@ -212,67 +230,73 @@ module Pod
# Adds a target dependency for each pod spec to each aggregate target and # Adds a target dependency for each pod spec to each aggregate target and
# links the pod targets among each other. # links the pod targets among each other.
# #
# @param [Array[Hash{String=>TargetInstallationResult}]] target_installation_results
# the installation results that were produced when all targets were installed. This includes
# pod target installation results and aggregate target installation results.
#
# @return [void] # @return [void]
# #
def set_target_dependencies def wire_target_dependencies(target_installation_results)
frameworks_group = project.frameworks_group frameworks_group = project.frameworks_group
test_only_pod_targets = pod_targets.dup pod_target_installation_results_hash = target_installation_results.pod_target_installation_results
pod_targets_for_deps = Set.new aggregate_target_installation_results_hash = target_installation_results.aggregate_target_installation_results
pod_extension_targets = Set.new
aggregate_targets.each do |aggregate_target| # Wire up aggregate targets
aggregate_target_installation_results_hash.values.each do |aggregate_target_installation_result|
aggregate_target = aggregate_target_installation_result.target
aggregate_native_target = aggregate_target_installation_result.native_target
is_app_extension = !(aggregate_target.user_targets.map(&:symbol_type) & is_app_extension = !(aggregate_target.user_targets.map(&:symbol_type) &
[:app_extension, :watch_extension, :watch2_extension, :tv_extension, :messages_extension]).empty? [:app_extension, :watch_extension, :watch2_extension, :tv_extension, :messages_extension]).empty?
is_app_extension ||= aggregate_target.user_targets.any? { |ut| ut.common_resolved_build_setting('APPLICATION_EXTENSION_API_ONLY') == 'YES' } is_app_extension ||= aggregate_target.user_targets.any? { |ut| ut.common_resolved_build_setting('APPLICATION_EXTENSION_API_ONLY') == 'YES' }
configure_app_extension_api_only_to_native_target(aggregate_native_target) if is_app_extension
# Wire up dependencies that are part of inherit search paths for this aggregate target.
aggregate_target.search_paths_aggregate_targets.each do |search_paths_target| aggregate_target.search_paths_aggregate_targets.each do |search_paths_target|
aggregate_target.native_target.add_dependency(search_paths_target.native_target) aggregate_native_target.add_dependency(aggregate_target_installation_results_hash[search_paths_target.name].native_target)
end end
# Wire up all pod target dependencies to aggregate target.
aggregate_target.pod_targets.each do |pod_target| aggregate_target.pod_targets.each do |pod_target|
test_only_pod_targets.delete(pod_target) pod_target_native_target = pod_target_installation_results_hash[pod_target.name].native_target
configure_app_extension_api_only_for_target(aggregate_target) if is_app_extension aggregate_native_target.add_dependency(pod_target_native_target)
configure_app_extension_api_only_to_native_target(pod_target_native_target) if is_app_extension
unless pod_target.should_build?
add_resource_bundles_to_native_target(pod_target, aggregate_target.native_target)
add_pod_target_test_dependencies(pod_target, frameworks_group)
next
end
aggregate_target.native_target.add_dependency(pod_target.native_target)
configure_app_extension_api_only_for_target(pod_target) if is_app_extension
if is_app_extension
pod_extension_targets << pod_target
end
pod_targets_for_deps << pod_target
unless pod_target.static_framework?
add_pod_target_test_dependencies(pod_target, frameworks_group)
end
end end
end end
# Wire up remaining pod targets used only by tests and are not used by any aggregate target. # Wire up pod targets
test_only_pod_targets.each do |pod_target| pod_target_installation_results_hash.values.each do |pod_target_installation_result|
unless pod_target.should_build? pod_target = pod_target_installation_result.target
add_pod_target_test_dependencies(pod_target, frameworks_group) native_target = pod_target_installation_result.native_target
next # First, wire up all resource bundles.
pod_target_installation_result.resource_bundle_targets.each do |resource_bundle_target|
native_target.add_dependency(resource_bundle_target)
if pod_target.requires_frameworks? && pod_target.should_build?
native_target.add_resources([resource_bundle_target.product_reference])
end
end end
unless pod_target.static_framework? # Wire up all dependencies to this pod target, if any.
pod_targets_for_deps << pod_target dependent_targets = pod_target.dependent_targets
add_pod_target_test_dependencies(pod_target, frameworks_group) dependent_targets.each do |dependent_target|
native_target.add_dependency(pod_target_installation_results_hash[dependent_target.name].native_target)
add_framework_file_reference_to_native_target(native_target, pod_target, dependent_target, frameworks_group)
end
# Wire up test native targets.
unless pod_target_installation_result.test_native_targets.empty?
test_dependent_targets = pod_target.all_dependent_targets
pod_target_installation_result.test_specs_by_native_target.each do |test_native_target, test_specs|
test_dependent_targets.each do |test_dependent_target|
dependency_installation_result = pod_target_installation_results_hash[test_dependent_target.name]
dependency_installation_result.test_resource_bundle_targets.each do |test_resource_bundle_target|
test_native_target.add_dependency(test_resource_bundle_target)
end
test_native_target.add_dependency(dependency_installation_result.native_target)
add_framework_file_reference_to_native_target(test_native_target, pod_target, test_dependent_target, frameworks_group)
test_spec_consumers = test_specs.map { |test_spec| test_spec.consumer(pod_target.platform) }
if test_spec_consumers.any?(&:requires_app_host?)
app_host_target = project.targets.find { |t| t.name == pod_target.app_host_label(test_specs.first.test_type) }
test_native_target.add_dependency(app_host_target)
end
end
end
end end
end
# Actually add the dependent targets
pod_targets_for_deps.each do |pod_target|
is_app_extension = pod_extension_targets.include? pod_target
add_dependent_targets_to_native_target(pod_target.dependent_targets,
pod_target.native_target,
is_app_extension,
pod_target.requires_frameworks? && !pod_target.static_framework?,
frameworks_group)
end end
end end
...@@ -307,55 +331,25 @@ module Pod ...@@ -307,55 +331,25 @@ module Pod
# @! group Private Helpers # @! group Private Helpers
private def add_system_frameworks_to_native_target(native_target, file_accessor)
def add_pod_target_test_dependencies(pod_target, frameworks_group)
test_dependent_targets = pod_target.all_dependent_targets
pod_target.test_specs_by_native_target.each do |test_native_target, test_specs|
test_dependent_targets.reject(&:should_build?).each do |test_dependent_target|
add_resource_bundles_to_native_target(test_dependent_target, test_native_target)
end
add_dependent_targets_to_native_target(test_dependent_targets, test_native_target, false, pod_target.requires_frameworks?, frameworks_group)
test_spec_consumers = test_specs.map { |test_spec| test_spec.consumer(pod_target.platform) }
if test_spec_consumers.any?(&:requires_app_host?)
app_host_target = project.targets.find { |t| t.name == pod_target.app_host_label(test_specs.first.test_type) }
test_native_target.add_dependency(app_host_target)
end
end
end
def add_dependent_targets_to_native_target(dependent_targets, native_target, is_app_extension, requires_frameworks, frameworks_group)
dependent_targets.each do |pod_dependency_target|
next unless pod_dependency_target.should_build?
native_target.add_dependency(pod_dependency_target.native_target)
configure_app_extension_api_only_for_target(pod_dependency_target) if is_app_extension
if requires_frameworks
product_ref = frameworks_group.files.find { |f| f.path == pod_dependency_target.product_name } ||
frameworks_group.new_product_ref_for_target(pod_dependency_target.product_basename, pod_dependency_target.product_type)
native_target.frameworks_build_phase.add_file_reference(product_ref, true)
end
end
end
def add_system_frameworks_to_native_target(file_accessor, native_target)
file_accessor.spec_consumer.frameworks.each do |framework| file_accessor.spec_consumer.frameworks.each do |framework|
native_target.add_system_framework(framework) native_target.add_system_framework(framework)
end end
end end
def add_resource_bundles_to_native_target(dependent_target, native_target) def add_framework_file_reference_to_native_target(native_target, pod_target, dependent_target, frameworks_group)
resource_bundle_targets = dependent_target.resource_bundle_targets + dependent_target.test_resource_bundle_targets if pod_target.requires_frameworks? && !pod_target.static_framework? && dependent_target.should_build?
resource_bundle_targets.each do |resource_bundle_target| product_ref = frameworks_group.files.find { |f| f.path == dependent_target.product_name } ||
native_target.add_dependency(resource_bundle_target) frameworks_group.new_product_ref_for_target(dependent_target.product_basename, dependent_target.product_type)
native_target.frameworks_build_phase.add_file_reference(product_ref, true)
end end
end end
# Sets the APPLICATION_EXTENSION_API_ONLY build setting to YES for all # Sets the APPLICATION_EXTENSION_API_ONLY build setting to YES for all
# configurations of the given target # configurations of the given native target.
# #
def configure_app_extension_api_only_for_target(target) def configure_app_extension_api_only_to_native_target(native_target)
target.native_target.build_configurations.each do |config| native_target.build_configurations.each do |config|
config.build_settings['APPLICATION_EXTENSION_API_ONLY'] = 'YES' config.build_settings['APPLICATION_EXTENSION_API_ONLY'] = 'YES'
end end
end end
......
...@@ -8,21 +8,21 @@ module Pod ...@@ -8,21 +8,21 @@ module Pod
class AggregateTargetInstaller < TargetInstaller class AggregateTargetInstaller < TargetInstaller
# Creates the target in the Pods project and the relative support files. # Creates the target in the Pods project and the relative support files.
# #
# @return [void] # @return [TargetInstallationResult] the result of the installation of this target.
# #
def install! def install!
UI.message "- Installing target `#{target.name}` #{target.platform}" do UI.message "- Installing target `#{target.name}` #{target.platform}" do
add_target native_target = add_target
create_support_files_dir create_support_files_dir
create_support_files_group create_support_files_group
create_xcconfig_file create_xcconfig_file(native_target)
if target.requires_frameworks? if target.requires_frameworks?
create_info_plist_file(target.info_plist_path, native_target, target.version, target.platform) create_info_plist_file(target.info_plist_path, native_target, target.version, target.platform)
create_module_map create_module_map(native_target)
create_umbrella_header create_umbrella_header(native_target)
elsif target.uses_swift? elsif target.uses_swift?
create_module_map create_module_map(native_target)
create_umbrella_header create_umbrella_header(native_target)
end end
# Because embedded targets live in their host target, CocoaPods # Because embedded targets live in their host target, CocoaPods
# copies all of the embedded target's pod_targets to its host # copies all of the embedded target's pod_targets to its host
...@@ -31,10 +31,11 @@ module Pod ...@@ -31,10 +31,11 @@ module Pod
# embedded in embedded targets. # embedded in embedded targets.
# #
create_embed_frameworks_script unless target.requires_host_target? create_embed_frameworks_script unless target.requires_host_target?
create_bridge_support_file create_bridge_support_file(native_target)
create_copy_resources_script create_copy_resources_script
create_acknowledgements create_acknowledgements
create_dummy_source create_dummy_source(native_target)
TargetInstallationResult.new(target, native_target)
end end
end end
...@@ -87,9 +88,12 @@ module Pod ...@@ -87,9 +88,12 @@ module Pod
# Generates the contents of the xcconfig file and saves it to disk. # Generates the contents of the xcconfig file and saves it to disk.
# #
# @param [PBXNativeTarget] native_target
# the native target to link the module map file into.
#
# @return [void] # @return [void]
# #
def create_xcconfig_file def create_xcconfig_file(native_target)
native_target.build_configurations.each do |configuration| native_target.build_configurations.each do |configuration|
path = target.xcconfig_path(configuration.name) path = target.xcconfig_path(configuration.name)
gen = Generator::XCConfig::AggregateXCConfig.new(target, configuration.name) gen = Generator::XCConfig::AggregateXCConfig.new(target, configuration.name)
...@@ -106,9 +110,12 @@ module Pod ...@@ -106,9 +110,12 @@ module Pod
# target because it is needed for environments interpreted at # target because it is needed for environments interpreted at
# runtime. # runtime.
# #
# @param [PBXNativeTarget] native_target
# the native target to add the bridge support file into.
#
# @return [void] # @return [void]
# #
def create_bridge_support_file def create_bridge_support_file(native_target)
if target.podfile.generate_bridge_support? if target.podfile.generate_bridge_support?
path = target.bridge_support_path path = target.bridge_support_path
headers = native_target.headers_build_phase.files.map { |bf| sandbox.root + bf.file_ref.path } headers = native_target.headers_build_phase.files.map { |bf| sandbox.root + bf.file_ref.path }
......
...@@ -25,33 +25,39 @@ module Pod ...@@ -25,33 +25,39 @@ module Pod
# Creates the target in the Pods project and the relative support files. # Creates the target in the Pods project and the relative support files.
# #
# @return [void] # @return [TargetInstallationResult] the result of the installation of this target.
# #
def install! def install!
unless target.should_build?
add_resources_bundle_targets
return
end
UI.message "- Installing target `#{target.name}` #{target.platform}" do UI.message "- Installing target `#{target.name}` #{target.platform}" do
add_target test_file_accessors, file_accessors = target.file_accessors.partition { |fa| fa.spec.test_specification? }
create_support_files_dir
if target.contains_test_specifications? unless target.should_build?
add_test_targets # For targets that should not be built (e.g. pre-built vendored frameworks etc), we add a placeholder
add_test_app_host_targets # PBXAggregateTarget that will be used to wire up dependencies later.
native_target = add_placeholder_target
resource_bundle_targets = add_resources_bundle_targets(file_accessors)
return TargetInstallationResult.new(target, native_target, resource_bundle_targets)
end end
add_resources_bundle_targets
add_files_to_build_phases create_support_files_dir
create_xcconfig_file
create_test_xcconfig_files if target.contains_test_specifications? native_target = add_target
resource_bundle_targets = add_resources_bundle_targets(file_accessors)
test_native_targets = add_test_targets
test_app_host_targets = add_test_app_host_targets(test_native_targets)
test_resource_bundle_targets = add_resources_bundle_targets(test_file_accessors)
add_files_to_build_phases(native_target, test_native_targets)
create_xcconfig_file(native_target, resource_bundle_targets)
create_test_xcconfig_files(test_native_targets, test_resource_bundle_targets)
if target.defines_module? if target.defines_module?
create_module_map do |generator| create_module_map(native_target) do |generator|
generator.headers.concat module_map_additional_headers generator.headers.concat module_map_additional_headers
end end
create_umbrella_header do |generator| create_umbrella_header(native_target) do |generator|
file_accessors = target.file_accessors
file_accessors = file_accessors.reject { |f| f.spec.test_specification? } if target.contains_test_specifications?
generator.imports += if header_mappings_dir generator.imports += if header_mappings_dir
file_accessors.flat_map(&:public_headers).map do |pathname| file_accessors.flat_map(&:public_headers).map do |pathname|
pathname.relative_path_from(header_mappings_dir) pathname.relative_path_from(header_mappings_dir)
...@@ -66,24 +72,24 @@ module Pod ...@@ -66,24 +72,24 @@ module Pod
unless target.static_framework? unless target.static_framework?
create_info_plist_file(target.info_plist_path, native_target, target.version, target.platform) create_info_plist_file(target.info_plist_path, native_target, target.version, target.platform)
end end
create_build_phase_to_symlink_header_folders create_build_phase_to_symlink_header_folders(native_target)
elsif target.uses_swift? elsif target.uses_swift?
add_swift_static_library_compatibility_header_phase add_swift_static_library_compatibility_header_phase(native_target)
end end
unless skip_pch?(target.non_test_specs) unless skip_pch?(target.non_test_specs)
path = target.prefix_header_path path = target.prefix_header_path
file_accessors = target.file_accessors.reject { |f| f.spec.test_specification? }
create_prefix_header(path, file_accessors, target.platform, [native_target]) create_prefix_header(path, file_accessors, target.platform, [native_target])
end end
unless skip_pch?(target.test_specs) unless skip_pch?(target.test_specs)
target.supported_test_types.each do |test_type| target.supported_test_types.each do |test_type|
path = target.prefix_header_path_for_test_type(test_type) path = target.prefix_header_path_for_test_type(test_type)
file_accessors = target.file_accessors.select { |f| f.spec.test_specification? } create_prefix_header(path, test_file_accessors, target.platform, test_native_targets)
create_prefix_header(path, file_accessors, target.platform, target.test_native_targets)
end end
end end
create_dummy_source create_dummy_source(native_target)
TargetInstallationResult.new(target, native_target, resource_bundle_targets, test_native_targets,
test_resource_bundle_targets, test_app_host_targets)
end end
end end
...@@ -185,11 +191,16 @@ module Pod ...@@ -185,11 +191,16 @@ module Pod
# #
# @return [void] # @return [void]
# #
def add_files_to_build_phases def add_files_to_build_phases(native_target, test_native_targets)
target.file_accessors.each do |file_accessor| target.file_accessors.each do |file_accessor|
consumer = file_accessor.spec_consumer consumer = file_accessor.spec_consumer
native_target = target.native_target_for_spec(consumer.spec) native_target = if !consumer.spec.test_specification?
native_target
else
test_native_target_from_spec_consumer(consumer, test_native_targets)
end
headers = file_accessor.headers headers = file_accessor.headers
public_headers = file_accessor.public_headers.map(&:realpath) public_headers = file_accessor.public_headers.map(&:realpath)
private_headers = file_accessor.private_headers.map(&:realpath) private_headers = file_accessor.private_headers.map(&:realpath)
...@@ -225,13 +236,16 @@ module Pod ...@@ -225,13 +236,16 @@ module Pod
# Adds the test app host targets for the library to the Pods project with the # Adds the test app host targets for the library to the Pods project with the
# appropriate build configurations. # appropriate build configurations.
# #
# @return [void] # @param [Array<PBXNativeTarget>] test_native_targets
# the test native targets to use when linking the app host to.
#
# @return [Array<PBXNativeTarget>] the app host targets created.
# #
def add_test_app_host_targets def add_test_app_host_targets(test_native_targets)
target.test_specs.each do |test_spec| target.test_specs.map do |test_spec|
spec_consumer = test_spec.consumer(target.platform) spec_consumer = test_spec.consumer(target.platform)
next unless spec_consumer.requires_app_host? next unless spec_consumer.requires_app_host?
name = target.app_host_label(test_spec.test_type) name = target.app_host_label(spec_consumer.test_type)
platform_name = target.platform.name platform_name = target.platform.name
app_host_target = project.targets.find { |t| t.name == name } app_host_target = project.targets.find { |t| t.name == name }
if app_host_target.nil? if app_host_target.nil?
...@@ -247,38 +261,38 @@ module Pod ...@@ -247,38 +261,38 @@ module Pod
create_info_plist_file(app_host_info_plist_path, app_host_target, '1.0.0', target.platform, :appl) create_info_plist_file(app_host_info_plist_path, app_host_target, '1.0.0', target.platform, :appl)
end end
# Wire all test native targets with the app host. # Wire all test native targets with the app host.
native_test_target = target.native_target_for_spec(test_spec) test_native_target = test_native_target_from_spec_consumer(spec_consumer, test_native_targets)
native_test_target.build_configurations.each do |configuration| test_native_target.build_configurations.each do |configuration|
test_host = "$(BUILT_PRODUCTS_DIR)/#{name}.app/" test_host = "$(BUILT_PRODUCTS_DIR)/#{name}.app/"
test_host << 'Contents/MacOS/' if target.platform == :osx test_host << 'Contents/MacOS/' if target.platform == :osx
test_host << name.to_s test_host << name.to_s
configuration.build_settings['TEST_HOST'] = test_host configuration.build_settings['TEST_HOST'] = test_host
end end
target_attributes = project.root_object.attributes['TargetAttributes'] || {} target_attributes = project.root_object.attributes['TargetAttributes'] || {}
target_attributes[native_test_target.uuid.to_s] = { 'TestTargetID' => app_host_target.uuid.to_s } target_attributes[test_native_target.uuid.to_s] = { 'TestTargetID' => app_host_target.uuid.to_s }
project.root_object.attributes['TargetAttributes'] = target_attributes project.root_object.attributes['TargetAttributes'] = target_attributes
end end.compact
end end
# Adds the test targets for the library to the Pods project with the # Adds the test targets for the library to the Pods project with the
# appropriate build configurations. # appropriate build configurations.
# #
# @return [void] # @return [Array<PBXNativeTarget>] the test native targets created.
# #
def add_test_targets def add_test_targets
target.supported_test_types.each do |test_type| target.supported_test_types.map do |test_type|
product_type = target.product_type_for_test_type(test_type) product_type = target.product_type_for_test_type(test_type)
name = target.test_target_label(test_type) name = target.test_target_label(test_type)
platform_name = target.platform.name platform_name = target.platform.name
language = target.all_dependent_targets.any?(&:uses_swift?) ? :swift : :objc language = target.all_dependent_targets.any?(&:uses_swift?) ? :swift : :objc
native_test_target = project.new_target(product_type, name, platform_name, deployment_target, nil, language) test_native_target = project.new_target(product_type, name, platform_name, deployment_target, nil, language)
native_test_target.product_reference.name = name test_native_target.product_reference.name = name
target.user_build_configurations.each do |bc_name, type| target.user_build_configurations.each do |bc_name, type|
native_test_target.add_build_configuration(bc_name, type) test_native_target.add_build_configuration(bc_name, type)
end end
native_test_target.build_configurations.each do |configuration| test_native_target.build_configurations.each do |configuration|
configuration.build_settings.merge!(custom_build_settings) configuration.build_settings.merge!(custom_build_settings)
# target_installer will automatically add an empty `OTHER_LDFLAGS`. For test # target_installer will automatically add an empty `OTHER_LDFLAGS`. For test
# targets those are set via a test xcconfig file instead. # targets those are set via a test xcconfig file instead.
...@@ -307,9 +321,9 @@ module Pod ...@@ -307,9 +321,9 @@ module Pod
# Generate vanila Info.plist for test target similar to the one xcode gererates for new test target. # Generate vanila Info.plist for test target similar to the one xcode gererates for new test target.
# This creates valid test bundle accessible at the runtime, allowing tests to load bundle resources # This creates valid test bundle accessible at the runtime, allowing tests to load bundle resources
# defined in podspec. # defined in podspec.
create_info_plist_file(target.info_plist_path_for_test_type(test_type), native_test_target, '1.0', target.platform, :bndl) create_info_plist_file(target.info_plist_path_for_test_type(test_type), test_native_target, '1.0', target.platform, :bndl)
target.test_native_targets << native_test_target test_native_target
end end
end end
...@@ -318,14 +332,17 @@ module Pod ...@@ -318,14 +332,17 @@ module Pod
# @note The source files are grouped by Pod and in turn by subspec # @note The source files are grouped by Pod and in turn by subspec
# (recursively) in the resources group. # (recursively) in the resources group.
# #
# @return [void] # @param [Array<Sandbox::FileAccessor>] file_accessors
# the file accessors list to generate resource bundles for.
# #
def add_resources_bundle_targets # @return [Array<PBXNativeTarget] the resource bundle native targets created.
target.file_accessors.each do |file_accessor| #
file_accessor.resource_bundles.each do |bundle_name, paths| def add_resources_bundle_targets(file_accessors)
file_accessors.flat_map do |file_accessor|
file_accessor.resource_bundles.map do |bundle_name, paths|
label = target.resources_bundle_target_label(bundle_name) label = target.resources_bundle_target_label(bundle_name)
bundle_target = project.new_resources_bundle(label, file_accessor.spec_consumer.platform_name) resource_bundle_target = project.new_resources_bundle(label, file_accessor.spec_consumer.platform_name)
bundle_target.product_reference.tap do |bundle_product| resource_bundle_target.product_reference.tap do |bundle_product|
bundle_file_name = "#{bundle_name}.bundle" bundle_file_name = "#{bundle_name}.bundle"
bundle_product.name = bundle_file_name bundle_product.name = bundle_file_name
end end
...@@ -333,42 +350,26 @@ module Pod ...@@ -333,42 +350,26 @@ module Pod
filter_resource_file_references(paths) do |resource_phase_refs, compile_phase_refs| filter_resource_file_references(paths) do |resource_phase_refs, compile_phase_refs|
# Resource bundles are only meant to have resources, so install everything # Resource bundles are only meant to have resources, so install everything
# into the resources phase. See note in filter_resource_file_references. # into the resources phase. See note in filter_resource_file_references.
bundle_target.add_resources(resource_phase_refs + compile_phase_refs) resource_bundle_target.add_resources(resource_phase_refs + compile_phase_refs)
end end
native_target = target.native_target_for_spec(file_accessor.spec_consumer.spec)
target.user_build_configurations.each do |bc_name, type| target.user_build_configurations.each do |bc_name, type|
bundle_target.add_build_configuration(bc_name, type) resource_bundle_target.add_build_configuration(bc_name, type)
end
bundle_target.deployment_target = deployment_target
test_specification = file_accessor.spec.test_specification?
if test_specification
target.test_resource_bundle_targets << bundle_target
else
target.resource_bundle_targets << bundle_target
end
if target.should_build?
native_target.add_dependency(bundle_target)
if target.requires_frameworks?
native_target.add_resources([bundle_target.product_reference])
end
end end
resource_bundle_target.deployment_target = deployment_target
# Create Info.plist file for bundle # Create Info.plist file for bundle
path = target.info_plist_path path = target.info_plist_path
path.dirname.mkdir unless path.dirname.exist? path.dirname.mkdir unless path.dirname.exist?
info_plist_path = path.dirname + "ResourceBundle-#{bundle_name}-#{path.basename}" info_plist_path = path.dirname + "ResourceBundle-#{bundle_name}-#{path.basename}"
create_info_plist_file(info_plist_path, bundle_target, target.version, target.platform, :bndl) create_info_plist_file(info_plist_path, resource_bundle_target, target.version, target.platform, :bndl)
bundle_target.build_configurations.each do |c| resource_bundle_target.build_configurations.each do |c|
c.build_settings['PRODUCT_NAME'] = bundle_name c.build_settings['PRODUCT_NAME'] = bundle_name
# Do not set the CONFIGURATION_BUILD_DIR for resource bundles that are only meant for test targets. # Do not set the CONFIGURATION_BUILD_DIR for resource bundles that are only meant for test targets.
# This is because the test target itself also does not set this configuration build dir and it expects # This is because the test target itself also does not set this configuration build dir and it expects
# all bundles to be copied from the default path. # all bundles to be copied from the default path.
unless test_specification unless file_accessor.spec.test_specification?
c.build_settings['CONFIGURATION_BUILD_DIR'] = target.configuration_build_dir('$(BUILD_DIR)/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)') c.build_settings['CONFIGURATION_BUILD_DIR'] = target.configuration_build_dir('$(BUILD_DIR)/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)')
end end
...@@ -383,15 +384,23 @@ module Pod ...@@ -383,15 +384,23 @@ module Pod
c.build_settings['TARGETED_DEVICE_FAMILY'] = family c.build_settings['TARGETED_DEVICE_FAMILY'] = family
end end
end end
resource_bundle_target
end end
end end
end end
# Generates the contents of the xcconfig file and saves it to disk. # Generates the contents of the xcconfig file and saves it to disk.
# #
# @param [PBXNativeTarget] native_target
# the native target to link the xcconfig file into.
#
# @param [Array<PBXNativeTarget>] resource_bundle_targets
# the additional resource bundle targets to link the xcconfig file into.
#
# @return [void] # @return [void]
# #
def create_xcconfig_file def create_xcconfig_file(native_target, resource_bundle_targets)
path = target.xcconfig_path path = target.xcconfig_path
xcconfig_gen = Generator::XCConfig::PodXCConfig.new(target) xcconfig_gen = Generator::XCConfig::PodXCConfig.new(target)
update_changed_file(xcconfig_gen, path) update_changed_file(xcconfig_gen, path)
...@@ -402,21 +411,27 @@ module Pod ...@@ -402,21 +411,27 @@ module Pod
end end
# also apply the private config to resource bundle targets. # also apply the private config to resource bundle targets.
apply_xcconfig_file_ref_to_resource_bundle_targets(target.resource_bundle_targets, xcconfig_file_ref) apply_xcconfig_file_ref_to_resource_bundle_targets(resource_bundle_targets, xcconfig_file_ref)
end end
# Generates the contents of the xcconfig file used for each test target type and saves it to disk. # Generates the contents of the xcconfig file used for each test target type and saves it to disk.
# #
# @param [Array<PBXNativeTarget>] test_native_targets
# the test native target to link the xcconfig file into.
#
# @param [Array<PBXNativeTarget>] test_resource_bundle_targets
# the additional test resource bundle targets to link the xcconfig file into.
#
# @return [void] # @return [void]
# #
def create_test_xcconfig_files def create_test_xcconfig_files(test_native_targets, test_resource_bundle_targets)
target.supported_test_types.each do |test_type| target.supported_test_types.each do |test_type|
path = target.xcconfig_path(test_type.to_s) path = target.xcconfig_path(test_type.to_s)
xcconfig_gen = Generator::XCConfig::PodXCConfig.new(target, true) xcconfig_gen = Generator::XCConfig::PodXCConfig.new(target, true)
update_changed_file(xcconfig_gen, path) update_changed_file(xcconfig_gen, path)
xcconfig_file_ref = add_file_to_support_group(path) xcconfig_file_ref = add_file_to_support_group(path)
target.test_native_targets.each do |test_target| test_native_targets.each do |test_target|
test_target.build_configurations.each do |test_target_bc| test_target.build_configurations.each do |test_target_bc|
test_target_swift_debug_hack(test_target_bc) test_target_swift_debug_hack(test_target_bc)
test_target_bc.base_configuration_reference = xcconfig_file_ref test_target_bc.base_configuration_reference = xcconfig_file_ref
...@@ -424,7 +439,7 @@ module Pod ...@@ -424,7 +439,7 @@ module Pod
end end
# also apply the private config to resource bundle test targets. # also apply the private config to resource bundle test targets.
apply_xcconfig_file_ref_to_resource_bundle_targets(target.test_resource_bundle_targets, xcconfig_file_ref) apply_xcconfig_file_ref_to_resource_bundle_targets(test_resource_bundle_targets, xcconfig_file_ref)
end end
end end
...@@ -489,9 +504,12 @@ module Pod ...@@ -489,9 +504,12 @@ module Pod
# header_mappings_dir interferes with xcodebuild's expectations # header_mappings_dir interferes with xcodebuild's expectations
# about the existence of private or public headers. # about the existence of private or public headers.
# #
# @param [PBXNativeTarget] native_target
# the native target to add the script phase into.
#
# @return [void] # @return [void]
# #
def create_build_phase_to_symlink_header_folders def create_build_phase_to_symlink_header_folders(native_target)
return unless target.platform.name == :osx && header_mappings_dir return unless target.platform.name == :osx && header_mappings_dir
build_phase = native_target.new_shell_script_build_phase('Create Symlinks to Header Folders') build_phase = native_target.new_shell_script_build_phase('Create Symlinks to Header Folders')
...@@ -515,7 +533,7 @@ module Pod ...@@ -515,7 +533,7 @@ module Pod
# @param [Platform] platform # @param [Platform] platform
# the platform to use for this prefix header. # the platform to use for this prefix header.
# #
# @param [Array<PBXNativetarget>] native_targets # @param [Array<PBXNativeTarget>] native_targets
# the native targets on which the prefix header should be configured for. # the native targets on which the prefix header should be configured for.
# #
# @return [void] # @return [void]
...@@ -600,8 +618,8 @@ module Pod ...@@ -600,8 +618,8 @@ module Pod
end end
end end
def create_module_map def create_module_map(native_target)
return super unless custom_module_map return super(native_target) unless custom_module_map
path = target.module_map_path path = target.module_map_path
UI.message "- Copying module map file to #{UI.path(path)}" do UI.message "- Copying module map file to #{UI.path(path)}" do
...@@ -631,8 +649,8 @@ module Pod ...@@ -631,8 +649,8 @@ module Pod
end end
end end
def create_umbrella_header def create_umbrella_header(native_target)
return super unless custom_module_map return super(native_target) unless custom_module_map
end end
def custom_module_map def custom_module_map
...@@ -688,15 +706,41 @@ module Pod ...@@ -688,15 +706,41 @@ module Pod
project.pod_support_files_group(pod_name, dir) project.pod_support_files_group(pod_name, dir)
end end
def test_native_target_from_spec_consumer(spec_consumer, test_native_targets)
test_native_targets.find do |native_target|
native_target.symbol_type == target.product_type_for_test_type(spec_consumer.test_type)
end
end
# Adds a placeholder native target for the library to the Pods project with the
# appropriate build configurations.
#
# @return [PBXAggregateTarget] the native target that was added.
#
def add_placeholder_target
native_target = project.new_aggregate_target(target.label)
native_target.deployment_target = deployment_target
target.user_build_configurations.each do |bc_name, type|
native_target.add_build_configuration(bc_name, type)
end
native_target.build_configurations.each do |configuration|
configuration.build_settings['ARCHS'] = target.archs
end
native_target
end
# Adds a shell script phase, intended only for static library targets that contain swift, # Adds a shell script phase, intended only for static library targets that contain swift,
# to copy the ObjC compatibility header (the -Swift.h file that the swift compiler generates) # to copy the ObjC compatibility header (the -Swift.h file that the swift compiler generates)
# to the built products directory. Additionally, the script phase copies the module map, appending a `.Swift` # to the built products directory. Additionally, the script phase copies the module map, appending a `.Swift`
# submodule that references the (moved) compatibility header. Since the module map has been moved, the umbrella header # submodule that references the (moved) compatibility header. Since the module map has been moved, the umbrella header
# is _also_ copied, so that it is sitting next to the module map. This is necessary for a successful archive build. # is _also_ copied, so that it is sitting next to the module map. This is necessary for a successful archive build.
# #
# @param [PBXNativeTarget] native_target
# the native target to add the Swift static library script phase into.
#
# @return [Void] # @return [Void]
# #
def add_swift_static_library_compatibility_header_phase def add_swift_static_library_compatibility_header_phase(native_target)
build_phase = native_target.new_shell_script_build_phase('Copy generated compatibility header') build_phase = native_target.new_shell_script_build_phase('Copy generated compatibility header')
relative_module_map_path = target.module_map_path.relative_path_from(target.sandbox.root) relative_module_map_path = target.module_map_path.relative_path_from(target.sandbox.root)
......
...@@ -6,16 +6,16 @@ module Pod ...@@ -6,16 +6,16 @@ module Pod
# the test targets included by each pod target. # the test targets included by each pod target.
# #
class PodTargetIntegrator class PodTargetIntegrator
# @return [PodTarget] the target that should be integrated. # @return [TargetInstallationResult] the installation result of the target that should be integrated.
# #
attr_reader :target attr_reader :target_installation_result
# Init a new PodTargetIntegrator. # Initialize a new instance
# #
# @param [PodTarget] target @see #target # @param [TargetInstallationResult] target_installation_result @see #target_installation_result
# #
def initialize(target) def initialize(target_installation_result)
@target = target @target_installation_result = target_installation_result
end end
# Integrates the pod target. # Integrates the pod target.
...@@ -24,13 +24,13 @@ module Pod ...@@ -24,13 +24,13 @@ module Pod
# #
def integrate! def integrate!
UI.section(integration_message) do UI.section(integration_message) do
target.test_specs_by_native_target.each do |native_target, test_specs| target_installation_result.test_specs_by_native_target.each do |test_native_target, test_specs|
add_embed_frameworks_script_phase(native_target) add_embed_frameworks_script_phase(test_native_target)
add_copy_resources_script_phase(native_target) add_copy_resources_script_phase(test_native_target)
UserProjectIntegrator::TargetIntegrator.create_or_update_user_script_phases(script_phases_for_specs(test_specs), native_target) UserProjectIntegrator::TargetIntegrator.create_or_update_user_script_phases(script_phases_for_specs(test_specs), test_native_target)
end end
specs = target.non_test_specs specs = target.non_test_specs
UserProjectIntegrator::TargetIntegrator.create_or_update_user_script_phases(script_phases_for_specs(specs), target.native_target) UserProjectIntegrator::TargetIntegrator.create_or_update_user_script_phases(script_phases_for_specs(specs), target_installation_result.native_target)
end end
end end
...@@ -89,6 +89,12 @@ module Pod ...@@ -89,6 +89,12 @@ module Pod
"Integrating target `#{target.name}`" "Integrating target `#{target.name}`"
end end
# @return [PodTarget] the target part of the installation result.
#
def target
target_installation_result.target
end
# @param [Array<Specification] specs # @param [Array<Specification] specs
# the specs to return script phrases from. # the specs to return script phrases from.
# #
......
module Pod
class Installer
class Xcode
class PodsProjectGenerator
# A simple container produced after a target installation is completed.
#
class TargetInstallationResult
# @return [Target] target
# The target this installation result is for.
#
attr_reader :target
# @return [PBXNativeTarget] native_target
# The native target that was produced for this target.
#
attr_reader :native_target
# @return [Array<PBXNativeTarget>] resource_bundle_targets
# The resource bundle targets that were produced for this target. Can be empty if the target had
# no resource bundles.
#
attr_reader :resource_bundle_targets
# @return [Array<PBXNativeTarget>] test_native_targets
# The test native targets that were produced for this target. Can be empty if there were no test
# native targets created (e.g. no test specs present).
#
attr_reader :test_native_targets
# @return [Array<PBXNativeTarget>] test_resource_bundle_targets
# The test resource bundle targets that were produced for this target. Can be empty if the target had
# no resource bundles for any tests.
#
attr_reader :test_resource_bundle_targets
# @return [Array<PBXNativeTarget>] test_app_host_targets
# The test app host native targets that were produced for this target. Can be empty.
#
attr_reader :test_app_host_targets
# Initialize a new instance
#
# @param [Target] target @see #target
# @param [PBXNativeTarget] native_target @see #native_target
# @param [Array<PBXNativeTarget>] resource_bundle_targets @see #resource_bundle_targets
# @param [Array<PBXNativeTarget>] test_native_targets @see #test_native_targets
# @param [Array<PBXNativeTarget>] test_resource_bundle_targets @see #test_resource_bundle_targets
# @param [Array<PBXNativeTarget>] test_app_host_targets @see #test_app_host_targets
#
def initialize(target, native_target, resource_bundle_targets = [], test_native_targets = [],
test_resource_bundle_targets = [], test_app_host_targets = [])
@target = target
@native_target = native_target
@resource_bundle_targets = resource_bundle_targets
@test_native_targets = test_native_targets
@test_resource_bundle_targets = test_resource_bundle_targets
@test_app_host_targets = test_app_host_targets
end
# Returns the corresponding native target to use based on the provided specification.
#
# @param [Specification] spec
# The specification to base from in order to find the native target.
#
# @return [PBXNativeTarget] the native target to use or `nil` if none is found.
#
def native_target_for_spec(spec)
return native_target unless spec.test_specification?
test_native_target_from_spec(spec)
end
# @return [Hash{Array => Specification}] a hash where the keys are the test native targets and the value
# an array of all the test specs associated with this native target.
#
def test_specs_by_native_target
target.test_specs.group_by do |test_spec|
test_native_target_from_spec(test_spec)
end
end
private
def test_native_target_from_spec(spec)
test_native_targets.find do |test_native_target|
test_native_target.symbol_type == target.product_type_for_test_type(spec.test_type)
end
end
end
end
end
end
end
...@@ -45,28 +45,28 @@ module Pod ...@@ -45,28 +45,28 @@ module Pod
# #
# @note The `PODS_HEADERS_SEARCH_PATHS` overrides the xcconfig. # @note The `PODS_HEADERS_SEARCH_PATHS` overrides the xcconfig.
# #
# @return [void] # @return [PBXNativeTarget] the native target that was added.
# #
def add_target def add_target
product_type = target.product_type product_type = target.product_type
name = target.label name = target.label
platform = target.platform.name platform = target.platform.name
language = target.uses_swift? ? :swift : :objc language = target.uses_swift? ? :swift : :objc
@native_target = project.new_target(product_type, name, platform, deployment_target, nil, language) native_target = project.new_target(product_type, name, platform, deployment_target, nil, language)
product_name = target.product_name product_name = target.product_name
product = @native_target.product_reference product = native_target.product_reference
product.name = product_name product.name = product_name
target.user_build_configurations.each do |bc_name, type| target.user_build_configurations.each do |bc_name, type|
@native_target.add_build_configuration(bc_name, type) native_target.add_build_configuration(bc_name, type)
end end
@native_target.build_configurations.each do |configuration| native_target.build_configurations.each do |configuration|
configuration.build_settings.merge!(custom_build_settings) configuration.build_settings.merge!(custom_build_settings)
end end
target.native_target = @native_target native_target
end end
# @return [String] The deployment target. # @return [String] The deployment target.
...@@ -175,9 +175,12 @@ module Pod ...@@ -175,9 +175,12 @@ module Pod
# Creates the module map file which ensures that the umbrella header is # Creates the module map file which ensures that the umbrella header is
# recognized with a customized path # recognized with a customized path
# #
# @param [PBXNativeTarget] native_target
# the native target to link the module map file into.
#
# @return [void] # @return [void]
# #
def create_module_map def create_module_map(native_target)
path = target.module_map_path path = target.module_map_path
UI.message "- Generating module map file at #{UI.path(path)}" do UI.message "- Generating module map file at #{UI.path(path)}" do
generator = Generator::ModuleMap.new(target) generator = Generator::ModuleMap.new(target)
...@@ -195,10 +198,15 @@ module Pod ...@@ -195,10 +198,15 @@ module Pod
# Generates a header which ensures that all header files are exported # Generates a header which ensures that all header files are exported
# in the module map # in the module map
# #
# @param [PBXNativeTarget] native_target
# the native target to link the umbrella header file into.
#
# @yield_param [Generator::UmbrellaHeader] # @yield_param [Generator::UmbrellaHeader]
# yielded once to configure the imports # yielded once to configure the imports
# #
def create_umbrella_header # @return [void]
#
def create_umbrella_header(native_target)
path = target.umbrella_header_path path = target.umbrella_header_path
UI.message "- Generating umbrella header at #{UI.path(path)}" do UI.message "- Generating umbrella header at #{UI.path(path)}" do
generator = Generator::UmbrellaHeader.new(target) generator = Generator::UmbrellaHeader.new(target)
...@@ -220,9 +228,12 @@ module Pod ...@@ -220,9 +228,12 @@ module Pod
# Generates a dummy source file for each target so libraries that contain # Generates a dummy source file for each target so libraries that contain
# only categories build. # only categories build.
# #
# @param [PBXNativeTarget] native_target
# the native target to link the dummy source file into.
#
# @return [void] # @return [void]
# #
def create_dummy_source def create_dummy_source(native_target)
path = target.dummy_source_path path = target.dummy_source_path
generator = Generator::DummySource.new(target.label) generator = Generator::DummySource.new(target.label)
update_changed_file(generator, path) update_changed_file(generator, path)
...@@ -230,13 +241,6 @@ module Pod ...@@ -230,13 +241,6 @@ module Pod
native_target.source_build_phase.add_file_reference(file_reference) native_target.source_build_phase.add_file_reference(file_reference)
end end
# @return [PBXNativeTarget] the target generated by the installation
# process.
#
# @note Generated by the {#add_target} step.
#
attr_reader :native_target
private private
#-----------------------------------------------------------------------# #-----------------------------------------------------------------------#
......
...@@ -142,6 +142,8 @@ module Pod ...@@ -142,6 +142,8 @@ module Pod
#-------------------------------------------------------------------------# #-------------------------------------------------------------------------#
# @!group Framework support
# @return [Boolean] whether the generated target needs to be implemented # @return [Boolean] whether the generated target needs to be implemented
# as a framework # as a framework
# #
...@@ -151,13 +153,6 @@ module Pod ...@@ -151,13 +153,6 @@ module Pod
#-------------------------------------------------------------------------# #-------------------------------------------------------------------------#
# @return [PBXNativeTarget] the target generated in the Pods project for
# this library.
#
attr_accessor :native_target
#-------------------------------------------------------------------------#
# @!group Support files # @!group Support files
# @return [Pathname] the folder where to store the support files of this # @return [Pathname] the folder where to store the support files of this
......
...@@ -63,7 +63,8 @@ module Pod ...@@ -63,7 +63,8 @@ module Pod
# @param [Array<String>] user_target_uuids @see #user_target_uuids # @param [Array<String>] user_target_uuids @see #user_target_uuids
# @param [Array<PodTarget>] pod_targets @see #pod_targets # @param [Array<PodTarget>] pod_targets @see #pod_targets
# #
def initialize(sandbox, host_requires_frameworks, user_build_configurations, archs, platform, target_definition, client_root, user_project, user_target_uuids, pod_targets) def initialize(sandbox, host_requires_frameworks, user_build_configurations, archs, platform, target_definition,
client_root, user_project, user_target_uuids, pod_targets)
super(sandbox, host_requires_frameworks, user_build_configurations, archs, platform) super(sandbox, host_requires_frameworks, user_build_configurations, archs, platform)
raise "Can't initialize an AggregateTarget without a TargetDefinition!" if target_definition.nil? raise "Can't initialize an AggregateTarget without a TargetDefinition!" if target_definition.nil?
raise "Can't initialize an AggregateTarget with an abstract TargetDefinition!" if target_definition.abstract? raise "Can't initialize an AggregateTarget with an abstract TargetDefinition!" if target_definition.abstract?
......
...@@ -48,21 +48,6 @@ module Pod ...@@ -48,21 +48,6 @@ module Pod
# #
attr_accessor :test_dependent_targets attr_accessor :test_dependent_targets
# return [Array<PBXNativeTarget>] the test target generated in the Pods project for
# this library or `nil` if there is no test target created.
#
attr_accessor :test_native_targets
# @return [Array<PBXNativeTarget>] the resource bundle targets belonging
# to this target.
#
attr_reader :resource_bundle_targets
# @return [Array<PBXNativeTarget>] the resource bundle test targets belonging
# to this target.
#
attr_reader :test_resource_bundle_targets
# Initialize a new instance # Initialize a new instance
# #
# @param [Sandbox] sandbox @see Target#sandbox # @param [Sandbox] sandbox @see Target#sandbox
...@@ -74,7 +59,8 @@ module Pod ...@@ -74,7 +59,8 @@ module Pod
# @param [Array<Sandbox::FileAccessor>] file_accessors @see #file_accessors # @param [Array<Sandbox::FileAccessor>] file_accessors @see #file_accessors
# @param [String] scope_suffix @see #scope_suffix # @param [String] scope_suffix @see #scope_suffix
# #
def initialize(sandbox, host_requires_frameworks, user_build_configurations, archs, platform, specs, target_definitions, file_accessors = [], scope_suffix = nil) def initialize(sandbox, host_requires_frameworks, user_build_configurations, archs, platform, specs,
target_definitions, file_accessors = [], scope_suffix = nil)
super(sandbox, host_requires_frameworks, user_build_configurations, archs, platform) super(sandbox, host_requires_frameworks, user_build_configurations, archs, platform)
raise "Can't initialize a PodTarget without specs!" if specs.nil? || specs.empty? raise "Can't initialize a PodTarget without specs!" if specs.nil? || specs.empty?
raise "Can't initialize a PodTarget without TargetDefinition!" if target_definitions.nil? || target_definitions.empty? raise "Can't initialize a PodTarget without TargetDefinition!" if target_definitions.nil? || target_definitions.empty?
...@@ -86,9 +72,6 @@ module Pod ...@@ -86,9 +72,6 @@ module Pod
@scope_suffix = scope_suffix @scope_suffix = scope_suffix
@test_specs, @non_test_specs = @specs.partition(&:test_specification?) @test_specs, @non_test_specs = @specs.partition(&:test_specification?)
@build_headers = Sandbox::HeadersStore.new(sandbox, 'Private', :private) @build_headers = Sandbox::HeadersStore.new(sandbox, 'Private', :private)
@resource_bundle_targets = []
@test_resource_bundle_targets = []
@test_native_targets = []
@dependent_targets = [] @dependent_targets = []
@test_dependent_targets = [] @test_dependent_targets = []
@build_config_cache = {} @build_config_cache = {}
...@@ -108,7 +91,6 @@ module Pod ...@@ -108,7 +91,6 @@ module Pod
cache[cache_key] cache[cache_key]
else else
target = PodTarget.new(sandbox, host_requires_frameworks, user_build_configurations, archs, platform, specs, [target_definition], file_accessors, target_definition.label) target = PodTarget.new(sandbox, host_requires_frameworks, user_build_configurations, archs, platform, specs, [target_definition], file_accessors, target_definition.label)
target.native_target = native_target
target.dependent_targets = dependent_targets.flat_map { |pt| pt.scoped(cache) }.select { |pt| pt.target_definitions == [target_definition] } target.dependent_targets = dependent_targets.flat_map { |pt| pt.scoped(cache) }.select { |pt| pt.target_definitions == [target_definition] }
target.test_dependent_targets = test_dependent_targets.flat_map { |pt| pt.scoped(cache) }.select { |pt| pt.target_definitions == [target_definition] } target.test_dependent_targets = test_dependent_targets.flat_map { |pt| pt.scoped(cache) }.select { |pt| pt.target_definitions == [target_definition] }
cache[cache_key] = target cache[cache_key] = target
...@@ -218,13 +200,6 @@ module Pod ...@@ -218,13 +200,6 @@ module Pod
!script_phases.empty? !script_phases.empty?
end end
# @return [Hash{Array => Specification}] a hash where the keys are the test native targets and the value
# an array of all the test specs associated with this native target.
#
def test_specs_by_native_target
test_specs.group_by { |test_spec| native_target_for_spec(test_spec) }
end
# @return [Boolean] Whether the target has any tests specifications. # @return [Boolean] Whether the target has any tests specifications.
# #
def contains_test_specifications? def contains_test_specifications?
...@@ -304,22 +279,6 @@ module Pod ...@@ -304,22 +279,6 @@ module Pod
end end
end end
# Returns the corresponding native target to use based on the provided specification.
# This is used to figure out whether to add a source file into the library native target or any of the
# test native targets.
#
# @param [Specification] spec
# The specification to base from in order to find the native target.
#
# @return [PBXNativeTarget] the native target to use or `nil` if none is found.
#
def native_target_for_spec(spec)
return native_target unless spec.test_specification?
test_native_targets.find do |native_target|
native_target.symbol_type == product_type_for_test_type(spec.test_type)
end
end
# Returns the corresponding native product type to use given the test type. # Returns the corresponding native product type to use given the test type.
# This is primarily used when creating the native targets in order to produce the correct test bundle target # This is primarily used when creating the native targets in order to produce the correct test bundle target
# based on the type of tests included. # based on the type of tests included.
......
...@@ -501,43 +501,33 @@ module Pod ...@@ -501,43 +501,33 @@ module Pod
perform_post_install_actions).each { |m| @installer.send(m) } perform_post_install_actions).each { |m| @installer.send(m) }
deployment_target = spec.subspec_by_name(subspec_name).deployment_target(consumer.platform_name) deployment_target = spec.subspec_by_name(subspec_name).deployment_target(consumer.platform_name)
configure_pod_targets(@installer.aggregate_targets, deployment_target) configure_pod_targets(@installer.aggregate_targets, @installer.target_installation_results, deployment_target)
@installer.pods_project.save @installer.pods_project.save
end end
def configure_pod_targets(targets, deployment_target) def configure_pod_targets(targets, target_installation_results, deployment_target)
test_only_pod_targets = @installer.pod_targets - targets.flat_map(&:pod_targets) target_installation_results.first.values.each do |pod_target_installation_result|
targets.each do |target| pod_target = pod_target_installation_result.target
target.pod_targets.each do |pod_target| native_target = pod_target_installation_result.native_target
update_pod_target_build_settings(pod_target) native_target.build_configuration_list.build_configurations.each do |build_configuration|
if pod_target.uses_swift? (build_configuration.build_settings['OTHER_CFLAGS'] ||= '$(inherited)') << ' -Wincomplete-umbrella'
pod_target.test_native_targets.each do |test_native_target| build_configuration.build_settings['SWIFT_VERSION'] = (pod_target.swift_version || swift_version) if pod_target.uses_swift?
test_native_target.build_configuration_list.build_configurations.each do |build_configuration| end
build_configuration.build_settings['SWIFT_VERSION'] = swift_version if pod_target.uses_swift?
end pod_target_installation_result.test_native_targets.each do |test_native_target|
test_native_target.build_configuration_list.build_configurations.each do |build_configuration|
build_configuration.build_settings['SWIFT_VERSION'] = swift_version
end end
end end
end end
end
targets.each do |target|
if target.pod_targets.any?(&:uses_swift?) && consumer.platform_name == :ios && if target.pod_targets.any?(&:uses_swift?) && consumer.platform_name == :ios &&
(deployment_target.nil? || Version.new(deployment_target).major < 8) (deployment_target.nil? || Version.new(deployment_target).major < 8)
uses_xctest = target.spec_consumers.any? { |c| (c.frameworks + c.weak_frameworks).include? 'XCTest' } uses_xctest = target.spec_consumers.any? { |c| (c.frameworks + c.weak_frameworks).include? 'XCTest' }
error('swift', 'Swift support uses dynamic frameworks and is therefore only supported on iOS > 8.') unless uses_xctest error('swift', 'Swift support uses dynamic frameworks and is therefore only supported on iOS > 8.') unless uses_xctest
end end
end end
# Wire up Swift version to pod targets used only by tests.
test_only_pod_targets.each do |test_pod_target|
update_pod_target_build_settings(test_pod_target)
end
end
def update_pod_target_build_settings(pod_target)
native_target = pod_target.native_target
unless native_target.nil?
native_target.build_configuration_list.build_configurations.each do |build_configuration|
(build_configuration.build_settings['OTHER_CFLAGS'] ||= '$(inherited)') << ' -Wincomplete-umbrella'
build_configuration.build_settings['SWIFT_VERSION'] = (pod_target.swift_version || swift_version) if pod_target.uses_swift?
end
end
end end
def validate_vendored_dynamic_frameworks def validate_vendored_dynamic_frameworks
...@@ -597,7 +587,7 @@ module Pod ...@@ -597,7 +587,7 @@ module Pod
UI.message "\nTesting with `xcodebuild`.\n".yellow do UI.message "\nTesting with `xcodebuild`.\n".yellow do
pod_target = @installer.pod_targets.find { |pt| pt.pod_name == spec.root.name } pod_target = @installer.pod_targets.find { |pt| pt.pod_name == spec.root.name }
consumer.spec.test_specs.each do |test_spec| consumer.spec.test_specs.each do |test_spec|
scheme = pod_target.native_target_for_spec(test_spec) scheme = @installer.target_installation_results.first[pod_target.name].native_target_for_spec(test_spec)
output = xcodebuild('test', scheme, 'Debug') output = xcodebuild('test', scheme, 'Debug')
parsed_output = parse_xcodebuild_output(output) parsed_output = parse_xcodebuild_output(output)
translate_output_to_linter_messages(parsed_output) translate_output_to_linter_messages(parsed_output)
......
Subproject commit 2ede36e05798057b7d21e6bd953497c52fad71bb Subproject commit 55202559c1b06409113d2a19b15fb065c3742115
...@@ -146,9 +146,10 @@ def fixture_pod_target_with_specs(specs, host_requires_frameworks = false, user_ ...@@ -146,9 +146,10 @@ def fixture_pod_target_with_specs(specs, host_requires_frameworks = false, user_
target_definitions, file_accessors, scope_suffix) target_definitions, file_accessors, scope_suffix)
end end
def fixture_aggregate_target(pod_targets = [], platform = Pod::Platform.new(:ios, '6.0'), target_definition = nil) def fixture_aggregate_target(pod_targets = [], host_requires_frameworks = false, user_build_configurations = {},
archs = [], platform = Pod::Platform.new(:ios, '6.0'), target_definition = nil)
target_definition ||= pod_targets.flat_map(&:target_definitions).first || fixture_target_definition target_definition ||= pod_targets.flat_map(&:target_definitions).first || fixture_target_definition
Pod::AggregateTarget.new(config.sandbox, false, {}, [], platform, Pod::AggregateTarget.new(config.sandbox, host_requires_frameworks, user_build_configurations, archs, platform,
target_definition, config.sandbox.root.dirname, nil, nil, pod_targets) target_definition, config.sandbox.root.dirname, nil, nil, pod_targets)
end end
......
...@@ -18,7 +18,7 @@ module Pod ...@@ -18,7 +18,7 @@ module Pod
@specs.first.user_target_xcconfig = { 'OTHER_LDFLAGS' => '-no_compact_unwind' } unless @specs.empty? @specs.first.user_target_xcconfig = { 'OTHER_LDFLAGS' => '-no_compact_unwind' } unless @specs.empty?
@specs.first.pod_target_xcconfig = { 'CLANG_CXX_LANGUAGE_STANDARD' => 'c++11' } unless @specs.empty? @specs.first.pod_target_xcconfig = { 'CLANG_CXX_LANGUAGE_STANDARD' => 'c++11' } unless @specs.empty?
@pod_targets = @specs.map { |spec| pod_target(spec, @target_definition) } @pod_targets = @specs.map { |spec| pod_target(spec, @target_definition) }
@target = fixture_aggregate_target(@pod_targets, Platform.new(:ios, '6.0'), @target_definition) @target = fixture_aggregate_target(@pod_targets, false, {}, [], Platform.new(:ios, '6.0'), @target_definition)
unless @specs.empty? unless @specs.empty?
@target.target_definition.whitelist_pod_for_configuration(@specs.first.name, 'Release') @target.target_definition.whitelist_pod_for_configuration(@specs.first.name, 'Release')
end end
......
...@@ -619,7 +619,7 @@ module Pod ...@@ -619,7 +619,7 @@ module Pod
describe 'for proper other ld flags' do describe 'for proper other ld flags' do
def stub_aggregate_target(pod_targets, target_definition = nil, search_paths_aggregate_targets: []) def stub_aggregate_target(pod_targets, target_definition = nil, search_paths_aggregate_targets: [])
target_definition.stubs(:abstract? => false) unless target_definition.respond_to?(:abstract?) target_definition.stubs(:abstract? => false) unless target_definition.respond_to?(:abstract?)
fixture_aggregate_target(pod_targets, Platform.ios, target_definition).tap do |aggregate_target| fixture_aggregate_target(pod_targets, false, {}, [], Platform.ios, target_definition).tap do |aggregate_target|
aggregate_target.search_paths_aggregate_targets.concat(search_paths_aggregate_targets).freeze aggregate_target.search_paths_aggregate_targets.concat(search_paths_aggregate_targets).freeze
end end
end end
......
...@@ -88,29 +88,25 @@ module Pod ...@@ -88,29 +88,25 @@ module Pod
end end
it 'does not enable the GCC_WARN_INHIBIT_ALL_WARNINGS flag by default' do it 'does not enable the GCC_WARN_INHIBIT_ALL_WARNINGS flag by default' do
@installer.install! @installer.install!.native_target.build_configurations.each do |config|
@installer.target.native_target.build_configurations.each do |config|
config.build_settings['GCC_WARN_INHIBIT_ALL_WARNINGS'].should.be.nil config.build_settings['GCC_WARN_INHIBIT_ALL_WARNINGS'].should.be.nil
end end
end end
it 'will be built as static library' do it 'will be built as static library' do
@installer.install! @installer.install!.native_target.build_configurations.each do |config|
@installer.target.native_target.build_configurations.each do |config|
config.build_settings['MACH_O_TYPE'].should == 'staticlib' config.build_settings['MACH_O_TYPE'].should == 'staticlib'
end end
end end
it 'will be skipped when installing' do it 'will be skipped when installing' do
@installer.install! @installer.install!.native_target.build_configurations.each do |config|
@installer.target.native_target.build_configurations.each do |config|
config.build_settings['SKIP_INSTALL'].should == 'YES' config.build_settings['SKIP_INSTALL'].should == 'YES'
end end
end end
it 'has a PRODUCT_BUNDLE_IDENTIFIER set' do it 'has a PRODUCT_BUNDLE_IDENTIFIER set' do
@installer.install! @installer.install!.native_target.build_configurations.each do |config|
@installer.target.native_target.build_configurations.each do |config|
config.build_settings['PRODUCT_BUNDLE_IDENTIFIER'].should == 'org.cocoapods.${PRODUCT_NAME:rfc1034identifier}' config.build_settings['PRODUCT_BUNDLE_IDENTIFIER'].should == 'org.cocoapods.${PRODUCT_NAME:rfc1034identifier}'
end end
end end
...@@ -219,8 +215,7 @@ module Pod ...@@ -219,8 +215,7 @@ module Pod
end end
it 'creates a dummy source to ensure the creation of a single base library' do it 'creates a dummy source to ensure the creation of a single base library' do
@installer.install! build_files = @installer.install!.native_target.source_build_phase.files
build_files = @installer.target.native_target.source_build_phase.files
build_file = build_files.find { |bf| bf.file_ref.path.include?('Pods-SampleProject-dummy.m') } build_file = build_files.find { |bf| bf.file_ref.path.include?('Pods-SampleProject-dummy.m') }
build_file.should.be.not.nil build_file.should.be.not.nil
build_file.file_ref.path.should == 'Pods-SampleProject-dummy.m' build_file.file_ref.path.should == 'Pods-SampleProject-dummy.m'
...@@ -251,9 +246,7 @@ module Pod ...@@ -251,9 +246,7 @@ module Pod
it 'installs umbrella headers for swift static libraries' do it 'installs umbrella headers for swift static libraries' do
@pod_target.stubs(:uses_swift? => true) @pod_target.stubs(:uses_swift? => true)
@target.stubs(:uses_swift? => true) @target.stubs(:uses_swift? => true)
@installer.install! build_files = @installer.install!.native_target.headers_build_phase.files
build_files = @installer.target.native_target.headers_build_phase.files
build_file = build_files.find { |bf| bf.file_ref.path.include?('Pods-SampleProject-umbrella.h') } build_file = build_files.find { |bf| bf.file_ref.path.include?('Pods-SampleProject-umbrella.h') }
build_file.should.not.be.nil build_file.should.not.be.nil
build_file.settings.should == { 'ATTRIBUTES' => ['Project'] } build_file.settings.should == { 'ATTRIBUTES' => ['Project'] }
...@@ -262,9 +255,7 @@ module Pod ...@@ -262,9 +255,7 @@ module Pod
it 'installs umbrella headers for frameworks' do it 'installs umbrella headers for frameworks' do
@pod_target.stubs(:requires_frameworks? => true) @pod_target.stubs(:requires_frameworks? => true)
@target.stubs(:requires_frameworks? => true) @target.stubs(:requires_frameworks? => true)
@installer.install! build_files = @installer.install!.native_target.headers_build_phase.files
build_files = @installer.target.native_target.headers_build_phase.files
build_file = build_files.find { |bf| bf.file_ref.path.include?('Pods-SampleProject-umbrella.h') } build_file = build_files.find { |bf| bf.file_ref.path.include?('Pods-SampleProject-umbrella.h') }
build_file.should.not.be.nil build_file.should.not.be.nil
build_file.settings.should == { 'ATTRIBUTES' => ['Public'] } build_file.settings.should == { 'ATTRIBUTES' => ['Public'] }
......
...@@ -76,8 +76,7 @@ module Pod ...@@ -76,8 +76,7 @@ module Pod
end end
it 'does not enable the GCC_WARN_INHIBIT_ALL_WARNINGS flag by default' do it 'does not enable the GCC_WARN_INHIBIT_ALL_WARNINGS flag by default' do
@installer.install! @installer.install!.native_target.build_configurations.each do |config|
@installer.target.native_target.build_configurations.each do |config|
config.build_settings['GCC_WARN_INHIBIT_ALL_WARNINGS'].should.be.nil config.build_settings['GCC_WARN_INHIBIT_ALL_WARNINGS'].should.be.nil
end end
end end
...@@ -182,13 +181,13 @@ module Pod ...@@ -182,13 +181,13 @@ module Pod
end end
it 'adds the native test target to the project for iOS targets with code signing' do it 'adds the native test target to the project for iOS targets with code signing' do
@installer.install! installation_result = @installer.install!
@project.targets.count.should == 2 @project.targets.count.should == 2
@project.targets.first.name.should == 'CoconutLib' @project.targets.first.name.should == 'CoconutLib'
native_test_target = @project.targets[1] test_native_target = @project.targets[1]
native_test_target.name.should == 'CoconutLib-Unit-Tests' test_native_target.name.should == 'CoconutLib-Unit-Tests'
native_test_target.product_reference.name.should == 'CoconutLib-Unit-Tests' test_native_target.product_reference.name.should == 'CoconutLib-Unit-Tests'
native_test_target.build_configurations.each do |bc| test_native_target.build_configurations.each do |bc|
bc.build_settings['PRODUCT_NAME'].should == 'CoconutLib-Unit-Tests' bc.build_settings['PRODUCT_NAME'].should == 'CoconutLib-Unit-Tests'
bc.build_settings['PRODUCT_MODULE_NAME'].should.be.nil bc.build_settings['PRODUCT_MODULE_NAME'].should.be.nil
bc.build_settings['CODE_SIGNING_REQUIRED'].should == 'YES' bc.build_settings['CODE_SIGNING_REQUIRED'].should == 'YES'
...@@ -196,18 +195,18 @@ module Pod ...@@ -196,18 +195,18 @@ module Pod
bc.build_settings['CODE_SIGN_IDENTITY'].should == 'iPhone Developer' bc.build_settings['CODE_SIGN_IDENTITY'].should == 'iPhone Developer'
bc.build_settings['INFOPLIST_FILE'].should == 'Target Support Files/CoconutLib/CoconutLib-Unit-Tests-Info.plist' bc.build_settings['INFOPLIST_FILE'].should == 'Target Support Files/CoconutLib/CoconutLib-Unit-Tests-Info.plist'
end end
native_test_target.symbol_type.should == :unit_test_bundle test_native_target.symbol_type.should == :unit_test_bundle
@coconut_pod_target.test_native_targets.count.should == 1 installation_result.test_native_targets.count.should == 1
end end
it 'adds the native test target to the project for OSX targets without code signing' do it 'adds the native test target to the project for OSX targets without code signing' do
@installer2.install! installation_result = @installer2.install!
@project.targets.count.should == 2 @project.targets.count.should == 2
@project.targets.first.name.should == 'CoconutLib' @project.targets.first.name.should == 'CoconutLib'
native_test_target = @project.targets[1] test_native_target = @project.targets[1]
native_test_target.name.should == 'CoconutLib-Unit-Tests' test_native_target.name.should == 'CoconutLib-Unit-Tests'
native_test_target.product_reference.name.should == 'CoconutLib-Unit-Tests' test_native_target.product_reference.name.should == 'CoconutLib-Unit-Tests'
native_test_target.build_configurations.each do |bc| test_native_target.build_configurations.each do |bc|
bc.build_settings['PRODUCT_NAME'].should == 'CoconutLib-Unit-Tests' bc.build_settings['PRODUCT_NAME'].should == 'CoconutLib-Unit-Tests'
bc.build_settings['PRODUCT_MODULE_NAME'].should.be.nil bc.build_settings['PRODUCT_MODULE_NAME'].should.be.nil
bc.build_settings['CODE_SIGNING_REQUIRED'].should.be.nil bc.build_settings['CODE_SIGNING_REQUIRED'].should.be.nil
...@@ -215,20 +214,20 @@ module Pod ...@@ -215,20 +214,20 @@ module Pod
bc.build_settings['CODE_SIGN_IDENTITY'].should == '' bc.build_settings['CODE_SIGN_IDENTITY'].should == ''
bc.build_settings['INFOPLIST_FILE'].should == 'Target Support Files/CoconutLib/CoconutLib-Unit-Tests-Info.plist' bc.build_settings['INFOPLIST_FILE'].should == 'Target Support Files/CoconutLib/CoconutLib-Unit-Tests-Info.plist'
end end
native_test_target.symbol_type.should == :unit_test_bundle test_native_target.symbol_type.should == :unit_test_bundle
@coconut_pod_target2.test_native_targets.count.should == 1 installation_result.test_native_targets.count.should == 1
end end
it 'adds swiftSwiftOnoneSupport ld flag to the debug configuration' do it 'adds swiftSwiftOnoneSupport ld flag to the debug configuration' do
@coconut_pod_target.stubs(:uses_swift?).returns(true) @coconut_pod_target.stubs(:uses_swift?).returns(true)
@installer.install! @installer.install!
native_test_target = @project.targets[1] test_native_target = @project.targets[1]
debug_configuration = native_test_target.build_configurations.find(&:debug?) debug_configuration = test_native_target.build_configurations.find(&:debug?)
debug_configuration.build_settings['OTHER_LDFLAGS'].sort.should == [ debug_configuration.build_settings['OTHER_LDFLAGS'].sort.should == [
'$(inherited)', '$(inherited)',
'-lswiftSwiftOnoneSupport', '-lswiftSwiftOnoneSupport',
] ]
release_configuration = native_test_target.build_configurations.find { |bc| bc.type == :release } release_configuration = test_native_target.build_configurations.find { |bc| bc.type == :release }
release_configuration.build_settings['OTHER_LDFLAGS'].should.be.nil release_configuration.build_settings['OTHER_LDFLAGS'].should.be.nil
end end
...@@ -241,9 +240,9 @@ module Pod ...@@ -241,9 +240,9 @@ module Pod
'Coconut.m', 'Coconut.m',
'CoconutLib-dummy.m', 'CoconutLib-dummy.m',
] ]
native_test_target = @project.targets[1] test_native_target = @project.targets[1]
native_test_target.source_build_phase.files.count.should == 1 test_native_target.source_build_phase.files.count.should == 1
native_test_target.source_build_phase.files.map(&:display_name).sort.should == [ test_native_target.source_build_phase.files.map(&:display_name).sort.should == [
'CoconutTests.m', 'CoconutTests.m',
] ]
end end
...@@ -264,9 +263,9 @@ module Pod ...@@ -264,9 +263,9 @@ module Pod
it 'adds test xcconfig file reference for test resource bundle targets' do it 'adds test xcconfig file reference for test resource bundle targets' do
@coconut_spec.test_specs.first.resource_bundle = { 'CoconutLibTestResources' => ['Model.xcdatamodeld'] } @coconut_spec.test_specs.first.resource_bundle = { 'CoconutLibTestResources' => ['Model.xcdatamodeld'] }
@installer.install! installation_result = @installer.install!
@coconut_pod_target.resource_bundle_targets.count.should == 0 installation_result.resource_bundle_targets.count.should == 0
@coconut_pod_target.test_resource_bundle_targets.count.should == 1 installation_result.test_resource_bundle_targets.count.should == 1
test_resource_bundle_target = @project.targets.find { |t| t.name == 'CoconutLib-CoconutLibTestResources' } test_resource_bundle_target = @project.targets.find { |t| t.name == 'CoconutLib-CoconutLibTestResources' }
test_resource_bundle_target.build_configurations.each do |bc| test_resource_bundle_target.build_configurations.each do |bc|
bc.base_configuration_reference.real_path.basename.to_s.should == 'CoconutLib.unit.xcconfig' bc.base_configuration_reference.real_path.basename.to_s.should == 'CoconutLib.unit.xcconfig'
...@@ -313,12 +312,12 @@ module Pod ...@@ -313,12 +312,12 @@ module Pod
app_host_target = @project.targets[2] app_host_target = @project.targets[2]
app_host_target.name.should == 'AppHost-iOS-Unit-Tests' app_host_target.name.should == 'AppHost-iOS-Unit-Tests'
app_host_target.symbol_type.should == :application app_host_target.symbol_type.should == :application
native_test_target = @project.targets[1] test_native_target = @project.targets[1]
native_test_target.build_configurations.each do |bc| test_native_target.build_configurations.each do |bc|
bc.build_settings['TEST_HOST'].should == '$(BUILT_PRODUCTS_DIR)/AppHost-iOS-Unit-Tests.app/AppHost-iOS-Unit-Tests' bc.build_settings['TEST_HOST'].should == '$(BUILT_PRODUCTS_DIR)/AppHost-iOS-Unit-Tests.app/AppHost-iOS-Unit-Tests'
end end
@project.root_object.attributes['TargetAttributes'].should == { @project.root_object.attributes['TargetAttributes'].should == {
native_test_target.uuid.to_s => { test_native_target.uuid.to_s => {
'TestTargetID' => app_host_target.uuid.to_s, 'TestTargetID' => app_host_target.uuid.to_s,
}, },
} }
...@@ -334,12 +333,12 @@ module Pod ...@@ -334,12 +333,12 @@ module Pod
bc.build_settings['PRODUCT_NAME'].should == 'AppHost-macOS-Unit-Tests' bc.build_settings['PRODUCT_NAME'].should == 'AppHost-macOS-Unit-Tests'
bc.build_settings['PRODUCT_BUNDLE_IDENTIFIER'].should == 'org.cocoapods.${PRODUCT_NAME:rfc1034identifier}' bc.build_settings['PRODUCT_BUNDLE_IDENTIFIER'].should == 'org.cocoapods.${PRODUCT_NAME:rfc1034identifier}'
end end
native_test_target = @project.targets[1] test_native_target = @project.targets[1]
native_test_target.build_configurations.each do |bc| test_native_target.build_configurations.each do |bc|
bc.build_settings['TEST_HOST'].should == '$(BUILT_PRODUCTS_DIR)/AppHost-macOS-Unit-Tests.app/Contents/MacOS/AppHost-macOS-Unit-Tests' bc.build_settings['TEST_HOST'].should == '$(BUILT_PRODUCTS_DIR)/AppHost-macOS-Unit-Tests.app/Contents/MacOS/AppHost-macOS-Unit-Tests'
end end
@project.root_object.attributes['TargetAttributes'].should == { @project.root_object.attributes['TargetAttributes'].should == {
native_test_target.uuid.to_s => { test_native_target.uuid.to_s => {
'TestTargetID' => app_host_target.uuid.to_s, 'TestTargetID' => app_host_target.uuid.to_s,
}, },
} }
...@@ -386,8 +385,7 @@ module Pod ...@@ -386,8 +385,7 @@ module Pod
#--------------------------------------# #--------------------------------------#
it 'adds the source files of each pod to the target of the Pod library' do it 'adds the source files of each pod to the target of the Pod library' do
@installer.install! names = @installer.install!.native_target.source_build_phase.files.map { |bf| bf.file_ref.display_name }
names = @installer.target.native_target.source_build_phase.files.map { |bf| bf.file_ref.display_name }
names.should.include('Banana.m') names.should.include('Banana.m')
end end
...@@ -717,9 +715,8 @@ module Pod ...@@ -717,9 +715,8 @@ module Pod
end end
it 'creates a dummy source to ensure the compilation of libraries with only categories' do it 'creates a dummy source to ensure the compilation of libraries with only categories' do
@installer.install!
dummy_source_basename = @pod_target.dummy_source_path.basename.to_s dummy_source_basename = @pod_target.dummy_source_path.basename.to_s
build_files = @installer.target.native_target.source_build_phase.files build_files = @installer.install!.native_target.source_build_phase.files
build_file = build_files.find { |bf| bf.file_ref.display_name == dummy_source_basename } build_file = build_files.find { |bf| bf.file_ref.display_name == dummy_source_basename }
build_file.should.be.not.nil build_file.should.be.not.nil
build_file.file_ref.path.should == dummy_source_basename build_file.file_ref.path.should == dummy_source_basename
...@@ -728,10 +725,11 @@ module Pod ...@@ -728,10 +725,11 @@ module Pod
#--------------------------------------------------------------------------------# #--------------------------------------------------------------------------------#
it 'does not create a target if the specification does not define source files' do it 'creates an aggregate placeholder native target if the target should not be built' do
@pod_target.file_accessors.first.stubs(:source_files).returns([]) @pod_target.stubs(:should_build?).returns(false)
@installer.install! @installer.install!
@project.targets.should == [] @project.targets.map(&:name).should == ['BananaLib']
@project.targets.first.class.should == Xcodeproj::Project::PBXAggregateTarget
end end
#--------------------------------------------------------------------------------# #--------------------------------------------------------------------------------#
...@@ -837,9 +835,7 @@ module Pod ...@@ -837,9 +835,7 @@ module Pod
it 'flags should not be added to dtrace files' do it 'flags should not be added to dtrace files' do
@installer.target.target_definitions.first.stubs(:inhibits_warnings_for_pod?).returns(true) @installer.target.target_definitions.first.stubs(:inhibits_warnings_for_pod?).returns(true)
@installer.install! dtrace_files = @installer.install!.native_target.source_build_phase.files.select do |sf|
dtrace_files = @installer.target.native_target.source_build_phase.files.select do |sf|
File.extname(sf.file_ref.path) == '.d' File.extname(sf.file_ref.path) == '.d'
end end
dtrace_files.each do |dt| dtrace_files.each do |dt|
......
...@@ -14,13 +14,12 @@ module Pod ...@@ -14,13 +14,12 @@ module Pod
@coconut_pod_target = PodTarget.new(config.sandbox, false, {}, [], Platform.ios, [@coconut_spec, *@coconut_spec.recursive_subspecs], [@target_definition]) @coconut_pod_target = PodTarget.new(config.sandbox, false, {}, [], Platform.ios, [@coconut_spec, *@coconut_spec.recursive_subspecs], [@target_definition])
@native_target = stub('NativeTarget', :shell_script_build_phases => [], :build_phases => [], :project => @project) @native_target = stub('NativeTarget', :shell_script_build_phases => [], :build_phases => [], :project => @project)
@test_native_target = stub('TestNativeTarget', :symbol_type => :unit_test_bundle, :build_phases => [], :shell_script_build_phases => [], :project => @project) @test_native_target = stub('TestNativeTarget', :symbol_type => :unit_test_bundle, :build_phases => [], :shell_script_build_phases => [], :project => @project)
@coconut_pod_target.stubs(:native_target).returns(@native_target) @target_installation_result = TargetInstallationResult.new(@coconut_pod_target, @native_target, [], [@test_native_target])
@coconut_pod_target.stubs(:test_native_targets).returns([@test_native_target])
end end
describe '#integrate!' do describe '#integrate!' do
it 'integrates test native targets with frameworks and resources script phases' do it 'integrates test native targets with frameworks and resources script phases' do
PodTargetIntegrator.new(@coconut_pod_target).integrate! PodTargetIntegrator.new(@target_installation_result).integrate!
@test_native_target.build_phases.count.should == 2 @test_native_target.build_phases.count.should == 2
@test_native_target.build_phases.map(&:display_name).should == [ @test_native_target.build_phases.map(&:display_name).should == [
'[CP] Embed Pods Frameworks', '[CP] Embed Pods Frameworks',
...@@ -36,7 +35,7 @@ module Pod ...@@ -36,7 +35,7 @@ module Pod
"${PODS_CONFIGURATION_BUILD_DIR}/DebugLib/DebugLibPng#{i}.png" "${PODS_CONFIGURATION_BUILD_DIR}/DebugLib/DebugLibPng#{i}.png"
end end
@coconut_pod_target.stubs(:resource_paths).returns(resource_paths) @coconut_pod_target.stubs(:resource_paths).returns(resource_paths)
PodTargetIntegrator.new(@coconut_pod_target).integrate! PodTargetIntegrator.new(@target_installation_result).integrate!
@test_native_target.build_phases.map(&:display_name).should == [ @test_native_target.build_phases.map(&:display_name).should == [
'[CP] Embed Pods Frameworks', '[CP] Embed Pods Frameworks',
'[CP] Copy Pods Resources', '[CP] Copy Pods Resources',
...@@ -50,7 +49,7 @@ module Pod ...@@ -50,7 +49,7 @@ module Pod
resource_paths = ['${PODS_CONFIGURATION_BUILD_DIR}/TestResourceBundle.bundle'] resource_paths = ['${PODS_CONFIGURATION_BUILD_DIR}/TestResourceBundle.bundle']
@coconut_pod_target.stubs(:framework_paths).returns(framework_paths) @coconut_pod_target.stubs(:framework_paths).returns(framework_paths)
@coconut_pod_target.stubs(:resource_paths).returns(resource_paths) @coconut_pod_target.stubs(:resource_paths).returns(resource_paths)
PodTargetIntegrator.new(@coconut_pod_target).integrate! PodTargetIntegrator.new(@target_installation_result).integrate!
@test_native_target.build_phases.count.should == 2 @test_native_target.build_phases.count.should == 2
@test_native_target.build_phases.map(&:display_name).should == [ @test_native_target.build_phases.map(&:display_name).should == [
'[CP] Embed Pods Frameworks', '[CP] Embed Pods Frameworks',
...@@ -74,7 +73,7 @@ module Pod ...@@ -74,7 +73,7 @@ module Pod
it 'integrates test native target with shell script phases' do it 'integrates test native target with shell script phases' do
@coconut_spec.test_specs.first.script_phase = { :name => 'Hello World', :script => 'echo "Hello World"' } @coconut_spec.test_specs.first.script_phase = { :name => 'Hello World', :script => 'echo "Hello World"' }
PodTargetIntegrator.new(@coconut_pod_target).integrate! PodTargetIntegrator.new(@target_installation_result).integrate!
@test_native_target.build_phases.count.should == 3 @test_native_target.build_phases.count.should == 3
@test_native_target.build_phases[2].display_name.should == '[CP-User] Hello World' @test_native_target.build_phases[2].display_name.should == '[CP-User] Hello World'
@test_native_target.build_phases[2].shell_script.should == 'echo "Hello World"' @test_native_target.build_phases[2].shell_script.should == 'echo "Hello World"'
...@@ -82,7 +81,7 @@ module Pod ...@@ -82,7 +81,7 @@ module Pod
it 'integrates native target with shell script phases' do it 'integrates native target with shell script phases' do
@coconut_spec.script_phase = { :name => 'Hello World', :script => 'echo "Hello World"' } @coconut_spec.script_phase = { :name => 'Hello World', :script => 'echo "Hello World"' }
PodTargetIntegrator.new(@coconut_pod_target).integrate! PodTargetIntegrator.new(@target_installation_result).integrate!
@native_target.build_phases.count.should == 1 @native_target.build_phases.count.should == 1
@native_target.build_phases[0].display_name.should == '[CP-User] Hello World' @native_target.build_phases[0].display_name.should == '[CP-User] Hello World'
@native_target.build_phases[0].shell_script.should == 'echo "Hello World"' @native_target.build_phases[0].shell_script.should == 'echo "Hello World"'
......
...@@ -15,8 +15,7 @@ module Pod ...@@ -15,8 +15,7 @@ module Pod
end end
it 'adds the architectures to the custom build configurations of the user target' do it 'adds the architectures to the custom build configurations of the user target' do
@installer.send(:add_target) @installer.send(:add_target).resolved_build_setting('ARCHS').should == {
@installer.send(:native_target).resolved_build_setting('ARCHS').should == {
'Release' => ['$(ARCHS_STANDARD_64_BIT)'], 'Release' => ['$(ARCHS_STANDARD_64_BIT)'],
'Debug' => ['$(ARCHS_STANDARD_64_BIT)'], 'Debug' => ['$(ARCHS_STANDARD_64_BIT)'],
'AppStore' => ['$(ARCHS_STANDARD_64_BIT)'], 'AppStore' => ['$(ARCHS_STANDARD_64_BIT)'],
...@@ -25,16 +24,15 @@ module Pod ...@@ -25,16 +24,15 @@ module Pod
end end
it 'always clears the OTHER_LDFLAGS and OTHER_LIBTOOLFLAGS, because these lib targets do not ever need any' do it 'always clears the OTHER_LDFLAGS and OTHER_LIBTOOLFLAGS, because these lib targets do not ever need any' do
@installer.send(:add_target) native_target = @installer.send(:add_target)
@installer.send(:native_target).resolved_build_setting('OTHER_LDFLAGS').values.uniq.should == [''] native_target.resolved_build_setting('OTHER_LDFLAGS').values.uniq.should == ['']
@installer.send(:native_target).resolved_build_setting('OTHER_LIBTOOLFLAGS').values.uniq.should == [''] native_target.resolved_build_setting('OTHER_LIBTOOLFLAGS').values.uniq.should == ['']
end end
it 'adds Swift-specific build settings to the build settings' do it 'adds Swift-specific build settings to the build settings' do
@target.stubs(:requires_frameworks?).returns(true) @target.stubs(:requires_frameworks?).returns(true)
@target.stubs(:uses_swift?).returns(true) @target.stubs(:uses_swift?).returns(true)
@installer.send(:add_target) @installer.send(:add_target).resolved_build_setting('SWIFT_OPTIMIZATION_LEVEL').should == {
@installer.send(:native_target).resolved_build_setting('SWIFT_OPTIMIZATION_LEVEL').should == {
'Release' => '-Owholemodule', 'Release' => '-Owholemodule',
'Debug' => '-Onone', 'Debug' => '-Onone',
'Test' => nil, 'Test' => nil,
...@@ -45,8 +43,7 @@ module Pod ...@@ -45,8 +43,7 @@ module Pod
it 'verify static framework is building a static library' do it 'verify static framework is building a static library' do
@target.stubs(:requires_frameworks?).returns(true) @target.stubs(:requires_frameworks?).returns(true)
@target.stubs(:static_framework?).returns(true) @target.stubs(:static_framework?).returns(true)
@installer.send(:add_target) @installer.send(:add_target).resolved_build_setting('MACH_O_TYPE').should == {
@installer.send(:native_target).resolved_build_setting('MACH_O_TYPE').should == {
'Release' => 'staticlib', 'Release' => 'staticlib',
'Debug' => 'staticlib', 'Debug' => 'staticlib',
'Test' => 'staticlib', 'Test' => 'staticlib',
......
...@@ -4,556 +4,466 @@ module Pod ...@@ -4,556 +4,466 @@ module Pod
class Installer class Installer
class Xcode class Xcode
describe PodsProjectGenerator do describe PodsProjectGenerator do
# @return [Lockfile]
#
def generate_lockfile(lockfile_version: Pod::VERSION)
hash = {}
hash['PODS'] = []
hash['DEPENDENCIES'] = []
hash['SPEC CHECKSUMS'] = {}
hash['COCOAPODS'] = lockfile_version
Pod::Lockfile.new(hash)
end
# @return [Podfile]
#
def generate_podfile(pods = ['JSONKit'])
Pod::Podfile.new do
platform :ios
project SpecHelper.create_sample_app_copy_from_fixture('SampleProject'), 'Test' => :debug, 'App Store' => :release
target 'SampleProject' do
pods.each { |name| pod name }
target 'SampleProjectTests' do
inherit! :search_paths
end
end
end
end
# @return [Podfile]
#
def generate_local_podfile
Pod::Podfile.new do
platform :ios
project SpecHelper.fixture('SampleProject/SampleProject'), 'Test' => :debug, 'App Store' => :release
target 'SampleProject' do
pod 'Reachability', :path => SpecHelper.fixture('integration/Reachability')
target 'SampleProjectTests' do
inherit! :search_paths
end
end
end
end
describe 'Generating Pods Project' do describe 'Generating Pods Project' do
before do before do
podfile = generate_podfile @ios_platform = Platform.new(:ios, '6.0')
lockfile = generate_lockfile @osx_platform = Platform.new(:osx, '10.8')
@installer = Pod::Installer.new(config.sandbox, podfile, lockfile)
@installer.send(:prepare) @ios_target_definition = fixture_target_definition('SampleApp-iOS', @ios_platform)
@installer.send(:analyze) @osx_target_definition = fixture_target_definition('SampleApp-macOS', @osx_platform)
@generator = @installer.send(:create_generator)
user_build_configurations = { 'Debug' => :debug, 'Release' => :release, 'App Store' => :release, 'Test' => :debug }
@monkey_spec = fixture_spec('monkey/monkey.podspec')
@monkey_ios_pod_target = fixture_pod_target(@monkey_spec, false,
user_build_configurations, [], @ios_platform,
[@ios_target_definition], 'iOS')
@monkey_osx_pod_target = fixture_pod_target(@monkey_spec, false,
user_build_configurations, [], @osx_platform,
[@osx_target_definition], 'macOS')
@banana_spec = fixture_spec('banana-lib/BananaLib.podspec')
@banana_ios_pod_target = fixture_pod_target(@banana_spec, false,
user_build_configurations, [], @ios_platform,
[@ios_target_definition], 'iOS')
@banana_osx_pod_target = fixture_pod_target(@banana_spec, false,
user_build_configurations, [], @osx_platform,
[@osx_target_definition], 'macOS')
@orangeframework_spec = fixture_spec('orange-framework/OrangeFramework.podspec')
@orangeframework_pod_target = fixture_pod_target_with_specs([@orangeframework_spec], false,
user_build_configurations, [], @ios_platform,
[@ios_target_definition])
@coconut_spec = fixture_spec('coconut-lib/CoconutLib.podspec')
@coconut_test_spec = @coconut_spec.test_specs.first
@coconut_ios_pod_target = fixture_pod_target_with_specs([@coconut_spec, @coconut_test_spec],
false,
user_build_configurations, [], @ios_platform,
[@ios_target_definition],
'iOS')
@coconut_ios_pod_target.dependent_targets = [@orangeframework_pod_target]
@coconut_osx_pod_target = fixture_pod_target_with_specs([@coconut_spec, @coconut_test_spec],
false,
user_build_configurations, [], @osx_platform,
[@osx_target_definition],
'macOS')
ios_pod_targets = [@banana_ios_pod_target, @monkey_ios_pod_target, @coconut_ios_pod_target,
@orangeframework_pod_target]
osx_pod_targets = [@banana_osx_pod_target, @monkey_osx_pod_target, @coconut_osx_pod_target]
pod_targets = ios_pod_targets + osx_pod_targets
@ios_target = fixture_aggregate_target(ios_pod_targets, false,
user_build_configurations, [], @ios_platform,
@ios_target_definition)
@osx_target = fixture_aggregate_target(osx_pod_targets, false,
user_build_configurations, [], @osx_platform,
@osx_target_definition)
aggregate_targets = [@ios_target, @osx_target]
@analysis_result = Pod::Installer::Analyzer::AnalysisResult.new
@analysis_result.targets = aggregate_targets
@installation_options = Pod::Installer::InstallationOptions.new
@generator = PodsProjectGenerator.new(config.sandbox, aggregate_targets, pod_targets, @analysis_result,
@installation_options, config)
end end
describe '#prepare' do it "creates build configurations for all of the user's targets" do
before do @generator.generate!
@generator.send(:prepare) @generator.project.build_configurations.map(&:name).sort.should == ['App Store', 'Debug', 'Release', 'Test']
end
it "creates build configurations for all of the user's targets" do
@generator.project.build_configurations.map(&:name).sort.should == ['App Store', 'Debug', 'Release', 'Test']
end
it 'sets STRIP_INSTALLED_PRODUCT to NO for all configurations for the whole project' do
@generator.project.build_settings('Debug')['STRIP_INSTALLED_PRODUCT'].should == 'NO'
@generator.project.build_settings('Test')['STRIP_INSTALLED_PRODUCT'].should == 'NO'
@generator.project.build_settings('Release')['STRIP_INSTALLED_PRODUCT'].should == 'NO'
@generator.project.build_settings('App Store')['STRIP_INSTALLED_PRODUCT'].should == 'NO'
end
it 'sets the SYMROOT to the default value for all configurations for the whole project' do
@generator.project.build_settings('Debug')['SYMROOT'].should == Pod::Project::LEGACY_BUILD_ROOT
@generator.project.build_settings('Test')['SYMROOT'].should == Pod::Project::LEGACY_BUILD_ROOT
@generator.project.build_settings('Release')['SYMROOT'].should == Pod::Project::LEGACY_BUILD_ROOT
@generator.project.build_settings('App Store')['SYMROOT'].should == Pod::Project::LEGACY_BUILD_ROOT
end
it 'creates the Pods project' do
@generator.send(:prepare)
@generator.project.class.should == Pod::Project
end
it 'preserves Pod paths specified as absolute or rooted to home' do
local_podfile = generate_local_podfile
local_installer = Pod::Installer.new(config.sandbox, local_podfile)
local_installer.send(:analyze)
local_generator = local_installer.send(:create_generator)
local_generator.send(:prepare)
group = local_generator.project.group_for_spec('Reachability')
Pathname.new(group.path).should.be.absolute
end
it 'adds the Podfile to the Pods project' do
config.stubs(:podfile_path).returns(Pathname.new('/Podfile'))
@generator.send(:prepare)
@generator.project['Podfile'].should.be.not.nil
end
it 'sets the deployment target for the whole project' do
osx_platform = Platform.new(:osx, '10.8')
ios_platform = Platform.new(:ios, '6.0')
target_definition_osx = fixture_target_definition('OSX Target', osx_platform)
target_definition_ios = fixture_target_definition('iOS Target', ios_platform)
aggregate_target_osx = AggregateTarget.new(config.sandbox, false, {}, [], osx_platform, target_definition_osx, config.sandbox.root.dirname, nil, nil, [])
aggregate_target_ios = AggregateTarget.new(config.sandbox, false, {}, [], ios_platform, target_definition_ios, config.sandbox.root.dirname, nil, nil, [])
@generator.stubs(:aggregate_targets).returns([aggregate_target_osx, aggregate_target_ios])
@generator.stubs(:pod_targets).returns([])
@generator.send(:prepare)
build_settings = @generator.project.build_configurations.map(&:build_settings)
build_settings.each do |build_setting|
build_setting['MACOSX_DEPLOYMENT_TARGET'].should == '10.8'
build_setting['IPHONEOS_DEPLOYMENT_TARGET'].should == '6.0'
end
end
end end
#-------------------------------------# it 'sets STRIP_INSTALLED_PRODUCT to NO for all configurations for the whole project' do
@generator.generate!
describe '#install_file_references' do @generator.project.build_settings('Debug')['STRIP_INSTALLED_PRODUCT'].should == 'NO'
it 'installs the file references' do @generator.project.build_settings('Test')['STRIP_INSTALLED_PRODUCT'].should == 'NO'
@generator.stubs(:pod_targets).returns([]) @generator.project.build_settings('Release')['STRIP_INSTALLED_PRODUCT'].should == 'NO'
PodsProjectGenerator::FileReferencesInstaller.any_instance.expects(:install!) @generator.project.build_settings('App Store')['STRIP_INSTALLED_PRODUCT'].should == 'NO'
@generator.send(:install_file_references)
end
end end
#-------------------------------------# it 'sets the SYMROOT to the default value for all configurations for the whole project' do
@generator.generate!
describe '#install_libraries' do @generator.project.build_settings('Debug')['SYMROOT'].should == Pod::Project::LEGACY_BUILD_ROOT
it 'install the targets of the Pod project' do @generator.project.build_settings('Test')['SYMROOT'].should == Pod::Project::LEGACY_BUILD_ROOT
spec = fixture_spec('banana-lib/BananaLib.podspec') @generator.project.build_settings('Release')['SYMROOT'].should == Pod::Project::LEGACY_BUILD_ROOT
target_definition = Podfile::TargetDefinition.new(:default, nil) @generator.project.build_settings('App Store')['SYMROOT'].should == Pod::Project::LEGACY_BUILD_ROOT
target_definition.set_platform(:ios, '8.0')
target_definition.abstract = false
target_definition.store_pod('BananaLib')
pod_target = PodTarget.new(config.sandbox, false, {}, [], Platform.ios, [spec], [target_definition])
@generator.stubs(:aggregate_targets).returns([])
@generator.stubs(:pod_targets).returns([pod_target])
PodsProjectGenerator::PodTargetInstaller.any_instance.expects(:install!)
@generator.send(:install_libraries)
end
it 'does not skip empty pod targets' do
spec = fixture_spec('banana-lib/BananaLib.podspec')
target_definition = Podfile::TargetDefinition.new(:default, nil)
target_definition.set_platform(:ios, '8.0')
target_definition.abstract = false
pod_target = PodTarget.new(config.sandbox, false, {}, [], Platform.ios, [spec], [target_definition])
@generator.stubs(:aggregate_targets).returns([])
@generator.stubs(:pod_targets).returns([pod_target])
PodsProjectGenerator::PodTargetInstaller.any_instance.expects(:install!).once
@generator.send(:install_libraries)
end
it 'adds the frameworks required by the pod to the project for informative purposes' do
Specification::Consumer.any_instance.stubs(:frameworks).returns(['QuartzCore'])
@installer.send(:install!)
names = @installer.pods_project['Frameworks']['iOS'].children.map(&:name)
names.sort.should == ['Foundation.framework', 'QuartzCore.framework']
end
end end
#-------------------------------------# it 'creates the correct Pods project' do
@generator.generate!
describe '#set_target_dependencies' do @generator.project.class.should == Pod::Project
def test_extension_target(symbol_type) end
mock_user_target = mock('usertarget', :symbol_type => symbol_type)
@target.stubs(:user_targets).returns([mock_user_target])
build_settings = {}
mock_configuration = mock('buildconfiguration', :build_settings => build_settings)
@mock_target.stubs(:build_configurations).returns([mock_configuration])
@generator.send(:set_target_dependencies)
build_settings.should == { 'APPLICATION_EXTENSION_API_ONLY' => 'YES' }
end
before do
spec = fixture_spec('banana-lib/BananaLib.podspec')
target_definition = Podfile::TargetDefinition.new(:default, @installer.podfile.root_target_definitions.first)
@pod_target = PodTarget.new(config.sandbox, false, {}, [], Platform.ios, [spec], [target_definition])
@target = AggregateTarget.new(config.sandbox, false, {}, [], Platform.ios, target_definition, config.sandbox.root.dirname, nil, nil, [@pod_target])
@mock_target = mock('PodNativeTarget')
mock_project = mock('PodsProject', :frameworks_group => mock('FrameworksGroup'))
@generator.stubs(:project).returns(mock_project)
@target.stubs(:native_target).returns(@mock_target)
@generator.stubs(:pod_targets).returns([@pod_target])
@generator.stubs(:aggregate_targets).returns([@target])
end
it 'sets resource bundles for not build pods as target dependencies of the user target' do
@pod_target.stubs(:resource_bundle_targets).returns(['dummy'])
@pod_target.stubs(:should_build? => false)
@mock_target.expects(:add_dependency).with('dummy')
@generator.send(:set_target_dependencies)
end
it 'adds target dependencies when inheriting search paths' do
native_target = mock('SearchPathsAggregateNativeTarget')
@target.stubs(:search_paths_aggregate_targets).returns([
mock('SearchPathsAggregateTarget', :native_target => native_target),
])
@mock_target.expects(:add_dependency).with(native_target)
@generator.send(:set_target_dependencies)
end
it 'configures APPLICATION_EXTENSION_API_ONLY for app extension targets' do
test_extension_target(:app_extension)
end
it 'configures APPLICATION_EXTENSION_API_ONLY for watch extension targets' do
test_extension_target(:watch_extension)
end
it 'configures APPLICATION_EXTENSION_API_ONLY for watchOS 2 extension targets' do
test_extension_target(:watch2_extension)
end
it 'configures APPLICATION_EXTENSION_API_ONLY for tvOS extension targets' do
test_extension_target(:tv_extension)
end
it 'configures APPLICATION_EXTENSION_API_ONLY for Messages extension targets' do
test_extension_target(:messages_extension)
end
it 'configures APPLICATION_EXTENSION_API_ONLY for targets where the user target has it set' do
mock_user_target = mock('UserTarget', :symbol_type => :application)
mock_user_target.expects(:common_resolved_build_setting).with('APPLICATION_EXTENSION_API_ONLY').returns('YES')
@target.stubs(:user_targets).returns([mock_user_target])
build_settings = {}
mock_configuration = mock('BuildConfiguration', :build_settings => build_settings)
@mock_target.stubs(:build_configurations).returns([mock_configuration])
@generator.send(:set_target_dependencies) it 'adds the Podfile to the Pods project' do
config.stubs(:podfile_path).returns(Pathname.new('/Podfile'))
@generator.generate!
@generator.project['Podfile'].should.be.not.nil
end
build_settings.should == { 'APPLICATION_EXTENSION_API_ONLY' => 'YES' } it 'sets the deployment target for the whole project' do
@generator.generate!
build_settings = @generator.project.build_configurations.map(&:build_settings)
build_settings.each do |build_setting|
build_setting['MACOSX_DEPLOYMENT_TARGET'].should == '10.8'
build_setting['IPHONEOS_DEPLOYMENT_TARGET'].should == '6.0'
end end
end
it 'does not try to set APPLICATION_EXTENSION_API_ONLY if there are no pod targets' do it 'installs file references' do
lambda do @generator.generate!
mock_user_target = mock('UserTarget', :symbol_type => :app_extension) banana_group = @generator.project.group_for_spec('BananaLib')
@target.stubs(:user_targets).returns([mock_user_target]) banana_group.files.map(&:name).sort.should == [
'Banana.h',
'Banana.m',
'BananaPrivate.h',
'BananaTrace.d',
'MoreBanana.h',
]
monkey_group = @generator.project.group_for_spec('monkey')
monkey_group.files.map(&:name).sort.should.be.empty # pre-built pod
organge_framework_group = @generator.project.group_for_spec('OrangeFramework')
organge_framework_group.files.map(&:name).sort.should. == [
'Juicer.swift',
]
coconut_group = @generator.project.group_for_spec('CoconutLib')
coconut_group.files.map(&:name).sort.should == [
'Coconut.h',
'Coconut.m',
]
end
@target.stubs(:native_target).returns(nil) it 'installs the correct targets in the project' do
@target.stubs(:pod_targets).returns([]) @generator.generate!
@generator.project.targets.map(&:name).sort.should == [
'BananaLib-iOS',
'BananaLib-macOS',
'CoconutLib-iOS',
'CoconutLib-iOS-Unit-Tests',
'CoconutLib-macOS',
'CoconutLib-macOS-Unit-Tests',
'OrangeFramework',
'Pods-SampleApp-iOS',
'Pods-SampleApp-macOS',
'monkey-iOS',
'monkey-macOS',
]
end
@generator.send(:set_target_dependencies) it 'sets the pod and aggregate target dependencies' do
end.should.not.raise NoMethodError @generator.generate!
end @generator.project.targets.find { |t| t.name == 'BananaLib-iOS' }.dependencies.map(&:name).should.be.empty
@generator.project.targets.find { |t| t.name == 'BananaLib-macOS' }.dependencies.map(&:name).should.be.empty
@generator.project.targets.find { |t| t.name == 'CoconutLib-macOS' }.dependencies.map(&:name).should.be.empty
@generator.project.targets.find { |t| t.name == 'monkey-iOS' }.dependencies.map(&:name).should.be.empty
@generator.project.targets.find { |t| t.name == 'monkey-macOS' }.dependencies.map(&:name).should.be.empty
@generator.project.targets.find { |t| t.name == 'CoconutLib-iOS' }.dependencies.map(&:name).sort.should == [
'OrangeFramework',
]
@generator.project.targets.find { |t| t.name == 'Pods-SampleApp-iOS' }.dependencies.map(&:name).sort.should == [
'BananaLib-iOS',
'CoconutLib-iOS',
'OrangeFramework',
'monkey-iOS',
]
@generator.project.targets.find { |t| t.name == 'Pods-SampleApp-macOS' }.dependencies.map(&:name).sort.should == [
'BananaLib-macOS',
'CoconutLib-macOS',
'monkey-macOS',
]
end end
#--------------------------------------# it 'adds system frameworks to targets' do
@generator.generate!
@generator.project.targets.find { |t| t.name == 'OrangeFramework' }.frameworks_build_phase.file_display_names.sort.should == [
'Foundation.framework',
'UIKit.framework',
]
end
describe '#set_test_target_dependencies' do it 'adds target dependencies when inheriting search paths' do
before do inherited_target_definition = fixture_target_definition('SampleApp-iOS-Tests', @ios_platform)
spec = fixture_spec('coconut-lib/CoconutLib.podspec') inherited_target = fixture_aggregate_target([], false,
@ios_target.user_build_configurations, [],
@ios_target.platform, inherited_target_definition)
inherited_target.search_paths_aggregate_targets << @ios_target
@generator.aggregate_targets << inherited_target
@generator.generate!
@generator.project.targets.find { |t| t.name == 'Pods-SampleApp-iOS-Tests' }.dependencies.map(&:name).sort.should == [
'Pods-SampleApp-iOS',
]
end
target_definition = Podfile::TargetDefinition.new(:default, @installer.podfile.root_target_definitions.first) it 'sets resource bundle target dependencies' do
@pod_target = PodTarget.new(config.sandbox, false, {}, [], Platform.ios, [spec, *spec.recursive_subspecs], [target_definition]) @banana_spec.resource_bundles = { 'BananaLibResourcesBundle' => '**/*' }
@target = AggregateTarget.new(config.sandbox, false, {}, [], Platform.ios, target_definition, config.sandbox.root.dirname, nil, nil, [@pod_target]) @generator.generate!
@generator.project.targets.find { |t| t.name == 'BananaLib-iOS-BananaLibResourcesBundle' }.should.not.be.nil
@generator.project.targets.find { |t| t.name == 'BananaLib-macOS-BananaLibResourcesBundle' }.should.not.be.nil
@generator.project.targets.find { |t| t.name == 'BananaLib-iOS' }.dependencies.map(&:name).should == [
'BananaLib-iOS-BananaLibResourcesBundle',
]
@generator.project.targets.find { |t| t.name == 'BananaLib-macOS' }.dependencies.map(&:name).should == [
'BananaLib-macOS-BananaLibResourcesBundle',
]
end
@mock_target = mock('PodNativeTarget') it 'sets test resource bundle dependencies' do
@coconut_test_spec.resource_bundles = { 'CoconutLibTestResourcesBundle' => '**/*' }
@generator.generate!
@generator.project.targets.find { |t| t.name == 'CoconutLib-iOS-CoconutLibTestResourcesBundle' }.should.not.be.nil
@generator.project.targets.find { |t| t.name == 'CoconutLib-macOS-CoconutLibTestResourcesBundle' }.should.not.be.nil
@generator.project.targets.find { |t| t.name == 'CoconutLib-iOS-Unit-Tests' }.dependencies.map(&:name).sort.should == [
'CoconutLib-iOS',
'CoconutLib-iOS-CoconutLibTestResourcesBundle',
'OrangeFramework',
]
@generator.project.targets.find { |t| t.name == 'CoconutLib-macOS-Unit-Tests' }.dependencies.map(&:name).sort.should == [
'CoconutLib-macOS',
'CoconutLib-macOS-CoconutLibTestResourcesBundle',
]
end
mock_project = mock('PodsProject', :frameworks_group => mock('FrameworksGroup')) it 'sets the app host dependency for the tests that need it' do
@generator.stubs(:project).returns(mock_project) @coconut_test_spec.ios.requires_app_host = true
@generator.generate!
@generator.project.targets.find { |t| t.name == 'AppHost-iOS-Unit-Tests' }.should.not.be.nil
@generator.project.targets.find { |t| t.name == 'CoconutLib-iOS-Unit-Tests' }.dependencies.map(&:name).sort.should == [
'AppHost-iOS-Unit-Tests',
'CoconutLib-iOS',
'OrangeFramework',
]
@generator.project.targets.find { |t| t.name == 'CoconutLib-macOS-Unit-Tests' }.dependencies.map(&:name).should == [
'CoconutLib-macOS',
]
end
@target.stubs(:native_target).returns(@mock_target) it 'configures APPLICATION_EXTENSION_API_ONLY for pod targets of an aggregate target' do
@generator.stubs(:pod_targets).returns([@pod_target]) user_target = stub('SampleApp-iOS-User-Target', :symbol_type => :app_extension)
@generator.stubs(:aggregate_targets).returns([@target]) @ios_target.stubs(:user_targets).returns([user_target])
@generator.generate!
@generator.project.targets.find { |t| t.name == 'Pods-SampleApp-iOS' }.dependencies.each do |dependency|
build_settings = @generator.project.targets.find { |t| t.name == dependency.name }.build_configurations.map(&:build_settings)
build_settings.each do |build_setting|
build_setting['APPLICATION_EXTENSION_API_ONLY'].should == 'YES'
end
end end
end
it 'adds all test dependent targets to test native targets' do it 'configures APPLICATION_EXTENSION_API_ONLY for app extension targets' do
mock_native_target = mock('CoconutLib') user_target = stub('SampleApp-iOS-User-Target', :symbol_type => :app_extension)
mock_test_native_target = mock('CoconutLib-Unit-Tests', :symbol_type => :unit_test_bundle) @ios_target.stubs(:user_targets).returns([user_target])
@generator.generate!
dependent_native_target = mock('DependentNativeTarget') build_settings = @generator.project.targets.find { |t| t.name == 'Pods-SampleApp-iOS' }.build_configurations.map(&:build_settings)
test_dependent_native_target = mock('TestDependentNativeTarget') build_settings.each do |build_setting|
build_setting['APPLICATION_EXTENSION_API_ONLY'].should == 'YES'
dependent_target = mock('dependent-target', :dependent_targets => [])
dependent_target.stubs(:should_build?).returns(true)
dependent_target.stubs(:native_target).returns(dependent_native_target)
test_dependent_target = mock('dependent-test-target', :native_target => test_dependent_native_target, :test_dependent_targets => [])
test_dependent_target.stubs(:should_build?).returns(true)
@pod_target.stubs(:native_target).returns(mock_native_target)
@pod_target.stubs(:test_native_targets).returns([mock_test_native_target])
@pod_target.stubs(:dependent_targets).returns([dependent_target])
@pod_target.stubs(:test_dependent_targets).returns([test_dependent_target])
@pod_target.stubs(:should_build? => true)
@mock_target.expects(:add_dependency).with(mock_native_target)
mock_native_target.expects(:add_dependency).with(dependent_native_target)
mock_native_target.expects(:add_dependency).with(test_dependent_native_target).never
mock_native_target.expects(:add_dependency).with(mock_native_target).never
mock_test_native_target.expects(:add_dependency).with(dependent_native_target)
mock_test_native_target.expects(:add_dependency).with(test_dependent_native_target)
mock_test_native_target.expects(:add_dependency).with(mock_native_target)
@generator.send(:set_target_dependencies)
end end
end
it 'adds all test dependent targets to test native targets for static frameworks' do it 'configures APPLICATION_EXTENSION_API_ONLY for watch2 extension targets' do
mock_native_target = mock('CoconutLib') user_target = stub('SampleApp-iOS-User-Target', :symbol_type => :watch2_extension)
dependent_native_target = mock('DependentNativeTarget') @ios_target.stubs(:user_targets).returns([user_target])
@generator.generate!
dependent_target = mock('dependent-target') build_settings = @generator.project.targets.find { |t| t.name == 'Pods-SampleApp-iOS' }.build_configurations.map(&:build_settings)
dependent_target.stubs(:should_build?).returns(true) build_settings.each do |build_setting|
dependent_target.stubs(:native_target).returns(dependent_native_target) build_setting['APPLICATION_EXTENSION_API_ONLY'].should == 'YES'
@pod_target.stubs(:native_target).returns(mock_native_target)
@pod_target.stubs(:dependent_targets).returns([dependent_target])
@pod_target.stubs(:should_build? => true)
@pod_target.stubs(:static_framework? => true)
@mock_target.expects(:add_dependency).with(mock_native_target)
mock_native_target.expects(:add_dependency).with(dependent_native_target)
mock_native_target.expects(:add_dependency).with(mock_native_target).never
@generator.send(:set_target_dependencies)
end end
end
it 'adds dependencies to pod targets that are not part of any aggregate target' do it 'configures APPLICATION_EXTENSION_API_ONLY for tvOS extension targets' do
@target.stubs(:pod_targets).returns([]) user_target = stub('SampleApp-iOS-User-Target', :symbol_type => :tv_extension)
@generator.expects(:pod_targets).returns([@pod_target]) @ios_target.stubs(:user_targets).returns([user_target])
mock_native_target = mock('CoconutLib') @generator.generate!
mock_test_native_target = mock('CoconutLib-Unit-Tests', :symbol_type => :unit_test_bundle) build_settings = @generator.project.targets.find { |t| t.name == 'Pods-SampleApp-iOS' }.build_configurations.map(&:build_settings)
build_settings.each do |build_setting|
dependent_native_target = mock('DependentNativeTarget') build_setting['APPLICATION_EXTENSION_API_ONLY'].should == 'YES'
dependent_target = mock('dependent-target', :dependent_targets => [])
dependent_target.stubs(:should_build?).returns(true)
dependent_target.stubs(:native_target).returns(dependent_native_target)
@pod_target.stubs(:native_target).returns(mock_native_target)
@pod_target.stubs(:test_native_targets).returns([mock_test_native_target])
@pod_target.stubs(:dependent_targets).returns([dependent_target])
@pod_target.stubs(:test_dependent_targets).returns([])
@pod_target.stubs(:should_build? => true)
mock_native_target.expects(:add_dependency).with(dependent_native_target)
mock_test_native_target.expects(:add_dependency).with(dependent_native_target)
mock_test_native_target.expects(:add_dependency).with(mock_native_target)
@generator.send(:set_target_dependencies)
end end
end
it 'adds test dependencies to test native targets for a pod target that should not be built' do it 'configures APPLICATION_EXTENSION_API_ONLY for Messages extension targets' do
mock_test_native_target = mock('CoconutLib-Unit-Tests', :symbol_type => :unit_test_bundle) user_target = stub('SampleApp-iOS-User-Target', :symbol_type => :messages_extension)
test_dependent_native_target = mock('TestDependentNativeTarget') @ios_target.stubs(:user_targets).returns([user_target])
test_dependent_target = mock('dependent-test-target', :should_build? => true, :native_target => test_dependent_native_target) @generator.generate!
test_dependent_target.expects(:should_build?).returns(true) build_settings = @generator.project.targets.find { |t| t.name == 'Pods-SampleApp-iOS' }.build_configurations.map(&:build_settings)
build_settings.each do |build_setting|
@pod_target.stubs(:test_native_targets).returns([mock_test_native_target]) build_setting['APPLICATION_EXTENSION_API_ONLY'].should == 'YES'
@pod_target.stubs(:all_dependent_targets).returns([test_dependent_target])
@pod_target.stubs(:should_build? => false)
mock_test_native_target.expects(:add_dependency).with(test_dependent_native_target)
@generator.send(:set_target_dependencies)
end end
end
it 'sets resource bundles for not build pods as target dependencies of the test target' do it "uses the user project's object version for the pods project" do
mock_test_native_target = mock('CoconutLib-Unit-Tests', :symbol_type => :unit_test_bundle) tmp_directory = Pathname(Dir.tmpdir) + 'CocoaPods'
FileUtils.mkdir_p(tmp_directory)
@pod_target.stubs(:test_native_targets).returns([mock_test_native_target]) proj = Xcodeproj::Project.new(tmp_directory + 'Yolo.xcodeproj', false, 1)
@pod_target.stubs(:test_dependent_targets).returns([]) proj.save
@pod_target.stubs(:should_build? => false)
@pod_target.stubs(:resource_bundle_targets).returns(['dummy'])
@mock_target.expects(:add_dependency).with('dummy')
mock_test_native_target.expects(:add_dependency).with('dummy')
@generator.send(:set_target_dependencies) user_target = stub('SampleApp-iOS-User-Target', :symbol_type => :application)
end user_target.expects(:common_resolved_build_setting).with('APPLICATION_EXTENSION_API_ONLY').returns('NO')
it 'sets the app host dependency target to the test native target if test spec requires app host' do target = AggregateTarget.new(config.sandbox, false, {}, [],
mock_app_host_target = mock(:name => 'AppHost-iOS-Unit-Tests') Platform.new(:ios, '6.0'), fixture_target_definition,
@generator.project.stubs(:targets).returns([mock_app_host_target]) config.sandbox.root.dirname, proj, nil, [])
mock_test_native_target = mock('CoconutLib-Unit-Tests', :symbol_type => :unit_test_bundle) target.stubs(:user_targets).returns([user_target])
test_dependent_native_target = mock('TestDependentNativeTarget')
test_dependent_target = mock('dependent-test-target', :should_build? => true, :native_target => test_dependent_native_target)
test_dependent_target.expects(:should_build?).returns(true)
@pod_target.test_specs.first.requires_app_host = true @generator = PodsProjectGenerator.new(config.sandbox, [target], [],
@pod_target.stubs(:test_native_targets).returns([mock_test_native_target]) @analysis_result, @installation_options, config)
@pod_target.stubs(:all_dependent_targets).returns([test_dependent_target]) @generator.generate!
@pod_target.stubs(:should_build? => false) @generator.project.object_version.should == '1'
mock_test_native_target.expects(:add_dependency).with(test_dependent_native_target) FileUtils.rm_rf(tmp_directory)
mock_test_native_target.expects(:add_dependency).with(mock_app_host_target)
@generator.send(:set_target_dependencies)
end
end end
#--------------------------------------#
describe '#write' do describe '#write' do
before do
@generator.stubs(:aggregate_targets).returns([])
@generator.stubs(:analysis_result).returns(stub(:all_user_build_configurations => {}, :target_inspections => nil))
@generator.send(:prepare)
end
it 'recursively sorts the project' do it 'recursively sorts the project' do
Xcodeproj::Project.any_instance.stubs(:recreate_user_schemes) @generator.generate!
@generator.project.main_group.expects(:sort) @generator.project.main_group.expects(:sort)
@generator.send(:write) Xcodeproj::Project.any_instance.stubs(:recreate_user_schemes)
@generator.write
end end
it 'saves the project to the given path' do it 'saves the project to the given path' do
@generator.generate!
Xcodeproj::Project.any_instance.stubs(:recreate_user_schemes) Xcodeproj::Project.any_instance.stubs(:recreate_user_schemes)
temporary_directory + 'Pods/Pods.xcodeproj' temporary_directory + 'Pods/Pods.xcodeproj'
@generator.project.expects(:save) @generator.project.expects(:save)
@generator.send(:write) @generator.write
end end
end
describe '#share_development_pod_schemes' do
it 'does not share by default' do
Xcodeproj::XCScheme.expects(:share_scheme).never
@generator.share_development_pod_schemes
end
it 'can share all schemes' do
@generator.installation_options.
stubs(:share_schemes_for_development_pods).
returns(true)
it "uses the user project's object version for the pods project" do @generator.generate!
tmp_directory = Pathname(Dir.tmpdir) + 'CocoaPods' @generator.sandbox.stubs(:development_pods).returns('BananaLib' => fixture('BananaLib'))
FileUtils.mkdir_p(tmp_directory)
proj = Xcodeproj::Project.new(tmp_directory + 'Yolo.xcodeproj', false, 1)
proj.save
aggregate_target = AggregateTarget.new(config.sandbox, false, {}, [], Platform.ios, fixture_target_definition, config.sandbox.root.dirname, proj, nil, []) Xcodeproj::XCScheme.expects(:share_scheme).with(
@generator.stubs(:aggregate_targets).returns([aggregate_target]) @generator.project.path,
'BananaLib-iOS')
@generator.send(:prepare) Xcodeproj::XCScheme.expects(:share_scheme).with(
@generator.project.object_version.should == '1' @generator.project.path,
'BananaLib-macOS')
FileUtils.rm_rf(tmp_directory) @generator.share_development_pod_schemes
end end
end
describe 'sharing schemes of development pods' do it 'shares test schemes' do
before do @generator.installation_options.
spec = fixture_spec('banana-lib/BananaLib.podspec') stubs(:share_schemes_for_development_pods).
pod_target = fixture_pod_target(spec) returns(true)
@generator.sandbox.stubs(:development_pods).returns('CoconutLib' => fixture('CoconutLib'))
@generator.stubs(:pod_targets).returns([pod_target]) @generator.generate!
@generator.sandbox.stubs(:development_pods).returns('BananaLib' => fixture('BananaLib'))
end
it 'does not share by default' do Xcodeproj::XCScheme.expects(:share_scheme).with(
Xcodeproj::XCScheme.expects(:share_scheme).never @generator.project.path,
@generator.send(:share_development_pod_schemes) 'CoconutLib-iOS')
end
it 'can share all schemes' do Xcodeproj::XCScheme.expects(:share_scheme).with(
@generator.installation_options. @generator.project.path,
stubs(:share_schemes_for_development_pods). 'CoconutLib-iOS-Unit-Tests')
returns(true)
Xcodeproj::XCScheme.expects(:share_scheme).with( Xcodeproj::XCScheme.expects(:share_scheme).with(
@generator.project.path, @generator.project.path,
'BananaLib') 'CoconutLib-macOS')
@generator.send(:share_development_pod_schemes)
end
it 'shares test schemes' do Xcodeproj::XCScheme.expects(:share_scheme).with(
spec = fixture_spec('coconut-lib/CoconutLib.podspec') @generator.project.path,
target_definition = Podfile::TargetDefinition.new(:default, @installer.podfile.root_target_definitions.first) 'CoconutLib-macOS-Unit-Tests')
pod_target = Pod::PodTarget.new(config.sandbox, false, {}, [], Platform.ios, [spec, *spec.recursive_subspecs], [target_definition])
pod_target.stubs(:should_build?).returns(true)
@generator.installation_options. @generator.share_development_pod_schemes
stubs(:share_schemes_for_development_pods). end
returns(true)
@generator.stubs(:pod_targets).returns([pod_target]) it 'allows opting out' do
@generator.sandbox.stubs(:development_pods).returns('CoconutLib' => fixture('CoconutLib')) @generator.installation_options.
stubs(:share_schemes_for_development_pods).
returns(false)
Xcodeproj::XCScheme.expects(:share_scheme).with( Xcodeproj::XCScheme.expects(:share_scheme).never
@generator.project.path, @generator.share_development_pod_schemes
'CoconutLib')
Xcodeproj::XCScheme.expects(:share_scheme).with( @generator.installation_options.
@generator.project.path, stubs(:share_schemes_for_development_pods).
'CoconutLib-Unit-Tests') returns(nil)
@generator.send(:share_development_pod_schemes) Xcodeproj::XCScheme.expects(:share_scheme).never
end @generator.share_development_pod_schemes
end
it 'allows opting out' do it 'allows specifying strings of pods to share' do
@generator.installation_options. @generator.installation_options.
stubs(:share_schemes_for_development_pods). stubs(:share_schemes_for_development_pods).
returns(false) returns(%w(BananaLib))
Xcodeproj::XCScheme.expects(:share_scheme).never @generator.generate!
@generator.send(:share_development_pod_schemes) @generator.sandbox.stubs(:development_pods).returns('BananaLib' => fixture('BananaLib'))
@generator.installation_options. Xcodeproj::XCScheme.expects(:share_scheme).with(
stubs(:share_schemes_for_development_pods). @generator.project.path,
returns(nil) 'BananaLib-iOS')
Xcodeproj::XCScheme.expects(:share_scheme).never Xcodeproj::XCScheme.expects(:share_scheme).with(
@generator.send(:share_development_pod_schemes) @generator.project.path,
end 'BananaLib-macOS')
it 'allows specifying strings of pods to share' do @generator.share_development_pod_schemes
@generator.installation_options.
stubs(:share_schemes_for_development_pods).
returns(%w(BananaLib))
Xcodeproj::XCScheme.expects(:share_scheme).with( @generator.installation_options.
@generator.project.path, stubs(:share_schemes_for_development_pods).
'BananaLib') returns(%w(orange-framework))
@generator.send(:share_development_pod_schemes)
@generator.installation_options. Xcodeproj::XCScheme.expects(:share_scheme).never
stubs(:share_schemes_for_development_pods). @generator.share_development_pod_schemes
returns(%w(orange-framework)) end
Xcodeproj::XCScheme.expects(:share_scheme).never it 'allows specifying regular expressions of pods to share' do
@generator.send(:share_development_pod_schemes) @generator.installation_options.
end stubs(:share_schemes_for_development_pods).
returns([/bAnaNalIb/i, /B*/])
it 'allows specifying regular expressions of pods to share' do @generator.generate!
@generator.installation_options. @generator.sandbox.stubs(:development_pods).returns('BananaLib' => fixture('BananaLib'))
stubs(:share_schemes_for_development_pods).
returns([/bAnaNalIb/i, /B*/])
Xcodeproj::XCScheme.expects(:share_scheme).with( Xcodeproj::XCScheme.expects(:share_scheme).with(
@generator.project.path, @generator.project.path,
'BananaLib') 'BananaLib-iOS')
@generator.send(:share_development_pod_schemes)
@generator.installation_options. Xcodeproj::XCScheme.expects(:share_scheme).with(
stubs(:share_schemes_for_development_pods). @generator.project.path,
returns([/banana$/, /[^\A]BananaLib/]) 'BananaLib-macOS')
Xcodeproj::XCScheme.expects(:share_scheme).never @generator.share_development_pod_schemes
@generator.send(:share_development_pod_schemes)
end
it 'raises when an invalid type is set' do @generator.installation_options.
@generator.installation_options. stubs(:share_schemes_for_development_pods).
stubs(:share_schemes_for_development_pods). returns([/banana$/, /[^\A]BananaLib/])
returns(Pathname('foo'))
Xcodeproj::XCScheme.expects(:share_scheme).never Xcodeproj::XCScheme.expects(:share_scheme).never
e = should.raise(Informative) { @generator.send(:share_development_pod_schemes) } @generator.share_development_pod_schemes
e.message.should.match /share_schemes_for_development_pods.*set it to true, false, or an array of pods to share schemes for/ end
end
end it 'raises when an invalid type is set' do
@generator.installation_options.
stubs(:share_schemes_for_development_pods).
returns(Pathname('foo'))
@generator.generate!
@generator.sandbox.stubs(:development_pods).returns('BananaLib' => fixture('BananaLib'))
Xcodeproj::XCScheme.expects(:share_scheme).never
e = should.raise(Informative) { @generator.share_development_pod_schemes }
e.message.should.match /share_schemes_for_development_pods.*set it to true, false, or an array of pods to share schemes for/
end end
end end
end end
......
...@@ -535,17 +535,6 @@ module Pod ...@@ -535,17 +535,6 @@ module Pod
@test_pod_target.app_host_label(:unit).should == 'AppHost-iOS-Unit-Tests' @test_pod_target.app_host_label(:unit).should == 'AppHost-iOS-Unit-Tests'
end end
it 'returns the correct native target based on the consumer provided' do
@test_pod_target.stubs(:native_target).returns(stub(:name => 'CoconutLib', :symbol_type => :dynamic_library, :product_reference => stub(:name => 'libCoconutLib.a')))
@test_pod_target.stubs(:test_native_targets).returns([stub(:name => 'CoconutLib-Unit-Tests', :symbol_type => :unit_test_bundle, :product_reference => stub(:name => 'CoconutLib-Unit-Tests'))])
native_target = @test_pod_target.native_target_for_spec(@coconut_spec)
native_target.name.should == 'CoconutLib'
native_target.product_reference.name.should == 'libCoconutLib.a'
test_native_target = @test_pod_target.native_target_for_spec(@coconut_spec.test_specs.first)
test_native_target.name.should == 'CoconutLib-Unit-Tests'
test_native_target.product_reference.name.should == 'CoconutLib-Unit-Tests'
end
it 'returns the correct product type for test type' do it 'returns the correct product type for test type' do
@test_pod_target.product_type_for_test_type(:unit).should == :unit_test_bundle @test_pod_target.product_type_for_test_type(:unit).should == :unit_test_bundle
end end
......
...@@ -1079,12 +1079,15 @@ module Pod ...@@ -1079,12 +1079,15 @@ module Pod
debug_configuration_two = stub(:build_settings => {}) debug_configuration_two = stub(:build_settings => {})
native_target_one = stub(:build_configuration_list => stub(:build_configurations => [debug_configuration_one])) native_target_one = stub(:build_configuration_list => stub(:build_configurations => [debug_configuration_one]))
native_target_two = stub(:build_configuration_list => stub(:build_configurations => [debug_configuration_two])) native_target_two = stub(:build_configuration_list => stub(:build_configurations => [debug_configuration_two]))
pod_target_one = stub(:uses_swift? => true, :swift_version => '4.0', :native_target => native_target_one, :test_native_targets => []) pod_target_one = stub(:name => 'PodTarget1', :uses_swift? => true, :swift_version => '4.0')
pod_target_two = stub(:uses_swift? => true, :swift_version => '3.2', :native_target => native_target_two, :test_native_targets => []) pod_target_two = stub(:name => 'PodTarget2', :uses_swift? => true, :swift_version => '3.2')
pod_target_installation_one = stub(:target => pod_target_one, :native_target => native_target_one, :test_native_targets => [])
pod_target_installation_two = stub(:target => pod_target_two, :native_target => native_target_two, :test_native_targets => [])
pod_target_installation_results = { 'PodTarget1' => pod_target_installation_one, 'PodTarget2' => pod_target_installation_two }
aggregate_target = stub(:pod_targets => [pod_target_one, pod_target_two]) aggregate_target = stub(:pod_targets => [pod_target_one, pod_target_two])
installer = stub(:pod_targets => [pod_target_one, pod_target_two]) installer = stub(:pod_targets => [pod_target_one, pod_target_two])
validator.instance_variable_set(:@installer, installer) validator.instance_variable_set(:@installer, installer)
validator.send(:configure_pod_targets, [aggregate_target], '9.0') validator.send(:configure_pod_targets, [aggregate_target], [pod_target_installation_results], '9.0')
debug_configuration_one.build_settings['SWIFT_VERSION'].should == '4.0' debug_configuration_one.build_settings['SWIFT_VERSION'].should == '4.0'
debug_configuration_two.build_settings['SWIFT_VERSION'].should == '3.2' debug_configuration_two.build_settings['SWIFT_VERSION'].should == '3.2'
end end
...@@ -1097,12 +1100,15 @@ module Pod ...@@ -1097,12 +1100,15 @@ module Pod
debug_configuration_two = stub(:build_settings => {}) debug_configuration_two = stub(:build_settings => {})
native_target_one = stub(:build_configuration_list => stub(:build_configurations => [debug_configuration_one])) native_target_one = stub(:build_configuration_list => stub(:build_configurations => [debug_configuration_one]))
native_target_two = stub(:build_configuration_list => stub(:build_configurations => [debug_configuration_two])) native_target_two = stub(:build_configuration_list => stub(:build_configurations => [debug_configuration_two]))
pod_target_one = stub(:uses_swift? => true, :swift_version => '4.0', :native_target => native_target_one, :test_native_targets => []) pod_target_one = stub(:name => 'PodTarget1', :uses_swift? => true, :swift_version => '4.0')
pod_target_two = stub(:uses_swift? => true, :swift_version => '3.2', :native_target => native_target_two, :test_native_targets => []) pod_target_two = stub(:name => 'PodTarget2', :uses_swift? => true, :swift_version => '3.2')
pod_target_installation_one = stub(:target => pod_target_one, :native_target => native_target_one, :test_native_targets => [])
pod_target_installation_two = stub(:target => pod_target_two, :native_target => native_target_two, :test_native_targets => [])
pod_target_installation_results = { 'PodTarget1' => pod_target_installation_one, 'PodTarget2' => pod_target_installation_two }
aggregate_target = stub(:pod_targets => [pod_target_one]) aggregate_target = stub(:pod_targets => [pod_target_one])
installer = stub(:pod_targets => [pod_target_one, pod_target_two]) installer = stub(:pod_targets => [pod_target_one, pod_target_two])
validator.instance_variable_set(:@installer, installer) validator.instance_variable_set(:@installer, installer)
validator.send(:configure_pod_targets, [aggregate_target], '9.0') validator.send(:configure_pod_targets, [aggregate_target], [pod_target_installation_results], '9.0')
debug_configuration_one.build_settings['SWIFT_VERSION'].should == '4.0' debug_configuration_one.build_settings['SWIFT_VERSION'].should == '4.0'
debug_configuration_two.build_settings['SWIFT_VERSION'].should == '3.2' debug_configuration_two.build_settings['SWIFT_VERSION'].should == '3.2'
end end
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment