Commit d504d84c authored by Marius Rackwitz's avatar Marius Rackwitz

Merge pull request #4146 from CocoaPods/mr-fix-scoping

Improve de-duplication for non-trivial cases
parents c1334d75 43332122
......@@ -8,12 +8,26 @@ To install release candidates run `[sudo] gem install cocoapods --pre`
##### Enhancements
* None.
* Allow deduplication to take effect even when the same pod is used with
different sets of subspecs across different platforms.
This changes the general naming scheme scoped pod targets. They are
suffixed now on base of what makes them different among others for the
same root spec instead of being prefixed by the dependant target.
[Marius Rackwitz](https://github.com/mrackwitz)
[#4146](https://github.com/CocoaPods/CocoaPods/pull/4146)
##### Bug Fixes
* None.
* Pods are built by default in another scoping level of the build products
directory identified by their name to prevent name clashes among
dependencies.
[Marius Rackwitz](https://github.com/mrackwitz)
[#4146](https://github.com/CocoaPods/CocoaPods/pull/4146)
* Fix mixed integrations where static libraries are used along frameworks
from different target definitions in one Podfile.
[Marius Rackwitz](https://github.com/mrackwitz)
[#4146](https://github.com/CocoaPods/CocoaPods/pull/4146)
## 1.0.0.beta.3 (2016-02-03)
......
......@@ -152,19 +152,22 @@ begin
namespace :fixture_tarballs do
task :default => :unpack
tarballs = FileList['spec/fixtures/**/*.tar.gz']
desc 'Check fixture tarballs for pending changes'
task :check_for_pending_changes do
repo_dir = 'spec/fixtures/banana-lib'
if Dir.exist?(repo_dir) && !Dir.chdir(repo_dir) { `git status --porcelain`.empty? }
puts red("[!] There are unsaved changes in '#{repo_dir}'. " \
'Please commit everything and run `rake spec:fixture_tarballs:rebuild`.')
exit 1
tarballs.each do |tarball|
repo_dir = "#{File.dirname(tarball)}/#{File.basename(tarball, '.tar.gz')}"
if Dir.exist?(repo_dir) && Dir.exist?("#{repo_dir}/.git") && !Dir.chdir(repo_dir) { `git status --porcelain`.empty? }
puts red("[!] There are unsaved changes in '#{repo_dir}'. " \
'Please commit everything and run `rake spec:fixture_tarballs:rebuild`.')
exit 1
end
end
end
desc 'Rebuild all the fixture tarballs'
task :rebuild => :check_for_pending_changes do
tarballs = FileList['spec/fixtures/**/*.tar.gz']
tarballs.each do |tarball|
basename = File.basename(tarball)
sh "cd #{File.dirname(tarball)} && rm #{basename} && env COPYFILE_DISABLE=1 tar -zcf #{basename} #{basename[0..-8]}"
......@@ -179,7 +182,6 @@ begin
exit 1 unless args[:force]
puts 'Continue anyway because `force` was applied.'
end
tarballs = FileList['spec/fixtures/**/*.tar.gz']
tarballs.each do |tarball|
basename = File.basename(tarball)
Dir.chdir(File.dirname(tarball)) do
......
......@@ -59,6 +59,7 @@ module Pod
'PODS_ROOT' => target.relative_pods_root,
'GCC_PREPROCESSOR_DEFINITIONS' => '$(inherited) COCOAPODS=1',
'FRAMEWORK_SEARCH_PATHS' => '$(inherited) ',
'LIBRARY_SEARCH_PATHS' => '$(inherited) ',
}
if pod_targets.any?(&:uses_swift?)
config['EMBEDDED_CONTENT_CONTAINS_SWIFT'] = 'YES'
......@@ -94,15 +95,11 @@ module Pod
#
def settings_to_import_pod_targets
if target.requires_frameworks?
framework_header_search_paths = pod_targets.select(&:should_build?).map do |target|
if target.scoped?
"$PODS_FRAMEWORK_BUILD_PATH/#{target.product_name}/Headers"
else
"$CONFIGURATION_BUILD_DIR/#{target.product_name}/Headers"
end
build_pod_targets = pod_targets.select(&:should_build?)
framework_header_search_paths = build_pod_targets.map do |target|
"#{target.build_product_path}/Headers"
end
build_settings = {
'PODS_FRAMEWORK_BUILD_PATH' => XCConfigHelper.quote([target.scoped_configuration_build_dir]),
# Make framework headers discoverable by `import "…"`
'OTHER_CFLAGS' => '$(inherited) ' + XCConfigHelper.quote(framework_header_search_paths, '-iquote'),
}
......@@ -112,9 +109,6 @@ module Pod
build_settings['HEADER_SEARCH_PATHS'] = '$(inherited) ' + XCConfigHelper.quote(library_header_search_paths)
build_settings['OTHER_CFLAGS'] += ' ' + XCConfigHelper.quote(library_header_search_paths, '-isystem')
end
if pod_targets.any? { |t| t.should_build? && t.scoped? }
build_settings['FRAMEWORK_SEARCH_PATHS'] = '$PODS_FRAMEWORK_BUILD_PATH'
end
build_settings
else
# Make headers discoverable from $PODS_ROOT/Headers directory
......@@ -137,9 +131,11 @@ module Pod
# - `@import …;` / `import …`
#
def generate_settings_to_import_pod_targets
@xcconfig.merge! XCConfigHelper.settings_for_dependent_targets(target, pod_targets)
@xcconfig.merge!(settings_to_import_pod_targets)
target.search_paths_aggregate_targets.each do |search_paths_target|
generator = AggregateXCConfig.new(search_paths_target, configuration_name)
@xcconfig.merge! XCConfigHelper.settings_for_dependent_targets(nil, search_paths_target.pod_targets)
@xcconfig.merge!(generator.settings_to_import_pod_targets)
end
end
......
......@@ -45,32 +45,25 @@ module Pod
search_paths = target_search_paths.concat(sandbox_search_paths).uniq
config = {
'FRAMEWORK_SEARCH_PATHS' => '$(inherited) ',
'GCC_PREPROCESSOR_DEFINITIONS' => '$(inherited) COCOAPODS=1',
'HEADER_SEARCH_PATHS' => XCConfigHelper.quote(search_paths),
'LIBRARY_SEARCH_PATHS' => '$(inherited) ',
'OTHER_LDFLAGS' => XCConfigHelper.default_ld_flags(target),
'PODS_ROOT' => '${SRCROOT}',
'HEADER_SEARCH_PATHS' => XCConfigHelper.quote(search_paths),
'GCC_PREPROCESSOR_DEFINITIONS' => '$(inherited) COCOAPODS=1',
'SKIP_INSTALL' => 'YES',
'FRAMEWORK_SEARCH_PATHS' => '$(inherited) ',
'PRODUCT_BUNDLE_IDENTIFIER' => 'org.cocoapods.${PRODUCT_NAME:rfc1034identifier}',
'SKIP_INSTALL' => 'YES',
# 'USE_HEADERMAP' => 'NO'
}
@xcconfig = Xcodeproj::Config.new(config)
if target.requires_frameworks? && target.scoped?
build_settings = {
'PODS_FRAMEWORK_BUILD_PATH' => XCConfigHelper.quote([target.configuration_build_dir]),
'FRAMEWORK_SEARCH_PATHS' => '$PODS_FRAMEWORK_BUILD_PATH',
'CONFIGURATION_BUILD_DIR' => '$PODS_FRAMEWORK_BUILD_PATH',
}
@xcconfig.merge!(build_settings)
end
XCConfigHelper.add_settings_for_file_accessors_of_target(target, @xcconfig)
target.file_accessors.each do |file_accessor|
@xcconfig.merge!(file_accessor.spec_consumer.pod_target_xcconfig)
end
XCConfigHelper.add_target_specific_settings(target, @xcconfig)
@xcconfig.merge! XCConfigHelper.settings_for_dependent_targets(target, target.dependent_targets)
@xcconfig
end
......
......@@ -4,6 +4,13 @@ module Pod
# Stores the shared logic of the classes of the XCConfig module.
#
module XCConfigHelper
# @return [String] Defined to hold the default Xcode build path, so
# that when this is overridden per {PodTarget}, it is still
# possible to reference other build products relative to the
# original path.
#
SHARED_BUILD_DIR_VARIABLE = 'PODS_SHARED_BUILD_DIR'.freeze
# Converts an array of strings to a single string where the each string
# is surrounded by double quotes and separated by a space. Used to
# represent strings in a xcconfig file.
......@@ -49,6 +56,8 @@ module Pod
# @param [Xcodeproj::Config] xcconfig
# The xcconfig to edit.
#
# @return [void]
#
def self.add_settings_for_file_accessors_of_target(target, xcconfig)
target.file_accessors.each do |file_accessor|
XCConfigHelper.add_spec_build_settings_to_xcconfig(file_accessor.spec_consumer, xcconfig)
......@@ -73,6 +82,8 @@ module Pod
# @param [Spec::FileAccessor] file_accessor
# The file accessor, which holds the list of static frameworks.
#
# @return [void]
#
def self.add_static_dependency_build_settings(target, xcconfig, file_accessor)
file_accessor.vendored_static_frameworks.each do |vendored_static_framework|
XCConfigHelper.add_framework_build_settings(vendored_static_framework, xcconfig, target.sandbox.root)
......@@ -90,6 +101,8 @@ module Pod
# @param [Xcodeproj::Config] xcconfig
# The xcconfig to edit.
#
# @return [void]
#
def self.add_dynamic_dependency_build_settings(target, xcconfig)
target.file_accessors.each do |file_accessor|
file_accessor.vendored_dynamic_frameworks.each do |vendored_dynamic_framework|
......@@ -110,6 +123,8 @@ module Pod
# @param [Xcodeproj::Config] xcconfig
# The xcconfig to edit.
#
# @return [void]
#
def self.add_spec_build_settings_to_xcconfig(consumer, xcconfig)
xcconfig.libraries.merge(consumer.libraries)
xcconfig.frameworks.merge(consumer.frameworks)
......@@ -129,6 +144,8 @@ module Pod
# @param [Pathname] sandbox_root
# The path retrieved from Sandbox#root.
#
# @return [void]
#
def self.add_framework_build_settings(framework_path, xcconfig, sandbox_root)
name = File.basename(framework_path, '.framework')
dirname = '${PODS_ROOT}/' + framework_path.dirname.relative_path_from(sandbox_root).to_s
......@@ -151,6 +168,8 @@ module Pod
# @param [Pathname] sandbox_root
# The path retrieved from Sandbox#root.
#
# @return [void]
#
def self.add_library_build_settings(library_path, xcconfig, sandbox_root)
extension = File.extname(library_path)
name = File.basename(library_path, extension).sub(/\Alib/, '')
......@@ -172,6 +191,8 @@ module Pod
# @param [Xcodeproj::Config] xcconfig
# The xcconfig to edit.
#
# @return [void]
#
def self.add_code_signing_settings(target, xcconfig)
build_settings = {}
if target.platform.to_sym == :osx
......@@ -189,6 +210,8 @@ module Pod
# @param [Xcodeproj::Config] xcconfig
# The xcconfig to edit.
#
# @return [void]
#
def self.add_target_specific_settings(target, xcconfig)
if target.requires_frameworks?
add_code_signing_settings(target, xcconfig)
......@@ -196,6 +219,46 @@ module Pod
add_language_specific_settings(target, xcconfig)
end
# Returns the search paths for frameworks and libraries the given target
# depends on, so that it can be correctly built and linked.
#
# @param [Target] target
# The target.
#
# @param [Array<PodTarget>] dependent_targets
# The pod targets the given target depends on.
#
# @return [Hash<String, String>] the settings
#
def self.settings_for_dependent_targets(target, dependent_targets)
dependent_targets = dependent_targets.select(&:should_build?)
has_configuration_build_dir = target.respond_to?(:configuration_build_dir)
if has_configuration_build_dir
build_dir_var = "$#{SHARED_BUILD_DIR_VARIABLE}"
build_settings = {
'CONFIGURATION_BUILD_DIR' => target.configuration_build_dir(build_dir_var),
SHARED_BUILD_DIR_VARIABLE => '$(BUILD_DIR)/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)',
}
else
build_dir_var = '$CONFIGURATION_BUILD_DIR'
build_settings = {}
end
unless dependent_targets.empty?
framework_search_paths = []
library_search_paths = []
dependent_targets.each do |dependent_target|
if dependent_target.requires_frameworks?
framework_search_paths << dependent_target.configuration_build_dir(build_dir_var)
else
library_search_paths << dependent_target.configuration_build_dir(build_dir_var)
end
end
build_settings['FRAMEWORK_SEARCH_PATHS'] = XCConfigHelper.quote(framework_search_paths.uniq)
build_settings['LIBRARY_SEARCH_PATHS'] = XCConfigHelper.quote(library_search_paths.uniq)
end
build_settings
end
# Checks if the given target requires language specific settings and
# configures the given Xcconfig.
#
......@@ -205,6 +268,8 @@ module Pod
# @param [Xcodeproj::Config] xcconfig
# The xcconfig to edit.
#
# @return [void]
#
def self.add_language_specific_settings(target, xcconfig)
if target.uses_swift?
build_settings = {
......
......@@ -108,7 +108,6 @@ module Pod
prepare
resolve_dependencies
download_dependencies
determine_dependency_product_types
verify_no_duplicate_framework_names
verify_no_static_framework_transitive_dependencies
verify_framework_usage
......@@ -376,22 +375,6 @@ module Pod
end
end
# Determines if the dependencies need to be built as dynamic frameworks or
# if they can be built as static libraries by checking for the Swift source
# presence. Therefore it is important that the file accessors of the
# #pod_targets are created.
#
# @return [void]
#
def determine_dependency_product_types
aggregate_targets.each do |aggregate_target|
aggregate_target.pod_targets.each do |pod_target|
pod_target.host_requires_frameworks ||= aggregate_target.requires_frameworks?
pod_target.platform = nil # needs to be recomputed
end
end
end
def verify_no_duplicate_framework_names
aggregate_targets.each do |aggregate_target|
aggregate_target.user_build_configurations.keys.each do |config|
......@@ -629,13 +612,11 @@ module Pod
def install_libraries
UI.message '- Installing targets' do
pod_targets.sort_by(&:name).each do |pod_target|
next if pod_target.target_definitions.all?(&:abstract?)
target_installer = PodTargetInstaller.new(sandbox, pod_target)
target_installer.install!
end
aggregate_targets.sort_by(&:name).each do |target|
next if target.target_definition.abstract?
target_installer = AggregateTargetInstaller.new(sandbox, target)
target_installer.install!
end
......@@ -679,23 +660,15 @@ module Pod
aggregate_target.native_target.add_dependency(pod_target.native_target)
configure_app_extension_api_only_for_target(pod_target) if is_app_extension
pod_target.dependencies.each do |dep|
unless dep == pod_target.pod_name
pod_dependency_target = aggregate_target.pod_targets.find { |target| target.pod_name == dep }
# TODO: remove me
unless pod_dependency_target
puts "[BUG] DEP: #{dep}"
end
next unless pod_dependency_target.should_build?
pod_target.native_target.add_dependency(pod_dependency_target.native_target)
configure_app_extension_api_only_for_target(pod_dependency_target) if is_app_extension
pod_target.dependent_targets.each do |pod_dependency_target|
next unless pod_dependency_target.should_build?
pod_target.native_target.add_dependency(pod_dependency_target.native_target)
configure_app_extension_api_only_for_target(pod_dependency_target) if is_app_extension
if pod_target.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)
pod_target.native_target.frameworks_build_phase.add_file_reference(product_ref, true)
end
if pod_target.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)
pod_target.native_target.frameworks_build_phase.add_file_reference(product_ref, true)
end
end
end
......
......@@ -13,6 +13,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 :PodVariant, 'cocoapods/installer/analyzer/pod_variant'
autoload :PodVariantSet, 'cocoapods/installer/analyzer/pod_variant_set'
autoload :TargetInspectionResult, 'cocoapods/installer/analyzer/target_inspection_result'
autoload :TargetInspector, 'cocoapods/installer/analyzer/target_inspector'
......@@ -228,8 +230,9 @@ module Pod
# @return [Array<AggregateTarget>]
#
def generate_targets
pod_targets = generate_pod_targets(result.specs_by_target)
aggregate_targets = result.specs_by_target.keys.reject(&:abstract?).map do |target_definition|
specs_by_target = result.specs_by_target.reject { |td, _| td.abstract? }
pod_targets = generate_pod_targets(specs_by_target)
aggregate_targets = specs_by_target.keys.map do |target_definition|
generate_target(target_definition, pod_targets)
end
aggregate_targets.each do |target|
......@@ -286,85 +289,84 @@ module Pod
# @return [Array<PodTarget>]
#
def generate_pod_targets(specs_by_target)
dedupe_cache = {}
if installation_options.deduplicate_targets?
all_specs = specs_by_target.flat_map do |target_definition, dependent_specs|
dependent_specs.group_by(&:root).map do |root_spec, specs|
[root_spec, specs, target_definition]
distinct_targets = specs_by_target.each_with_object({}) do |dependency, hash|
target_definition, dependent_specs = *dependency
dependent_specs.group_by(&:root).each do |root_spec, specs|
pod_variant = PodVariant.new(specs, target_definition.platform, target_definition.uses_frameworks?)
hash[root_spec] ||= {}
(hash[root_spec][pod_variant] ||= []) << target_definition
end
end
distinct_targets = all_specs.each_with_object({}) do |dependency, hash|
root_spec, specs, target_definition = *dependency
hash[root_spec] ||= {}
(hash[root_spec][[specs, target_definition.platform]] ||= []) << target_definition
end
pod_targets = distinct_targets.flat_map do |_, targets_by_distinctors|
if targets_by_distinctors.count > 1
# There are different sets of subspecs or the spec is used across different platforms
targets_by_distinctors.flat_map do |distinctor, target_definitions|
specs, = *distinctor
generate_pod_target(target_definitions, specs).scoped(dedupe_cache)
end
else
(specs, _), target_definitions = targets_by_distinctors.first
generate_pod_target(target_definitions, specs)
pod_targets = distinct_targets.flat_map do |_root, target_definitions_by_variant|
suffixes = PodVariantSet.new(target_definitions_by_variant.keys).scope_suffixes
target_definitions_by_variant.flat_map do |variant, target_definitions|
generate_pod_target(target_definitions, variant.specs, :scope_suffix => suffixes[variant])
end
end
# A `PodTarget` can't be deduplicated if any of its
# transitive dependencies can't be deduplicated.
pod_targets.flat_map do |target|
dependent_targets = transitive_dependencies_for_pod_target(target, pod_targets)
target.dependent_targets = dependent_targets
if dependent_targets.any?(&:scoped?)
target.scoped(dedupe_cache)
else
target
all_specs = specs_by_target.values.flatten.uniq
pod_targets_by_name = pod_targets.group_by(&:pod_name).each_with_object({}) do |(name, values), hash|
# Sort the target by the number of activated subspecs, so that
# we prefer a minimal target as transitive dependency.
hash[name] = values.sort_by { |pt| pt.specs.count }
end
pod_targets.each do |target|
dependencies = transitive_dependencies_for_specs(target.specs, target.platform, all_specs).group_by(&:root)
target.dependent_targets = dependencies.map do |root_spec, deps|
pod_targets_by_name[root_spec.name].find do |t|
next false if t.platform.symbolic_name != target.platform.symbolic_name ||
t.requires_frameworks? != target.requires_frameworks?
spec_names = t.specs.map(&:name)
deps.all? { |dep| spec_names.include?(dep.name) }
end
end
end
else
pod_targets = specs_by_target.flat_map do |target_definition, specs|
grouped_specs = specs.group_by.group_by(&:root).values.uniq
grouped_specs.flat_map do |pod_specs|
dedupe_cache = {}
specs_by_target.flat_map do |target_definition, specs|
grouped_specs = specs.group_by(&:root).values.uniq
pod_targets = grouped_specs.flat_map do |pod_specs|
generate_pod_target([target_definition], pod_specs).scoped(dedupe_cache)
end
end
pod_targets.each do |target|
target.dependent_targets = transitive_dependencies_for_pod_target(target, pod_targets)
pod_targets.each do |target|
dependencies = transitive_dependencies_for_specs(target.specs, target.platform, specs).group_by(&:root)
target.dependent_targets = pod_targets.reject { |t| dependencies[t.root_spec].nil? }
end
end
end
end
# Finds the names of the Pods upon which the given target _transitively_
# depends.
# Returns the specs upon which the given specs _transitively_ depend.
#
# @note: This is implemented in the analyzer, because we don't have to
# care about the requirements after dependency resolution.
#
# @param [PodTarget] pod_target
# The pod target, whose dependencies should be returned.
# @param [Array<Specification>] specs
# The specs, whose dependencies should be returned.
#
# @param [Array<PodTarget>] targets
# All pod targets, which are integrated alongside.
# @param [Platform] platform
# The platform for which the dependencies should be returned.
#
# @return [Array<PodTarget>]
# @param [Array<Specification>] all_specs
# All specifications which are installed alongside.
#
def transitive_dependencies_for_pod_target(pod_target, targets)
if targets.any?
dependent_targets = pod_target.dependencies.flat_map do |dep|
next [] if pod_target.pod_name == dep
targets.select { |t| t.pod_name == dep }
end
remaining_targets = targets - dependent_targets
dependent_targets += dependent_targets.flat_map do |target|
transitive_dependencies_for_pod_target(target, remaining_targets)
end
dependent_targets.uniq
else
[]
end
# @return [Array<Specification>]
#
def transitive_dependencies_for_specs(specs, platform, all_specs)
return [] if specs.empty? || all_specs.empty?
dependent_specs = specs.flat_map do |spec|
spec.consumer(platform).dependencies.flat_map do |dependency|
all_specs.find do |s|
next false if specs.include?(s)
s.name == dependency.name
end
end.compact
end.uniq
remaining_specs = all_specs - dependent_specs
dependent_specs + transitive_dependencies_for_specs(dependent_specs, platform, remaining_specs)
end
# Create a target for each spec group
......@@ -372,13 +374,17 @@ module Pod
# @param [TargetDefinitions] target_definitions
# the aggregate target
#
# @param [Array<Specification>] specs
# @param [Array<Specification>] pod_specs
# the specifications of an equal root.
#
# @param [String] scope_suffix
# @see PodTarget#scope_suffix
#
# @return [PodTarget]
#
def generate_pod_target(target_definitions, pod_specs)
pod_target = PodTarget.new(pod_specs, target_definitions, sandbox)
def generate_pod_target(target_definitions, pod_specs, scope_suffix: nil)
pod_target = PodTarget.new(pod_specs, target_definitions, sandbox, scope_suffix)
pod_target.host_requires_frameworks = target_definitions.any?(&:uses_frameworks?)
if installation_options.integrate_targets?
target_inspections = result.target_inspections.select { |t, _| target_definitions.include?(t) }.values
......
......@@ -21,8 +21,8 @@ module Pod
#
attr_accessor :sandbox_state
# @return [Array<Target>] The Podfile targets containing library
# dependencies.
# @return [Array<AggregateTarget>] The aggregate targets created for each
# {TargetDefinition} from the {Podfile}.
#
attr_accessor :targets
......
module Pod
class Installer
class Analyzer
# Bundles the information needed to setup a {PodTarget}.
class PodVariant
# @return [Array<Specification>] the spec and subspecs for the target
#
attr_accessor :specs
# @return [Platform] the platform
#
attr_accessor :platform
# @return [Bool] whether this pod should be built as framework
#
attr_accessor :requires_frameworks
alias_method :requires_frameworks?, :requires_frameworks
# @return [Specification] the root specification
#
def root_spec
specs.first.root
end
# Initialize a new instance from its attributes.
#
# @param [Array<String>] specs @see #specs
# @param [Platform] platform @see #platform
# @param [Bool] requires_frameworks @see #requires_frameworks?
#
def initialize(specs, platform, requires_frameworks = false)
self.specs = specs
self.platform = platform
self.requires_frameworks = requires_frameworks
end
# @return [Bool] whether the {PodVariant} is equal to another taking all
# all their attributes into account
#
def ==(other)
self.class == other.class &&
specs == other.specs &&
platform == other.platform &&
requires_frameworks == other.requires_frameworks
end
alias_method :eql?, :==
# Hashes the instance by all its attributes.
#
# This adds support to make instances usable as Hash keys.
#
# @!visibility private
def hash
[specs, platform, requires_frameworks].hash
end
end
end
end
end
require 'set'
module Pod
class Installer
class Analyzer
# Collects all {PodVariant}.
class PodVariantSet
# @return [Array<PodVariant>] the different variants.
#
attr_accessor :variants
# Initialize a new instance.
#
# @param [Array<PodVariant>] variants @see #variants
#
def initialize(variants)
self.variants = variants
end
# Describes what makes each {PodVariant} distinct among the others.
#
# @return [Hash<PodVariant, String>]
#
def scope_suffixes
return { variants.first => nil } if variants.count == 1
scope_by_specs
end
# Groups the collection by result of the block.
#
# @param [Block<Variant, #hash>] block
# @return [Array<PodVariantSet>]
#
def group_by(&block)
variants.group_by(&block).map { |_, v| PodVariantSet.new(v) }
end
# @private
#
# Prepends the given scoped {PodVariant}s with another scoping label, if there
# was more than one group of {PodVariant}s given.
#
# @param [Array<Hash<PodVariant, String>>] scoped_variants
# {PodVariant}s, which where grouped on base of a criteria, which is used
# in the block argument to generate a descriptive label.
#
# @param [Block<PodVariant, String>] block
# takes a {PodVariant} and returns a scope suffix which is prepended, if
# necessary.
#
# @return [Hash<PodVariant, String>]
#
def scope_if_necessary(scoped_variants, &block)
if scoped_variants.count == 1
return scoped_variants.first
end
Hash[scoped_variants.flat_map do |variants|
variants.map do |variant, suffix|
prefix = block.call(variant)
scope = [prefix, suffix].compact.join('-')
[variant, !scope.empty? ? scope : nil]
end
end]
end
# @private
# @return [Hash<PodVariant, String>]
#
def scope_by_build_type
scope_if_necessary(group_by(&:requires_frameworks).map(&:scope_by_platform)) do |variant|
variant.requires_frameworks? ? 'framework' : 'library'
end
end
# @private
# @return [Hash<PodVariant, String>]
#
def scope_by_platform
grouped_variants = group_by { |v| v.platform.name }
if grouped_variants.all? { |set| set.variants.count == 1 }
# => Platform name
platform_name_proc = proc { |v| Platform.string_name(v.platform.symbolic_name).tr(' ', '') }
else
grouped_variants = group_by(&:platform)
# => Platform name + SDK version
platform_name_proc = proc { |v| v.platform.to_s.tr(' ', '') }
end
scope_if_necessary(grouped_variants.map(&:scope_without_suffix), &platform_name_proc)
end
# @private
# @return [Hash<PodVariant, String>]
#
def scope_by_specs
root_spec = variants.first.root_spec
specs = [root_spec]
if root_spec.default_subspecs.empty?
specs += root_spec.subspecs.compact
else
specs += root_spec.default_subspecs.map do |subspec_name|
root_spec.subspec_by_name("#{root_spec.name}/#{subspec_name}")
end
end
default_specs = Set.new(specs)
grouped_variants = group_by(&:specs)
all_spec_variants = grouped_variants.map { |set| set.variants.first.specs }
common_specs = all_spec_variants.map(&:to_set).flatten.inject(&:&)
omit_common_specs = common_specs.any? && common_specs.proper_superset?(default_specs)
scope_if_necessary(grouped_variants.map(&:scope_by_build_type)) do |variant|
specs = variant.specs.to_set
# The current variant contains all default specs
omit_default_specs = default_specs.any? && default_specs.subset?(specs)
if omit_default_specs
specs -= default_specs
end
# There are common specs, which are different from the default specs
if omit_common_specs
specs -= common_specs
end
spec_names = specs.map do |spec|
spec.root? ? '.root' : spec.name.split('/')[1..-1].join('_')
end.sort
if spec_names.empty?
omit_common_specs ? '.common' : nil
else
if omit_common_specs
spec_names.unshift('.common')
elsif omit_default_specs
spec_names.unshift('.default')
end
spec_names.reduce('') do |acc, name|
"#{acc}#{acc.empty? || name[0] == '.' ? '' : '-'}#{name}"
end
end
end
end
# @private
#
# Helps to define scope suffixes recursively.
#
# @return [Hash<PodVariant, String>]
#
def scope_without_suffix
Hash[variants.map { |v| [v, nil] }]
end
end
end
end
end
......@@ -151,7 +151,7 @@ module Pod
end
frameworks_by_config[config] = relevant_pod_targets.flat_map do |pod_target|
frameworks = pod_target.file_accessors.flat_map(&:vendored_dynamic_artifacts).map { |fw| "${PODS_ROOT}/#{fw.relative_path_from(sandbox.root)}" }
frameworks << "#{target_definition.label}/#{pod_target.product_name}" if pod_target.should_build? && pod_target.requires_frameworks?
frameworks << pod_target.build_product_path if pod_target.should_build? && pod_target.requires_frameworks?
frameworks
end
end
......
......@@ -216,7 +216,7 @@ module Pod
end
def targets_to_integrate
targets.reject { |target| target.target_definition.abstract? }
targets
end
# Prints a warning informing the user that a build configuration of
......
......@@ -13,6 +13,7 @@ module Pod
# @param [Sandbox] sandbox @see sandbox
#
def initialize(target_definition, sandbox)
raise "Can't initialize an AggregateTarget with an abstract TargetDefinition" if target_definition.abstract?
super()
@target_definition = target_definition
@sandbox = sandbox
......@@ -205,13 +206,6 @@ module Pod
"${SRCROOT}/#{relative_to_srcroot(embed_frameworks_script_path)}"
end
# @return [String] The scoped configuration build dir, relevant if the
# target is integrated as framework.
#
def scoped_configuration_build_dir
"$(BUILD_DIR)/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)/#{target_definition.label}"
end
private
# @!group Private Helpers
......
......@@ -19,19 +19,25 @@ module Pod
# @return [Bool] whether the target needs to be scoped by target definition,
# because the spec is used with different subspec sets across them.
#
# @note For frameworks the target products of {PodTarget}s are named
# after their specs. The namespacing cannot directly happen in
# the product name itself, because this must be equal to the module
# name and this will be used in source code, which should stay
# agnostic over the dependency manager.
# @note The target products of {PodTarget}s are named after their specs.
# The namespacing cannot directly happen in the product name itself,
# because this must be equal to the module name and this will be
# used in source code, which should stay agnostic over the
# dependency manager.
# We need namespacing because multiple targets can exist for the
# same podspec and their products should not collide. This
# duplication is needed when multiple user targets have the same
# dependency, but they require different sets of subspecs or they
# are on different platforms.
#
attr_reader :scoped
alias_method :scoped?, :scoped
def scoped?
!scope_suffix.nil?
end
# @return [String] used for the label and the directory name, which is used to
# scope the build product in the default configuration build dir.
#
attr_reader :scope_suffix
# @return [Array<PodTarget>] the targets that this target has a dependency
# upon.
......@@ -41,16 +47,18 @@ module Pod
# @param [Array<Specification>] @spec #see spec
# @param [Array<TargetDefinition>] target_definitions @see target_definitions
# @param [Sandbox] sandbox @see sandbox
# @param [Bool] scoped @see scoped
# @param [String] scope_suffix @see scope_suffix
#
def initialize(specs, target_definitions, sandbox, scoped = false)
def initialize(specs, target_definitions, sandbox, scope_suffix = nil)
raise "Can't initialize a PodTarget without specs!" if specs.nil? || specs.empty?
raise "Can't initialize a PodTarget without TargetDefinition!" if target_definitions.nil? || target_definitions.empty?
raise "Can't initialize a PodTarget with only abstract TargetDefinitions" if target_definitions.all?(&:abstract?)
raise "Can't initialize a PodTarget with an empty string scope suffix!" if scope_suffix == ''
super()
@specs = specs
@target_definitions = target_definitions
@sandbox = sandbox
@scoped = scoped
@scope_suffix = scope_suffix
@build_headers = Sandbox::HeadersStore.new(sandbox, 'Private')
@file_accessors = []
@resource_bundle_targets = []
......@@ -67,7 +75,7 @@ module Pod
if cache[cache_key]
cache[cache_key]
else
target = PodTarget.new(specs, [target_definition], sandbox, true)
target = PodTarget.new(specs, [target_definition], sandbox, target_definition.label)
target.file_accessors = file_accessors
target.user_build_configurations = user_build_configurations
target.native_target = native_target
......@@ -82,7 +90,11 @@ module Pod
#
def label
if scoped?
"#{target_definitions.first.label}-#{root_spec.name}"
if scope_suffix[0] == '.'
"#{root_spec.name}#{scope_suffix}"
else
"#{root_spec.name}-#{scope_suffix}"
end
else
root_spec.name
end
......@@ -241,15 +253,24 @@ module Pod
end
end
# @return [String] The configuration build dir, relevant if the target is
# integrated as framework.
# @param [String] dir
# The directory (which might be a variable) relative to which
# the returned path should be. This must be used if the
# $CONFIGURATION_BUILD_DIR is modified.
#
def configuration_build_dir
if scoped?
"$(BUILD_DIR)/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)/#{target_definitions.first.label}"
else
'$(BUILD_DIR)/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)'
end
# @return [String] The absolute path to the configuration build dir
#
def configuration_build_dir(dir = '$CONFIGURATION_BUILD_DIR')
"#{dir}/#{label}"
end
# @param [String] dir
# @see #configuration_build_dir
#
# @return [String] The absolute path to the build product
#
def build_product_path(dir = '$CONFIGURATION_BUILD_DIR')
"#{configuration_build_dir(dir)}/#{product_name}"
end
private
......
......@@ -428,7 +428,7 @@ module Pod
# for all available platforms with xcodebuild.
#
def install_pod
%i(determine_dependency_product_types verify_no_duplicate_framework_names
%i(verify_no_duplicate_framework_names
verify_no_static_framework_transitive_dependencies
verify_framework_usage generate_pods_project integrate_user_project
perform_post_install_actions).each { |m| @installer.send(m) }
......
Subproject commit 05c3fc9beea098b5e1ce3aaa882d454511e6348c
Subproject commit 1adc26822f4509232f6953e421d592753ac98c19
Pod::Spec.new do |s|
s.name = "matryoshka"
s.version = "1.0.0"
s.author = { "Matryona Malyutin" => "matryona@malyutin.local" }
s.summary = "👩‍👩‍👧"
s.description = "Four levels: outmost (root), outer, inner"
s.homepage = "http://httpbin.org/html"
s.source = { :git => "http://malyutin.local/matryoshka.git", :tag => s.version.to_s }
s.license = 'MIT'
s.source_files = 'Outmost.{h,m}'
s.default_subspecs = 'Outer'
s.subspec 'Outer' do |outer_subspec|
outer_subspec.source_files = 'Outer/Outer.{h,m}'
outer_subspec.subspec 'Inner' do |inner_subspec|
inner_subspec.source_files = 'Inner/Inner.{h,m}'
end
end
s.subspec 'Foo' do |ss|
ss.source_files = 'Foo/Foo.{h,m}'
end
s.subspec 'Bar' do |ss|
ss.source_files = 'Bar/Bar.{h,m}'
end
end
......@@ -13,4 +13,6 @@ Pod::Spec.new do |s|
s.source_files = 'Source/Juicer.swift'
s.frameworks = 'UIKit'
s.dependency 'matryoshka'
end
......@@ -13,4 +13,6 @@ Pod::Spec.new do |s|
s.source_files = 'Source/Juicer.swift'
s.frameworks = 'UIKit'
s.dependency 'matryoshka'
end
{
"name": "matryoshka",
"version": "1.0.0",
"authors": {
"Matryona Malyutin": "matryona@malyutin.local"
},
"summary": "👩‍👩‍👧",
"description": "Four levels: outmost (root), outer, inner",
"homepage": "http://httpbin.org/html",
"source": {
"git": "http://malyutin.local/matroyshka.git",
"tag": "1.0.0"
},
"license": "MIT",
"source_files": "Outmost.{h,m}",
"default_subspecs": "Outer",
"platforms": {
"osx": null,
"ios": null,
"tvos": null,
"watchos": null
},
"subspecs": [
{
"name": "Outer",
"source_files": "Outer/Outer.{h,m}",
"subspecs": [
{
"name": "Inner",
"source_files": "Inner/Inner.{h,m}"
}
]
},
{
"name": "Foo",
"source_files": "Foo/Foo.{h,m}"
},
{
"name": "Bar",
"source_files": "Bar/Bar.{h,m}"
}
]
}
......@@ -116,14 +116,15 @@ def fixture_file_accessor(spec_or_name, platform = Pod::Platform.ios)
end
def fixture_target_definition(name = 'Pods', platform = Pod::Platform.ios)
Pod::Podfile::TargetDefinition.new(name, Pod::Podfile.new, 'name' => name, 'platform' => platform)
platform_hash = { platform.symbolic_name => platform.deployment_target }
Pod::Podfile::TargetDefinition.new(name, Pod::Podfile.new, 'name' => name, 'platform' => platform_hash)
end
def fixture_pod_target(spec_or_name, target_definition = nil)
def fixture_pod_target(spec_or_name, target_definitions = [])
spec = spec_or_name.is_a?(Pod::Specification) ? spec_or_name : fixture_spec(spec_or_name)
target_definition ||= fixture_target_definition
target_definition.store_pod(spec.name)
Pod::PodTarget.new([spec], [target_definition], config.sandbox).tap do |pod_target|
target_definitions << fixture_target_definition if target_definitions.empty?
target_definitions.each { |td| td.store_pod(spec.name) }
Pod::PodTarget.new([spec], target_definitions, config.sandbox).tap do |pod_target|
pod_target.file_accessors << fixture_file_accessor(spec, pod_target.platform)
consumer = spec.consumer(pod_target.platform)
pod_target.spec_consumers << consumer
......
......@@ -4,24 +4,22 @@ module Pod
module Generator
module XCConfig
describe AggregateXCConfig do
def spec
fixture_spec('banana-lib/BananaLib.podspec')
def specs
[fixture_spec('banana-lib/BananaLib.podspec')]
end
def pod_target(spec)
fixture_pod_target(spec)
def pod_target(spec, target_definition)
fixture_pod_target(spec, [target_definition])
end
before do
@spec = spec
@spec.user_target_xcconfig = { 'OTHER_LDFLAGS' => '-no_compact_unwind' }
@spec.pod_target_xcconfig = { 'CLANG_CXX_LANGUAGE_STANDARD' => 'c++11' }
@pod_target = pod_target(@spec)
@consumer = @pod_target.spec_consumers.last
@target = fixture_aggregate_target([@pod_target])
@target.target_definition.should == @pod_target.target_definitions.first
@target.target_definition.whitelist_pod_for_configuration(@spec.name, 'Release')
@podfile = @target.target_definition.podfile
@target_definition = fixture_target_definition
@specs = specs
@specs.first.user_target_xcconfig = { 'OTHER_LDFLAGS' => '-no_compact_unwind' }
@specs.first.pod_target_xcconfig = { 'CLANG_CXX_LANGUAGE_STANDARD' => 'c++11' }
@pod_targets = @specs.map { |spec| pod_target(spec, @target_definition) }
@target = fixture_aggregate_target(@pod_targets, @target_definition)
@target.target_definition.whitelist_pod_for_configuration(@specs.first.name, 'Release')
@generator = AggregateXCConfig.new(@target, 'Release')
end
......@@ -33,6 +31,8 @@ module Pod
#--------------------------------------------------------------------#
before do
@consumer = @pod_targets.first.spec_consumers.last
@podfile = @target.target_definition.podfile
@xcconfig = @generator.generate
end
......@@ -74,7 +74,7 @@ module Pod
describe 'if a pod target does not contain source files' do
before do
@pod_target.file_accessors.first.stubs(:source_files).returns([])
@pod_targets.first.file_accessors.first.stubs(:source_files).returns([])
@xcconfig = @generator.generate
end
......@@ -94,8 +94,8 @@ module Pod
#-----------------------------------------------------------------------#
describe 'with library' do
def spec
fixture_spec('banana-lib/BananaLib.podspec')
def specs
[fixture_spec('banana-lib/BananaLib.podspec')]
end
behaves_like 'AggregateXCConfig'
......@@ -115,12 +115,12 @@ module Pod
end
describe 'with a scoped pod target' do
def pod_target(spec)
fixture_pod_target(spec).scoped.first
def pod_target(spec, target_definition)
fixture_pod_target(spec, [target_definition]).scoped.first
end
it 'links the pod targets with the aggregate target' do
@xcconfig.to_hash['OTHER_LDFLAGS'].should.include '-l"Pods-BananaLib"'
@xcconfig.to_hash['OTHER_LDFLAGS'].should.include '-l"BananaLib-Pods"'
end
end
......@@ -138,8 +138,8 @@ module Pod
end
describe 'with framework' do
def spec
fixture_spec('orange-framework/OrangeFramework.podspec')
def specs
[fixture_spec('orange-framework/OrangeFramework.podspec')]
end
before do
......@@ -153,8 +153,8 @@ module Pod
end
describe 'with a vendored-library pod' do
def spec
fixture_spec('monkey/monkey.podspec')
def specs
[fixture_spec('monkey/monkey.podspec')]
end
it 'does add the framework build path to the xcconfig' do
......@@ -171,8 +171,8 @@ module Pod
end
it 'includes the public header paths as system headers' do
expected = '$(inherited) -iquote "$CONFIGURATION_BUILD_DIR/OrangeFramework.framework/Headers" -isystem "${PODS_ROOT}/Headers/Public"'
@generator.stubs(:pod_targets).returns([@pod_target, pod_target(fixture_spec('orange-framework/OrangeFramework.podspec'))])
expected = '$(inherited) -iquote "$CONFIGURATION_BUILD_DIR/OrangeFramework/OrangeFramework.framework/Headers" -isystem "${PODS_ROOT}/Headers/Public"'
@generator.stubs(:pod_targets).returns([@pod_targets.first, pod_target(fixture_spec('orange-framework/OrangeFramework.podspec'), @target_definition)])
@xcconfig = @generator.generate
@xcconfig.to_hash['OTHER_CFLAGS'].should == expected
end
......@@ -188,32 +188,39 @@ module Pod
end
end
it 'sets the PODS_FRAMEWORK_BUILD_PATH build variable' do
@xcconfig.to_hash['PODS_FRAMEWORK_BUILD_PATH'].should == '"$(BUILD_DIR)/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)/Pods"'
end
describe 'with a scoped pod target' do
def pod_target(spec)
fixture_pod_target(spec).scoped.first
def specs
[
fixture_spec('banana-lib/BananaLib.podspec'),
fixture_spec('orange-framework/OrangeFramework.podspec'),
]
end
def pod_target(spec, target_definition)
target_definition = fixture_target_definition(spec.name)
target_definition.stubs(:parent).returns(@target_definition.podfile)
fixture_pod_target(spec, [target_definition, @target_definition].uniq).tap do |pod_target|
pod_target.stubs(:scope_suffix).returns('iOS')
end
end
it 'adds the framework build path to the xcconfig, with quotes, as framework search paths' do
@xcconfig.to_hash['FRAMEWORK_SEARCH_PATHS'].should == '$(inherited) $PODS_FRAMEWORK_BUILD_PATH'
@xcconfig.to_hash['FRAMEWORK_SEARCH_PATHS'].should == '$(inherited) "$CONFIGURATION_BUILD_DIR/BananaLib-iOS" "$CONFIGURATION_BUILD_DIR/OrangeFramework-iOS"'
end
it 'adds the framework header paths to the xcconfig, with quotes, as local headers' do
expected = '$(inherited) -iquote "$PODS_FRAMEWORK_BUILD_PATH/OrangeFramework.framework/Headers"'
expected = '$(inherited) -iquote "$CONFIGURATION_BUILD_DIR/BananaLib-iOS/BananaLib.framework/Headers" -iquote "$CONFIGURATION_BUILD_DIR/OrangeFramework-iOS/OrangeFramework.framework/Headers"'
@xcconfig.to_hash['OTHER_CFLAGS'].should == expected
end
end
describe 'with an unscoped pod target' do
it 'adds the framework build path to the xcconfig, with quotes, as framework search paths' do
@xcconfig.to_hash['FRAMEWORK_SEARCH_PATHS'].should.be.nil
@xcconfig.to_hash['FRAMEWORK_SEARCH_PATHS'].should == '$(inherited) "$CONFIGURATION_BUILD_DIR/OrangeFramework"'
end
it 'adds the framework header paths to the xcconfig, with quotes, as local headers' do
expected = '$(inherited) -iquote "$CONFIGURATION_BUILD_DIR/OrangeFramework.framework/Headers"'
expected = '$(inherited) -iquote "$CONFIGURATION_BUILD_DIR/OrangeFramework/OrangeFramework.framework/Headers"'
@xcconfig.to_hash['OTHER_CFLAGS'].should == expected
end
end
......@@ -271,12 +278,16 @@ module Pod
#-----------------------------------------------------------------------#
describe 'with multiple pod targets with user_target_xcconfigs' do
def specs
[
fixture_spec('banana-lib/BananaLib.podspec'),
fixture_spec('orange-framework/OrangeFramework.podspec'),
]
end
before do
spec_b = fixture_spec('orange-framework/OrangeFramework.podspec')
@pod_target_b = fixture_pod_target(spec_b)
@consumer_a = @consumer
@consumer_b = @pod_target_b.spec_consumers.last
@target.pod_targets << @pod_target_b
@consumer_a = @pod_targets[0].spec_consumers.last
@consumer_b = @pod_targets[1].spec_consumers.last
end
describe 'with boolean build settings' do
......@@ -315,7 +326,7 @@ module Pod
it 'adds values from all subspecs' do
@consumer_b.stubs(:user_target_xcconfig).returns('OTHER_CPLUSPLUSFLAGS' => '-std=c++1y')
consumer_c = mock(:user_target_xcconfig => { 'OTHER_CPLUSPLUSFLAGS' => '-stdlib=libc++' })
@pod_target_b.stubs(:spec_consumers).returns([@consumer_b, consumer_c])
@pod_targets[1].stubs(:spec_consumers).returns([@consumer_b, consumer_c])
@xcconfig = @generator.generate
@xcconfig.to_hash['OTHER_CPLUSPLUSFLAGS'].should == '-std=c++1y -stdlib=libc++'
end
......
require File.expand_path('../../../../spec_helper', __FILE__)
module Pod
describe PodVariantSet = Installer::Analyzer::PodVariantSet do
describe '#scope_suffixes' do
before do
@root_spec = fixture_spec('matryoshka/matryoshka.podspec')
@default_subspec = @root_spec.subspec_by_name('matryoshka/Outer')
@inner_subspec = @root_spec.subspec_by_name('matryoshka/Outer/Inner')
@foo_subspec = @root_spec.subspec_by_name('matryoshka/Foo')
@bar_subspec = @root_spec.subspec_by_name('matryoshka/Bar')
end
PodVariant = Pod::Installer::Analyzer::PodVariant.freeze
it 'returns an empty scope if there is only one variant' do
variants = PodVariantSet.new([PodVariant.new([@root_spec], Platform.ios)])
variants.scope_suffixes.values.should == [nil]
end
it 'returns scopes by built types if they qualify' do
variants = PodVariantSet.new([
PodVariant.new([@root_spec], Platform.ios, true),
PodVariant.new([@root_spec], Platform.ios, false),
])
variants.scope_suffixes.values.should == %w(framework library)
end
it 'returns scopes by platform names if they qualify' do
variants = PodVariantSet.new([
PodVariant.new([@root_spec], Platform.ios),
PodVariant.new([@root_spec], Platform.osx),
])
variants.scope_suffixes.values.should == %w(iOS OSX)
end
it 'returns scopes by versioned platform names if they qualify' do
variants = PodVariantSet.new([
PodVariant.new([@root_spec], Platform.ios),
PodVariant.new([@root_spec], Platform.new(:ios, '7.0')),
])
variants.scope_suffixes.values.should == %w(iOS iOS7.0)
end
it 'returns scopes by subspec names if they qualify' do
variants = PodVariantSet.new([
PodVariant.new([@foo_subspec], Platform.ios),
PodVariant.new([@bar_subspec], Platform.ios),
])
variants.scope_suffixes.values.should == %w(Foo Bar)
end
it 'returns scopes by subspec names if they qualify and handle partial root spec presence well' do
variants = PodVariantSet.new([
PodVariant.new([@foo_subspec], Platform.ios),
PodVariant.new([@root_spec, @bar_subspec], Platform.ios),
])
variants.scope_suffixes.values.should == %w(Foo .root-Bar)
end
it 'allows to differentiate between an exclusive variant with a specific subspec and ' \
'an inclusive variant with the default subspecs plus a non-default subspec' do
variants = PodVariantSet.new([
PodVariant.new([@foo_subspec], Platform.ios),
PodVariant.new([@root_spec, @default_subspec, @foo_subspec], Platform.ios),
])
variants.scope_suffixes.values.should == %w(Foo .default-Foo)
end
it 'omits default specs' do
variants = PodVariantSet.new([
PodVariant.new([@root_spec, @default_subspec], Platform.ios),
PodVariant.new([@root_spec, @default_subspec, @foo_subspec], Platform.ios),
PodVariant.new([@root_spec, @default_subspec, @bar_subspec], Platform.ios),
])
variants.scope_suffixes.values.should == [nil, '.default-Foo', '.default-Bar']
end
it 'omits common specs' do
variants = PodVariantSet.new([
PodVariant.new([@root_spec, @default_subspec, @inner_subspec], Platform.ios),
PodVariant.new([@root_spec, @default_subspec, @inner_subspec, @foo_subspec], Platform.ios),
PodVariant.new([@root_spec, @default_subspec, @inner_subspec, @bar_subspec], Platform.ios),
])
variants.scope_suffixes.values.should == %w(.common .common-Foo .common-Bar)
end
it 'returns scopes by platform names and subspec names if they qualify' do
variants = PodVariantSet.new([
PodVariant.new([@root_spec, @default_subspec], Platform.ios),
PodVariant.new([@root_spec, @default_subspec], Platform.osx),
PodVariant.new([@root_spec, @default_subspec, @foo_subspec], Platform.ios),
PodVariant.new([@root_spec, @default_subspec, @bar_subspec], Platform.osx),
])
variants.scope_suffixes.values.should == %w(
iOS
OSX
.default-Foo
.default-Bar
)
end
it 'returns scopes by versioned platform names and subspec names if they qualify' do
variants = PodVariantSet.new([
PodVariant.new([@root_spec, @default_subspec], Platform.new(:ios, '7.0')),
PodVariant.new([@root_spec, @default_subspec], Platform.ios),
PodVariant.new([@root_spec, @default_subspec, @foo_subspec], Platform.ios),
PodVariant.new([@root_spec, @default_subspec], Platform.osx),
PodVariant.new([@root_spec, @default_subspec, @foo_subspec], Platform.osx),
PodVariant.new([@root_spec, @default_subspec, @bar_subspec], Platform.osx),
])
variants.scope_suffixes.values.should == %w(
iOS7.0
iOS
OSX
.default-Foo-iOS
.default-Foo-OSX
.default-Bar
)
end
it 'returns scopes by built types, versioned platform names and subspec names' do
variants = PodVariantSet.new([
PodVariant.new([@root_spec, @default_subspec], Platform.new(:ios, '7.0')),
PodVariant.new([@root_spec, @default_subspec], Platform.ios),
PodVariant.new([@root_spec, @default_subspec], Platform.osx, true),
PodVariant.new([@root_spec, @default_subspec, @foo_subspec], Platform.osx, true),
])
variants.scope_suffixes.values.should == %w(
library-iOS7.0
library-iOS
framework
.default-Foo
)
end
end
end
end
require File.expand_path('../../../../spec_helper', __FILE__)
module Pod
describe PodVariant = Installer::Analyzer::PodVariant do
before do
@specs = [stub('Spec'), stub('Spec/Foo')]
@platform = Platform.ios
end
it 'can be initialized with specs and platform' do
variant = PodVariant.new(@specs, @platform)
variant.specs.should == @specs
variant.platform.should == @platform
variant.requires_frameworks.should == false
end
it 'can be initialized with specs, platform and whether it requires frameworks' do
variant = PodVariant.new(@specs, @platform, true)
variant.specs.should == @specs
variant.platform.should == @platform
variant.requires_frameworks.should == true
end
it 'can return the root spec' do
spec = fixture_spec('banana-lib/BananaLib.podspec')
variant = PodVariant.new([spec], Platform.ios)
variant.root_spec.should == spec
end
it 'can be compared for equality with another variant with the same specs, platform and value for whether it requires frameworks' do
spec = PodVariant.new(@specs, @platform, false)
spec.should == PodVariant.new(@specs, @platform, false)
spec.should.not == PodVariant.new([@specs.first], @platform, false)
spec.should.not == PodVariant.new(@specs, Platform.osx, false)
spec.should.not == PodVariant.new(@specs, @platform, true)
end
it 'can be used as hash keys' do
k0 = PodVariant.new(@specs, @platform, false)
v0 = stub('Value at index 0')
k1 = PodVariant.new(@specs, @platform, true)
v1 = stub('Value at index 1')
hash = { k0 => v0, k1 => v1 }
hash[k0].should == v0
hash[k1].should == v1
end
end
end
......@@ -4,6 +4,11 @@ module Pod
describe Installer::Analyzer do
describe 'Analysis' do
before do
repos = [fixture('spec-repos/test_repo'), fixture('spec-repos/master')]
aggregate = Pod::Source::Aggregate.new(repos)
Pod::SourcesManager.stubs(:aggregate).returns(aggregate)
aggregate.sources.first.stubs(:url).returns(SpecHelper.test_repo_url)
@podfile = Pod::Podfile.new do
platform :ios, '6.0'
project 'SampleProject/SampleProject'
......@@ -131,13 +136,19 @@ module Pod
#--------------------------------------#
it 'generates the model to represent the target definitions' do
target = @analyzer.analyze.targets.first
target.pod_targets.map(&:name).sort.should == [
'JSONKit',
'AFNetworking',
'SVPullToRefresh',
'Pods-SampleProject-libextobjc',
].sort
result = @analyzer.analyze
target, test_target = result.targets
test_target.pod_targets.map(&:name).sort.should == %w(
libextobjc-EXTKeyPathCoding-EXTSynthesize
).sort
target.pod_targets.map(&:name).sort.should == %w(
JSONKit
AFNetworking
libextobjc-EXTKeyPathCoding
SVPullToRefresh
).sort
target.support_files_dir.should == config.sandbox.target_support_files_dir('Pods-SampleProject')
target.pod_targets.map(&:archs).uniq.should == [[]]
......@@ -156,42 +167,69 @@ module Pod
target.platform.to_s.should == 'iOS 6.0'
end
it 'generates the set of dependent pod targets' do
@podfile = Pod::Podfile.new do
platform :ios, '8.0'
project 'SampleProject/SampleProject'
pod 'RestKit', '~> 0.23.0'
target 'TestRunner' do
pod 'RestKit/Testing', '~> 0.23.0'
describe 'dependent pod targets' do
it 'picks transitive dependencies up' do
@podfile = Pod::Podfile.new do
platform :ios, '8.0'
project 'SampleProject/SampleProject'
pod 'RestKit', '~> 0.23.0'
target 'TestRunner' do
pod 'RestKit/Testing', '~> 0.23.0'
end
end
@analyzer = Pod::Installer::Analyzer.new(config.sandbox, @podfile, nil)
result = @analyzer.analyze
result.targets.count.should == 1
target = result.targets.first
restkit_target = target.pod_targets.find { |pt| pt.pod_name == 'RestKit' }
restkit_target.dependent_targets.map(&:pod_name).sort.should == %w(
AFNetworking
ISO8601DateFormatterValueTransformer
RKValueTransformers
SOCKit
TransitionKit
)
restkit_target.dependent_targets.all?(&:scoped).should.be.true
end
@analyzer = Pod::Installer::Analyzer.new(config.sandbox, @podfile, nil)
target = @analyzer.analyze.targets.first
restkit_target = target.pod_targets.find { |pt| pt.pod_name == 'RestKit' }
restkit_target.should.be.scoped
restkit_target.dependent_targets.map(&:pod_name).sort.should == %w(
AFNetworking
ISO8601DateFormatterValueTransformer
RKValueTransformers
SOCKit
TransitionKit
)
restkit_target.dependent_targets.all?(&:scoped).should.be.true
end
describe 'deduplication' do
before do
repos = [fixture('spec-repos/test_repo'), fixture('spec-repos/master')]
aggregate = Pod::Source::Aggregate.new(repos)
Pod::SourcesManager.stubs(:aggregate).returns(aggregate)
aggregate.sources.first.stubs(:url).returns(SpecHelper.test_repo_url)
it 'picks the right variants up when there are multiple' do
@podfile = Pod::Podfile.new do
source SpecHelper.test_repo_url
platform :ios, '8.0'
project 'SampleProject/SampleProject'
# The order of target definitions is important for this test.
target 'TestRunner' do
pod 'OrangeFramework'
pod 'matryoshka/Foo'
end
target 'SampleProject' do
pod 'OrangeFramework'
end
end
@analyzer = Pod::Installer::Analyzer.new(config.sandbox, @podfile, nil)
result = @analyzer.analyze
result.targets.count.should == 2
pod_target = result.targets[0].pod_targets.find { |pt| pt.pod_name == 'OrangeFramework' }
pod_target.dependent_targets.count == 1
pod_target.dependent_targets.first.specs.map(&:name).should == %w(
matryoshka
matryoshka/Outer
matryoshka/Outer/Inner
)
end
end
describe 'deduplication' do
it 'deduplicate targets if possible' do
podfile = Pod::Podfile.new do
source SpecHelper.test_repo_url
platform :ios, '6.0'
project 'SampleProject/SampleProject'
target 'SampleProject' do
pod 'BananaLib'
pod 'monkey'
......@@ -201,48 +239,48 @@ module Pod
pod 'monkey'
end
end
target 'CLITool' do
platform :osx, '10.10'
pod 'monkey'
end
end
analyzer = Pod::Installer::Analyzer.new(config.sandbox, podfile)
analyzer.analyze
analyzer.analyze.targets.flat_map { |at| at.pod_targets.map { |pt| "#{at.name}/#{pt.name}" } }.sort.should == %w(
Pods-SampleProject-TestRunner/BananaLib
Pods-SampleProject-TestRunner/monkey
Pods-SampleProject/BananaLib
Pods-SampleProject/monkey
).sort
result = analyzer.analyze
pod_targets = result.targets.flat_map(&:pod_targets).uniq
Hash[pod_targets.map { |t| [t.label, t.target_definitions.map(&:label).sort] }.sort].should == {
'BananaLib' => %w(Pods-SampleProject Pods-SampleProject-TestRunner),
'monkey-iOS' => %w(Pods-SampleProject Pods-SampleProject-TestRunner),
'monkey-OSX' => %w(Pods-CLITool),
}
end
it "doesn't deduplicate targets, where transitive dependencies can't be deduplicated" do
it "doesn't deduplicate targets across different integration modes" do
podfile = Pod::Podfile.new do
source SpecHelper.test_repo_url
platform :ios, '6.0'
project 'SampleProject/SampleProject'
pod 'BananaLib'
pod 'monkey'
xcodeproj 'SampleProject/SampleProject'
target 'SampleProject' do
use_frameworks!
pod 'BananaLib'
target 'TestRunner' do
use_frameworks!(false)
pod 'BananaLib'
pod 'monkey'
end
end
target 'CLITool' do
platform :osx, '10.10'
pod 'monkey'
end
end
analyzer = Pod::Installer::Analyzer.new(config.sandbox, podfile)
analyzer.analyze
analyzer.analyze.targets.flat_map { |at| at.pod_targets.map { |pt| "#{at.name}/#{pt.name}" } }.sort.should == %w(
Pods-CLITool/Pods-CLITool-monkey
Pods-SampleProject-TestRunner/Pods-SampleProject-TestRunner-BananaLib
Pods-SampleProject-TestRunner/Pods-SampleProject-TestRunner-monkey
Pods-SampleProject/Pods-SampleProject-BananaLib
Pods-SampleProject/Pods-SampleProject-monkey
).sort
result = analyzer.analyze
pod_targets = result.targets.flat_map(&:pod_targets).uniq.sort_by(&:name)
Hash[pod_targets.map { |t| [t.label, t.target_definitions.map(&:label)] }].should == {
'BananaLib-library' => %w(Pods-SampleProject-TestRunner),
'BananaLib-framework' => %w(Pods-SampleProject),
'monkey-library' => %w(Pods-SampleProject-TestRunner),
'monkey-framework' => %w(Pods-SampleProject),
}
end
it "doesn't deduplicate targets when deduplication is disabled" do
......@@ -262,13 +300,13 @@ module Pod
end
end
analyzer = Pod::Installer::Analyzer.new(config.sandbox, podfile)
analyzer.analyze
result = analyzer.analyze
analyzer.analyze.targets.flat_map { |at| at.pod_targets.map { |pt| "#{at.name}/#{pt.name}" } }.sort.should == %w(
Pods-SampleProject-TestRunner/Pods-SampleProject-TestRunner-BananaLib
Pods-SampleProject-TestRunner/Pods-SampleProject-TestRunner-monkey
Pods-SampleProject/Pods-SampleProject-BananaLib
Pods-SampleProject/Pods-SampleProject-monkey
result.targets.flat_map { |at| at.pod_targets.map { |pt| "#{at.name}/#{pt.name}" } }.sort.should == %w(
Pods-SampleProject-TestRunner/BananaLib-Pods-SampleProject-TestRunner
Pods-SampleProject-TestRunner/monkey-Pods-SampleProject-TestRunner
Pods-SampleProject/BananaLib-Pods-SampleProject
Pods-SampleProject/monkey-Pods-SampleProject
).sort
end
end
......
......@@ -177,9 +177,9 @@ module Pod
describe 'Private Helpers' do
describe '#file_accessors' do
it 'returns the file accessors' do
pod_target_1 = PodTarget.new([stub('Spec')], [stub('TargetDefinition')], config.sandbox)
pod_target_1 = PodTarget.new([stub('Spec')], [fixture_target_definition], config.sandbox)
pod_target_1.file_accessors = [fixture_file_accessor('banana-lib/BananaLib.podspec')]
pod_target_2 = PodTarget.new([stub('Spec')], [stub('TargetDefinition')], config.sandbox)
pod_target_2 = PodTarget.new([stub('Spec')], [fixture_target_definition], config.sandbox)
pod_target_2.file_accessors = [fixture_file_accessor('banana-lib/BananaLib.podspec')]
installer = Installer::FileReferencesInstaller.new(config.sandbox, [pod_target_1, pod_target_2], @project)
roots = installer.send(:file_accessors).map { |fa| fa.path_list.root }
......@@ -187,7 +187,7 @@ module Pod
end
it 'handles pods without file accessors' do
pod_target_1 = PodTarget.new([stub('Spec')], [stub('TargetDefinition')], config.sandbox)
pod_target_1 = PodTarget.new([stub('Spec')], [fixture_target_definition], config.sandbox)
pod_target_1.file_accessors = []
installer = Installer::FileReferencesInstaller.new(config.sandbox, [pod_target_1], @project)
installer.send(:file_accessors).should == []
......
......@@ -6,10 +6,11 @@ module Pod
before do
config.sandbox.prepare
@podfile = Podfile.new do
platform :ios
project 'dummy'
platform :ios, '6.0'
project 'SampleProject/SampleProject'
target 'SampleProject'
end
@target_definition = @podfile.target_definitions['Pods']
@target_definition = @podfile.target_definitions['SampleProject']
@project = Project.new(config.sandbox.project_path)
config.sandbox.project = @project
......@@ -23,12 +24,10 @@ module Pod
end
@target = AggregateTarget.new(@target_definition, config.sandbox)
@target.stubs(:platform).returns(Platform.new(:ios, '6.0'))
@target.client_root = config.sandbox.root.dirname
@target.user_build_configurations = { 'Debug' => :debug, 'Release' => :release, 'AppStore' => :release, 'Test' => :debug }
@pod_target = PodTarget.new([@spec], [@target_definition], config.sandbox)
@pod_target.stubs(:platform).returns(Platform.new(:ios, '6.0'))
@pod_target.user_build_configurations = @target.user_build_configurations
@pod_target.file_accessors = [file_accessor]
......@@ -41,17 +40,17 @@ module Pod
it 'adds file references for the support files of the target' do
@installer.install!
group = @project.support_files_group['Pods']
group = @project.support_files_group['Pods-SampleProject']
group.children.map(&:display_name).sort.should == [
'Pods-acknowledgements.markdown',
'Pods-acknowledgements.plist',
'Pods-dummy.m',
'Pods-frameworks.sh',
'Pods-resources.sh',
'Pods.appstore.xcconfig',
'Pods.debug.xcconfig',
'Pods.release.xcconfig',
'Pods.test.xcconfig',
'Pods-SampleProject-acknowledgements.markdown',
'Pods-SampleProject-acknowledgements.plist',
'Pods-SampleProject-dummy.m',
'Pods-SampleProject-frameworks.sh',
'Pods-SampleProject-resources.sh',
'Pods-SampleProject.appstore.xcconfig',
'Pods-SampleProject.debug.xcconfig',
'Pods-SampleProject.release.xcconfig',
'Pods-SampleProject.test.xcconfig',
]
end
......@@ -138,16 +137,16 @@ module Pod
it 'creates a create copy resources script' do
@installer.install!
support_files_dir = config.sandbox.target_support_files_dir('Pods')
script = support_files_dir + 'Pods-resources.sh'
support_files_dir = config.sandbox.target_support_files_dir('Pods-SampleProject')
script = support_files_dir + 'Pods-SampleProject-resources.sh'
script.read.should.include?('logo-sidebar.png')
end
it 'does not add framework resources to copy resources script' do
@pod_target.stubs(:requires_frameworks? => true)
@installer.install!
support_files_dir = config.sandbox.target_support_files_dir('Pods')
script = support_files_dir + 'Pods-resources.sh'
support_files_dir = config.sandbox.target_support_files_dir('Pods-SampleProject')
script = support_files_dir + 'Pods-SampleProject-resources.sh'
script.read.should.not.include?('logo-sidebar.png')
end
......@@ -161,8 +160,8 @@ module Pod
@pod_target.stubs(:requires_frameworks? => true)
@target.stubs(:requires_frameworks? => true)
@installer.install!
support_files_dir = config.sandbox.target_support_files_dir('Pods')
script = support_files_dir + 'Pods-frameworks.sh'
support_files_dir = config.sandbox.target_support_files_dir('Pods-SampleProject')
script = support_files_dir + 'Pods-SampleProject-frameworks.sh'
script.read.should.include?('BananaLib.framework')
end
......@@ -186,28 +185,28 @@ module Pod
@pod_target.stubs(:requires_frameworks? => true)
@target.stubs(:requires_frameworks? => true)
@installer.install!
support_files_dir = config.sandbox.target_support_files_dir('Pods')
script = support_files_dir + 'Pods-frameworks.sh'
support_files_dir = config.sandbox.target_support_files_dir('Pods-SampleProject')
script = support_files_dir + 'Pods-SampleProject-frameworks.sh'
script.read.should.not.include?('BananaLib.framework')
end
it 'creates the acknowledgements files ' do
@installer.install!
support_files_dir = config.sandbox.target_support_files_dir('Pods')
markdown = support_files_dir + 'Pods-acknowledgements.markdown'
support_files_dir = config.sandbox.target_support_files_dir('Pods-SampleProject')
markdown = support_files_dir + 'Pods-SampleProject-acknowledgements.markdown'
markdown.read.should.include?('Permission is hereby granted')
plist = support_files_dir + 'Pods-acknowledgements.plist'
plist = support_files_dir + 'Pods-SampleProject-acknowledgements.plist'
plist.read.should.include?('Permission is hereby granted')
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_file = build_files.find { |bf| bf.file_ref.path.include?('Pods-dummy.m') }
build_file = build_files.find { |bf| bf.file_ref.path.include?('Pods-SampleProject-dummy.m') }
build_file.should.be.not.nil
build_file.file_ref.path.should == 'Pods-dummy.m'
support_files_dir = config.sandbox.target_support_files_dir('Pods')
dummy = support_files_dir + 'Pods-dummy.m'
build_file.file_ref.path.should == 'Pods-SampleProject-dummy.m'
support_files_dir = config.sandbox.target_support_files_dir('Pods-SampleProject')
dummy = support_files_dir + 'Pods-SampleProject-dummy.m'
dummy.read.should.include?('@interface PodsDummy_Pods')
end
end
......
......@@ -7,9 +7,10 @@ module Pod
config.sandbox.prepare
@podfile = Podfile.new do
platform :ios, '6.0'
project 'dummy'
project 'SampleProject/SampleProject'
target 'SampleProject'
end
@target_definition = @podfile.target_definitions['Pods']
@target_definition = @podfile.target_definitions['SampleProject']
@project = Project.new(config.sandbox.project_path)
config.sandbox.project = @project
......@@ -141,47 +142,44 @@ module Pod
@installer.install!
group = @project['Pods/BananaLib/Support Files']
group.children.map(&:display_name).sort.should == [
'Pods-BananaLib-dummy.m',
'Pods-BananaLib-prefix.pch',
'Pods-BananaLib.xcconfig',
'BananaLib-Pods-SampleProject-dummy.m',
'BananaLib-Pods-SampleProject-prefix.pch',
'BananaLib-Pods-SampleProject.xcconfig',
]
end
it 'adds the target for the static library to the project' do
@installer.install!
@project.targets.count.should == 1
@project.targets.first.name.should == 'Pods-BananaLib'
@project.targets.first.name.should == 'BananaLib-Pods-SampleProject'
end
it 'adds the resource bundle targets' do
@pod_target.file_accessors.first.stubs(:resource_bundles).returns('banana_bundle' => [])
@installer.install!
bundle_target = @project.targets.find { |t| t.name == 'Pods-BananaLib-banana_bundle' }
bundle_target.should.be.an.instance_of Xcodeproj::Project::Object::PBXNativeTarget
bundle_target.product_reference.name.should == 'banana_bundle.bundle'
bundle_target.product_reference.path.should == 'banana_bundle.bundle'
bundle_target.platform_name.should == :ios
bundle_target.deployment_target.should == '4.3'
end
it 'adds the build configurations to the resources bundle targets' do
@pod_target.file_accessors.first.stubs(:resource_bundles).returns('banana_bundle' => [])
@installer.install!
bundle_target = @project.targets.find { |t| t.name == 'Pods-BananaLib-banana_bundle' }
describe 'resource bundle targets' do
before do
@pod_target.file_accessors.first.stubs(:resource_bundles).returns('banana_bundle' => [])
@installer.install!
@bundle_target = @project.targets.find { |t| t.name == 'BananaLib-Pods-SampleProject-banana_bundle' }
end
file = config.sandbox.root + @pod_target.xcconfig_path
bundle_target.build_configurations.each do |bc|
bc.base_configuration_reference.real_path.should == file
it 'adds the resource bundle targets' do
@bundle_target.should.be.an.instance_of Xcodeproj::Project::Object::PBXNativeTarget
@bundle_target.product_reference.name.should == 'banana_bundle.bundle'
@bundle_target.product_reference.path.should == 'banana_bundle.bundle'
@bundle_target.platform_name.should == :ios
@bundle_target.deployment_target.should == '4.3'
end
end
it 'sets the correct targeted device family for the resource bundle targets' do
@pod_target.file_accessors.first.stubs(:resource_bundles).returns('banana_bundle' => [])
@installer.install!
bundle_target = @project.targets.find { |t| t.name == 'Pods-BananaLib-banana_bundle' }
it 'adds the build configurations to the resources bundle targets' do
file = config.sandbox.root + @pod_target.xcconfig_path
@bundle_target.build_configurations.each do |bc|
bc.base_configuration_reference.real_path.should == file
end
end
bundle_target.build_configurations.each do |bc|
bc.build_settings['TARGETED_DEVICE_FAMILY'].should == '1,2'
it 'sets the correct targeted device family for the resource bundle targets' do
@bundle_target.build_configurations.each do |bc|
bc.build_settings['TARGETED_DEVICE_FAMILY'].should == '1,2'
end
end
end
end
......@@ -206,23 +204,24 @@ module Pod
@project.targets.first.name.should == 'BananaLib'
end
it 'adds the resource bundle targets' do
@pod_target.file_accessors.first.stubs(:resource_bundles).returns('banana_bundle' => [])
@installer.install!
bundle_target = @project.targets.find { |t| t.name == 'BananaLib-banana_bundle' }
bundle_target.should.be.an.instance_of Xcodeproj::Project::Object::PBXNativeTarget
bundle_target.product_reference.name.should == 'banana_bundle.bundle'
bundle_target.product_reference.path.should == 'banana_bundle.bundle'
end
describe 'resource bundle targets' do
before do
@pod_target.file_accessors.first.stubs(:resource_bundles).returns('banana_bundle' => [])
@installer.install!
@bundle_target = @project.targets.find { |t| t.name == 'BananaLib-banana_bundle' }
end
it 'adds the build configurations to the resources bundle targets' do
@pod_target.file_accessors.first.stubs(:resource_bundles).returns('banana_bundle' => [])
@installer.install!
bundle_target = @project.targets.find { |t| t.name == 'BananaLib-banana_bundle' }
it 'adds the resource bundle targets' do
@bundle_target.should.be.an.instance_of Xcodeproj::Project::Object::PBXNativeTarget
@bundle_target.product_reference.name.should == 'banana_bundle.bundle'
@bundle_target.product_reference.path.should == 'banana_bundle.bundle'
end
file = config.sandbox.root + @pod_target.xcconfig_path
bundle_target.build_configurations.each do |bc|
bc.base_configuration_reference.real_path.should == file
it 'adds the build configurations to the resources bundle targets' do
file = config.sandbox.root + @pod_target.xcconfig_path
@bundle_target.build_configurations.each do |bc|
bc.base_configuration_reference.real_path.should == file
end
end
end
end
......@@ -275,7 +274,7 @@ module Pod
before do
@project.add_pod_group('snake', fixture('snake'))
@pod_target = fixture_pod_target('snake/snake.podspec', @target_definition)
@pod_target = fixture_pod_target('snake/snake.podspec', [@target_definition])
@pod_target.user_build_configurations = { 'Debug' => :debug, 'Release' => :release }
@pod_target.stubs(:requires_frameworks? => true)
group = @project.group_for_spec('snake')
......
......@@ -5,9 +5,10 @@ module Pod
before do
@podfile = Podfile.new do
platform :ios
project 'dummy'
project 'SampleProject/SampleProject'
target 'SampleProject'
end
@target_definition = @podfile.target_definitions['Pods']
@target_definition = @podfile.target_definitions['SampleProject']
@project = Project.new(config.sandbox.project_path)
config.sandbox.project = @project
......
......@@ -205,12 +205,6 @@ module Pod
@integrator.send(:targets_to_integrate).map(&:name).should == ['Pods-SampleProject', 'Pods-SampleProject-empty']
end
it 'does skip libraries with only abstract target definitions' do
@integrator.targets.map(&:name).should == ['Pods-SampleProject', 'Pods-SampleProject-empty']
@podfile.target_definition_list.each { |td| td.abstract = true }
@integrator.send(:targets_to_integrate).map(&:name).should == []
end
it 'skips saving projects that are not dirtied (but touches them instead)' do
project = mock('Project')
project.stubs(:path).returns(Pathname('project.xcodeproj'))
......
......@@ -61,7 +61,6 @@ module Pod
before do
@installer.stubs(:resolve_dependencies)
@installer.stubs(:download_dependencies)
@installer.stubs(:determine_dependency_product_types)
@installer.stubs(:verify_no_duplicate_framework_names)
@installer.stubs(:verify_no_static_framework_transitive_dependencies)
@installer.stubs(:verify_framework_usage)
......@@ -232,6 +231,7 @@ module Pod
use_frameworks!
pod 'BananaLib', :path => (fixture_path + 'banana-lib').to_s
pod 'OrangeFramework', :path => (fixture_path + 'orange-framework').to_s
pod 'matryoshka', :path => (fixture_path + 'matryoshka').to_s
pod 'monkey', :path => (fixture_path + 'monkey').to_s
target 'SampleProject'
......@@ -251,6 +251,7 @@ module Pod
target.pod_targets.select(&:requires_frameworks?).map(&:name).sort.should == %w(
BananaLib
OrangeFramework
matryoshka
monkey
)
end
......@@ -271,6 +272,7 @@ module Pod
project 'SampleProject/SampleProject'
pod 'BananaLib', :path => (fixture_path + 'banana-lib').to_s
pod 'OrangeFramework', :path => (fixture_path + 'orange-framework').to_s
pod 'matryoshka', :path => (fixture_path + 'matryoshka').to_s
pod 'monkey', :path => (fixture_path + 'monkey').to_s
target 'SampleProject'
end
......@@ -315,6 +317,7 @@ module Pod
use_frameworks!
pod 'BananaLib', :path => (fixture_path + 'banana-lib').to_s
pod 'OrangeFramework', :path => (fixture_path + 'orange-framework').to_s
pod 'matryoshka', :path => (fixture_path + 'matryoshka').to_s
pod 'monkey', :path => (fixture_path + 'monkey').to_s
target 'SampleProject'
end
......@@ -358,6 +361,7 @@ module Pod
platform :ios, '8.0'
project 'SampleProject/SampleProject'
pod 'OrangeFramework', :path => (fixture_path + 'orange-framework').to_s
pod 'matryoshka', :path => (fixture_path + 'matryoshka').to_s
target 'SampleProject'
end
lockfile = generate_lockfile
......@@ -443,7 +447,7 @@ module Pod
@analysis_result = Installer::Analyzer::AnalysisResult.new
@analysis_result.specifications = []
@analysis_result.sandbox_state = Installer::Analyzer::SpecsState.new
@pod_targets = [PodTarget.new([stub('Spec')], [stub('TargetDefinition')], config.sandbox)]
@pod_targets = [PodTarget.new([stub('Spec')], [fixture_target_definition], config.sandbox)]
@installer.stubs(:analysis_result).returns(@analysis_result)
@installer.stubs(:pod_targets).returns(@pod_targets)
end
......@@ -484,7 +488,7 @@ module Pod
it 'correctly configures the Pod source installer' do
spec = fixture_spec('banana-lib/BananaLib.podspec')
pod_target = PodTarget.new([spec], [stub('TargetDefinition')], config.sandbox)
pod_target = PodTarget.new([spec], [fixture_target_definition], config.sandbox)
pod_target.stubs(:platform).returns(:ios)
@installer.stubs(:pod_targets).returns([pod_target])
@installer.instance_variable_set(:@installed_specs, [])
......@@ -494,7 +498,7 @@ module Pod
it 'maintains the list of the installed specs' do
spec = fixture_spec('banana-lib/BananaLib.podspec')
pod_target = PodTarget.new([spec], [stub('TargetDefinition')], config.sandbox)
pod_target = PodTarget.new([spec], [fixture_target_definition], config.sandbox)
pod_target.stubs(:platform).returns(:ios)
@installer.stubs(:pod_targets).returns([pod_target, pod_target])
@installer.instance_variable_set(:@installed_specs, [])
......@@ -583,15 +587,11 @@ module Pod
end
it 'sets the deployment target for the whole project' do
pod_target_ios = PodTarget.new([stub('Spec')], [stub('TargetDefinition')], config.sandbox)
pod_target_osx = PodTarget.new([stub('Spec')], [stub('TargetDefinition')], config.sandbox)
pod_target_ios.stubs(:platform).returns(Platform.new(:ios, '6.0'))
pod_target_osx.stubs(:platform).returns(Platform.new(:osx, '10.8'))
aggregate_target_ios = AggregateTarget.new(nil, config.sandbox)
aggregate_target_osx = AggregateTarget.new(nil, config.sandbox)
aggregate_target_ios.stubs(:platform).returns(Platform.new(:ios, '6.0'))
aggregate_target_osx.stubs(:platform).returns(Platform.new(:osx, '10.8'))
@installer.stubs(:aggregate_targets).returns([aggregate_target_ios, aggregate_target_osx])
target_definition_osx = fixture_target_definition('OSX Target', Platform.new(:osx, '10.8'))
target_definition_ios = fixture_target_definition('iOS Target', Platform.new(:ios, '6.0'))
aggregate_target_osx = AggregateTarget.new(target_definition_osx, config.sandbox)
aggregate_target_ios = AggregateTarget.new(target_definition_ios, config.sandbox)
@installer.stubs(:aggregate_targets).returns([aggregate_target_osx, aggregate_target_ios])
@installer.stubs(:pod_targets).returns([])
@installer.send(:prepare_pods_project)
build_settings = @installer.pods_project.build_configurations.map(&:build_settings)
......@@ -779,9 +779,8 @@ module Pod
proj = Xcodeproj::Project.new(tmp_directory + 'Yolo.xcodeproj', false, 1)
proj.save
aggregate_target = AggregateTarget.new(nil, config.sandbox)
aggregate_target.stubs(:platform).returns(Platform.new(:ios, '6.0'))
aggregate_target.stubs(:user_project).returns(proj)
aggregate_target = AggregateTarget.new(fixture_target_definition, config.sandbox)
aggregate_target.user_project = proj
@installer.stubs(:aggregate_targets).returns([aggregate_target])
@installer.send(:prepare_pods_project)
......@@ -823,7 +822,7 @@ module Pod
describe 'Integrating client projects' do
it 'integrates the client projects' do
@installer.stubs(:aggregate_targets).returns([AggregateTarget.new(nil, config.sandbox)])
@installer.stubs(:aggregate_targets).returns([AggregateTarget.new(fixture_target_definition, config.sandbox)])
Installer::UserProjectIntegrator.any_instance.expects(:integrate!)
@installer.send(:integrate_user_project)
end
......
......@@ -80,10 +80,6 @@ module Pod
it 'returns the path of the xcconfig file relative to the user project' do
@target.xcconfig_relative_path('Release').should == 'Pods/Target Support Files/Pods/Pods.release.xcconfig'
end
it 'returns the path for the CONFIGURATION_BUILD_DIR build setting' do
@target.scoped_configuration_build_dir.should == '$(BUILD_DIR)/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)/Pods'
end
end
describe 'Pod targets' do
......@@ -198,7 +194,7 @@ module Pod
describe 'With frameworks' do
before do
@pod_target = fixture_pod_target('orange-framework/OrangeFramework.podspec', fixture_target_definition('iOS Example'))
@pod_target = fixture_pod_target('orange-framework/OrangeFramework.podspec', [fixture_target_definition('iOS Example')])
@target = AggregateTarget.new(@pod_target.target_definitions.first, config.sandbox)
@target.stubs(:requires_frameworks?).returns(true)
@target.pod_targets = [@pod_target]
......
......@@ -30,17 +30,24 @@ module Pod
it 'returns its name' do
@pod_target.name.should == 'BananaLib'
@pod_target.scoped.first.name.should == 'Pods-BananaLib'
@pod_target.scoped.first.name.should == 'BananaLib-Pods'
end
it 'returns its label' do
@pod_target.label.should == 'BananaLib'
@pod_target.scoped.first.label.should == 'Pods-BananaLib'
@pod_target.scoped.first.label.should == 'BananaLib-Pods'
end
it 'returns its label' do
@pod_target.label.should == 'BananaLib'
@pod_target.scoped.first.label.should == 'BananaLib-Pods'
spec_scoped_pod_target = @pod_target.scoped.first.tap { |t| t.stubs(:scope_suffix).returns('.default-GreenBanana') }
spec_scoped_pod_target.label.should == 'BananaLib.default-GreenBanana'
end
it 'returns the name of its product' do
@pod_target.product_name.should == 'libBananaLib.a'
@pod_target.scoped.first.product_name.should == 'libPods-BananaLib.a'
@pod_target.scoped.first.product_name.should == 'libBananaLib-Pods.a'
end
it 'returns the spec consumers for the pod targets' do
......@@ -57,7 +64,7 @@ module Pod
it 'returns the name of the resources bundle target' do
@pod_target.resources_bundle_target_label('Fruits').should == 'BananaLib-Fruits'
@pod_target.scoped.first.resources_bundle_target_label('Fruits').should == 'Pods-BananaLib-Fruits'
@pod_target.scoped.first.resources_bundle_target_label('Fruits').should == 'BananaLib-Pods-Fruits'
end
it 'returns the name of the Pods on which this target depends' do
......@@ -109,7 +116,7 @@ module Pod
'Pods/Target Support Files/BananaLib/BananaLib.release.xcconfig',
)
@pod_target.scoped.first.xcconfig_path('Release').to_s.should.include?(
'Pods/Target Support Files/Pods-BananaLib/Pods-BananaLib.release.xcconfig',
'Pods/Target Support Files/BananaLib-Pods/BananaLib-Pods.release.xcconfig',
)
end
......@@ -118,7 +125,7 @@ module Pod
'Pods/Target Support Files/BananaLib/BananaLib.release-1.xcconfig',
)
@pod_target.scoped.first.xcconfig_path("Release#{File::SEPARATOR}1").to_s.should.include?(
'Pods/Target Support Files/Pods-BananaLib/Pods-BananaLib.release-1.xcconfig',
'Pods/Target Support Files/BananaLib-Pods/BananaLib-Pods.release-1.xcconfig',
)
end
......@@ -127,7 +134,7 @@ module Pod
'Pods/Target Support Files/BananaLib/BananaLib-prefix.pch',
)
@pod_target.scoped.first.prefix_header_path.to_s.should.include?(
'Pods/Target Support Files/Pods-BananaLib/Pods-BananaLib-prefix.pch',
'Pods/Target Support Files/BananaLib-Pods/BananaLib-Pods-prefix.pch',
)
end
......@@ -142,7 +149,7 @@ module Pod
'Pods/Target Support Files/BananaLib/Info.plist',
)
@pod_target.scoped.first.info_plist_path.to_s.should.include?(
'Pods/Target Support Files/Pods-BananaLib/Info.plist',
'Pods/Target Support Files/BananaLib-Pods/Info.plist',
)
end
......@@ -151,7 +158,7 @@ module Pod
'Pods/Target Support Files/BananaLib/BananaLib-dummy.m',
)
@pod_target.scoped.first.dummy_source_path.to_s.should.include?(
'Pods/Target Support Files/Pods-BananaLib/Pods-BananaLib-dummy.m',
'Pods/Target Support Files/BananaLib-Pods/BananaLib-Pods-dummy.m',
)
end
......@@ -162,8 +169,17 @@ module Pod
end
it 'returns the path for the CONFIGURATION_BUILD_DIR build setting' do
@pod_target.configuration_build_dir.should == '$(BUILD_DIR)/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)'
@pod_target.scoped.first.configuration_build_dir.should == '$(BUILD_DIR)/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)/Pods'
@pod_target.configuration_build_dir.should == '$CONFIGURATION_BUILD_DIR/BananaLib'
@pod_target.scoped.first.configuration_build_dir.should == '$CONFIGURATION_BUILD_DIR/BananaLib-Pods'
@pod_target.configuration_build_dir('$PODS_SHARED_BUILD_DIR').should == '$PODS_SHARED_BUILD_DIR/BananaLib'
@pod_target.scoped.first.configuration_build_dir('$PODS_SHARED_BUILD_DIR').should == '$PODS_SHARED_BUILD_DIR/BananaLib-Pods'
end
it 'returns the path for the CONFIGURATION_BUILD_DIR build setting' do
@pod_target.build_product_path.should == '$CONFIGURATION_BUILD_DIR/BananaLib/libBananaLib.a'
@pod_target.scoped.first.build_product_path.should == '$CONFIGURATION_BUILD_DIR/BananaLib-Pods/libBananaLib-Pods.a'
@pod_target.build_product_path('$BUILT_PRODUCTS_DIR').should == '$BUILT_PRODUCTS_DIR/BananaLib/libBananaLib.a'
@pod_target.scoped.first.build_product_path('$BUILT_PRODUCTS_DIR').should == '$BUILT_PRODUCTS_DIR/BananaLib-Pods/libBananaLib-Pods.a'
end
end
......@@ -192,7 +208,7 @@ module Pod
it 'returns the library name' do
@pod_target.static_library_name.should == 'libBananaLib.a'
@pod_target.scoped.first.static_library_name.should == 'libPods-BananaLib.a'
@pod_target.scoped.first.static_library_name.should == 'libBananaLib-Pods.a'
end
it 'returns :framework as product type' do
......@@ -207,7 +223,7 @@ module Pod
describe 'Host does not requires frameworks' do
it 'returns the product name' do
@pod_target.product_name.should == 'libBananaLib.a'
@pod_target.scoped.first.product_name.should == 'libPods-BananaLib.a'
@pod_target.scoped.first.product_name.should == 'libBananaLib-Pods.a'
end
it 'returns the framework name' do
......@@ -216,7 +232,7 @@ module Pod
it 'returns the library name' do
@pod_target.static_library_name.should == 'libBananaLib.a'
@pod_target.scoped.first.static_library_name.should == 'libPods-BananaLib.a'
@pod_target.scoped.first.static_library_name.should == 'libBananaLib-Pods.a'
end
it 'returns :static_library as product type' do
......@@ -253,7 +269,7 @@ module Pod
it 'returns the library name' do
@pod_target.static_library_name.should == 'libOrangeFramework.a'
@pod_target.scoped.first.static_library_name.should == 'libPods-OrangeFramework.a'
@pod_target.scoped.first.static_library_name.should == 'libOrangeFramework-Pods.a'
end
it 'returns :framework as product type' do
......
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