Commit a5f0f487 authored by Marius Rackwitz's avatar Marius Rackwitz

[Analyzer] Extract TargetInspector

parent 2187a0a5
...@@ -10,6 +10,8 @@ module Pod ...@@ -10,6 +10,8 @@ module Pod
autoload :SandboxAnalyzer, 'cocoapods/installer/analyzer/sandbox_analyzer' autoload :SandboxAnalyzer, 'cocoapods/installer/analyzer/sandbox_analyzer'
autoload :SpecsState, 'cocoapods/installer/analyzer/specs_state' autoload :SpecsState, 'cocoapods/installer/analyzer/specs_state'
autoload :LockingDependencyAnalyzer, 'cocoapods/installer/analyzer/locking_dependency_analyzer' 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. # @return [Sandbox] The sandbox where the Pods should be installed.
# #
...@@ -38,7 +40,6 @@ module Pod ...@@ -38,7 +40,6 @@ module Pod
@update = false @update = false
@allow_pre_downloads = true @allow_pre_downloads = true
@archs_by_target_def = {}
end end
# Performs the analysis. # Performs the analysis.
...@@ -56,7 +57,11 @@ module Pod ...@@ -56,7 +57,11 @@ module Pod
validate_podfile! validate_podfile!
validate_lockfile_version! validate_lockfile_version!
@result = AnalysisResult.new @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 @result.podfile_state = generate_podfile_state
@locked_dependencies = generate_version_locking_dependencies @locked_dependencies = generate_version_locking_dependencies
...@@ -245,15 +250,12 @@ module Pod ...@@ -245,15 +250,12 @@ module Pod
target.host_requires_frameworks |= target_definition.uses_frameworks? target.host_requires_frameworks |= target_definition.uses_frameworks?
if config.integrate_targets? if config.integrate_targets?
project_path = compute_user_project_path(target_definition) target_inspection = result.target_inspections[target_definition]
user_project = Xcodeproj::Project.open(project_path) target.user_project_path = target_inspection.project_path
native_targets = compute_user_project_targets(target_definition, user_project) target.client_root = target.user_project_path.dirname
target.user_target_uuids = target_inspection.project_target_uuids
target.user_project_path = project_path target.user_build_configurations = target_inspection.build_configurations
target.client_root = project_path.dirname target.archs = target_inspection.archs
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]
else else
target.client_root = config.installation_root target.client_root = config.installation_root
target.user_target_uuids = [] target.user_target_uuids = []
...@@ -323,8 +325,9 @@ module Pod ...@@ -323,8 +325,9 @@ module Pod
pod_target = PodTarget.new(pod_specs, target.target_definition, sandbox) pod_target = PodTarget.new(pod_specs, target.target_definition, sandbox)
if config.integrate_targets? if config.integrate_targets?
pod_target.user_build_configurations = target.user_build_configurations target_inspections = result.target_inspections.select { |t, _| target_definitions.include?(t) }.values
pod_target.archs = @archs_by_target_def[target.target_definition] pod_target.user_build_configurations = target_inspections.map(&:build_configurations).reduce({}, &:merge)
pod_target.archs = target_inspections.map(&:archs).uniq.sort
else else
pod_target.user_build_configurations = {} pod_target.user_build_configurations = {}
if target.platform.name == :osx if target.platform.name == :osx
...@@ -580,193 +583,36 @@ module Pod ...@@ -580,193 +583,36 @@ module Pod
# @!group Analysis sub-steps # @!group Analysis sub-steps
# Returns the path of the user project that the {TargetDefinition} # Checks whether the platform is specified if not integrating
# 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.
# #
# @note This resolves to the lowest deployment target across the user # @return [void]
# targets.
#
# @todo Is assigning the platform to the target definition the best way
# to go?
# #
def compute_platform_for_target_definition(target_definition, user_targets) def check_platform_specifications
return target_definition.platform if target_definition.platform unless config.integrate_targets?
name = nil podfile.target_definition_list.each do |target_definition|
deployment_target = nil unless target_definition.platform
raise Informative, 'It is necessary to specify the platform in the Podfile if not integrating.'
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 end
target_definition.set_platform(name, deployment_target)
Platform.new(name, deployment_target)
end 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 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 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 # @note The platforms are computed and added to each target_definition
# because it might be necessary to infer the platform from the # because it might be necessary to infer the platform from the
# user targets. # user targets.
# #
# @return [void] # @return [Hash{TargetDefinition => TargetInspectionResult}]
# #
def inspect_targets_to_integrate def inspect_targets_to_integrate
inspection_result = {}
UI.section 'Inspecting targets to integrate' do UI.section 'Inspecting targets to integrate' do
podfile.target_definition_list.each do |target_definition| podfile.target_definition_list.each do |target_definition|
if config.integrate_targets? inspection_result[target_definition] = TargetInspector.new(target_definition).inspect!
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
end end
end end
inspection_result
end end
end end
end end
......
...@@ -26,6 +26,10 @@ module Pod ...@@ -26,6 +26,10 @@ module Pod
# #
attr_accessor :targets 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 # @return [Hash{String=>Symbol}] A hash representing all the user build
# configurations across all integration targets. Each key # configurations across all integration targets. Each key
# corresponds to the name of a configuration and its value to # 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 ...@@ -331,271 +331,6 @@ module Pod
#-------------------------------------------------------------------------# #-------------------------------------------------------------------------#
describe 'Private helpers' do 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 '#sources' do
describe 'when there are no explicit sources' do describe 'when there are no explicit sources' do
it 'defaults to the master spec repository' do it 'defaults to the master spec repository' do
......
...@@ -143,11 +143,11 @@ module Pod ...@@ -143,11 +143,11 @@ module Pod
target = @installer.aggregate_targets.first target = @installer.aggregate_targets.first
target.requires_frameworks?.should == true target.requires_frameworks?.should == true
target.pod_targets.select(&:requires_frameworks?).map(&:name).sort.should == [ target.pod_targets.select(&:requires_frameworks?).map(&:name).sort.should == %w(
'BananaLib', BananaLib
'OrangeFramework', OrangeFramework
'monkey', monkey
] )
end end
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