Remove all PBX state from targets, improve project generation performance

parent 1c6dedd1
......@@ -8,6 +8,10 @@ To install release candidates run `[sudo] gem install cocoapods --pre`
##### 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.
[Jacek Suliga](https://github.com/jmkk)
......
......@@ -173,14 +173,14 @@ module Pod
private
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
# Generate the 'Pods/Pods.xcodeproj' project.
#
def generate_pods_project(generator = create_generator)
UI.section 'Generating Pods project' do
generator.generate!
@target_installation_results = generator.generate!
@pods_project = generator.project
run_podfile_post_install_hooks
generator.write
......@@ -200,6 +200,11 @@ module Pod
#
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.
#
attr_reader :pods_project
......
......@@ -6,10 +6,15 @@ module Pod
class PodsProjectGenerator
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_installation_result'
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/aggregate_target_installer'
# @return [Sandbox] The sandbox where the Pods should be installed.
#
attr_reader :sandbox
# @return [Pod::Project] the `Pods/Pods.xcodeproj` project.
#
attr_reader :project
......@@ -20,10 +25,6 @@ module Pod
#
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.
#
attr_reader :pod_targets
......@@ -43,16 +44,16 @@ module Pod
# Initialize a new instance
#
# @param [Array<AggregateTarget>] aggregate_targets @see #aggregate_targets
# @param [Sandbox] sandbox @see #sandbox
# @param [Array<AggregateTarget>] aggregate_targets @see #aggregate_targets
# @param [Array<PodTarget>] pod_targets @see #pod_targets
# @param [Analyzer] analysis_result @see #analysis_result
# @param [InstallationOptions] installation_options @see #installation_options
# @param [Config] config @see #config
#
def initialize(aggregate_targets, sandbox, pod_targets, analysis_result, installation_options, config)
@aggregate_targets = aggregate_targets
def initialize(sandbox, aggregate_targets, pod_targets, analysis_result, installation_options, config)
@sandbox = sandbox
@aggregate_targets = aggregate_targets
@pod_targets = pod_targets
@analysis_result = analysis_result
@installation_options = installation_options
......@@ -62,9 +63,10 @@ module Pod
def generate!
prepare
install_file_references
install_libraries
integrate_targets
set_target_dependencies
@target_installation_results = install_libraries
integrate_targets(@target_installation_results.pod_target_installation_results)
wire_target_dependencies(@target_installation_results)
@target_installation_results
end
def write
......@@ -76,11 +78,16 @@ module Pod
UI.message('- Generating deterministic UUIDs') { project.predictabilize_uuids }
end
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|
next unless target.respond_to?(:symbol_type)
next unless library_product_types.include? target.symbol_type
pod_target = pod_targets.find { |pt| pt.native_target == target }
next if pod_target.nil? || pod_target.test_native_targets.empty?
pod_target.test_native_targets.each { |test_native_target| scheme.add_test_target(test_native_target) }
pod_target_installation_results.each do |pod_target_installation_result|
next unless pod_target_installation_result.native_target == target
pod_target_installation_result.test_native_targets.each do |test_native_target|
scheme.add_test_target(test_native_target)
end
end
end
project.save
end
......@@ -104,6 +111,8 @@ module Pod
private
InstallationResults = Struct.new(:pod_target_installation_results, :aggregate_target_installation_results)
def create_project
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)
......@@ -170,41 +179,50 @@ module Pod
pod_target.umbrella_header_path
end.compact.group_by(&:dirname)
pod_targets.sort_by(&:name).each do |pod_target|
target_installer = PodTargetInstaller.new(sandbox, project, pod_target, umbrella_headers_by_dir)
target_installer.install!
end
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)
[pod_target.name, target_installer.install!]
end]
aggregate_targets.sort_by(&:name).each do |target|
target_installer = AggregateTargetInstaller.new(sandbox, project, target)
target_installer.install!
# Hook up system framework dependencies for the pod targets that were just installed.
pod_target_installation_result_values = pod_target_installation_results.values.compact
unless pod_target_installation_result_values.empty?
add_system_framework_dependencies(pod_target_installation_result_values)
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
def integrate_targets
pod_targets_to_integrate = pod_targets.select { |pt| !pt.test_native_targets.empty? || pt.contains_script_phases? }
unless pod_targets_to_integrate.empty?
def integrate_targets(pod_target_installation_results)
pod_installations_to_integrate = pod_target_installation_results.values.select do |pod_target_installation_result|
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
pod_targets_to_integrate.each do |pod_target|
PodTargetIntegrator.new(pod_target).integrate!
pod_installations_to_integrate.each do |pod_target_installation_result|
PodTargetIntegrator.new(pod_target_installation_result).integrate!
end
end
end
end
def add_system_framework_dependencies
# @TODO: Add Specs
pod_targets.select(&:should_build?).sort_by(&:name).each do |pod_target|
test_file_accessors, file_accessors = pod_target.file_accessors.partition { |fa| fa.spec.test_specification? }
file_accessors.each do |file_accessor|
add_system_frameworks_to_native_target(file_accessor, pod_target.native_target)
end
test_file_accessors.each do |test_file_accessor|
native_target = pod_target.native_target_for_spec(test_file_accessor.spec)
add_system_frameworks_to_native_target(test_file_accessor, native_target)
def add_system_framework_dependencies(pod_target_installation_results)
sorted_installation_results = pod_target_installation_results.sort_by do |pod_target_installation_result|
pod_target_installation_result.target.name
end
sorted_installation_results.each do |target_installation_result|
pod_target = target_installation_result.target
next unless pod_target.should_build?
pod_target.file_accessors.each do |file_accessor|
native_target = target_installation_result.native_target_for_spec(file_accessor.spec)
add_system_frameworks_to_native_target(native_target, file_accessor)
end
end
end
......@@ -212,67 +230,73 @@ module Pod
# Adds a target dependency for each pod spec to each aggregate target and
# 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]
#
def set_target_dependencies
def wire_target_dependencies(target_installation_results)
frameworks_group = project.frameworks_group
test_only_pod_targets = pod_targets.dup
pod_targets_for_deps = Set.new
pod_extension_targets = Set.new
aggregate_targets.each do |aggregate_target|
pod_target_installation_results_hash = target_installation_results.pod_target_installation_results
aggregate_target_installation_results_hash = target_installation_results.aggregate_target_installation_results
# 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) &
[: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' }
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.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
# Wire up all pod target dependencies to aggregate target.
aggregate_target.pod_targets.each do |pod_target|
test_only_pod_targets.delete(pod_target)
configure_app_extension_api_only_for_target(aggregate_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
pod_target_native_target = pod_target_installation_results_hash[pod_target.name].native_target
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
end
end
# Wire up remaining pod targets used only by tests and are not used by any aggregate target.
test_only_pod_targets.each do |pod_target|
unless pod_target.should_build?
add_pod_target_test_dependencies(pod_target, frameworks_group)
next
# Wire up pod targets
pod_target_installation_results_hash.values.each do |pod_target_installation_result|
pod_target = pod_target_installation_result.target
native_target = pod_target_installation_result.native_target
# 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
unless pod_target.static_framework?
pod_targets_for_deps << pod_target
add_pod_target_test_dependencies(pod_target, frameworks_group)
# Wire up all dependencies to this pod target, if any.
dependent_targets = pod_target.dependent_targets
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
# 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
......@@ -307,55 +331,25 @@ module Pod
# @! group Private Helpers
private
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)
def add_system_frameworks_to_native_target(native_target, file_accessor)
file_accessor.spec_consumer.frameworks.each do |framework|
native_target.add_system_framework(framework)
end
end
def add_resource_bundles_to_native_target(dependent_target, native_target)
resource_bundle_targets = dependent_target.resource_bundle_targets + dependent_target.test_resource_bundle_targets
resource_bundle_targets.each do |resource_bundle_target|
native_target.add_dependency(resource_bundle_target)
def add_framework_file_reference_to_native_target(native_target, pod_target, dependent_target, frameworks_group)
if pod_target.requires_frameworks? && !pod_target.static_framework? && dependent_target.should_build?
product_ref = frameworks_group.files.find { |f| f.path == dependent_target.product_name } ||
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
# 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)
target.native_target.build_configurations.each do |config|
def configure_app_extension_api_only_to_native_target(native_target)
native_target.build_configurations.each do |config|
config.build_settings['APPLICATION_EXTENSION_API_ONLY'] = 'YES'
end
end
......
......@@ -8,21 +8,21 @@ module Pod
class AggregateTargetInstaller < TargetInstaller
# 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!
UI.message "- Installing target `#{target.name}` #{target.platform}" do
add_target
native_target = add_target
create_support_files_dir
create_support_files_group
create_xcconfig_file
create_xcconfig_file(native_target)
if target.requires_frameworks?
create_info_plist_file(target.info_plist_path, native_target, target.version, target.platform)
create_module_map
create_umbrella_header
create_module_map(native_target)
create_umbrella_header(native_target)
elsif target.uses_swift?
create_module_map
create_umbrella_header
create_module_map(native_target)
create_umbrella_header(native_target)
end
# Because embedded targets live in their host target, CocoaPods
# copies all of the embedded target's pod_targets to its host
......@@ -31,10 +31,11 @@ module Pod
# embedded in embedded targets.
#
create_embed_frameworks_script unless target.requires_host_target?
create_bridge_support_file
create_bridge_support_file(native_target)
create_copy_resources_script
create_acknowledgements
create_dummy_source
create_dummy_source(native_target)
TargetInstallationResult.new(target, native_target)
end
end
......@@ -87,9 +88,12 @@ module Pod
# 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]
#
def create_xcconfig_file
def create_xcconfig_file(native_target)
native_target.build_configurations.each do |configuration|
path = target.xcconfig_path(configuration.name)
gen = Generator::XCConfig::AggregateXCConfig.new(target, configuration.name)
......@@ -106,9 +110,12 @@ module Pod
# target because it is needed for environments interpreted at
# runtime.
#
# @param [PBXNativeTarget] native_target
# the native target to add the bridge support file into.
#
# @return [void]
#
def create_bridge_support_file
def create_bridge_support_file(native_target)
if target.podfile.generate_bridge_support?
path = target.bridge_support_path
headers = native_target.headers_build_phase.files.map { |bf| sandbox.root + bf.file_ref.path }
......
......@@ -25,33 +25,39 @@ module Pod
# 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!
unless target.should_build?
add_resources_bundle_targets
return
end
UI.message "- Installing target `#{target.name}` #{target.platform}" do
add_target
create_support_files_dir
if target.contains_test_specifications?
add_test_targets
add_test_app_host_targets
test_file_accessors, file_accessors = target.file_accessors.partition { |fa| fa.spec.test_specification? }
unless target.should_build?
# For targets that should not be built (e.g. pre-built vendored frameworks etc), we add a placeholder
# 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
add_resources_bundle_targets
add_files_to_build_phases
create_xcconfig_file
create_test_xcconfig_files if target.contains_test_specifications?
create_support_files_dir
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?
create_module_map do |generator|
create_module_map(native_target) do |generator|
generator.headers.concat module_map_additional_headers
end
create_umbrella_header do |generator|
file_accessors = target.file_accessors
file_accessors = file_accessors.reject { |f| f.spec.test_specification? } if target.contains_test_specifications?
create_umbrella_header(native_target) do |generator|
generator.imports += if header_mappings_dir
file_accessors.flat_map(&:public_headers).map do |pathname|
pathname.relative_path_from(header_mappings_dir)
......@@ -66,24 +72,24 @@ module Pod
unless target.static_framework?
create_info_plist_file(target.info_plist_path, native_target, target.version, target.platform)
end
create_build_phase_to_symlink_header_folders
create_build_phase_to_symlink_header_folders(native_target)
elsif target.uses_swift?
add_swift_static_library_compatibility_header_phase
add_swift_static_library_compatibility_header_phase(native_target)
end
unless skip_pch?(target.non_test_specs)
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])
end
unless skip_pch?(target.test_specs)
target.supported_test_types.each do |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, file_accessors, target.platform, target.test_native_targets)
create_prefix_header(path, test_file_accessors, target.platform, test_native_targets)
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
......@@ -185,11 +191,16 @@ module Pod
#
# @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|
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
public_headers = file_accessor.public_headers.map(&:realpath)
private_headers = file_accessor.private_headers.map(&:realpath)
......@@ -225,13 +236,16 @@ module Pod
# Adds the test app host targets for the library to the Pods project with the
# 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
target.test_specs.each do |test_spec|
def add_test_app_host_targets(test_native_targets)
target.test_specs.map do |test_spec|
spec_consumer = test_spec.consumer(target.platform)
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
app_host_target = project.targets.find { |t| t.name == name }
if app_host_target.nil?
......@@ -247,38 +261,38 @@ module Pod
create_info_plist_file(app_host_info_plist_path, app_host_target, '1.0.0', target.platform, :appl)
end
# Wire all test native targets with the app host.
native_test_target = target.native_target_for_spec(test_spec)
native_test_target.build_configurations.each do |configuration|
test_native_target = test_native_target_from_spec_consumer(spec_consumer, test_native_targets)
test_native_target.build_configurations.each do |configuration|
test_host = "$(BUILT_PRODUCTS_DIR)/#{name}.app/"
test_host << 'Contents/MacOS/' if target.platform == :osx
test_host << name.to_s
configuration.build_settings['TEST_HOST'] = test_host
end
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
end
end.compact
end
# Adds the test targets for the library to the Pods project with the
# appropriate build configurations.
#
# @return [void]
# @return [Array<PBXNativeTarget>] the test native targets created.
#
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)
name = target.test_target_label(test_type)
platform_name = target.platform.name
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)
native_test_target.product_reference.name = name
test_native_target = project.new_target(product_type, name, platform_name, deployment_target, nil, language)
test_native_target.product_reference.name = name
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
native_test_target.build_configurations.each do |configuration|
test_native_target.build_configurations.each do |configuration|
configuration.build_settings.merge!(custom_build_settings)
# target_installer will automatically add an empty `OTHER_LDFLAGS`. For test
# targets those are set via a test xcconfig file instead.
......@@ -307,9 +321,9 @@ module Pod
# 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
# 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
......@@ -318,14 +332,17 @@ module Pod
# @note The source files are grouped by Pod and in turn by subspec
# (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
target.file_accessors.each do |file_accessor|
file_accessor.resource_bundles.each do |bundle_name, paths|
# @return [Array<PBXNativeTarget] the resource bundle native targets created.
#
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)
bundle_target = project.new_resources_bundle(label, file_accessor.spec_consumer.platform_name)
bundle_target.product_reference.tap do |bundle_product|
resource_bundle_target = project.new_resources_bundle(label, file_accessor.spec_consumer.platform_name)
resource_bundle_target.product_reference.tap do |bundle_product|
bundle_file_name = "#{bundle_name}.bundle"
bundle_product.name = bundle_file_name
end
......@@ -333,42 +350,26 @@ module Pod
filter_resource_file_references(paths) do |resource_phase_refs, compile_phase_refs|
# Resource bundles are only meant to have resources, so install everything
# 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
native_target = target.native_target_for_spec(file_accessor.spec_consumer.spec)
target.user_build_configurations.each do |bc_name, type|
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
resource_bundle_target.add_build_configuration(bc_name, type)
end
resource_bundle_target.deployment_target = deployment_target
# Create Info.plist file for bundle
path = target.info_plist_path
path.dirname.mkdir unless path.dirname.exist?
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
# 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
# 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)')
end
......@@ -383,15 +384,23 @@ module Pod
c.build_settings['TARGETED_DEVICE_FAMILY'] = family
end
end
resource_bundle_target
end
end
end
# 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]
#
def create_xcconfig_file
def create_xcconfig_file(native_target, resource_bundle_targets)
path = target.xcconfig_path
xcconfig_gen = Generator::XCConfig::PodXCConfig.new(target)
update_changed_file(xcconfig_gen, path)
......@@ -402,21 +411,27 @@ module Pod
end
# 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
# 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]
#
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|
path = target.xcconfig_path(test_type.to_s)
xcconfig_gen = Generator::XCConfig::PodXCConfig.new(target, true)
update_changed_file(xcconfig_gen, 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_swift_debug_hack(test_target_bc)
test_target_bc.base_configuration_reference = xcconfig_file_ref
......@@ -424,7 +439,7 @@ module Pod
end
# 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
......@@ -489,9 +504,12 @@ module Pod
# header_mappings_dir interferes with xcodebuild's expectations
# about the existence of private or public headers.
#
# @param [PBXNativeTarget] native_target
# the native target to add the script phase into.
#
# @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
build_phase = native_target.new_shell_script_build_phase('Create Symlinks to Header Folders')
......@@ -515,7 +533,7 @@ module Pod
# @param [Platform] platform
# 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.
#
# @return [void]
......@@ -600,8 +618,8 @@ module Pod
end
end
def create_module_map
return super unless custom_module_map
def create_module_map(native_target)
return super(native_target) unless custom_module_map
path = target.module_map_path
UI.message "- Copying module map file to #{UI.path(path)}" do
......@@ -631,8 +649,8 @@ module Pod
end
end
def create_umbrella_header
return super unless custom_module_map
def create_umbrella_header(native_target)
return super(native_target) unless custom_module_map
end
def custom_module_map
......@@ -688,15 +706,41 @@ module Pod
project.pod_support_files_group(pod_name, dir)
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,
# 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`
# 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.
#
# @param [PBXNativeTarget] native_target
# the native target to add the Swift static library script phase into.
#
# @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')
relative_module_map_path = target.module_map_path.relative_path_from(target.sandbox.root)
......
......@@ -6,16 +6,16 @@ module Pod
# the test targets included by each pod target.
#
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)
@target = target
def initialize(target_installation_result)
@target_installation_result = target_installation_result
end
# Integrates the pod target.
......@@ -24,13 +24,13 @@ module Pod
#
def integrate!
UI.section(integration_message) do
target.test_specs_by_native_target.each do |native_target, test_specs|
add_embed_frameworks_script_phase(native_target)
add_copy_resources_script_phase(native_target)
UserProjectIntegrator::TargetIntegrator.create_or_update_user_script_phases(script_phases_for_specs(test_specs), native_target)
target_installation_result.test_specs_by_native_target.each do |test_native_target, test_specs|
add_embed_frameworks_script_phase(test_native_target)
add_copy_resources_script_phase(test_native_target)
UserProjectIntegrator::TargetIntegrator.create_or_update_user_script_phases(script_phases_for_specs(test_specs), test_native_target)
end
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
......@@ -89,6 +89,12 @@ module Pod
"Integrating target `#{target.name}`"
end
# @return [PodTarget] the target part of the installation result.
#
def target
target_installation_result.target
end
# @param [Array<Specification] specs
# 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
#
# @note The `PODS_HEADERS_SEARCH_PATHS` overrides the xcconfig.
#
# @return [void]
# @return [PBXNativeTarget] the native target that was added.
#
def add_target
product_type = target.product_type
name = target.label
platform = target.platform.name
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 = @native_target.product_reference
product = native_target.product_reference
product.name = product_name
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
@native_target.build_configurations.each do |configuration|
native_target.build_configurations.each do |configuration|
configuration.build_settings.merge!(custom_build_settings)
end
target.native_target = @native_target
native_target
end
# @return [String] The deployment target.
......@@ -175,9 +175,12 @@ module Pod
# Creates the module map file which ensures that the umbrella header is
# recognized with a customized path
#
# @param [PBXNativeTarget] native_target
# the native target to link the module map file into.
#
# @return [void]
#
def create_module_map
def create_module_map(native_target)
path = target.module_map_path
UI.message "- Generating module map file at #{UI.path(path)}" do
generator = Generator::ModuleMap.new(target)
......@@ -195,10 +198,15 @@ module Pod
# Generates a header which ensures that all header files are exported
# in the module map
#
# @param [PBXNativeTarget] native_target
# the native target to link the umbrella header file into.
#
# @yield_param [Generator::UmbrellaHeader]
# yielded once to configure the imports
#
def create_umbrella_header
# @return [void]
#
def create_umbrella_header(native_target)
path = target.umbrella_header_path
UI.message "- Generating umbrella header at #{UI.path(path)}" do
generator = Generator::UmbrellaHeader.new(target)
......@@ -220,9 +228,12 @@ module Pod
# Generates a dummy source file for each target so libraries that contain
# only categories build.
#
# @param [PBXNativeTarget] native_target
# the native target to link the dummy source file into.
#
# @return [void]
#
def create_dummy_source
def create_dummy_source(native_target)
path = target.dummy_source_path
generator = Generator::DummySource.new(target.label)
update_changed_file(generator, path)
......@@ -230,13 +241,6 @@ module Pod
native_target.source_build_phase.add_file_reference(file_reference)
end
# @return [PBXNativeTarget] the target generated by the installation
# process.
#
# @note Generated by the {#add_target} step.
#
attr_reader :native_target
private
#-----------------------------------------------------------------------#
......
......@@ -142,6 +142,8 @@ module Pod
#-------------------------------------------------------------------------#
# @!group Framework support
# @return [Boolean] whether the generated target needs to be implemented
# as a framework
#
......@@ -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
# @return [Pathname] the folder where to store the support files of this
......
......@@ -63,7 +63,8 @@ module Pod
# @param [Array<String>] user_target_uuids @see #user_target_uuids
# @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)
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?
......
......@@ -48,21 +48,6 @@ module Pod
#
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
#
# @param [Sandbox] sandbox @see Target#sandbox
......@@ -74,7 +59,8 @@ module Pod
# @param [Array<Sandbox::FileAccessor>] file_accessors @see #file_accessors
# @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)
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?
......@@ -86,9 +72,6 @@ module Pod
@scope_suffix = scope_suffix
@test_specs, @non_test_specs = @specs.partition(&:test_specification?)
@build_headers = Sandbox::HeadersStore.new(sandbox, 'Private', :private)
@resource_bundle_targets = []
@test_resource_bundle_targets = []
@test_native_targets = []
@dependent_targets = []
@test_dependent_targets = []
@build_config_cache = {}
......@@ -108,7 +91,6 @@ module Pod
cache[cache_key]
else
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.test_dependent_targets = test_dependent_targets.flat_map { |pt| pt.scoped(cache) }.select { |pt| pt.target_definitions == [target_definition] }
cache[cache_key] = target
......@@ -218,13 +200,6 @@ module Pod
!script_phases.empty?
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.
#
def contains_test_specifications?
......@@ -304,22 +279,6 @@ module Pod
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.
# 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.
......
......@@ -501,43 +501,33 @@ module Pod
perform_post_install_actions).each { |m| @installer.send(m) }
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
end
def configure_pod_targets(targets, deployment_target)
test_only_pod_targets = @installer.pod_targets - targets.flat_map(&:pod_targets)
targets.each do |target|
target.pod_targets.each do |pod_target|
update_pod_target_build_settings(pod_target)
if pod_target.uses_swift?
pod_target.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
def configure_pod_targets(targets, target_installation_results, deployment_target)
target_installation_results.first.values.each do |pod_target_installation_result|
pod_target = pod_target_installation_result.target
native_target = pod_target_installation_result.native_target
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
if pod_target.uses_swift?
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
targets.each do |target|
if target.pod_targets.any?(&:uses_swift?) && consumer.platform_name == :ios &&
(deployment_target.nil? || Version.new(deployment_target).major < 8)
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
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
def validate_vendored_dynamic_frameworks
......@@ -597,7 +587,7 @@ module Pod
UI.message "\nTesting with `xcodebuild`.\n".yellow do
pod_target = @installer.pod_targets.find { |pt| pt.pod_name == spec.root.name }
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')
parsed_output = parse_xcodebuild_output(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_
target_definitions, file_accessors, scope_suffix)
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
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)
end
......
......@@ -18,7 +18,7 @@ module Pod
@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?
@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?
@target.target_definition.whitelist_pod_for_configuration(@specs.first.name, 'Release')
end
......
......@@ -607,7 +607,7 @@ module Pod
describe 'for proper other ld flags' do
def stub_aggregate_target(pod_targets, target_definition = nil, search_paths_aggregate_targets: [])
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
end
end
......
......@@ -88,29 +88,25 @@ module Pod
end
it 'does not enable the GCC_WARN_INHIBIT_ALL_WARNINGS flag by default' do
@installer.install!
@installer.target.native_target.build_configurations.each do |config|
@installer.install!.native_target.build_configurations.each do |config|
config.build_settings['GCC_WARN_INHIBIT_ALL_WARNINGS'].should.be.nil
end
end
it 'will be built as static library' do
@installer.install!
@installer.target.native_target.build_configurations.each do |config|
@installer.install!.native_target.build_configurations.each do |config|
config.build_settings['MACH_O_TYPE'].should == 'staticlib'
end
end
it 'will be skipped when installing' do
@installer.install!
@installer.target.native_target.build_configurations.each do |config|
@installer.install!.native_target.build_configurations.each do |config|
config.build_settings['SKIP_INSTALL'].should == 'YES'
end
end
it 'has a PRODUCT_BUNDLE_IDENTIFIER set' do
@installer.install!
@installer.target.native_target.build_configurations.each do |config|
@installer.install!.native_target.build_configurations.each do |config|
config.build_settings['PRODUCT_BUNDLE_IDENTIFIER'].should == 'org.cocoapods.${PRODUCT_NAME:rfc1034identifier}'
end
end
......@@ -219,8 +215,7 @@ module Pod
end
it 'creates a dummy source to ensure the creation of a single base library' do
@installer.install!
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.path.include?('Pods-SampleProject-dummy.m') }
build_file.should.be.not.nil
build_file.file_ref.path.should == 'Pods-SampleProject-dummy.m'
......@@ -251,9 +246,7 @@ module Pod
it 'installs umbrella headers for swift static libraries' do
@pod_target.stubs(:uses_swift? => true)
@target.stubs(:uses_swift? => true)
@installer.install!
build_files = @installer.target.native_target.headers_build_phase.files
build_files = @installer.install!.native_target.headers_build_phase.files
build_file = build_files.find { |bf| bf.file_ref.path.include?('Pods-SampleProject-umbrella.h') }
build_file.should.not.be.nil
build_file.settings.should == { 'ATTRIBUTES' => ['Project'] }
......@@ -262,9 +255,7 @@ module Pod
it 'installs umbrella headers for frameworks' do
@pod_target.stubs(:requires_frameworks? => true)
@target.stubs(:requires_frameworks? => true)
@installer.install!
build_files = @installer.target.native_target.headers_build_phase.files
build_files = @installer.install!.native_target.headers_build_phase.files
build_file = build_files.find { |bf| bf.file_ref.path.include?('Pods-SampleProject-umbrella.h') }
build_file.should.not.be.nil
build_file.settings.should == { 'ATTRIBUTES' => ['Public'] }
......
......@@ -76,8 +76,7 @@ module Pod
end
it 'does not enable the GCC_WARN_INHIBIT_ALL_WARNINGS flag by default' do
@installer.install!
@installer.target.native_target.build_configurations.each do |config|
@installer.install!.native_target.build_configurations.each do |config|
config.build_settings['GCC_WARN_INHIBIT_ALL_WARNINGS'].should.be.nil
end
end
......@@ -182,13 +181,13 @@ module Pod
end
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.first.name.should == 'CoconutLib'
native_test_target = @project.targets[1]
native_test_target.name.should == 'CoconutLib-Unit-Tests'
native_test_target.product_reference.name.should == 'CoconutLib-Unit-Tests'
native_test_target.build_configurations.each do |bc|
test_native_target = @project.targets[1]
test_native_target.name.should == 'CoconutLib-Unit-Tests'
test_native_target.product_reference.name.should == 'CoconutLib-Unit-Tests'
test_native_target.build_configurations.each do |bc|
bc.build_settings['PRODUCT_NAME'].should == 'CoconutLib-Unit-Tests'
bc.build_settings['PRODUCT_MODULE_NAME'].should.be.nil
bc.build_settings['CODE_SIGNING_REQUIRED'].should == 'YES'
......@@ -196,18 +195,18 @@ module Pod
bc.build_settings['CODE_SIGN_IDENTITY'].should == 'iPhone Developer'
bc.build_settings['INFOPLIST_FILE'].should == 'Target Support Files/CoconutLib/CoconutLib-Unit-Tests-Info.plist'
end
native_test_target.symbol_type.should == :unit_test_bundle
@coconut_pod_target.test_native_targets.count.should == 1
test_native_target.symbol_type.should == :unit_test_bundle
installation_result.test_native_targets.count.should == 1
end
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.first.name.should == 'CoconutLib'
native_test_target = @project.targets[1]
native_test_target.name.should == 'CoconutLib-Unit-Tests'
native_test_target.product_reference.name.should == 'CoconutLib-Unit-Tests'
native_test_target.build_configurations.each do |bc|
test_native_target = @project.targets[1]
test_native_target.name.should == 'CoconutLib-Unit-Tests'
test_native_target.product_reference.name.should == 'CoconutLib-Unit-Tests'
test_native_target.build_configurations.each do |bc|
bc.build_settings['PRODUCT_NAME'].should == 'CoconutLib-Unit-Tests'
bc.build_settings['PRODUCT_MODULE_NAME'].should.be.nil
bc.build_settings['CODE_SIGNING_REQUIRED'].should.be.nil
......@@ -215,20 +214,20 @@ module Pod
bc.build_settings['CODE_SIGN_IDENTITY'].should == ''
bc.build_settings['INFOPLIST_FILE'].should == 'Target Support Files/CoconutLib/CoconutLib-Unit-Tests-Info.plist'
end
native_test_target.symbol_type.should == :unit_test_bundle
@coconut_pod_target2.test_native_targets.count.should == 1
test_native_target.symbol_type.should == :unit_test_bundle
installation_result.test_native_targets.count.should == 1
end
it 'adds swiftSwiftOnoneSupport ld flag to the debug configuration' do
@coconut_pod_target.stubs(:uses_swift?).returns(true)
@installer.install!
native_test_target = @project.targets[1]
debug_configuration = native_test_target.build_configurations.find(&:debug?)
test_native_target = @project.targets[1]
debug_configuration = test_native_target.build_configurations.find(&:debug?)
debug_configuration.build_settings['OTHER_LDFLAGS'].sort.should == [
'$(inherited)',
'-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
end
......@@ -241,9 +240,9 @@ module Pod
'Coconut.m',
'CoconutLib-dummy.m',
]
native_test_target = @project.targets[1]
native_test_target.source_build_phase.files.count.should == 1
native_test_target.source_build_phase.files.map(&:display_name).sort.should == [
test_native_target = @project.targets[1]
test_native_target.source_build_phase.files.count.should == 1
test_native_target.source_build_phase.files.map(&:display_name).sort.should == [
'CoconutTests.m',
]
end
......@@ -264,9 +263,9 @@ module Pod
it 'adds test xcconfig file reference for test resource bundle targets' do
@coconut_spec.test_specs.first.resource_bundle = { 'CoconutLibTestResources' => ['Model.xcdatamodeld'] }
@installer.install!
@coconut_pod_target.resource_bundle_targets.count.should == 0
@coconut_pod_target.test_resource_bundle_targets.count.should == 1
installation_result = @installer.install!
installation_result.resource_bundle_targets.count.should == 0
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.build_configurations.each do |bc|
bc.base_configuration_reference.real_path.basename.to_s.should == 'CoconutLib.unit.xcconfig'
......@@ -313,12 +312,12 @@ module Pod
app_host_target = @project.targets[2]
app_host_target.name.should == 'AppHost-iOS-Unit-Tests'
app_host_target.symbol_type.should == :application
native_test_target = @project.targets[1]
native_test_target.build_configurations.each do |bc|
test_native_target = @project.targets[1]
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'
end
@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,
},
}
......@@ -334,12 +333,12 @@ module Pod
bc.build_settings['PRODUCT_NAME'].should == 'AppHost-macOS-Unit-Tests'
bc.build_settings['PRODUCT_BUNDLE_IDENTIFIER'].should == 'org.cocoapods.${PRODUCT_NAME:rfc1034identifier}'
end
native_test_target = @project.targets[1]
native_test_target.build_configurations.each do |bc|
test_native_target = @project.targets[1]
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'
end
@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,
},
}
......@@ -386,8 +385,7 @@ module Pod
#--------------------------------------#
it 'adds the source files of each pod to the target of the Pod library' do
@installer.install!
names = @installer.target.native_target.source_build_phase.files.map { |bf| bf.file_ref.display_name }
names = @installer.install!.native_target.source_build_phase.files.map { |bf| bf.file_ref.display_name }
names.should.include('Banana.m')
end
......@@ -717,9 +715,8 @@ module Pod
end
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
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.should.be.not.nil
build_file.file_ref.path.should == dummy_source_basename
......@@ -728,10 +725,11 @@ module Pod
#--------------------------------------------------------------------------------#
it 'does not create a target if the specification does not define source files' do
@pod_target.file_accessors.first.stubs(:source_files).returns([])
it 'creates an aggregate placeholder native target if the target should not be built' do
@pod_target.stubs(:should_build?).returns(false)
@installer.install!
@project.targets.should == []
@project.targets.map(&:name).should == ['BananaLib']
@project.targets.first.class.should == Xcodeproj::Project::PBXAggregateTarget
end
#--------------------------------------------------------------------------------#
......@@ -837,9 +835,7 @@ module Pod
it 'flags should not be added to dtrace files' do
@installer.target.target_definitions.first.stubs(:inhibits_warnings_for_pod?).returns(true)
@installer.install!
dtrace_files = @installer.target.native_target.source_build_phase.files.select do |sf|
dtrace_files = @installer.install!.native_target.source_build_phase.files.select do |sf|
File.extname(sf.file_ref.path) == '.d'
end
dtrace_files.each do |dt|
......
......@@ -14,13 +14,12 @@ module Pod
@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)
@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)
@coconut_pod_target.stubs(:test_native_targets).returns([@test_native_target])
@target_installation_result = TargetInstallationResult.new(@coconut_pod_target, @native_target, [], [@test_native_target])
end
describe '#integrate!' 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.map(&:display_name).should == [
'[CP] Embed Pods Frameworks',
......@@ -36,7 +35,7 @@ module Pod
"${PODS_CONFIGURATION_BUILD_DIR}/DebugLib/DebugLibPng#{i}.png"
end
@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 == [
'[CP] Embed Pods Frameworks',
'[CP] Copy Pods Resources',
......@@ -50,7 +49,7 @@ module Pod
resource_paths = ['${PODS_CONFIGURATION_BUILD_DIR}/TestResourceBundle.bundle']
@coconut_pod_target.stubs(:framework_paths).returns(framework_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.map(&:display_name).should == [
'[CP] Embed Pods Frameworks',
......@@ -74,7 +73,7 @@ module Pod
it 'integrates test native target with shell script phases' do
@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[2].display_name.should == '[CP-User] Hello World'
@test_native_target.build_phases[2].shell_script.should == 'echo "Hello World"'
......@@ -82,7 +81,7 @@ module Pod
it 'integrates native target with shell script phases' do
@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[0].display_name.should == '[CP-User] Hello World'
@native_target.build_phases[0].shell_script.should == 'echo "Hello World"'
......
......@@ -15,8 +15,7 @@ module Pod
end
it 'adds the architectures to the custom build configurations of the user target' do
@installer.send(:add_target)
@installer.send(:native_target).resolved_build_setting('ARCHS').should == {
@installer.send(:add_target).resolved_build_setting('ARCHS').should == {
'Release' => ['$(ARCHS_STANDARD_64_BIT)'],
'Debug' => ['$(ARCHS_STANDARD_64_BIT)'],
'AppStore' => ['$(ARCHS_STANDARD_64_BIT)'],
......@@ -25,16 +24,15 @@ module Pod
end
it 'always clears the OTHER_LDFLAGS and OTHER_LIBTOOLFLAGS, because these lib targets do not ever need any' do
@installer.send(:add_target)
@installer.send(:native_target).resolved_build_setting('OTHER_LDFLAGS').values.uniq.should == ['']
@installer.send(:native_target).resolved_build_setting('OTHER_LIBTOOLFLAGS').values.uniq.should == ['']
native_target = @installer.send(:add_target)
native_target.resolved_build_setting('OTHER_LDFLAGS').values.uniq.should == ['']
native_target.resolved_build_setting('OTHER_LIBTOOLFLAGS').values.uniq.should == ['']
end
it 'adds Swift-specific build settings to the build settings' do
@target.stubs(:requires_frameworks?).returns(true)
@target.stubs(:uses_swift?).returns(true)
@installer.send(:add_target)
@installer.send(:native_target).resolved_build_setting('SWIFT_OPTIMIZATION_LEVEL').should == {
@installer.send(:add_target).resolved_build_setting('SWIFT_OPTIMIZATION_LEVEL').should == {
'Release' => '-Owholemodule',
'Debug' => '-Onone',
'Test' => nil,
......@@ -45,8 +43,7 @@ module Pod
it 'verify static framework is building a static library' do
@target.stubs(:requires_frameworks?).returns(true)
@target.stubs(:static_framework?).returns(true)
@installer.send(:add_target)
@installer.send(:native_target).resolved_build_setting('MACH_O_TYPE').should == {
@installer.send(:add_target).resolved_build_setting('MACH_O_TYPE').should == {
'Release' => 'staticlib',
'Debug' => 'staticlib',
'Test' => 'staticlib',
......
......@@ -4,556 +4,466 @@ module Pod
class Installer
class Xcode
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
before do
podfile = generate_podfile
lockfile = generate_lockfile
@installer = Pod::Installer.new(config.sandbox, podfile, lockfile)
@installer.send(:prepare)
@installer.send(:analyze)
@generator = @installer.send(:create_generator)
@ios_platform = Platform.new(:ios, '6.0')
@osx_platform = Platform.new(:osx, '10.8')
@ios_target_definition = fixture_target_definition('SampleApp-iOS', @ios_platform)
@osx_target_definition = fixture_target_definition('SampleApp-macOS', @osx_platform)
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
describe '#prepare' do
before do
@generator.send(:prepare)
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
it "creates build configurations for all of the user's targets" do
@generator.generate!
@generator.project.build_configurations.map(&:name).sort.should == ['App Store', 'Debug', 'Release', 'Test']
end
#-------------------------------------#
describe '#install_file_references' do
it 'installs the file references' do
@generator.stubs(:pod_targets).returns([])
PodsProjectGenerator::FileReferencesInstaller.any_instance.expects(:install!)
@generator.send(:install_file_references)
end
it 'sets STRIP_INSTALLED_PRODUCT to NO for all configurations for the whole project' do
@generator.generate!
@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
#-------------------------------------#
describe '#install_libraries' do
it 'install the targets of the Pod project' 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
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
it 'sets the SYMROOT to the default value for all configurations for the whole project' do
@generator.generate!
@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
#-------------------------------------#
describe '#set_target_dependencies' do
def test_extension_target(symbol_type)
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])
it 'creates the correct Pods project' do
@generator.generate!
@generator.project.class.should == Pod::Project
end
@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
it 'does not try to set APPLICATION_EXTENSION_API_ONLY if there are no pod targets' do
lambda do
mock_user_target = mock('UserTarget', :symbol_type => :app_extension)
@target.stubs(:user_targets).returns([mock_user_target])
it 'installs file references' do
@generator.generate!
banana_group = @generator.project.group_for_spec('BananaLib')
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)
@target.stubs(:pod_targets).returns([])
it 'installs the correct targets in the project' do
@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)
end.should.not.raise NoMethodError
end
it 'sets the pod and aggregate target dependencies' do
@generator.generate!
@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
#--------------------------------------#
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
before do
spec = fixture_spec('coconut-lib/CoconutLib.podspec')
it 'adds target dependencies when inheriting search paths' do
inherited_target_definition = fixture_target_definition('SampleApp-iOS-Tests', @ios_platform)
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)
@pod_target = PodTarget.new(config.sandbox, false, {}, [], Platform.ios, [spec, *spec.recursive_subspecs], [target_definition])
@target = AggregateTarget.new(config.sandbox, false, {}, [], Platform.ios, target_definition, config.sandbox.root.dirname, nil, nil, [@pod_target])
it 'sets resource bundle target dependencies' do
@banana_spec.resource_bundles = { 'BananaLibResourcesBundle' => '**/*' }
@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'))
@generator.stubs(:project).returns(mock_project)
it 'sets the app host dependency for the tests that need it' do
@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)
@generator.stubs(:pod_targets).returns([@pod_target])
@generator.stubs(:aggregate_targets).returns([@target])
it 'configures APPLICATION_EXTENSION_API_ONLY for pod targets of an aggregate target' do
user_target = stub('SampleApp-iOS-User-Target', :symbol_type => :app_extension)
@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
it 'adds all test dependent targets to test native targets' do
mock_native_target = mock('CoconutLib')
mock_test_native_target = mock('CoconutLib-Unit-Tests', :symbol_type => :unit_test_bundle)
dependent_native_target = mock('DependentNativeTarget')
test_dependent_native_target = mock('TestDependentNativeTarget')
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)
it 'configures APPLICATION_EXTENSION_API_ONLY for app extension targets' do
user_target = stub('SampleApp-iOS-User-Target', :symbol_type => :app_extension)
@ios_target.stubs(:user_targets).returns([user_target])
@generator.generate!
build_settings = @generator.project.targets.find { |t| t.name == 'Pods-SampleApp-iOS' }.build_configurations.map(&:build_settings)
build_settings.each do |build_setting|
build_setting['APPLICATION_EXTENSION_API_ONLY'].should == 'YES'
end
end
it 'adds all test dependent targets to test native targets for static frameworks' do
mock_native_target = mock('CoconutLib')
dependent_native_target = mock('DependentNativeTarget')
dependent_target = mock('dependent-target')
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(: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)
it 'configures APPLICATION_EXTENSION_API_ONLY for watch2 extension targets' do
user_target = stub('SampleApp-iOS-User-Target', :symbol_type => :watch2_extension)
@ios_target.stubs(:user_targets).returns([user_target])
@generator.generate!
build_settings = @generator.project.targets.find { |t| t.name == 'Pods-SampleApp-iOS' }.build_configurations.map(&:build_settings)
build_settings.each do |build_setting|
build_setting['APPLICATION_EXTENSION_API_ONLY'].should == 'YES'
end
end
it 'adds dependencies to pod targets that are not part of any aggregate target' do
@target.stubs(:pod_targets).returns([])
@generator.expects(:pod_targets).returns([@pod_target])
mock_native_target = mock('CoconutLib')
mock_test_native_target = mock('CoconutLib-Unit-Tests', :symbol_type => :unit_test_bundle)
dependent_native_target = mock('DependentNativeTarget')
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)
it 'configures APPLICATION_EXTENSION_API_ONLY for tvOS extension targets' do
user_target = stub('SampleApp-iOS-User-Target', :symbol_type => :tv_extension)
@ios_target.stubs(:user_targets).returns([user_target])
@generator.generate!
build_settings = @generator.project.targets.find { |t| t.name == 'Pods-SampleApp-iOS' }.build_configurations.map(&:build_settings)
build_settings.each do |build_setting|
build_setting['APPLICATION_EXTENSION_API_ONLY'].should == 'YES'
end
end
it 'adds test dependencies to test native targets for a pod target that should not be built' do
mock_test_native_target = mock('CoconutLib-Unit-Tests', :symbol_type => :unit_test_bundle)
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.stubs(:test_native_targets).returns([mock_test_native_target])
@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)
it 'configures APPLICATION_EXTENSION_API_ONLY for Messages extension targets' do
user_target = stub('SampleApp-iOS-User-Target', :symbol_type => :messages_extension)
@ios_target.stubs(:user_targets).returns([user_target])
@generator.generate!
build_settings = @generator.project.targets.find { |t| t.name == 'Pods-SampleApp-iOS' }.build_configurations.map(&:build_settings)
build_settings.each do |build_setting|
build_setting['APPLICATION_EXTENSION_API_ONLY'].should == 'YES'
end
end
it 'sets resource bundles for not build pods as target dependencies of the test target' do
mock_test_native_target = mock('CoconutLib-Unit-Tests', :symbol_type => :unit_test_bundle)
@pod_target.stubs(:test_native_targets).returns([mock_test_native_target])
@pod_target.stubs(:test_dependent_targets).returns([])
@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')
it "uses the user project's object version for the pods project" do
tmp_directory = Pathname(Dir.tmpdir) + 'CocoaPods'
FileUtils.mkdir_p(tmp_directory)
proj = Xcodeproj::Project.new(tmp_directory + 'Yolo.xcodeproj', false, 1)
proj.save
@generator.send(:set_target_dependencies)
end
user_target = stub('SampleApp-iOS-User-Target', :symbol_type => :application)
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
mock_app_host_target = mock(:name => 'AppHost-iOS-Unit-Tests')
@generator.project.stubs(:targets).returns([mock_app_host_target])
target = AggregateTarget.new(config.sandbox, false, {}, [],
Platform.new(:ios, '6.0'), fixture_target_definition,
config.sandbox.root.dirname, proj, nil, [])
mock_test_native_target = mock('CoconutLib-Unit-Tests', :symbol_type => :unit_test_bundle)
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)
target.stubs(:user_targets).returns([user_target])
@pod_target.test_specs.first.requires_app_host = true
@pod_target.stubs(:test_native_targets).returns([mock_test_native_target])
@pod_target.stubs(:all_dependent_targets).returns([test_dependent_target])
@pod_target.stubs(:should_build? => false)
@generator = PodsProjectGenerator.new(config.sandbox, [target], [],
@analysis_result, @installation_options, config)
@generator.generate!
@generator.project.object_version.should == '1'
mock_test_native_target.expects(:add_dependency).with(test_dependent_native_target)
mock_test_native_target.expects(:add_dependency).with(mock_app_host_target)
@generator.send(:set_target_dependencies)
end
FileUtils.rm_rf(tmp_directory)
end
#--------------------------------------#
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
Xcodeproj::Project.any_instance.stubs(:recreate_user_schemes)
@generator.generate!
@generator.project.main_group.expects(:sort)
@generator.send(:write)
Xcodeproj::Project.any_instance.stubs(:recreate_user_schemes)
@generator.write
end
it 'saves the project to the given path' do
@generator.generate!
Xcodeproj::Project.any_instance.stubs(:recreate_user_schemes)
temporary_directory + 'Pods/Pods.xcodeproj'
@generator.project.expects(:save)
@generator.send(:write)
@generator.write
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
tmp_directory = Pathname(Dir.tmpdir) + 'CocoaPods'
FileUtils.mkdir_p(tmp_directory)
proj = Xcodeproj::Project.new(tmp_directory + 'Yolo.xcodeproj', false, 1)
proj.save
@generator.generate!
@generator.sandbox.stubs(:development_pods).returns('BananaLib' => fixture('BananaLib'))
aggregate_target = AggregateTarget.new(config.sandbox, false, {}, [], Platform.ios, fixture_target_definition, config.sandbox.root.dirname, proj, nil, [])
@generator.stubs(:aggregate_targets).returns([aggregate_target])
Xcodeproj::XCScheme.expects(:share_scheme).with(
@generator.project.path,
'BananaLib-iOS')
@generator.send(:prepare)
@generator.project.object_version.should == '1'
Xcodeproj::XCScheme.expects(:share_scheme).with(
@generator.project.path,
'BananaLib-macOS')
FileUtils.rm_rf(tmp_directory)
@generator.share_development_pod_schemes
end
end
describe 'sharing schemes of development pods' do
before do
spec = fixture_spec('banana-lib/BananaLib.podspec')
pod_target = fixture_pod_target(spec)
it 'shares test schemes' do
@generator.installation_options.
stubs(:share_schemes_for_development_pods).
returns(true)
@generator.sandbox.stubs(:development_pods).returns('CoconutLib' => fixture('CoconutLib'))
@generator.stubs(:pod_targets).returns([pod_target])
@generator.sandbox.stubs(:development_pods).returns('BananaLib' => fixture('BananaLib'))
end
@generator.generate!
it 'does not share by default' do
Xcodeproj::XCScheme.expects(:share_scheme).never
@generator.send(:share_development_pod_schemes)
end
Xcodeproj::XCScheme.expects(:share_scheme).with(
@generator.project.path,
'CoconutLib-iOS')
it 'can share all schemes' do
@generator.installation_options.
stubs(:share_schemes_for_development_pods).
returns(true)
Xcodeproj::XCScheme.expects(:share_scheme).with(
@generator.project.path,
'CoconutLib-iOS-Unit-Tests')
Xcodeproj::XCScheme.expects(:share_scheme).with(
@generator.project.path,
'BananaLib')
@generator.send(:share_development_pod_schemes)
end
Xcodeproj::XCScheme.expects(:share_scheme).with(
@generator.project.path,
'CoconutLib-macOS')
it 'shares test schemes' do
spec = fixture_spec('coconut-lib/CoconutLib.podspec')
target_definition = Podfile::TargetDefinition.new(:default, @installer.podfile.root_target_definitions.first)
pod_target = Pod::PodTarget.new(config.sandbox, false, {}, [], Platform.ios, [spec, *spec.recursive_subspecs], [target_definition])
pod_target.stubs(:should_build?).returns(true)
Xcodeproj::XCScheme.expects(:share_scheme).with(
@generator.project.path,
'CoconutLib-macOS-Unit-Tests')
@generator.installation_options.
stubs(:share_schemes_for_development_pods).
returns(true)
@generator.share_development_pod_schemes
end
@generator.stubs(:pod_targets).returns([pod_target])
@generator.sandbox.stubs(:development_pods).returns('CoconutLib' => fixture('CoconutLib'))
it 'allows opting out' do
@generator.installation_options.
stubs(:share_schemes_for_development_pods).
returns(false)
Xcodeproj::XCScheme.expects(:share_scheme).with(
@generator.project.path,
'CoconutLib')
Xcodeproj::XCScheme.expects(:share_scheme).never
@generator.share_development_pod_schemes
Xcodeproj::XCScheme.expects(:share_scheme).with(
@generator.project.path,
'CoconutLib-Unit-Tests')
@generator.installation_options.
stubs(:share_schemes_for_development_pods).
returns(nil)
@generator.send(:share_development_pod_schemes)
end
Xcodeproj::XCScheme.expects(:share_scheme).never
@generator.share_development_pod_schemes
end
it 'allows opting out' do
@generator.installation_options.
stubs(:share_schemes_for_development_pods).
returns(false)
it 'allows specifying strings of pods to share' do
@generator.installation_options.
stubs(:share_schemes_for_development_pods).
returns(%w(BananaLib))
Xcodeproj::XCScheme.expects(:share_scheme).never
@generator.send(:share_development_pod_schemes)
@generator.generate!
@generator.sandbox.stubs(:development_pods).returns('BananaLib' => fixture('BananaLib'))
@generator.installation_options.
stubs(:share_schemes_for_development_pods).
returns(nil)
Xcodeproj::XCScheme.expects(:share_scheme).with(
@generator.project.path,
'BananaLib-iOS')
Xcodeproj::XCScheme.expects(:share_scheme).never
@generator.send(:share_development_pod_schemes)
end
Xcodeproj::XCScheme.expects(:share_scheme).with(
@generator.project.path,
'BananaLib-macOS')
it 'allows specifying strings of pods to share' do
@generator.installation_options.
stubs(:share_schemes_for_development_pods).
returns(%w(BananaLib))
@generator.share_development_pod_schemes
Xcodeproj::XCScheme.expects(:share_scheme).with(
@generator.project.path,
'BananaLib')
@generator.send(:share_development_pod_schemes)
@generator.installation_options.
stubs(:share_schemes_for_development_pods).
returns(%w(orange-framework))
@generator.installation_options.
stubs(:share_schemes_for_development_pods).
returns(%w(orange-framework))
Xcodeproj::XCScheme.expects(:share_scheme).never
@generator.share_development_pod_schemes
end
Xcodeproj::XCScheme.expects(:share_scheme).never
@generator.send(:share_development_pod_schemes)
end
it 'allows specifying regular expressions of pods to share' do
@generator.installation_options.
stubs(:share_schemes_for_development_pods).
returns([/bAnaNalIb/i, /B*/])
it 'allows specifying regular expressions of pods to share' do
@generator.installation_options.
stubs(:share_schemes_for_development_pods).
returns([/bAnaNalIb/i, /B*/])
@generator.generate!
@generator.sandbox.stubs(:development_pods).returns('BananaLib' => fixture('BananaLib'))
Xcodeproj::XCScheme.expects(:share_scheme).with(
@generator.project.path,
'BananaLib')
@generator.send(:share_development_pod_schemes)
Xcodeproj::XCScheme.expects(:share_scheme).with(
@generator.project.path,
'BananaLib-iOS')
@generator.installation_options.
stubs(:share_schemes_for_development_pods).
returns([/banana$/, /[^\A]BananaLib/])
Xcodeproj::XCScheme.expects(:share_scheme).with(
@generator.project.path,
'BananaLib-macOS')
Xcodeproj::XCScheme.expects(:share_scheme).never
@generator.send(:share_development_pod_schemes)
end
@generator.share_development_pod_schemes
it 'raises when an invalid type is set' do
@generator.installation_options.
stubs(:share_schemes_for_development_pods).
returns(Pathname('foo'))
@generator.installation_options.
stubs(:share_schemes_for_development_pods).
returns([/banana$/, /[^\A]BananaLib/])
Xcodeproj::XCScheme.expects(:share_scheme).never
e = should.raise(Informative) { @generator.send(: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
Xcodeproj::XCScheme.expects(:share_scheme).never
@generator.share_development_pod_schemes
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
......
......@@ -535,17 +535,6 @@ module Pod
@test_pod_target.app_host_label(:unit).should == 'AppHost-iOS-Unit-Tests'
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
@test_pod_target.product_type_for_test_type(:unit).should == :unit_test_bundle
end
......
......@@ -1079,12 +1079,15 @@ module Pod
debug_configuration_two = stub(:build_settings => {})
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]))
pod_target_one = stub(:uses_swift? => true, :swift_version => '4.0', :native_target => native_target_one, :test_native_targets => [])
pod_target_two = stub(:uses_swift? => true, :swift_version => '3.2', :native_target => native_target_two, :test_native_targets => [])
pod_target_one = stub(:name => 'PodTarget1', :uses_swift? => true, :swift_version => '4.0')
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])
installer = stub(:pod_targets => [pod_target_one, pod_target_two])
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_two.build_settings['SWIFT_VERSION'].should == '3.2'
end
......@@ -1097,12 +1100,15 @@ module Pod
debug_configuration_two = stub(:build_settings => {})
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]))
pod_target_one = stub(:uses_swift? => true, :swift_version => '4.0', :native_target => native_target_one, :test_native_targets => [])
pod_target_two = stub(:uses_swift? => true, :swift_version => '3.2', :native_target => native_target_two, :test_native_targets => [])
pod_target_one = stub(:name => 'PodTarget1', :uses_swift? => true, :swift_version => '4.0')
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])
installer = stub(:pod_targets => [pod_target_one, pod_target_two])
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_two.build_settings['SWIFT_VERSION'].should == '3.2'
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