Commit a5f0f487 authored by Marius Rackwitz's avatar Marius Rackwitz

[Analyzer] Extract TargetInspector

parent 2187a0a5
......@@ -10,6 +10,8 @@ module Pod
autoload :SandboxAnalyzer, 'cocoapods/installer/analyzer/sandbox_analyzer'
autoload :SpecsState, 'cocoapods/installer/analyzer/specs_state'
autoload :LockingDependencyAnalyzer, 'cocoapods/installer/analyzer/locking_dependency_analyzer'
autoload :TargetInspectionResult, 'cocoapods/installer/analyzer/target_inspection_result'
autoload :TargetInspector, 'cocoapods/installer/analyzer/target_inspector'
# @return [Sandbox] The sandbox where the Pods should be installed.
#
......@@ -38,7 +40,6 @@ module Pod
@update = false
@allow_pre_downloads = true
@archs_by_target_def = {}
end
# Performs the analysis.
......@@ -56,7 +57,11 @@ module Pod
validate_podfile!
validate_lockfile_version!
@result = AnalysisResult.new
inspect_targets_to_integrate
if config.integrate_targets?
@result.target_inspections = inspect_targets_to_integrate
else
check_platform_specifications
end
@result.podfile_state = generate_podfile_state
@locked_dependencies = generate_version_locking_dependencies
......@@ -245,15 +250,12 @@ module Pod
target.host_requires_frameworks |= target_definition.uses_frameworks?
if config.integrate_targets?
project_path = compute_user_project_path(target_definition)
user_project = Xcodeproj::Project.open(project_path)
native_targets = compute_user_project_targets(target_definition, user_project)
target.user_project_path = project_path
target.client_root = project_path.dirname
target.user_target_uuids = native_targets.map(&:uuid)
target.user_build_configurations = compute_user_build_configurations(target_definition, native_targets)
target.archs = @archs_by_target_def[target_definition]
target_inspection = result.target_inspections[target_definition]
target.user_project_path = target_inspection.project_path
target.client_root = target.user_project_path.dirname
target.user_target_uuids = target_inspection.project_target_uuids
target.user_build_configurations = target_inspection.build_configurations
target.archs = target_inspection.archs
else
target.client_root = config.installation_root
target.user_target_uuids = []
......@@ -323,8 +325,9 @@ module Pod
pod_target = PodTarget.new(pod_specs, target.target_definition, sandbox)
if config.integrate_targets?
pod_target.user_build_configurations = target.user_build_configurations
pod_target.archs = @archs_by_target_def[target.target_definition]
target_inspections = result.target_inspections.select { |t, _| target_definitions.include?(t) }.values
pod_target.user_build_configurations = target_inspections.map(&:build_configurations).reduce({}, &:merge)
pod_target.archs = target_inspections.map(&:archs).uniq.sort
else
pod_target.user_build_configurations = {}
if target.platform.name == :osx
......@@ -580,193 +583,36 @@ module Pod
# @!group Analysis sub-steps
# Returns the path of the user project that the {TargetDefinition}
# should integrate.
#
# @raise If the project is implicit and there are multiple projects.
#
# @raise If the path doesn't exits.
#
# @return [Pathname] the path of the user project.
#
def compute_user_project_path(target_definition)
if target_definition.user_project_path
path = config.installation_root + target_definition.user_project_path
path = "#{path}.xcodeproj" unless File.extname(path) == '.xcodeproj'
path = Pathname.new(path)
unless path.exist?
raise Informative, 'Unable to find the Xcode project ' \
"`#{path}` for the target `#{target_definition.label}`."
end
else
xcodeprojs = config.installation_root.children.select { |e| e.fnmatch('*.xcodeproj') }
if xcodeprojs.size == 1
path = xcodeprojs.first
else
raise Informative, 'Could not automatically select an Xcode project. ' \
"Specify one in your Podfile like so:\n\n" \
" xcodeproj 'path/to/Project.xcodeproj'\n"
end
end
path
end
# Returns a list of the targets from the project of {TargetDefinition}
# that needs to be integrated.
#
# @note The method first looks if there is a target specified with
# the `link_with` option of the {TargetDefinition}. Otherwise
# it looks for the target that has the same name of the target
# definition. Finally if no target was found the first
# encountered target is returned (it is assumed to be the one
# to integrate in simple projects).
#
# @note This will only return targets that do **not** already have
# the Pods library in their frameworks build phase.
#
#
def compute_user_project_targets(target_definition, user_project)
if link_with = target_definition.link_with
targets = native_targets(user_project).select { |t| link_with.include?(t.name) }
raise Informative, "Unable to find the targets named `#{link_with.to_sentence}` to link with target definition `#{target_definition.name}`" if targets.empty?
elsif target_definition.link_with_first_target?
targets = [native_targets(user_project).first].compact
raise Informative, 'Unable to find a target' if targets.empty?
else
target = native_targets(user_project).find { |t| t.name == target_definition.name.to_s }
targets = [target].compact
raise Informative, "Unable to find a target named `#{target_definition.name}`" if targets.empty?
end
targets
end
# @return [Array<PBXNativeTarget>] Returns the user’s targets, excluding
# aggregate targets.
#
def native_targets(user_project)
user_project.targets.reject do |target|
target.is_a? Xcodeproj::Project::Object::PBXAggregateTarget
end
end
# Checks if any of the targets for the {TargetDefinition} computed before
# by #compute_user_project_targets require to be build as a framework due
# the presence of Swift source code in any of the source build phases.
#
# @param [TargetDefinition] target_definition
# the target definition
#
# @param [Array<PBXNativeTarget>] native_targets
# the targets which are checked for presence of Swift source code
#
# @return [Boolean] Whether the user project targets to integrate into
# uses Swift
#
def compute_user_project_targets_require_framework(target_definition, native_targets)
file_predicate = nil
file_predicate = proc do |file_ref|
if file_ref.respond_to?(:last_known_file_type)
file_ref.last_known_file_type == 'sourcecode.swift'
elsif file_ref.respond_to?(:files)
file_ref.files.any?(&file_predicate)
else
false
end
end
target_definition.platform.supports_dynamic_frameworks? || native_targets.any? do |target|
target.source_build_phase.files.any? do |build_file|
file_predicate.call(build_file.file_ref)
end
end
end
# @return [Hash{String=>Symbol}] A hash representing the user build
# configurations where each key corresponds to the name of a
# configuration and its value to its type (`:debug` or `:release`).
#
def compute_user_build_configurations(target_definition, user_targets)
if user_targets
user_targets.map { |t| t.build_configurations.map(&:name) }.flatten.reduce({}) do |hash, name|
hash[name] = name == 'Debug' ? :debug : :release
hash
end.merge(target_definition.build_configurations || {})
else
target_definition.build_configurations || {}
end
end
# @return [Platform] The platform for the library.
# Checks whether the platform is specified if not integrating
#
# @note This resolves to the lowest deployment target across the user
# targets.
#
# @todo Is assigning the platform to the target definition the best way
# to go?
# @return [void]
#
def compute_platform_for_target_definition(target_definition, user_targets)
return target_definition.platform if target_definition.platform
name = nil
deployment_target = nil
user_targets.each do |target|
name ||= target.platform_name
raise Informative, 'Targets with different platforms' unless name == target.platform_name
if !deployment_target || deployment_target > Version.new(target.deployment_target)
deployment_target = Version.new(target.deployment_target)
end
def check_platform_specifications
unless config.integrate_targets?
podfile.target_definition_list.each do |target_definition|
unless target_definition.platform
raise Informative, 'It is necessary to specify the platform in the Podfile if not integrating.'
end
target_definition.set_platform(name, deployment_target)
Platform.new(name, deployment_target)
end
# @return [Platform] The platform for the library.
#
# @note This resolves to the lowest deployment target across the user
# targets.
#
# @todo Is assigning the platform to the target definition the best way
# to go?
#
def compute_archs_for_target_definition(target_definition, user_targets)
archs = []
user_targets.each do |target|
target_archs = target.common_resolved_build_setting('ARCHS')
archs.concat(Array(target_archs))
end
archs = archs.compact.uniq.sort
UI.message('Using `ARCHS` setting to build architectures of ' \
"target `#{target_definition.label}`: " \
"(`#{archs.join('`, `')}`)")
archs.length > 1 ? archs : archs.first
end
# Precompute the platforms for each target_definition in the Podfile
# Precompute information for each target_definition in the Podfile
#
# @note The platforms are computed and added to each target_definition
# because it might be necessary to infer the platform from the
# user targets.
#
# @return [void]
# @return [Hash{TargetDefinition => TargetInspectionResult}]
#
def inspect_targets_to_integrate
inspection_result = {}
UI.section 'Inspecting targets to integrate' do
podfile.target_definition_list.each do |target_definition|
if config.integrate_targets?
project_path = compute_user_project_path(target_definition)
user_project = Xcodeproj::Project.open(project_path)
targets = compute_user_project_targets(target_definition, user_project)
compute_platform_for_target_definition(target_definition, targets)
archs = compute_archs_for_target_definition(target_definition, targets)
@archs_by_target_def[target_definition] = archs
else
unless target_definition.platform
raise Informative, 'It is necessary to specify the platform in the Podfile if not integrating.'
end
end
inspection_result[target_definition] = TargetInspector.new(target_definition).inspect!
end
end
inspection_result
end
end
end
......
......@@ -26,6 +26,10 @@ module Pod
#
attr_accessor :targets
# @return [Hash{TargetDefinition => Array<TargetInspectionResult>}] the
# results of inspecting the user targets
attr_accessor :target_inspections
# @return [Hash{String=>Symbol}] A hash representing all the user build
# configurations across all integration targets. Each key
# corresponds to the name of a configuration and its value to
......
module Pod
class Installer
class Analyzer
class TargetInspectionResult
# @return [TargetDefinition] the target definition, whose project was
# inspected
#
attr_accessor :target_definition
# @return [Pathname] the path of the user project that the
# #target_definition should integrate
#
attr_accessor :project_path
# @return [Array<String>] the uuid of the user'S targets
#
attr_accessor :project_target_uuids
# @return [Hash{String=>Symbol}] A hash representing the user build
# configurations where each key corresponds to the name of a
# configuration and its value to its type (`:debug` or
# `:release`).
#
attr_accessor :build_configurations
# @return [Platform] the platform of the user targets
#
attr_accessor :platform
# @return [Array<String>] the architectures used by user's targets
#
attr_accessor :archs
# @return [Bool] whether frameworks are recommended for the integration
# due to the presence of Swift source in the user's targets
#
attr_accessor :recommends_frameworks
end
end
end
end
module Pod
class Installer
class Analyzer
class TargetInspector
include Config::Mixin
# @return [TargetDefinition] the target definition to inspect
#
attr_accessor :target_definition
# Initialize a new instance
#
# @param [TargetDefinition] target_definition
# the target definition
#
def initialize(target_definition)
@target_definition = target_definition
end
# Inspect the #target_definition
#
# @return [TargetInspectionResult]
#
def inspect!
project_path = compute_project_path
user_project = Xcodeproj::Project.open(project_path)
targets = compute_targets(user_project)
result = TargetInspectionResult.new
result.target_definition = target_definition
result.project_path = project_path
result.project_target_uuids = targets.map(&:uuid)
result.build_configurations = compute_build_configurations(targets)
result.platform = compute_platform(targets)
result.archs = compute_archs(targets)
result
end
#-----------------------------------------------------------------------#
private
# Returns the path of the user project that the #target_definition
# should integrate.
#
# @raise If the project is implicit and there are multiple projects.
#
# @raise If the path doesn't exits.
#
# @return [Pathname] the path of the user project.
#
def compute_project_path
if target_definition.user_project_path
path = config.installation_root + target_definition.user_project_path
path = "#{path}.xcodeproj" unless File.extname(path) == '.xcodeproj'
path = Pathname.new(path)
unless path.exist?
raise Informative, 'Unable to find the Xcode project ' \
"`#{path}` for the target `#{target_definition.label}`."
end
else
xcodeprojs = config.installation_root.children.select { |e| e.fnmatch('*.xcodeproj') }
if xcodeprojs.size == 1
path = xcodeprojs.first
else
raise Informative, 'Could not automatically select an Xcode project. ' \
"Specify one in your Podfile like so:\n\n" \
" xcodeproj 'path/to/Project.xcodeproj'\n"
end
end
path
end
# Returns a list of the targets from the project of #target_definition
# that needs to be integrated.
#
# @note The method first looks if there is a target specified with
# the `link_with` option of the {TargetDefinition}. Otherwise
# it looks for the target that has the same name of the target
# definition. Finally if no target was found the first
# encountered target is returned (it is assumed to be the one
# to integrate in simple projects).
#
# @param [Xcodeproj::Project] user_project
# the user project
#
# @return [Array<PBXNativeTarget>]
#
def compute_targets(user_project)
native_targets = user_project.native_targets
if link_with = target_definition.link_with
targets = native_targets.select { |t| link_with.include?(t.name) }
raise Informative, "Unable to find the targets named `#{link_with.to_sentence}` to link with target definition `#{target_definition.name}`" if targets.empty?
elsif target_definition.link_with_first_target?
targets = [native_targets.first].compact
raise Informative, 'Unable to find a target' if targets.empty?
else
target = native_targets.find { |t| t.name == target_definition.name.to_s }
targets = [target].compact
raise Informative, "Unable to find a target named `#{target_definition.name}`" if targets.empty?
end
targets
end
# @param [Array<PBXNativeTarget] the user's targets of the project of
# #target_definition which needs to be integrated
#
# @return [Hash{String=>Symbol}] A hash representing the user build
# configurations where each key corresponds to the name of a
# configuration and its value to its type (`:debug` or `:release`).
#
def compute_build_configurations(user_targets)
if user_targets
user_targets.flat_map { |t| t.build_configurations.map(&:name) }.each_with_object({}) do |name, hash|
hash[name] = name == 'Debug' ? :debug : :release
end.merge(target_definition.build_configurations || {})
else
target_definition.build_configurations || {}
end
end
# @param [Array<PBXNativeTarget] the user's targets of the project of
# #target_definition which needs to be integrated
#
# @return [Platform] The platform of the user's targets
#
# @note This resolves to the lowest deployment target across the user
# targets.
#
# @todo Is assigning the platform to the target definition the best way
# to go?
#
def compute_platform(user_targets)
return target_definition.platform if target_definition.platform
name = nil
deployment_target = nil
user_targets.each do |target|
name ||= target.platform_name
raise Informative, 'Targets with different platforms' unless name == target.platform_name
if !deployment_target || deployment_target > Version.new(target.deployment_target)
deployment_target = Version.new(target.deployment_target)
end
end
target_definition.set_platform(name, deployment_target)
Platform.new(name, deployment_target)
end
# Computes the architectures relevant for the user's targets.
#
# @param [Array<PBXNativeTarget] the user's targets of the project of
# #target_definition which needs to be integrated
#
# @return [Array<String>]
#
def compute_archs(user_targets)
archs = []
user_targets.each do |target|
target_archs = target.common_resolved_build_setting('ARCHS')
archs.concat(Array(target_archs))
end
archs = archs.compact.uniq.sort
UI.message('Using `ARCHS` setting to build architectures of ' \
"target `#{target_definition.label}`: " \
"(`#{archs.join('`, `')}`)")
archs.length > 1 ? archs : archs.first
end
# Checks if any of the targets for the {TargetDefinition} computed before
# by #compute_user_project_targets is recommended to be build as a framework
# due the presence of Swift source code in any of the source build phases.
#
# @param [TargetDefinition] target_definition
# the target definition
#
# @param [Array<PBXNativeTarget>] native_targets
# the targets which are checked for presence of Swift source code
#
# @return [Boolean] Whether the user project targets to integrate into
# uses Swift
#
def compute_recommends_frameworks(target_definition, native_targets)
file_predicate = nil
file_predicate = proc do |file_ref|
if file_ref.respond_to?(:last_known_file_type)
file_ref.last_known_file_type == 'sourcecode.swift'
elsif file_ref.respond_to?(:files)
file_ref.files.any?(&file_predicate)
else
false
end
end
target_definition.platform.supports_dynamic_frameworks? || native_targets.any? do |target|
target.source_build_phase.files.any? do |build_file|
file_predicate.call(build_file.file_ref)
end
end
end
end
end
end
end
require File.expand_path('../../../../spec_helper', __FILE__)
module Pod
describe TargetInspector = Installer::Analyzer::TargetInspector do
before do
SpecHelper.create_sample_app_copy_from_fixture('SampleProject')
end
describe '#compute_project_path' do
it 'uses the path specified in the target definition while computing the path of the user project' do
target_definition = Podfile::TargetDefinition.new(:default, nil)
target_definition.user_project_path = 'SampleProject/SampleProject'
path = TargetInspector.new(target_definition).send(:compute_project_path)
path.to_s.should.include 'SampleProject/SampleProject.xcodeproj'
end
it 'raises if the user project of the target definition does not exists while computing the path of the user project' do
target_definition = Podfile::TargetDefinition.new(:default, nil)
target_definition.user_project_path = 'Test'
e = lambda { TargetInspector.new(target_definition).send(:compute_project_path) }.should.raise Informative
e.message.should.match /Unable to find/
end
it 'looks if there is only one project if not specified in the target definition' do
target_definition = Podfile::TargetDefinition.new(:default, nil)
config.installation_root = config.installation_root + 'SampleProject'
path = TargetInspector.new(target_definition).send(:compute_project_path)
path.to_s.should.include 'SampleProject/SampleProject.xcodeproj'
end
it 'raise if there is no project and none specified in the target definition' do
target_definition = Podfile::TargetDefinition.new(:default, nil)
e = lambda { TargetInspector.new(target_definition).send(:compute_project_path) }.should.raise Informative
e.message.should.match /Could not.*select.*project/
end
it 'finds project even when path contains special chars' do
SpecHelper.create_sample_app_copy_from_fixture('Project[With]Special{chars}in*path?')
target_definition = Podfile::TargetDefinition.new(:default, nil)
config.installation_root = config.installation_root + 'Project[With]Special{chars}in*path?'
path = TargetInspector.new(target_definition).send(:compute_project_path)
path.to_s.should.include 'Project[With]Special{chars}in*path?/Project[With]Special{chars}in*path?.xcodeproj'
end
end
#--------------------------------------#
describe '#compute_targets' do
it 'returns the targets specified in the target definition' do
target_definition = Podfile::TargetDefinition.new(:default, nil)
target_definition.link_with = ['UserTarget']
user_project = Xcodeproj::Project.new('path')
user_project.new_target(:application, 'FirstTarget', :ios)
user_project.new_target(:application, 'UserTarget', :ios)
targets = TargetInspector.new(target_definition).send(:compute_targets, user_project)
targets.map(&:name).should == ['UserTarget']
end
it 'raises if it is unable to find the targets specified by the target definition' do
target_definition = Podfile::TargetDefinition.new(:default, nil)
target_definition.link_with = ['UserTarget']
user_project = Xcodeproj::Project.new('path')
e = lambda { TargetInspector.new(target_definition).send(:compute_targets, user_project) }.should.raise Informative
e.message.should.match /Unable to find the targets/
end
it 'returns the target with the same name of the target definition' do
target_definition = Podfile::TargetDefinition.new('UserTarget', nil)
user_project = Xcodeproj::Project.new('path')
user_project.new_target(:application, 'FirstTarget', :ios)
user_project.new_target(:application, 'UserTarget', :ios)
targets = TargetInspector.new(target_definition).send(:compute_targets, user_project)
targets.map(&:name).should == ['UserTarget']
end
it 'raises if the name of the target definition does not match any file' do
target_definition = Podfile::TargetDefinition.new('UserTarget', nil)
user_project = Xcodeproj::Project.new('path')
e = lambda { TargetInspector.new(target_definition).send(:compute_targets, user_project) }.should.raise Informative
e.message.should.match /Unable to find a target named/
end
it 'returns the first target of the project if the target definition is named default' do
target_definition = Podfile::TargetDefinition.new('Pods', nil)
target_definition.link_with_first_target = true
user_project = Xcodeproj::Project.new('path')
user_project.new_target(:application, 'FirstTarget', :ios)
user_project.new_target(:application, 'UserTarget', :ios)
targets = TargetInspector.new(target_definition).send(:compute_targets, user_project)
targets.map(&:name).should == ['FirstTarget']
end
it 'raises if the default target definition cannot be linked because there are no user targets' do
target_definition = Podfile::TargetDefinition.new(:default, nil)
user_project = Xcodeproj::Project.new('path')
e = lambda { TargetInspector.new(target_definition).send(:compute_targets, user_project) }.should.raise Informative
e.message.should.match /Unable to find a target/
end
end
#--------------------------------------#
describe '#compute_build_configurations' do
it 'returns the user build configurations of the user targets' do
user_project = Xcodeproj::Project.new('path')
target = user_project.new_target(:application, 'Target', :ios)
configuration = user_project.new(Xcodeproj::Project::Object::XCBuildConfiguration)
configuration.name = 'AppStore'
target.build_configuration_list.build_configurations << configuration
target_definition = Podfile::TargetDefinition.new(:default, nil)
user_targets = [target]
configurations = TargetInspector.new(target_definition).send(:compute_build_configurations, user_targets)
configurations.should == {
'Debug' => :debug,
'Release' => :release,
'AppStore' => :release,
}
end
it 'returns the user build configurations specified in the target definition' do
target_definition = Podfile::TargetDefinition.new(:default, nil)
target_definition.build_configurations = { 'AppStore' => :release }
user_targets = []
configurations = TargetInspector.new(target_definition).send(:compute_build_configurations, user_targets)
configurations.should == { 'AppStore' => :release }
end
end
#--------------------------------------#
describe '#compute_archs' do
it 'handles a single ARCH defined in a single user target' do
user_project = Xcodeproj::Project.new('path')
target = user_project.new_target(:application, 'Target', :ios)
target.build_configuration_list.set_setting('ARCHS', 'armv7')
target_definition = Podfile::TargetDefinition.new(:default, nil)
target_definition.set_platform(:ios, '4.0')
user_targets = [target]
archs = TargetInspector.new(target_definition).send(:compute_archs, user_targets)
archs.should == 'armv7'
end
it 'handles a single ARCH defined in multiple user targets' do
user_project = Xcodeproj::Project.new('path')
targeta = user_project.new_target(:application, 'Target', :ios)
targeta.build_configuration_list.set_setting('ARCHS', 'armv7')
targetb = user_project.new_target(:application, 'Target', :ios)
targetb.build_configuration_list.set_setting('ARCHS', 'armv7')
target_definition = Podfile::TargetDefinition.new(:default, nil)
target_definition.set_platform(:ios, '4.0')
user_targets = [targeta, targetb]
archs = TargetInspector.new(target_definition).send(:compute_archs, user_targets)
archs.should == 'armv7'
end
it 'handles an Array of ARCHs defined in a single user target' do
user_project = Xcodeproj::Project.new('path')
target = user_project.new_target(:application, 'Target', :ios)
target.build_configuration_list.set_setting('ARCHS', %w(armv7 i386))
target_definition = Podfile::TargetDefinition.new(:default, nil)
target_definition.set_platform(:ios, '4.0')
user_targets = [target]
archs = TargetInspector.new(target_definition).send(:compute_archs, user_targets)
%w(armv7 i386).each { |a| archs.should.include a }
end
it 'handles an Array of ARCHs defined multiple user targets' do
user_project = Xcodeproj::Project.new('path')
targeta = user_project.new_target(:application, 'Target', :ios)
targeta.build_configuration_list.set_setting('ARCHS', %w(armv7 armv7s))
targetb = user_project.new_target(:application, 'Target', :ios)
targetb.build_configuration_list.set_setting('ARCHS', %w(armv7 i386))
target_definition = Podfile::TargetDefinition.new(:default, nil)
target_definition.set_platform(:ios, '4.0')
user_targets = [targeta, targetb]
archs = TargetInspector.new(target_definition).send(:compute_archs, user_targets)
%w(armv7 armv7s i386).each { |a| archs.should.include a }
end
end
#--------------------------------------#
describe '#compute_platform' do
it 'returns the platform specified in the target definition' do
target_definition = Podfile::TargetDefinition.new(:default, nil)
target_definition.set_platform(:ios, '4.0')
user_targets = []
configurations = TargetInspector.new(target_definition).send(:compute_platform, user_targets)
configurations.should == Platform.new(:ios, '4.0')
end
it 'infers the platform from the user targets' do
user_project = Xcodeproj::Project.new('path')
target = user_project.new_target(:application, 'Target', :ios)
target.build_configuration_list.set_setting('SDKROOT', 'iphoneos')
target.build_configuration_list.set_setting('IPHONEOS_DEPLOYMENT_TARGET', '4.0')
target_definition = Podfile::TargetDefinition.new(:default, nil)
user_targets = [target]
configurations = TargetInspector.new(target_definition).send(:compute_platform, user_targets)
configurations.should == Platform.new(:ios, '4.0')
end
it 'uses the lowest deployment target of the user targets if inferring the platform' do
user_project = Xcodeproj::Project.new('path')
target1 = user_project.new_target(:application, 'Target', :ios)
target1.build_configuration_list.build_configurations.first
target1.build_configuration_list.set_setting('SDKROOT', 'iphoneos')
target1.build_configuration_list.set_setting('IPHONEOS_DEPLOYMENT_TARGET', '4.0')
target2 = user_project.new_target(:application, 'Target', :ios)
target2.build_configuration_list.set_setting('SDKROOT', 'iphoneos')
target2.build_configuration_list.set_setting('IPHONEOS_DEPLOYMENT_TARGET', '6.0')
target_definition = Podfile::TargetDefinition.new(:default, nil)
user_targets = [target1, target2]
configurations = TargetInspector.new(target_definition).send(:compute_platform, user_targets)
configurations.should == Platform.new(:ios, '4.0')
end
it 'raises if the user targets have a different platform' do
user_project = Xcodeproj::Project.new('path')
target1 = user_project.new_target(:application, 'Target', :ios)
target1.build_configuration_list.set_setting('SDKROOT', 'iphoneos')
target1.build_configuration_list.set_setting('IPHONEOS_DEPLOYMENT_TARGET', '4.0')
target2 = user_project.new_target(:application, 'Target', :ios)
target2.build_configuration_list.set_setting('SDKROOT', 'macosx')
target2.build_configuration_list.set_setting('IPHONEOS_DEPLOYMENT_TARGET', '10.6')
target_definition = Podfile::TargetDefinition.new(:default, nil)
user_targets = [target1, target2]
e = lambda { TargetInspector.new(target_definition).send(:compute_platform, user_targets) }.should.raise Informative
e.message.should.match /Targets with different platforms/
end
end
end
end
......@@ -331,271 +331,6 @@ module Pod
#-------------------------------------------------------------------------#
describe 'Private helpers' do
describe '#compute_user_project_targets' do
it 'uses the path specified in the target definition while computing the path of the user project' do
target_definition = Podfile::TargetDefinition.new(:default, nil)
target_definition.user_project_path = 'SampleProject/SampleProject'
path = @analyzer.send(:compute_user_project_path, target_definition)
path.to_s.should.include 'SampleProject/SampleProject.xcodeproj'
end
it 'raises if the user project of the target definition does not exists while computing the path of the user project' do
target_definition = Podfile::TargetDefinition.new(:default, nil)
target_definition.user_project_path = 'Test'
e = lambda { @analyzer.send(:compute_user_project_path, target_definition) }.should.raise Informative
e.message.should.match /Unable to find/
end
it 'looks if there is only one project if not specified in the target definition' do
target_definition = Podfile::TargetDefinition.new(:default, nil)
config.installation_root = config.installation_root + 'SampleProject'
path = @analyzer.send(:compute_user_project_path, target_definition)
path.to_s.should.include 'SampleProject/SampleProject.xcodeproj'
end
it 'raise if there is no project and none specified in the target definition' do
target_definition = Podfile::TargetDefinition.new(:default, nil)
e = lambda { @analyzer.send(:compute_user_project_path, target_definition) }.should.raise Informative
e.message.should.match /Could not.*select.*project/
end
it 'finds project even when path contains special chars' do
SpecHelper.create_sample_app_copy_from_fixture('Project[With]Special{chars}in*path?')
target_definition = Podfile::TargetDefinition.new(:default, nil)
config.installation_root = config.installation_root + 'Project[With]Special{chars}in*path?'
path = @analyzer.send(:compute_user_project_path, target_definition)
path.to_s.should.include 'Project[With]Special{chars}in*path?/Project[With]Special{chars}in*path?.xcodeproj'
end
it 'does not take aggregate targets into consideration' do
aggregate_class = Xcodeproj::Project::Object::PBXAggregateTarget
sample_project_path = SpecHelper.create_sample_app_copy_from_fixture('SampleProject')
sample_project = Xcodeproj::Project.open(sample_project_path)
sample_project.targets.map(&:class).should.include(aggregate_class)
native_targets = @analyzer.send(:native_targets, sample_project).map(&:class)
native_targets.should.not.include(aggregate_class)
end
end
#--------------------------------------#
describe '#compute_user_project_targets' do
it 'returns the targets specified in the target definition' do
target_definition = Podfile::TargetDefinition.new(:default, nil)
target_definition.link_with = ['UserTarget']
user_project = Xcodeproj::Project.new('path')
user_project.new_target(:application, 'FirstTarget', :ios)
user_project.new_target(:application, 'UserTarget', :ios)
targets = @analyzer.send(:compute_user_project_targets, target_definition, user_project)
targets.map(&:name).should == ['UserTarget']
end
it 'raises if it is unable to find the targets specified by the target definition' do
target_definition = Podfile::TargetDefinition.new(:default, nil)
target_definition.link_with = ['UserTarget']
user_project = Xcodeproj::Project.new('path')
e = lambda { @analyzer.send(:compute_user_project_targets, target_definition, user_project) }.should.raise Informative
e.message.should.match /Unable to find the targets/
end
it 'returns the target with the same name of the target definition' do
target_definition = Podfile::TargetDefinition.new('UserTarget', nil)
user_project = Xcodeproj::Project.new('path')
user_project.new_target(:application, 'FirstTarget', :ios)
user_project.new_target(:application, 'UserTarget', :ios)
targets = @analyzer.send(:compute_user_project_targets, target_definition, user_project)
targets.map(&:name).should == ['UserTarget']
end
it 'raises if the name of the target definition does not match any file' do
target_definition = Podfile::TargetDefinition.new('UserTarget', nil)
user_project = Xcodeproj::Project.new('path')
e = lambda { @analyzer.send(:compute_user_project_targets, target_definition, user_project) }.should.raise Informative
e.message.should.match /Unable to find a target named/
end
it 'returns the first target of the project if the target definition is named default' do
target_definition = Podfile::TargetDefinition.new('Pods', nil)
target_definition.link_with_first_target = true
user_project = Xcodeproj::Project.new('path')
user_project.new_target(:application, 'FirstTarget', :ios)
user_project.new_target(:application, 'UserTarget', :ios)
targets = @analyzer.send(:compute_user_project_targets, target_definition, user_project)
targets.map(&:name).should == ['FirstTarget']
end
it 'raises if the default target definition cannot be linked because there are no user targets' do
target_definition = Podfile::TargetDefinition.new(:default, nil)
user_project = Xcodeproj::Project.new('path')
e = lambda { @analyzer.send(:compute_user_project_targets, target_definition, user_project) }.should.raise Informative
e.message.should.match /Unable to find a target/
end
end
#--------------------------------------#
describe '#compute_user_build_configurations' do
it 'returns the user build configurations of the user targets' do
user_project = Xcodeproj::Project.new('path')
target = user_project.new_target(:application, 'Target', :ios)
configuration = user_project.new(Xcodeproj::Project::Object::XCBuildConfiguration)
configuration.name = 'AppStore'
target.build_configuration_list.build_configurations << configuration
target_definition = Podfile::TargetDefinition.new(:default, nil)
user_targets = [target]
configurations = @analyzer.send(:compute_user_build_configurations, target_definition, user_targets)
configurations.should == {
'Debug' => :debug,
'Release' => :release,
'AppStore' => :release,
}
end
it 'returns the user build configurations specified in the target definition' do
target_definition = Podfile::TargetDefinition.new(:default, nil)
target_definition.build_configurations = { 'AppStore' => :release }
user_targets = []
configurations = @analyzer.send(:compute_user_build_configurations, target_definition, user_targets)
configurations.should == { 'AppStore' => :release }
end
end
#--------------------------------------#
describe '#compute_archs_for_target_definition' do
it 'handles a single ARCH defined in a single user target' do
user_project = Xcodeproj::Project.new('path')
target = user_project.new_target(:application, 'Target', :ios)
target.build_configuration_list.set_setting('ARCHS', 'armv7')
target_definition = Podfile::TargetDefinition.new(:default, nil)
target_definition.set_platform(:ios, '4.0')
user_targets = [target]
archs = @analyzer.send(:compute_archs_for_target_definition, target_definition, user_targets)
archs.should == 'armv7'
end
it 'handles a single ARCH defined in multiple user targets' do
user_project = Xcodeproj::Project.new('path')
targeta = user_project.new_target(:application, 'Target', :ios)
targeta.build_configuration_list.set_setting('ARCHS', 'armv7')
targetb = user_project.new_target(:application, 'Target', :ios)
targetb.build_configuration_list.set_setting('ARCHS', 'armv7')
target_definition = Podfile::TargetDefinition.new(:default, nil)
target_definition.set_platform(:ios, '4.0')
user_targets = [targeta, targetb]
archs = @analyzer.send(:compute_archs_for_target_definition, target_definition, user_targets)
archs.should == 'armv7'
end
it 'handles an Array of ARCHs defined in a single user target' do
user_project = Xcodeproj::Project.new('path')
target = user_project.new_target(:application, 'Target', :ios)
target.build_configuration_list.set_setting('ARCHS', %w(armv7 i386))
target_definition = Podfile::TargetDefinition.new(:default, nil)
target_definition.set_platform(:ios, '4.0')
user_targets = [target]
archs = @analyzer.send(:compute_archs_for_target_definition, target_definition, user_targets)
%w(armv7 i386).each { |a| archs.should.include a }
end
it 'handles an Array of ARCHs defined multiple user targets' do
user_project = Xcodeproj::Project.new('path')
targeta = user_project.new_target(:application, 'Target', :ios)
targeta.build_configuration_list.set_setting('ARCHS', %w(armv7 armv7s))
targetb = user_project.new_target(:application, 'Target', :ios)
targetb.build_configuration_list.set_setting('ARCHS', %w(armv7 i386))
target_definition = Podfile::TargetDefinition.new(:default, nil)
target_definition.set_platform(:ios, '4.0')
user_targets = [targeta, targetb]
archs = @analyzer.send(:compute_archs_for_target_definition, target_definition, user_targets)
%w(armv7 armv7s i386).each { |a| archs.should.include a }
end
end
#--------------------------------------#
describe '#compute_platform_for_target_definition' do
it 'returns the platform specified in the target definition' do
target_definition = Podfile::TargetDefinition.new(:default, nil)
target_definition.set_platform(:ios, '4.0')
user_targets = []
configurations = @analyzer.send(:compute_platform_for_target_definition, target_definition, user_targets)
configurations.should == Platform.new(:ios, '4.0')
end
it 'infers the platform from the user targets' do
user_project = Xcodeproj::Project.new('path')
target = user_project.new_target(:application, 'Target', :ios)
target.build_configuration_list.set_setting('SDKROOT', 'iphoneos')
target.build_configuration_list.set_setting('IPHONEOS_DEPLOYMENT_TARGET', '4.0')
target_definition = Podfile::TargetDefinition.new(:default, nil)
user_targets = [target]
configurations = @analyzer.send(:compute_platform_for_target_definition, target_definition, user_targets)
configurations.should == Platform.new(:ios, '4.0')
end
it 'uses the lowest deployment target of the user targets if inferring the platform' do
user_project = Xcodeproj::Project.new('path')
target1 = user_project.new_target(:application, 'Target', :ios)
target1.build_configuration_list.build_configurations.first
target1.build_configuration_list.set_setting('SDKROOT', 'iphoneos')
target1.build_configuration_list.set_setting('IPHONEOS_DEPLOYMENT_TARGET', '4.0')
target2 = user_project.new_target(:application, 'Target', :ios)
target2.build_configuration_list.set_setting('SDKROOT', 'iphoneos')
target2.build_configuration_list.set_setting('IPHONEOS_DEPLOYMENT_TARGET', '6.0')
target_definition = Podfile::TargetDefinition.new(:default, nil)
user_targets = [target1, target2]
configurations = @analyzer.send(:compute_platform_for_target_definition, target_definition, user_targets)
configurations.should == Platform.new(:ios, '4.0')
end
it 'raises if the user targets have a different platform' do
user_project = Xcodeproj::Project.new('path')
target1 = user_project.new_target(:application, 'Target', :ios)
target1.build_configuration_list.set_setting('SDKROOT', 'iphoneos')
target1.build_configuration_list.set_setting('IPHONEOS_DEPLOYMENT_TARGET', '4.0')
target2 = user_project.new_target(:application, 'Target', :ios)
target2.build_configuration_list.set_setting('SDKROOT', 'macosx')
target2.build_configuration_list.set_setting('IPHONEOS_DEPLOYMENT_TARGET', '10.6')
target_definition = Podfile::TargetDefinition.new(:default, nil)
user_targets = [target1, target2]
e = lambda { @analyzer.send(:compute_platform_for_target_definition, target_definition, user_targets) }.should.raise Informative
e.message.should.match /Targets with different platforms/
end
end
#--------------------------------------#
describe '#sources' do
describe 'when there are no explicit sources' do
it 'defaults to the master spec repository' do
......
......@@ -143,11 +143,11 @@ module Pod
target = @installer.aggregate_targets.first
target.requires_frameworks?.should == true
target.pod_targets.select(&:requires_frameworks?).map(&:name).sort.should == [
'BananaLib',
'OrangeFramework',
'monkey',
]
target.pod_targets.select(&:requires_frameworks?).map(&:name).sort.should == %w(
BananaLib
OrangeFramework
monkey
)
end
end
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment