Unverified Commit 93011ece authored by Samuel Giddins's avatar Samuel Giddins Committed by GitHub

Merge pull request #7449 from CocoaPods/seg-more-perf

More performance improvements
parents 2619458c bb81dffc
...@@ -140,8 +140,7 @@ module Pod ...@@ -140,8 +140,7 @@ module Pod
# #
def self.links_dependency?(aggregate_target, pod_target) def self.links_dependency?(aggregate_target, pod_target)
return true if aggregate_target.nil? || aggregate_target.target_definition.inheritance == 'complete' return true if aggregate_target.nil? || aggregate_target.target_definition.inheritance == 'complete'
targets = aggregate_target.pod_targets - aggregate_target.search_paths_aggregate_targets.flat_map(&:pod_targets) aggregate_target.pod_targets_to_link.include?(pod_target)
targets.include?(pod_target)
end end
# Adds build settings for dynamic vendored frameworks and libraries. # Adds build settings for dynamic vendored frameworks and libraries.
......
...@@ -429,7 +429,7 @@ module Pod ...@@ -429,7 +429,7 @@ module Pod
end end
def print_post_install_message def print_post_install_message
podfile_dependencies = podfile.dependencies.uniq.size podfile_dependencies = analysis_result.podfile_dependency_cache.podfile_dependencies.size
pods_installed = root_specs.size pods_installed = root_specs.size
title_options = { :verbose_prefix => '-> '.green } title_options = { :verbose_prefix => '-> '.green }
UI.titled_section('Pod installation complete! ' \ UI.titled_section('Pod installation complete! ' \
...@@ -548,7 +548,7 @@ module Pod ...@@ -548,7 +548,7 @@ module Pod
# @return [void] # @return [void]
# #
def write_lockfiles def write_lockfiles
external_source_pods = podfile.dependencies.select(&:external_source).map(&:root_name).uniq external_source_pods = analysis_result.podfile_dependency_cache.podfile_dependencies.select(&:external_source).map(&:root_name).uniq
checkout_options = sandbox.checkout_sources.select { |root_name, _| external_source_pods.include? root_name } checkout_options = sandbox.checkout_sources.select { |root_name, _| external_source_pods.include? root_name }
@lockfile = Lockfile.generate(podfile, analysis_result.specifications, checkout_options, analysis_result.specs_by_source) @lockfile = Lockfile.generate(podfile, analysis_result.specifications, checkout_options, analysis_result.specs_by_source)
......
...@@ -10,11 +10,12 @@ module Pod ...@@ -10,11 +10,12 @@ module Pod
delegate_installation_options { podfile } delegate_installation_options { podfile }
autoload :AnalysisResult, 'cocoapods/installer/analyzer/analysis_result' autoload :AnalysisResult, 'cocoapods/installer/analyzer/analysis_result'
autoload :SandboxAnalyzer, 'cocoapods/installer/analyzer/sandbox_analyzer'
autoload :SpecsState, 'cocoapods/installer/analyzer/specs_state'
autoload :LockingDependencyAnalyzer, 'cocoapods/installer/analyzer/locking_dependency_analyzer' autoload :LockingDependencyAnalyzer, 'cocoapods/installer/analyzer/locking_dependency_analyzer'
autoload :PodfileDependencyCache, 'cocoapods/installer/analyzer/podfile_dependency_cache'
autoload :PodVariant, 'cocoapods/installer/analyzer/pod_variant' autoload :PodVariant, 'cocoapods/installer/analyzer/pod_variant'
autoload :PodVariantSet, 'cocoapods/installer/analyzer/pod_variant_set' autoload :PodVariantSet, 'cocoapods/installer/analyzer/pod_variant_set'
autoload :SandboxAnalyzer, 'cocoapods/installer/analyzer/sandbox_analyzer'
autoload :SpecsState, 'cocoapods/installer/analyzer/specs_state'
autoload :TargetInspectionResult, 'cocoapods/installer/analyzer/target_inspection_result' autoload :TargetInspectionResult, 'cocoapods/installer/analyzer/target_inspection_result'
autoload :TargetInspector, 'cocoapods/installer/analyzer/target_inspector' autoload :TargetInspector, 'cocoapods/installer/analyzer/target_inspector'
...@@ -54,6 +55,7 @@ module Pod ...@@ -54,6 +55,7 @@ module Pod
@has_dependencies = true @has_dependencies = true
@test_pod_target_analyzer_cache = {} @test_pod_target_analyzer_cache = {}
@test_pod_target_key = Struct.new(:name, :pod_targets) @test_pod_target_key = Struct.new(:name, :pod_targets)
@podfile_dependency_cache = PodfileDependencyCache.from_podfile(podfile)
end end
# Performs the analysis. # Performs the analysis.
...@@ -71,6 +73,7 @@ module Pod ...@@ -71,6 +73,7 @@ module Pod
validate_podfile! validate_podfile!
validate_lockfile_version! validate_lockfile_version!
@result = AnalysisResult.new @result = AnalysisResult.new
@result.podfile_dependency_cache = @podfile_dependency_cache
if installation_options.integrate_targets? if installation_options.integrate_targets?
@result.target_inspections = inspect_targets_to_integrate @result.target_inspections = inspect_targets_to_integrate
else else
...@@ -186,7 +189,7 @@ module Pod ...@@ -186,7 +189,7 @@ module Pod
alias_method :specs_updated?, :specs_updated alias_method :specs_updated?, :specs_updated
def validate_podfile! def validate_podfile!
validator = Installer::PodfileValidator.new(podfile) validator = Installer::PodfileValidator.new(podfile, @podfile_dependency_cache)
validator.validate validator.validate
unless validator.valid? unless validator.valid?
...@@ -234,7 +237,7 @@ module Pod ...@@ -234,7 +237,7 @@ module Pod
pods_state pods_state
else else
state = SpecsState.new state = SpecsState.new
state.added.merge(podfile.dependencies.map(&:root_name)) state.added.merge(@podfile_dependency_cache.podfile_dependencies.map(&:root_name))
state state
end end
end end
...@@ -395,8 +398,7 @@ module Pod ...@@ -395,8 +398,7 @@ module Pod
embedded_targets = aggregate_targets.select(&:requires_host_target?) embedded_targets = aggregate_targets.select(&:requires_host_target?)
analyze_host_targets_in_podfile(aggregate_targets, embedded_targets) analyze_host_targets_in_podfile(aggregate_targets, embedded_targets)
use_frameworks_embedded_targets = embedded_targets.select(&:requires_frameworks?) use_frameworks_embedded_targets, non_use_frameworks_embedded_targets = embedded_targets.partition(&:requires_frameworks?)
non_use_frameworks_embedded_targets = embedded_targets.reject(&:requires_frameworks?)
aggregate_targets.each do |target| aggregate_targets.each do |target|
# For targets that require frameworks, we always have to copy their pods to their # For targets that require frameworks, we always have to copy their pods to their
# host targets because those frameworks will all be loaded from the host target's bundle # host targets because those frameworks will all be loaded from the host target's bundle
...@@ -408,9 +410,9 @@ module Pod ...@@ -408,9 +410,9 @@ module Pod
end end
end end
aggregate_targets.each do |target| aggregate_targets.each do |target|
target.search_paths_aggregate_targets = aggregate_targets.select do |aggregate_target| target.search_paths_aggregate_targets.concat(aggregate_targets.select do |aggregate_target|
target.target_definition.targets_to_inherit_search_paths.include?(aggregate_target.target_definition) target.target_definition.targets_to_inherit_search_paths.include?(aggregate_target.target_definition)
end end).freeze
end end
end end
...@@ -634,7 +636,7 @@ module Pod ...@@ -634,7 +636,7 @@ module Pod
else else
pods_to_update = result.podfile_state.changed + result.podfile_state.deleted pods_to_update = result.podfile_state.changed + result.podfile_state.deleted
pods_to_update += update[:pods] if update_mode == :selected pods_to_update += update[:pods] if update_mode == :selected
local_pod_names = podfile.dependencies.select(&:local?).map(&:root_name) local_pod_names = @podfile_dependency_cache.podfile_dependencies.select(&:local?).map(&:root_name)
pods_to_unlock = local_pod_names.reject do |pod_name| pods_to_unlock = local_pod_names.reject do |pod_name|
sandbox.specification(pod_name).checksum == lockfile.checksum(pod_name) sandbox.specification(pod_name).checksum == lockfile.checksum(pod_name)
end end
...@@ -675,7 +677,7 @@ module Pod ...@@ -675,7 +677,7 @@ module Pod
end end
def verify_no_pods_with_different_sources! def verify_no_pods_with_different_sources!
deps_with_different_sources = podfile.dependencies.group_by(&:root_name). deps_with_different_sources = @podfile_dependency_cache.podfile_dependencies.group_by(&:root_name).
select { |_root_name, dependencies| dependencies.map(&:external_source).uniq.count > 1 } select { |_root_name, dependencies| dependencies.map(&:external_source).uniq.count > 1 }
deps_with_different_sources.each do |root_name, dependencies| deps_with_different_sources.each do |root_name, dependencies|
raise Informative, 'There are multiple dependencies with different ' \ raise Informative, 'There are multiple dependencies with different ' \
...@@ -698,7 +700,7 @@ module Pod ...@@ -698,7 +700,7 @@ module Pod
def dependencies_to_fetch def dependencies_to_fetch
@deps_to_fetch ||= begin @deps_to_fetch ||= begin
deps_to_fetch = [] deps_to_fetch = []
deps_with_external_source = podfile.dependencies.select(&:external_source) deps_with_external_source = @podfile_dependency_cache.podfile_dependencies.select(&:external_source)
if update_mode == :all if update_mode == :all
deps_to_fetch = deps_with_external_source deps_to_fetch = deps_with_external_source
...@@ -731,7 +733,7 @@ module Pod ...@@ -731,7 +733,7 @@ module Pod
elsif update_mode == :all elsif update_mode == :all
pods_to_fetch += result.podfile_state.unchanged + result.podfile_state.deleted pods_to_fetch += result.podfile_state.unchanged + result.podfile_state.deleted
end end
pods_to_fetch += podfile.dependencies. pods_to_fetch += @podfile_dependency_cache.podfile_dependencies.
select { |dep| Hash(dep.external_source).key?(:podspec) && sandbox.specification_path(dep.root_name).nil? }. select { |dep| Hash(dep.external_source).key?(:podspec) && sandbox.specification_path(dep.root_name).nil? }.
map(&:root_name) map(&:root_name)
pods_to_fetch pods_to_fetch
...@@ -739,7 +741,7 @@ module Pod ...@@ -739,7 +741,7 @@ module Pod
end end
def store_existing_checkout_options def store_existing_checkout_options
podfile.dependencies.select(&:external_source).each do |dep| @podfile_dependency_cache.podfile_dependencies.select(&:external_source).each do |dep|
if checkout_options = lockfile && lockfile.checkout_options_for_pod_named(dep.root_name) if checkout_options = lockfile && lockfile.checkout_options_for_pod_named(dep.root_name)
sandbox.store_checkout_source(dep.root_name, checkout_options) sandbox.store_checkout_source(dep.root_name, checkout_options)
end end
...@@ -766,7 +768,7 @@ module Pod ...@@ -766,7 +768,7 @@ module Pod
# grouped by target. # grouped by target.
# #
def resolve_dependencies def resolve_dependencies
duplicate_dependencies = podfile.dependencies.group_by(&:name). duplicate_dependencies = @podfile_dependency_cache.podfile_dependencies.group_by(&:name).
select { |_name, dependencies| dependencies.count > 1 } select { |_name, dependencies| dependencies.count > 1 }
duplicate_dependencies.each do |name, dependencies| duplicate_dependencies.each do |name, dependencies|
UI.warn "There are duplicate dependencies on `#{name}` in #{UI.path podfile.defined_in_file}:\n\n" \ UI.warn "There are duplicate dependencies on `#{name}` in #{UI.path podfile.defined_in_file}:\n\n" \
...@@ -857,8 +859,8 @@ module Pod ...@@ -857,8 +859,8 @@ module Pod
plugin_sources = @plugin_sources || [] plugin_sources = @plugin_sources || []
# Add any sources specified using the :source flag on individual dependencies. # Add any sources specified using the :source flag on individual dependencies.
dependency_sources = podfile.dependencies.map(&:podspec_repo).compact dependency_sources = @podfile_dependency_cache.podfile_dependencies.map(&:podspec_repo).compact
all_dependencies_have_sources = dependency_sources.count == podfile.dependencies.count all_dependencies_have_sources = dependency_sources.count == @podfile_dependency_cache.podfile_dependencies.count
if all_dependencies_have_sources if all_dependencies_have_sources
sources = dependency_sources sources = dependency_sources
...@@ -890,7 +892,7 @@ module Pod ...@@ -890,7 +892,7 @@ module Pod
# #
def verify_platforms_specified! def verify_platforms_specified!
unless installation_options.integrate_targets? unless installation_options.integrate_targets?
podfile.target_definition_list.each do |target_definition| @podfile_dependency_cache.target_definition_list.each do |target_definition|
if !target_definition.empty? && target_definition.platform.nil? if !target_definition.empty? && target_definition.platform.nil?
raise Informative, 'It is necessary to specify the platform in the Podfile if not integrating.' raise Informative, 'It is necessary to specify the platform in the Podfile if not integrating.'
end end
...@@ -909,7 +911,7 @@ module Pod ...@@ -909,7 +911,7 @@ module Pod
def inspect_targets_to_integrate def inspect_targets_to_integrate
inspection_result = {} inspection_result = {}
UI.section 'Inspecting targets to integrate' do UI.section 'Inspecting targets to integrate' do
inspectors = podfile.target_definition_list.map do |target_definition| inspectors = @podfile_dependency_cache.target_definition_list.map do |target_definition|
next if target_definition.abstract? next if target_definition.abstract?
TargetInspector.new(target_definition, config.installation_root) TargetInspector.new(target_definition, config.installation_root)
end.compact end.compact
......
...@@ -33,8 +33,14 @@ module Pod ...@@ -33,8 +33,14 @@ module Pod
# @return [Hash{TargetDefinition => Array<TargetInspectionResult>}] the # @return [Hash{TargetDefinition => Array<TargetInspectionResult>}] the
# results of inspecting the user targets # results of inspecting the user targets
#
attr_accessor :target_inspections attr_accessor :target_inspections
# @return [PodfileDependencyCache] the cache of all dependencies in the
# podfile.
#
attr_accessor :podfile_dependency_cache
# @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
# Caches podfile & target definition dependencies, so they do not need to be re-computed
# from the internal hash on each access
#
class PodfileDependencyCache
# @return [Array<Pod::Dependency>]
# All the dependencies in the podfile
#
attr_reader :podfile_dependencies
def initialize(podfile_dependencies, dependencies_by_target_definition)
@podfile_dependencies = podfile_dependencies
@dependencies_by_target_definition = dependencies_by_target_definition
end
# Returns the dependencies for the given target definition
#
def target_definition_dependencies(target_definition)
@dependencies_by_target_definition[target_definition] ||
raise(ArgumentError, "dependencies for #{target_definition.inspect} do not exist in the cache")
end
# Returns a list of all of the target definitions in the Podfile
#
def target_definition_list
@dependencies_by_target_definition.keys
end
# Creates a {PodfileDependencyCache} from the given {Podfile}
#
def self.from_podfile(podfile)
podfile_dependencies = []
dependencies_by_target_definition = {}
podfile.target_definition_list.each do |target_definition|
deps = target_definition.dependencies.freeze
podfile_dependencies.concat deps
dependencies_by_target_definition[target_definition] = deps
end
podfile_dependencies.uniq!
new(podfile_dependencies.freeze, dependencies_by_target_definition.freeze)
end
end
end
end
end
...@@ -20,8 +20,9 @@ module Pod ...@@ -20,8 +20,9 @@ module Pod
# @param [Podfile] podfile # @param [Podfile] podfile
# The podfile to validate # The podfile to validate
# #
def initialize(podfile) def initialize(podfile, podfile_dependency_cache = Analyzer::PodfileDependencyCache.from_podfile(podfile))
@podfile = podfile @podfile = podfile
@podfile_dependency_cache = podfile_dependency_cache
@errors = [] @errors = []
@warnings = [] @warnings = []
@validated = false @validated = false
...@@ -67,11 +68,7 @@ module Pod ...@@ -67,11 +68,7 @@ module Pod
end end
def validate_pod_directives def validate_pod_directives
dependencies = podfile.target_definitions.flat_map do |_, target| @podfile_dependency_cache.podfile_dependencies.each do |dependency|
target.dependencies
end.uniq
dependencies.each do |dependency|
validate_conflicting_external_sources!(dependency) validate_conflicting_external_sources!(dependency)
end end
end end
...@@ -106,7 +103,7 @@ module Pod ...@@ -106,7 +103,7 @@ module Pod
# @return [void] # @return [void]
# #
def validate_dependencies_are_present! def validate_dependencies_are_present!
if podfile.target_definitions.values.all?(&:empty?) if @podfile_dependency_cache.target_definition_list.all?(&:empty?)
add_warning 'The Podfile does not contain any dependencies.' add_warning 'The Podfile does not contain any dependencies.'
end end
end end
...@@ -116,8 +113,8 @@ module Pod ...@@ -116,8 +113,8 @@ module Pod
# target, or be inherited by a target where `inheritance == complete`. # target, or be inherited by a target where `inheritance == complete`.
# #
def validate_no_abstract_only_pods! def validate_no_abstract_only_pods!
all_dependencies = podfile.dependencies all_dependencies = @podfile_dependency_cache.podfile_dependencies
concrete_dependencies = podfile.target_definition_list.reject(&:abstract?).flat_map(&:dependencies).uniq concrete_dependencies = @podfile_dependency_cache.target_definition_list.reject(&:abstract?).flat_map { |td| @podfile_dependency_cache.target_definition_dependencies(td) }
abstract_only_dependencies = all_dependencies - concrete_dependencies abstract_only_dependencies = all_dependencies - concrete_dependencies
abstract_only_dependencies.each do |dep| abstract_only_dependencies.each do |dep|
add_error "The dependency `#{dep}` is not used in any concrete target." add_error "The dependency `#{dep}` is not used in any concrete target."
...@@ -125,7 +122,7 @@ module Pod ...@@ -125,7 +122,7 @@ module Pod
end end
def validate_no_duplicate_targets! def validate_no_duplicate_targets!
podfile.target_definition_list.group_by { |td| [td.name, td.user_project_path] }. @podfile_dependency_cache.target_definition_list.group_by { |td| [td.name, td.user_project_path] }.
each do |(name, project), definitions| each do |(name, project), definitions|
next unless definitions.size > 1 next unless definitions.size > 1
error = "The target `#{name}` is declared twice" error = "The target `#{name}` is declared twice"
......
...@@ -40,6 +40,15 @@ module Pod ...@@ -40,6 +40,15 @@ module Pod
# #
attr_reader :development_pods attr_reader :development_pods
# Overridden to generate UUIDs in a much faster way, since we don't need to check for collisions
# (as the Pods project is regenerated each time, and thus all UUIDs will have come from this method)
def generate_available_uuid_list(count = 100)
start = @generated_uuids.size
uniques = Array.new(count) { |i| format('%011X0', start + i) }
@generated_uuids += uniques
@available_uuids += uniques
end
public public
# @!group Legacy Xcode build root # @!group Legacy Xcode build root
......
...@@ -85,9 +85,11 @@ module Pod ...@@ -85,9 +85,11 @@ module Pod
# @param [Array<Dependency>] locked_dependencies @see locked_dependencies # @param [Array<Dependency>] locked_dependencies @see locked_dependencies
# @param [Array<Source>, Source] sources @see sources # @param [Array<Source>, Source] sources @see sources
# #
def initialize(sandbox, podfile, locked_dependencies, sources) def initialize(sandbox, podfile, locked_dependencies, sources,
podfile_dependency_cache: Installer::Analyzer::PodfileDependencyCache.from_podfile(podfile))
@sandbox = sandbox @sandbox = sandbox
@podfile = podfile @podfile = podfile
@podfile_dependency_cache = podfile_dependency_cache
@locked_dependencies = locked_dependencies @locked_dependencies = locked_dependencies
@sources = Array(sources) @sources = Array(sources)
@platforms_by_dependency = Hash.new { |h, k| h[k] = [] } @platforms_by_dependency = Hash.new { |h, k| h[k] = [] }
...@@ -107,11 +109,13 @@ module Pod ...@@ -107,11 +109,13 @@ module Pod
# definition. # definition.
# #
def resolve def resolve
dependencies = podfile.target_definition_list.flat_map do |target| dependencies = @podfile_dependency_cache.target_definition_list.flat_map do |target|
target.dependencies.each do |dep| @podfile_dependency_cache.target_definition_dependencies(target).each do |dep|
@platforms_by_dependency[dep].push(target.platform).uniq! if target.platform next unless target.platform
@platforms_by_dependency[dep].push(target.platform)
end end
end end
@platforms_by_dependency.each_value(&:uniq!)
@activated = Molinillo::Resolver.new(self, self).resolve(dependencies, locked_dependencies) @activated = Molinillo::Resolver.new(self, self).resolve(dependencies, locked_dependencies)
resolver_specs_by_target resolver_specs_by_target
rescue Molinillo::ResolverError => e rescue Molinillo::ResolverError => e
...@@ -125,9 +129,9 @@ module Pod ...@@ -125,9 +129,9 @@ module Pod
# #
def resolver_specs_by_target def resolver_specs_by_target
@resolver_specs_by_target ||= {}.tap do |resolver_specs_by_target| @resolver_specs_by_target ||= {}.tap do |resolver_specs_by_target|
podfile.target_definition_list.each do |target| dependencies = {}
dependencies = {} @podfile_dependency_cache.target_definition_list.each do |target|
specs = target.dependencies.flat_map do |dep| specs = @podfile_dependency_cache.target_definition_dependencies(target).flat_map do |dep|
name = dep.name name = dep.name
node = @activated.vertex_named(name) node = @activated.vertex_named(name)
(valid_dependencies_for_target_from_node(target, dependencies, node) << node).map { |s| [s, node.payload.test_specification?] } (valid_dependencies_for_target_from_node(target, dependencies, node) << node).map { |s| [s, node.payload.test_specification?] }
...@@ -559,11 +563,11 @@ module Pod ...@@ -559,11 +563,11 @@ module Pod
# dependencies for `target`. # dependencies for `target`.
# #
def valid_dependencies_for_target_from_node(target, dependencies, node) def valid_dependencies_for_target_from_node(target, dependencies, node)
dependencies[node.name] ||= begin dependencies[[node.name, target.platform]] ||= begin
validate_platform(node.payload, target) validate_platform(node.payload, target)
dependency_nodes = [] dependency_nodes = []
node.outgoing_edges.each do |edge| node.outgoing_edges.each do |edge|
next unless edge_is_valid_for_target?(edge, target) next unless edge_is_valid_for_target_platform?(edge, target.platform)
dependency_nodes << edge.destination dependency_nodes << edge.destination
end end
...@@ -574,14 +578,14 @@ module Pod ...@@ -574,14 +578,14 @@ module Pod
end end
# Whether the given `edge` should be followed to find dependencies for the # Whether the given `edge` should be followed to find dependencies for the
# given `target`. # given `target_platform`.
# #
# @return [Bool] # @return [Bool]
# #
def edge_is_valid_for_target?(edge, target) def edge_is_valid_for_target_platform?(edge, target_platform)
requirement_name = edge.requirement.name requirement_name = edge.requirement.name
edge.origin.payload.all_dependencies(target.platform).any? do |dep| edge.origin.payload.all_dependencies(target_platform).any? do |dep|
dep.name == requirement_name dep.name == requirement_name
end end
end end
......
...@@ -140,7 +140,7 @@ module Pod ...@@ -140,7 +140,7 @@ module Pod
# @return [Array<AggregateTarget>] The aggregate targets whose pods this # @return [Array<AggregateTarget>] The aggregate targets whose pods this
# target must be able to import, but will not directly link against. # target must be able to import, but will not directly link against.
# #
attr_accessor :search_paths_aggregate_targets attr_reader :search_paths_aggregate_targets
# @param [String] build_configuration The build configuration for which the # @param [String] build_configuration The build configuration for which the
# the pod targets should be returned. # the pod targets should be returned.
...@@ -149,11 +149,16 @@ module Pod ...@@ -149,11 +149,16 @@ module Pod
# configuration. # configuration.
# #
def pod_targets_for_build_configuration(build_configuration) def pod_targets_for_build_configuration(build_configuration)
pod_targets.select do |pod_target| @pod_targets_for_build_configuration ||= {}
@pod_targets_for_build_configuration[build_configuration] ||= pod_targets.select do |pod_target|
pod_target.include_in_build_config?(target_definition, build_configuration) pod_target.include_in_build_config?(target_definition, build_configuration)
end end
end end
def pod_targets_to_link
@pod_targets_to_link ||= pod_targets.to_set - search_paths_aggregate_targets.flat_map(&:pod_targets)
end
# @return [Array<Specification>] The specifications used by this aggregate target. # @return [Array<Specification>] The specifications used by this aggregate target.
# #
def specs def specs
...@@ -191,9 +196,7 @@ module Pod ...@@ -191,9 +196,7 @@ module Pod
@framework_paths_by_config ||= begin @framework_paths_by_config ||= begin
framework_paths_by_config = {} framework_paths_by_config = {}
user_build_configurations.keys.each do |config| user_build_configurations.keys.each do |config|
relevant_pod_targets = pod_targets.select do |pod_target| relevant_pod_targets = pod_targets_for_build_configuration(config)
pod_target.include_in_build_config?(target_definition, config)
end
framework_paths_by_config[config] = relevant_pod_targets.flat_map { |pt| pt.framework_paths(false) } framework_paths_by_config[config] = relevant_pod_targets.flat_map { |pt| pt.framework_paths(false) }
end end
framework_paths_by_config framework_paths_by_config
...@@ -208,8 +211,7 @@ module Pod ...@@ -208,8 +211,7 @@ module Pod
pod_target.should_build? && pod_target.requires_frameworks? && !pod_target.static_framework? pod_target.should_build? && pod_target.requires_frameworks? && !pod_target.static_framework?
end end
user_build_configurations.keys.each_with_object({}) do |config, resources_by_config| user_build_configurations.keys.each_with_object({}) do |config, resources_by_config|
resources_by_config[config] = relevant_pod_targets.flat_map do |pod_target| resources_by_config[config] = (relevant_pod_targets & pod_targets_for_build_configuration(config)).flat_map do |pod_target|
next [] unless pod_target.include_in_build_config?(target_definition, config)
(pod_target.resource_paths(false) + [bridge_support_file].compact).uniq (pod_target.resource_paths(false) + [bridge_support_file].compact).uniq
end end
end end
......
...@@ -522,10 +522,8 @@ module Pod ...@@ -522,10 +522,8 @@ module Pod
if whitelists.empty? if whitelists.empty?
@build_config_cache[key] = true @build_config_cache[key] = true
true
elsif whitelists.count == 1 elsif whitelists.count == 1
@build_config_cache[key] = whitelists.first @build_config_cache[key] = whitelists.first
whitelists.first
else else
raise Informative, "The subspecs of `#{pod_name}` are linked to " \ raise Informative, "The subspecs of `#{pod_name}` are linked to " \
"different build configurations for the `#{target_definition}` " \ "different build configurations for the `#{target_definition}` " \
......
...@@ -497,7 +497,7 @@ module Pod ...@@ -497,7 +497,7 @@ module Pod
it 'should include inherited search paths' do it 'should include inherited search paths' do
# It's the responsibility of the analyzer to # It's the responsibility of the analyzer to
# populate this when the file is loaded. # populate this when the file is loaded.
@blank_target.search_paths_aggregate_targets = [@target] @blank_target.search_paths_aggregate_targets.replace [@target]
@xcconfig = @generator.generate @xcconfig = @generator.generate
@xcconfig.to_hash['FRAMEWORK_SEARCH_PATHS'].should.not.be.nil @xcconfig.to_hash['FRAMEWORK_SEARCH_PATHS'].should.not.be.nil
end end
......
...@@ -12,8 +12,8 @@ module Pod ...@@ -12,8 +12,8 @@ module Pod
describe '::default_ld_flags' do describe '::default_ld_flags' do
it 'returns the default linker flags' do it 'returns the default linker flags' do
podfile = stub(:set_arc_compatibility_flag? => false) podfile = stub('podfile', :set_arc_compatibility_flag? => false)
target = stub(:podfile => podfile) target = stub('target', :podfile => podfile)
result = @sut.default_ld_flags(target) result = @sut.default_ld_flags(target)
result.should == '' result.should == ''
...@@ -22,9 +22,9 @@ module Pod ...@@ -22,9 +22,9 @@ module Pod
end end
it 'includes the ARC compatibility flag if required by the Podfile' do it 'includes the ARC compatibility flag if required by the Podfile' do
podfile = stub(:set_arc_compatibility_flag? => true) podfile = stub('podfile', :set_arc_compatibility_flag? => true)
spec_consumer = stub(:requires_arc? => true) spec_consumer = stub('spec_consumer', :requires_arc? => true)
target = stub(:podfile => podfile, :spec_consumers => [spec_consumer]) target = stub('target', :podfile => podfile, :spec_consumers => [spec_consumer])
result = @sut.default_ld_flags(target) result = @sut.default_ld_flags(target)
result.should == '-fobjc-arc' result.should == '-fobjc-arc'
...@@ -52,107 +52,109 @@ module Pod ...@@ -52,107 +52,109 @@ module Pod
describe '::add_spec_build_settings_to_xcconfig' do describe '::add_spec_build_settings_to_xcconfig' do
it 'adds the libraries of the xcconfig' do it 'adds the libraries of the xcconfig' do
xcconfig = Xcodeproj::Config.new xcconfig = Xcodeproj::Config.new
consumer = stub( consumer = stub('consumer',
:pod_target_xcconfig => {}, :pod_target_xcconfig => {},
:libraries => ['xml2'], :libraries => ['xml2'],
:frameworks => [], :frameworks => [],
:weak_frameworks => [], :weak_frameworks => [],
:platform_name => :ios, :platform_name => :ios,
) )
@sut.add_spec_build_settings_to_xcconfig(consumer, xcconfig) @sut.add_spec_build_settings_to_xcconfig(consumer, xcconfig)
xcconfig.to_hash['OTHER_LDFLAGS'].should == '-l"xml2"' xcconfig.to_hash['OTHER_LDFLAGS'].should == '-l"xml2"'
end end
it 'check that subspec subsets are removed from frameworks search paths' do it 'check that subspec subsets are removed from frameworks search paths' do
target1 = stub( target1 = stub('target1',
:specs => %w(A, B), :specs => %w(A, B),
:should_build? => true, :should_build? => true,
:requires_frameworks? => true, :requires_frameworks? => true,
:configuration_build_dir => 'AB', :configuration_build_dir => 'AB',
) )
target2 = stub( target2 = stub('target2',
:specs => ['B'], :specs => ['B'],
:should_build? => true, :should_build? => true,
:requires_frameworks? => true, :requires_frameworks? => true,
:configuration_build_dir => 'B', :configuration_build_dir => 'B',
) )
dependent_targets = [target1, target2] dependent_targets = [target1, target2]
build_settings = @sut.search_paths_for_dependent_targets(nil, dependent_targets) build_settings = @sut.search_paths_for_dependent_targets(nil, dependent_targets)
build_settings['FRAMEWORK_SEARCH_PATHS'].should == '"AB"' build_settings['FRAMEWORK_SEARCH_PATHS'].should == '"AB"'
end end
it 'adds the libraries of the xcconfig for a static framework' do it 'adds the libraries of the xcconfig for a static framework' do
spec = stub(:test_specification? => false) spec = stub('spec', :test_specification? => false)
target_definition = stub(:inheritance => 'search_paths') target_definition = stub('target_definition', :inheritance => 'search_paths')
consumer = stub( consumer = stub('consumer',
:pod_target_xcconfig => {}, :pod_target_xcconfig => {},
:libraries => ['xml2'], :libraries => ['xml2'],
:frameworks => [], :frameworks => [],
:weak_frameworks => [], :weak_frameworks => [],
:platform_name => :ios, :platform_name => :ios,
) )
file_accessor = stub( file_accessor = stub('file_accessor',
:spec => spec, :spec => spec,
:spec_consumer => consumer, :spec_consumer => consumer,
:vendored_static_frameworks => [], :vendored_static_frameworks => [],
:vendored_dynamic_frameworks => [], :vendored_dynamic_frameworks => [],
:vendored_static_libraries => [], :vendored_static_libraries => [],
:vendored_dynamic_libraries => [], :vendored_dynamic_libraries => [],
) )
pod_target = stub( pod_target = stub('pod_target',
:name => 'BananaLib', :name => 'BananaLib',
:sandbox => config.sandbox, :sandbox => config.sandbox,
:should_build? => true, :should_build? => true,
:requires_frameworks? => true, :requires_frameworks? => true,
:static_framework? => true, :static_framework? => true,
:dependent_targets => [], :dependent_targets => [],
:file_accessors => [file_accessor], :file_accessors => [file_accessor],
) )
pod_targets = [pod_target] pod_targets = [pod_target]
aggregate_target = stub( aggregate_target = stub('aggregate_target',
:target_definition => target_definition, :target_definition => target_definition,
:pod_targets => pod_targets, :pod_targets => pod_targets,
:search_paths_aggregate_targets => [], :search_paths_aggregate_targets => [],
) :pod_targets_to_link => pod_targets,
)
xcconfig = Xcodeproj::Config.new xcconfig = Xcodeproj::Config.new
@sut.generate_vendored_build_settings(aggregate_target, pod_targets, xcconfig) @sut.generate_vendored_build_settings(aggregate_target, pod_targets, xcconfig)
xcconfig.to_hash['OTHER_LDFLAGS'].should == '-l"xml2"' xcconfig.to_hash['OTHER_LDFLAGS'].should == '-l"xml2"'
end end
it 'checks OTHER_LDFLAGS and FRAMEWORK_SEARCH_PATHS for a vendored dependencies to a static framework' do it 'checks OTHER_LDFLAGS and FRAMEWORK_SEARCH_PATHS for a vendored dependencies to a static framework' do
spec = stub(:test_specification? => false) spec = stub('spec', :test_specification? => false)
target_definition = stub(:inheritance => 'search_paths') target_definition = stub('target_definition', :inheritance => 'search_paths')
consumer = stub( consumer = stub('consumer',
:pod_target_xcconfig => {}, :pod_target_xcconfig => {},
:libraries => ['xml2'], :libraries => ['xml2'],
:frameworks => [], :frameworks => [],
:weak_frameworks => [], :weak_frameworks => [],
:platform_name => :ios, :platform_name => :ios,
) )
file_accessor = stub( file_accessor = stub('file_accessor',
:spec => spec, :spec => spec,
:spec_consumer => consumer, :spec_consumer => consumer,
:vendored_static_frameworks => [config.sandbox.root + 'StaticFramework.framework'], :vendored_static_frameworks => [config.sandbox.root + 'StaticFramework.framework'],
:vendored_static_libraries => [config.sandbox.root + 'StaticLibrary.a'], :vendored_static_libraries => [config.sandbox.root + 'StaticLibrary.a'],
:vendored_dynamic_frameworks => [config.sandbox.root + 'VendoredFramework.framework'], :vendored_dynamic_frameworks => [config.sandbox.root + 'VendoredFramework.framework'],
:vendored_dynamic_libraries => [config.sandbox.root + 'VendoredDyld.dyld'], :vendored_dynamic_libraries => [config.sandbox.root + 'VendoredDyld.dyld'],
) )
dep_target = stub( dep_target = stub('dep_target',
:name => 'BananaLib', :name => 'BananaLib',
:sandbox => config.sandbox, :sandbox => config.sandbox,
:should_build? => false, :should_build? => false,
:requires_frameworks? => true, :requires_frameworks? => true,
:static_framework? => false, :static_framework? => false,
:dependent_targets => [], :dependent_targets => [],
:file_accessors => [file_accessor], :file_accessors => [file_accessor],
) )
dep_targets = [dep_target] dep_targets = [dep_target]
target = stub( target = stub('target',
:target_definition => target_definition, :target_definition => target_definition,
:pod_targets => dep_targets, :pod_targets => dep_targets,
:search_paths_aggregate_targets => [], :search_paths_aggregate_targets => [],
:static_framework => true, :static_framework => true,
) :pod_targets_to_link => dep_targets,
)
xcconfig = Xcodeproj::Config.new xcconfig = Xcodeproj::Config.new
@sut.generate_vendored_build_settings(target, dep_targets, xcconfig, true) @sut.generate_vendored_build_settings(target, dep_targets, xcconfig, true)
xcconfig.to_hash['OTHER_LDFLAGS'].should == '-l"StaticLibrary" -l"VendoredDyld" -l"xml2" -framework "StaticFramework" -framework "VendoredFramework"' xcconfig.to_hash['OTHER_LDFLAGS'].should == '-l"StaticLibrary" -l"VendoredDyld" -l"xml2" -framework "StaticFramework" -framework "VendoredFramework"'
...@@ -172,38 +174,38 @@ module Pod ...@@ -172,38 +174,38 @@ module Pod
end end
it 'check that include_ld_flags being false doesnt generate OTHER_LDFLAGS' do it 'check that include_ld_flags being false doesnt generate OTHER_LDFLAGS' do
spec = stub(:test_specification? => false) spec = stub('spec', :test_specification? => false)
target_definition = stub(:inheritance => 'search_paths') target_definition = stub('target_definition', :inheritance => 'search_paths')
consumer = stub( consumer = stub('consumer',
:pod_target_xcconfig => {}, :pod_target_xcconfig => {},
:libraries => ['xml2'], :libraries => ['xml2'],
:frameworks => [], :frameworks => [],
:weak_frameworks => [], :weak_frameworks => [],
:platform_name => :ios, :platform_name => :ios,
) )
file_accessor = stub( file_accessor = stub('file_accessor',
:spec => spec, :spec => spec,
:spec_consumer => consumer, :spec_consumer => consumer,
:vendored_static_frameworks => [config.sandbox.root + 'StaticFramework.framework'], :vendored_static_frameworks => [config.sandbox.root + 'StaticFramework.framework'],
:vendored_static_libraries => [config.sandbox.root + 'StaticLibrary.a'], :vendored_static_libraries => [config.sandbox.root + 'StaticLibrary.a'],
:vendored_dynamic_frameworks => [config.sandbox.root + 'VendoredFramework.framework'], :vendored_dynamic_frameworks => [config.sandbox.root + 'VendoredFramework.framework'],
:vendored_dynamic_libraries => [config.sandbox.root + 'VendoredDyld.dyld'], :vendored_dynamic_libraries => [config.sandbox.root + 'VendoredDyld.dyld'],
) )
dep_target = stub( dep_target = stub('dep_target',
:name => 'BananaLib', :name => 'BananaLib',
:sandbox => config.sandbox, :sandbox => config.sandbox,
:should_build? => false, :should_build? => false,
:requires_frameworks? => true, :requires_frameworks? => true,
:static_framework? => false, :static_framework? => false,
:dependent_targets => [], :dependent_targets => [],
:file_accessors => [file_accessor], :file_accessors => [file_accessor],
) )
dep_targets = [dep_target] dep_targets = [dep_target]
target = stub( target = stub('target',
:target_definition => target_definition, :target_definition => target_definition,
:pod_targets => dep_targets, :pod_targets => dep_targets,
:search_paths_aggregate_targets => [], :search_paths_aggregate_targets => [],
) )
xcconfig = Xcodeproj::Config.new xcconfig = Xcodeproj::Config.new
@sut.generate_vendored_build_settings(target, dep_targets, xcconfig, false) @sut.generate_vendored_build_settings(target, dep_targets, xcconfig, false)
xcconfig.to_hash['OTHER_LDFLAGS'].should.nil? xcconfig.to_hash['OTHER_LDFLAGS'].should.nil?
...@@ -211,42 +213,42 @@ module Pod ...@@ -211,42 +213,42 @@ module Pod
end end
it 'makes sure setting from search_paths get propagated for static frameworks' do it 'makes sure setting from search_paths get propagated for static frameworks' do
target_definition = stub(:inheritance => 'search_paths') target_definition = stub('target_definition', :inheritance => 'search_paths')
consumer = stub( consumer = stub('consumer',
:pod_target_xcconfig => {}, :pod_target_xcconfig => {},
:libraries => ['xml2'], :libraries => ['xml2'],
:frameworks => ['Foo'], :frameworks => ['Foo'],
:weak_frameworks => [], :weak_frameworks => [],
:platform_name => :ios, :platform_name => :ios,
) )
file_accessor = stub( file_accessor = stub('file_accessor',
:spec_consumer => consumer, :spec_consumer => consumer,
:vendored_static_frameworks => [], :vendored_static_frameworks => [],
:vendored_dynamic_frameworks => [], :vendored_dynamic_frameworks => [],
:vendored_static_libraries => [], :vendored_static_libraries => [],
:vendored_dynamic_libraries => [], :vendored_dynamic_libraries => [],
) )
pod_target = stub( pod_target = stub('pod_target',
:name => 'BananaLib', :name => 'BananaLib',
:sandbox => config.sandbox, :sandbox => config.sandbox,
:should_build? => true, :should_build? => true,
:requires_frameworks? => true, :requires_frameworks? => true,
:static_framework? => true, :static_framework? => true,
:dependent_targets => [], :dependent_targets => [],
:file_accessors => [file_accessor], :file_accessors => [file_accessor],
:product_basename => 'Foo', :product_basename => 'Foo',
) )
pod_targets = [pod_target] pod_targets = [pod_target]
aggregate_target = stub( aggregate_target = stub('aggregate_target',
:target_definition => target_definition, :target_definition => target_definition,
:pod_targets => pod_targets, :pod_targets => pod_targets,
:search_paths_aggregate_targets => [], :search_paths_aggregate_targets => [],
) )
test_aggregate_target = stub( test_aggregate_target = stub('test_aggregate_target',
:target_definition => target_definition, :target_definition => target_definition,
:pod_targets => [], :pod_targets => [],
:search_paths_aggregate_targets => [aggregate_target], :search_paths_aggregate_targets => [aggregate_target],
) )
xcconfig = Xcodeproj::Config.new xcconfig = Xcodeproj::Config.new
@sut.generate_other_ld_flags(test_aggregate_target, [], xcconfig) @sut.generate_other_ld_flags(test_aggregate_target, [], xcconfig)
xcconfig.to_hash['OTHER_LDFLAGS'].should == '-framework "Foo"' xcconfig.to_hash['OTHER_LDFLAGS'].should == '-framework "Foo"'
...@@ -254,51 +256,51 @@ module Pod ...@@ -254,51 +256,51 @@ module Pod
it 'includes HEADER_SEARCH_PATHS from search paths' do it 'includes HEADER_SEARCH_PATHS from search paths' do
xcconfig = Xcodeproj::Config.new xcconfig = Xcodeproj::Config.new
spec_consumer = stub(:user_target_xcconfig => { 'HEADER_SEARCH_PATHS' => 'my/path' }) spec_consumer = stub('spec_consumer', :user_target_xcconfig => { 'HEADER_SEARCH_PATHS' => 'my/path' })
pod_target = stub(:spec_consumers => [spec_consumer]) pod_target = stub('pod_target', :spec_consumers => [spec_consumer])
search_path_target = stub( search_path_target = stub('search_path_target',
:pod_targets_for_build_configuration => [pod_target], :pod_targets_for_build_configuration => [pod_target],
:pod_targets => [pod_target], :pod_targets => [pod_target],
) )
@sut.propagate_header_search_paths_from_search_paths(search_path_target, xcconfig) @sut.propagate_header_search_paths_from_search_paths(search_path_target, xcconfig)
xcconfig.to_hash['HEADER_SEARCH_PATHS'].should == '$(inherited) my/path' xcconfig.to_hash['HEADER_SEARCH_PATHS'].should == '$(inherited) my/path'
end end
it 'adds the frameworks of the xcconfig' do it 'adds the frameworks of the xcconfig' do
xcconfig = Xcodeproj::Config.new xcconfig = Xcodeproj::Config.new
consumer = stub( consumer = stub('consumer',
:pod_target_xcconfig => {}, :pod_target_xcconfig => {},
:libraries => [], :libraries => [],
:frameworks => ['CoreAnimation'], :frameworks => ['CoreAnimation'],
:weak_frameworks => [], :weak_frameworks => [],
:platform_name => :ios, :platform_name => :ios,
) )
@sut.add_spec_build_settings_to_xcconfig(consumer, xcconfig) @sut.add_spec_build_settings_to_xcconfig(consumer, xcconfig)
xcconfig.to_hash['OTHER_LDFLAGS'].should == '-framework "CoreAnimation"' xcconfig.to_hash['OTHER_LDFLAGS'].should == '-framework "CoreAnimation"'
end end
it 'adds the weak frameworks of the xcconfig' do it 'adds the weak frameworks of the xcconfig' do
xcconfig = Xcodeproj::Config.new xcconfig = Xcodeproj::Config.new
consumer = stub( consumer = stub('consumer',
:pod_target_xcconfig => {}, :pod_target_xcconfig => {},
:libraries => [], :libraries => [],
:frameworks => [], :frameworks => [],
:weak_frameworks => ['iAd'], :weak_frameworks => ['iAd'],
:platform_name => :ios, :platform_name => :ios,
) )
@sut.add_spec_build_settings_to_xcconfig(consumer, xcconfig) @sut.add_spec_build_settings_to_xcconfig(consumer, xcconfig)
xcconfig.to_hash['OTHER_LDFLAGS'].should == '-weak_framework "iAd"' xcconfig.to_hash['OTHER_LDFLAGS'].should == '-weak_framework "iAd"'
end end
it 'adds the ios developer frameworks search paths if needed' do it 'adds the ios developer frameworks search paths if needed' do
xcconfig = Xcodeproj::Config.new xcconfig = Xcodeproj::Config.new
consumer = stub( consumer = stub('consumer',
:pod_target_xcconfig => {}, :pod_target_xcconfig => {},
:libraries => [], :libraries => [],
:frameworks => ['SenTestingKit'], :frameworks => ['SenTestingKit'],
:weak_frameworks => [], :weak_frameworks => [],
:platform_name => :ios, :platform_name => :ios,
) )
@sut.add_spec_build_settings_to_xcconfig(consumer, xcconfig) @sut.add_spec_build_settings_to_xcconfig(consumer, xcconfig)
xcconfig.to_hash['FRAMEWORK_SEARCH_PATHS'].should.not.include('SDKROOT') xcconfig.to_hash['FRAMEWORK_SEARCH_PATHS'].should.not.include('SDKROOT')
xcconfig.to_hash['FRAMEWORK_SEARCH_PATHS'].should.not.include('DEVELOPER_LIBRARY_DIR') xcconfig.to_hash['FRAMEWORK_SEARCH_PATHS'].should.not.include('DEVELOPER_LIBRARY_DIR')
...@@ -306,13 +308,13 @@ module Pod ...@@ -306,13 +308,13 @@ module Pod
it 'adds the osx developer frameworks search paths if needed' do it 'adds the osx developer frameworks search paths if needed' do
xcconfig = Xcodeproj::Config.new xcconfig = Xcodeproj::Config.new
consumer = stub( consumer = stub('consumer',
:pod_target_xcconfig => {}, :pod_target_xcconfig => {},
:libraries => [], :libraries => [],
:frameworks => ['SenTestingKit'], :frameworks => ['SenTestingKit'],
:weak_frameworks => [], :weak_frameworks => [],
:platform_name => :osx, :platform_name => :osx,
) )
@sut.add_spec_build_settings_to_xcconfig(consumer, xcconfig) @sut.add_spec_build_settings_to_xcconfig(consumer, xcconfig)
xcconfig.to_hash['FRAMEWORK_SEARCH_PATHS'].should.not.include('DEVELOPER_LIBRARY_DIR') xcconfig.to_hash['FRAMEWORK_SEARCH_PATHS'].should.not.include('DEVELOPER_LIBRARY_DIR')
xcconfig.to_hash['FRAMEWORK_SEARCH_PATHS'].should.not.include('SDKROOT') xcconfig.to_hash['FRAMEWORK_SEARCH_PATHS'].should.not.include('SDKROOT')
...@@ -398,7 +400,7 @@ module Pod ...@@ -398,7 +400,7 @@ module Pod
describe '::add_language_specific_settings' do describe '::add_language_specific_settings' do
it 'does not add OTHER_SWIFT_FLAGS to the xcconfig if the target does not use swift' do it 'does not add OTHER_SWIFT_FLAGS to the xcconfig if the target does not use swift' do
target = stub(:uses_swift? => false) target = stub('target', :uses_swift? => false)
xcconfig = Xcodeproj::Config.new xcconfig = Xcodeproj::Config.new
@sut.add_language_specific_settings(target, xcconfig) @sut.add_language_specific_settings(target, xcconfig)
other_swift_flags = xcconfig.to_hash['OTHER_SWIFT_FLAGS'] other_swift_flags = xcconfig.to_hash['OTHER_SWIFT_FLAGS']
...@@ -406,7 +408,7 @@ module Pod ...@@ -406,7 +408,7 @@ module Pod
end end
it 'does not add the -suppress-warnings flag to the xcconfig if the target uses swift, but does not inhibit warnings' do it 'does not add the -suppress-warnings flag to the xcconfig if the target uses swift, but does not inhibit warnings' do
target = stub(:uses_swift? => true, :inhibit_warnings? => false) target = stub('target', :uses_swift? => true, :inhibit_warnings? => false)
xcconfig = Xcodeproj::Config.new xcconfig = Xcodeproj::Config.new
@sut.add_language_specific_settings(target, xcconfig) @sut.add_language_specific_settings(target, xcconfig)
other_swift_flags = xcconfig.to_hash['OTHER_SWIFT_FLAGS'] other_swift_flags = xcconfig.to_hash['OTHER_SWIFT_FLAGS']
...@@ -414,7 +416,7 @@ module Pod ...@@ -414,7 +416,7 @@ module Pod
end end
it 'adds the -suppress-warnings flag to the xcconfig if the target uses swift and inhibits warnings' do it 'adds the -suppress-warnings flag to the xcconfig if the target uses swift and inhibits warnings' do
target = stub(:uses_swift? => true, :inhibit_warnings? => true) target = stub('target', :uses_swift? => true, :inhibit_warnings? => true)
xcconfig = Xcodeproj::Config.new xcconfig = Xcodeproj::Config.new
@sut.add_language_specific_settings(target, xcconfig) @sut.add_language_specific_settings(target, xcconfig)
other_swift_flags = xcconfig.to_hash['OTHER_SWIFT_FLAGS'] other_swift_flags = xcconfig.to_hash['OTHER_SWIFT_FLAGS']
...@@ -426,71 +428,71 @@ module Pod ...@@ -426,71 +428,71 @@ module Pod
describe 'concerning settings for file accessors' do describe 'concerning settings for file accessors' do
it 'does not propagate framework or libraries from a test specification to an aggregate target' do it 'does not propagate framework or libraries from a test specification to an aggregate target' do
spec = stub(:test_specification? => true) spec = stub('spec', :test_specification? => true)
consumer = stub( consumer = stub('consumer',
:libraries => ['xml2'], :libraries => ['xml2'],
:frameworks => ['XCTest'], :frameworks => ['XCTest'],
:weak_frameworks => [], :weak_frameworks => [],
:spec => spec, :spec => spec,
) )
file_accessor = stub( file_accessor = stub('file_accessor',
:spec => spec, :spec => spec,
:spec_consumer => consumer, :spec_consumer => consumer,
:vendored_static_frameworks => [config.sandbox.root + 'StaticFramework.framework'], :vendored_static_frameworks => [config.sandbox.root + 'StaticFramework.framework'],
:vendored_static_libraries => [config.sandbox.root + 'StaticLibrary.a'], :vendored_static_libraries => [config.sandbox.root + 'StaticLibrary.a'],
:vendored_dynamic_frameworks => [config.sandbox.root + 'VendoredFramework.framework'], :vendored_dynamic_frameworks => [config.sandbox.root + 'VendoredFramework.framework'],
:vendored_dynamic_libraries => [config.sandbox.root + 'VendoredDyld.dyld'], :vendored_dynamic_libraries => [config.sandbox.root + 'VendoredDyld.dyld'],
) )
pod_target = stub( pod_target = stub('pod_target',
:file_accessors => [file_accessor], :file_accessors => [file_accessor],
:requires_frameworks? => true, :requires_frameworks? => true,
:dependent_targets => [], :dependent_targets => [],
:sandbox => config.sandbox, :sandbox => config.sandbox,
) )
target_definition = stub(:inheritance => 'complete') target_definition = stub('target_definition', :inheritance => 'complete')
aggregate_target = stub(:target_definition => target_definition) aggregate_target = stub('aggregate_target', :target_definition => target_definition)
xcconfig = Xcodeproj::Config.new xcconfig = Xcodeproj::Config.new
@sut.add_settings_for_file_accessors_of_target(aggregate_target, pod_target, xcconfig) @sut.add_settings_for_file_accessors_of_target(aggregate_target, pod_target, xcconfig)
xcconfig.to_hash['OTHER_LDFLAGS'].should.be.nil xcconfig.to_hash['OTHER_LDFLAGS'].should.be.nil
end end
it 'propagates correct frameworks or libraries to both test and non test xcconfigs' do it 'propagates correct frameworks or libraries to both test and non test xcconfigs' do
spec = stub(:test_specification? => false) spec = stub('spec', :test_specification? => false)
consumer = stub( consumer = stub('consumer',
:libraries => [], :libraries => [],
:frameworks => [], :frameworks => [],
:weak_frameworks => [], :weak_frameworks => [],
:spec => spec, :spec => spec,
) )
file_accessor = stub( file_accessor = stub('file_accessor',
:spec => spec, :spec => spec,
:spec_consumer => consumer, :spec_consumer => consumer,
:vendored_static_frameworks => [config.sandbox.root + 'StaticFramework.framework'], :vendored_static_frameworks => [config.sandbox.root + 'StaticFramework.framework'],
:vendored_static_libraries => [config.sandbox.root + 'StaticLibrary.a'], :vendored_static_libraries => [config.sandbox.root + 'StaticLibrary.a'],
:vendored_dynamic_frameworks => [config.sandbox.root + 'VendoredFramework.framework'], :vendored_dynamic_frameworks => [config.sandbox.root + 'VendoredFramework.framework'],
:vendored_dynamic_libraries => [config.sandbox.root + 'VendoredDyld.dyld'], :vendored_dynamic_libraries => [config.sandbox.root + 'VendoredDyld.dyld'],
) )
test_spec = stub(:test_specification? => true) test_spec = stub('test_spec', :test_specification? => true)
test_consumer = stub( test_consumer = stub('test_consumer',
:libraries => ['xml2'], :libraries => ['xml2'],
:frameworks => ['XCTest'], :frameworks => ['XCTest'],
:weak_frameworks => [], :weak_frameworks => [],
:spec => test_spec, :spec => test_spec,
) )
test_file_accessor = stub( test_file_accessor = stub('test_file_accessor',
:spec => test_spec, :spec => test_spec,
:spec_consumer => test_consumer, :spec_consumer => test_consumer,
:vendored_static_frameworks => [], :vendored_static_frameworks => [],
:vendored_static_libraries => [], :vendored_static_libraries => [],
:vendored_dynamic_frameworks => [], :vendored_dynamic_frameworks => [],
:vendored_dynamic_libraries => [], :vendored_dynamic_libraries => [],
) )
pod_target = stub( pod_target = stub('pod_target',
:file_accessors => [file_accessor, test_file_accessor], :file_accessors => [file_accessor, test_file_accessor],
:requires_frameworks? => true, :requires_frameworks? => true,
:dependent_targets => [], :dependent_targets => [],
:sandbox => config.sandbox, :sandbox => config.sandbox,
) )
xcconfig = Xcodeproj::Config.new xcconfig = Xcodeproj::Config.new
@sut.add_settings_for_file_accessors_of_target(nil, pod_target, xcconfig, true, false) @sut.add_settings_for_file_accessors_of_target(nil, pod_target, xcconfig, true, false)
xcconfig.to_hash['OTHER_LDFLAGS'].should == '-l"StaticLibrary" -l"VendoredDyld" -framework "StaticFramework" -framework "VendoredFramework"' xcconfig.to_hash['OTHER_LDFLAGS'].should == '-l"StaticLibrary" -l"VendoredDyld" -framework "StaticFramework" -framework "VendoredFramework"'
...@@ -500,56 +502,56 @@ module Pod ...@@ -500,56 +502,56 @@ module Pod
end end
it 'does propagate framework or libraries from a non test specification to an aggregate target' do it 'does propagate framework or libraries from a non test specification to an aggregate target' do
spec = stub(:test_specification? => false) spec = stub('spec', :test_specification? => false)
consumer = stub( consumer = stub('consumer',
:libraries => ['xml2'], :libraries => ['xml2'],
:frameworks => ['XCTest'], :frameworks => ['XCTest'],
:weak_frameworks => [], :weak_frameworks => [],
:spec => spec, :spec => spec,
) )
file_accessor = stub( file_accessor = stub('file_accessor',
:spec => spec, :spec => spec,
:spec_consumer => consumer, :spec_consumer => consumer,
:vendored_static_frameworks => [config.sandbox.root + 'StaticFramework.framework'], :vendored_static_frameworks => [config.sandbox.root + 'StaticFramework.framework'],
:vendored_static_libraries => [config.sandbox.root + 'StaticLibrary.a'], :vendored_static_libraries => [config.sandbox.root + 'StaticLibrary.a'],
:vendored_dynamic_frameworks => [config.sandbox.root + 'VendoredFramework.framework'], :vendored_dynamic_frameworks => [config.sandbox.root + 'VendoredFramework.framework'],
:vendored_dynamic_libraries => [config.sandbox.root + 'VendoredDyld.dyld'], :vendored_dynamic_libraries => [config.sandbox.root + 'VendoredDyld.dyld'],
) )
pod_target = stub( pod_target = stub('pod_target',
:file_accessors => [file_accessor], :file_accessors => [file_accessor],
:requires_frameworks? => true, :requires_frameworks? => true,
:dependent_targets => [], :dependent_targets => [],
:sandbox => config.sandbox, :sandbox => config.sandbox,
) )
target_definition = stub(:inheritance => 'complete') target_definition = stub('target_definition', :inheritance => 'complete')
aggregate_target = stub(:target_definition => target_definition) aggregate_target = stub('aggregate_target', :target_definition => target_definition)
xcconfig = Xcodeproj::Config.new xcconfig = Xcodeproj::Config.new
@sut.add_settings_for_file_accessors_of_target(aggregate_target, pod_target, xcconfig) @sut.add_settings_for_file_accessors_of_target(aggregate_target, pod_target, xcconfig)
xcconfig.to_hash['OTHER_LDFLAGS'].should.be == '-l"StaticLibrary" -l"VendoredDyld" -l"xml2" -framework "StaticFramework" -framework "VendoredFramework" -framework "XCTest"' xcconfig.to_hash['OTHER_LDFLAGS'].should.be == '-l"StaticLibrary" -l"VendoredDyld" -l"xml2" -framework "StaticFramework" -framework "VendoredFramework" -framework "XCTest"'
end end
it 'does propagate framework or libraries to a nil aggregate target' do it 'does propagate framework or libraries to a nil aggregate target' do
spec = stub(:test_specification? => false) spec = stub('spec', :test_specification? => false)
consumer = stub( consumer = stub('consumer',
:libraries => ['xml2'], :libraries => ['xml2'],
:frameworks => ['XCTest'], :frameworks => ['XCTest'],
:weak_frameworks => [], :weak_frameworks => [],
:spec => spec, :spec => spec,
) )
file_accessor = stub( file_accessor = stub('file_accessor',
:spec => spec, :spec => spec,
:spec_consumer => consumer, :spec_consumer => consumer,
:vendored_static_frameworks => [config.sandbox.root + 'StaticFramework.framework'], :vendored_static_frameworks => [config.sandbox.root + 'StaticFramework.framework'],
:vendored_static_libraries => [config.sandbox.root + 'StaticLibrary.a'], :vendored_static_libraries => [config.sandbox.root + 'StaticLibrary.a'],
:vendored_dynamic_frameworks => [config.sandbox.root + 'VendoredFramework.framework'], :vendored_dynamic_frameworks => [config.sandbox.root + 'VendoredFramework.framework'],
:vendored_dynamic_libraries => [config.sandbox.root + 'VendoredDyld.dyld'], :vendored_dynamic_libraries => [config.sandbox.root + 'VendoredDyld.dyld'],
) )
pod_target = stub( pod_target = stub('pod_target',
:file_accessors => [file_accessor], :file_accessors => [file_accessor],
:requires_frameworks? => true, :requires_frameworks? => true,
:dependent_targets => [], :dependent_targets => [],
:sandbox => config.sandbox, :sandbox => config.sandbox,
) )
xcconfig = Xcodeproj::Config.new xcconfig = Xcodeproj::Config.new
@sut.add_settings_for_file_accessors_of_target(nil, pod_target, xcconfig) @sut.add_settings_for_file_accessors_of_target(nil, pod_target, xcconfig)
xcconfig.to_hash['OTHER_LDFLAGS'].should.be == '-l"StaticLibrary" -l"VendoredDyld" -l"xml2" -framework "StaticFramework" -framework "VendoredFramework" -framework "XCTest"' xcconfig.to_hash['OTHER_LDFLAGS'].should.be == '-l"StaticLibrary" -l"VendoredDyld" -l"xml2" -framework "StaticFramework" -framework "VendoredFramework" -framework "XCTest"'
...@@ -557,6 +559,13 @@ module Pod ...@@ -557,6 +559,13 @@ module Pod
end end
describe 'for proper other ld flags' do describe 'for proper other ld flags' do
def stub_aggregate_target(pod_targets, target_definition = nil, search_paths_aggregate_targets: [])
target_definition.stubs(:abstract? => false) unless target_definition.respond_to?(:abstract?)
fixture_aggregate_target(pod_targets, target_definition).tap do |aggregate_target|
aggregate_target.search_paths_aggregate_targets.concat(search_paths_aggregate_targets).freeze
end
end
before do before do
@root = fixture('banana-lib') @root = fixture('banana-lib')
@path_list = Sandbox::PathList.new(@root) @path_list = Sandbox::PathList.new(@root)
...@@ -566,9 +575,9 @@ module Pod ...@@ -566,9 +575,9 @@ module Pod
end end
it 'should not include static framework other ld flags when inheriting search paths' do it 'should not include static framework other ld flags when inheriting search paths' do
target_definition = stub(:inheritance => 'search_paths') target_definition = stub('target_definition', :inheritance => 'search_paths')
aggregate_target = stub(:target_definition => target_definition, :pod_targets => [], :search_paths_aggregate_targets => []) aggregate_target = stub_aggregate_target([], target_definition)
pod_target = stub(:sandbox => config.sandbox) pod_target = stub('pod_target', :sandbox => config.sandbox)
xcconfig = Xcodeproj::Config.new xcconfig = Xcodeproj::Config.new
@sut.add_static_dependency_build_settings(aggregate_target, pod_target, xcconfig, @accessor, true) @sut.add_static_dependency_build_settings(aggregate_target, pod_target, xcconfig, @accessor, true)
xcconfig.to_hash['LIBRARY_SEARCH_PATHS'].should == '"${PODS_ROOT}/../../spec/fixtures/banana-lib"' xcconfig.to_hash['LIBRARY_SEARCH_PATHS'].should == '"${PODS_ROOT}/../../spec/fixtures/banana-lib"'
...@@ -577,9 +586,9 @@ module Pod ...@@ -577,9 +586,9 @@ module Pod
end end
it 'should include static framework other ld flags when inheriting search paths but explicitly declared' do it 'should include static framework other ld flags when inheriting search paths but explicitly declared' do
target_definition = stub(:inheritance => 'search_paths') target_definition = stub('target_definition', :inheritance => 'search_paths')
pod_target = stub(:name => 'BananaLib', :sandbox => config.sandbox) pod_target = stub('pod_target', :name => 'BananaLib', :sandbox => config.sandbox)
aggregate_target = stub(:target_definition => target_definition, :pod_targets => [pod_target], :search_paths_aggregate_targets => []) aggregate_target = stub_aggregate_target([pod_target], target_definition)
xcconfig = Xcodeproj::Config.new xcconfig = Xcodeproj::Config.new
@sut.add_static_dependency_build_settings(aggregate_target, pod_target, xcconfig, @accessor, true) @sut.add_static_dependency_build_settings(aggregate_target, pod_target, xcconfig, @accessor, true)
xcconfig.to_hash['LIBRARY_SEARCH_PATHS'].should == '"${PODS_ROOT}/../../spec/fixtures/banana-lib"' xcconfig.to_hash['LIBRARY_SEARCH_PATHS'].should == '"${PODS_ROOT}/../../spec/fixtures/banana-lib"'
...@@ -588,9 +597,9 @@ module Pod ...@@ -588,9 +597,9 @@ module Pod
end end
it 'should include static framework other ld flags when not inheriting search paths' do it 'should include static framework other ld flags when not inheriting search paths' do
target_definition = stub(:inheritance => 'complete') target_definition = stub('target_definition', :inheritance => 'complete')
aggregate_target = stub(:target_definition => target_definition) aggregate_target = stub_aggregate_target([], target_definition)
pod_target = stub(:sandbox => config.sandbox) pod_target = stub('pod_target', :sandbox => config.sandbox)
xcconfig = Xcodeproj::Config.new xcconfig = Xcodeproj::Config.new
@sut.add_static_dependency_build_settings(aggregate_target, pod_target, xcconfig, @accessor, true) @sut.add_static_dependency_build_settings(aggregate_target, pod_target, xcconfig, @accessor, true)
xcconfig.to_hash['LIBRARY_SEARCH_PATHS'].should == '"${PODS_ROOT}/../../spec/fixtures/banana-lib"' xcconfig.to_hash['LIBRARY_SEARCH_PATHS'].should == '"${PODS_ROOT}/../../spec/fixtures/banana-lib"'
...@@ -599,7 +608,7 @@ module Pod ...@@ -599,7 +608,7 @@ module Pod
end end
it 'should include static framework for pod targets' do it 'should include static framework for pod targets' do
pod_target = stub(:sandbox => config.sandbox) pod_target = stub('pod_target', :sandbox => config.sandbox)
xcconfig = Xcodeproj::Config.new xcconfig = Xcodeproj::Config.new
@sut.add_static_dependency_build_settings(nil, pod_target, xcconfig, @accessor, true) @sut.add_static_dependency_build_settings(nil, pod_target, xcconfig, @accessor, true)
xcconfig.to_hash['LIBRARY_SEARCH_PATHS'].should == '"${PODS_ROOT}/../../spec/fixtures/banana-lib"' xcconfig.to_hash['LIBRARY_SEARCH_PATHS'].should == '"${PODS_ROOT}/../../spec/fixtures/banana-lib"'
...@@ -608,55 +617,55 @@ module Pod ...@@ -608,55 +617,55 @@ module Pod
end end
it 'should link static dependency for pod targets' do it 'should link static dependency for pod targets' do
pod_target = stub(:name => 'BananaLib', :sandbox => config.sandbox) pod_target = stub('pod_target', :name => 'BananaLib', :sandbox => config.sandbox)
@sut.links_dependency?(nil, pod_target).should.be.true @sut.links_dependency?(nil, pod_target).should.be.true
end end
it 'should link static dependency when target explicitly specifies it' do it 'should link static dependency when target explicitly specifies it' do
target_definition = stub(:inheritance => 'complete') target_definition = stub('target_definition', :inheritance => 'complete')
pod_target = stub(:name => 'BananaLib', :sandbox => config.sandbox) pod_target = stub('pod_target', :name => 'BananaLib', :sandbox => config.sandbox)
aggregate_target = stub(:target_definition => target_definition, :pod_targets => [pod_target], :search_paths_aggregate_targets => []) aggregate_target = stub_aggregate_target([pod_target], target_definition)
@sut.links_dependency?(aggregate_target, pod_target).should.be.true @sut.links_dependency?(aggregate_target, pod_target).should.be.true
end end
it 'should link static dependency when target explicitly specifies it even with search paths' do it 'should link static dependency when target explicitly specifies it even with search paths' do
target_definition = stub(:inheritance => 'search_paths') target_definition = stub('target_definition', :inheritance => 'search_paths')
pod_target = stub(:name => 'BananaLib', :sandbox => config.sandbox) pod_target = stub('pod_target', :name => 'BananaLib', :sandbox => config.sandbox)
aggregate_target = stub(:target_definition => target_definition, :pod_targets => [pod_target], :search_paths_aggregate_targets => []) aggregate_target = stub_aggregate_target([pod_target], target_definition)
@sut.links_dependency?(aggregate_target, pod_target).should.be.true @sut.links_dependency?(aggregate_target, pod_target).should.be.true
end end
it 'should not link static dependency when inheriting search paths and parent includes dependency' do it 'should not link static dependency when inheriting search paths and parent includes dependency' do
parent_target_definition = stub parent_target_definition = stub
child_target_definition = stub(:inheritance => 'search_paths') child_target_definition = stub('child_target_definition', :inheritance => 'search_paths')
pod_target = stub(:name => 'BananaLib', :sandbox => config.sandbox) pod_target = stub('pod_target', :name => 'BananaLib', :sandbox => config.sandbox)
parent_aggregate_target = stub(:target_definition => parent_target_definition, :pod_targets => [pod_target], :search_paths_aggregate_targets => []) parent_aggregate_target = stub_aggregate_target([pod_target], parent_target_definition)
child_aggregate_target = stub(:target_definition => child_target_definition, :pod_targets => [], :search_paths_aggregate_targets => [parent_aggregate_target]) child_aggregate_target = stub_aggregate_target([], child_target_definition, :search_paths_aggregate_targets => [parent_aggregate_target])
@sut.links_dependency?(child_aggregate_target, pod_target).should.be.false @sut.links_dependency?(child_aggregate_target, pod_target).should.be.false
end end
it 'should link static transitive dependencies if the parent does not link them' do it 'should link static transitive dependencies if the parent does not link them' do
child_pod_target = stub(:name => 'ChildPod', :sandbox => config.sandbox) child_pod_target = stub('child_pod_target', :name => 'ChildPod', :sandbox => config.sandbox)
parent_pod_target = stub(:name => 'ParentPod', :sandbox => config.sandbox, :dependent_targets => [child_pod_target]) parent_pod_target = stub('parent_pod_target', :name => 'ParentPod', :sandbox => config.sandbox, :dependent_targets => [child_pod_target])
parent_target_definition = stub parent_target_definition = stub
child_target_definition = stub(:inheritance => 'search_paths') child_target_definition = stub('child_target_definition', :inheritance => 'search_paths')
parent_aggregate_target = stub(:target_definition => parent_target_definition, :pod_targets => [], :search_paths_aggregate_targets => []) parent_aggregate_target = stub_aggregate_target([], parent_target_definition)
child_aggregate_target = stub(:target_definition => child_target_definition, :pod_targets => [parent_pod_target, child_pod_target], :search_paths_aggregate_targets => [parent_aggregate_target]) child_aggregate_target = stub_aggregate_target([parent_pod_target, child_pod_target], child_target_definition, :search_paths_aggregate_targets => [parent_aggregate_target])
@sut.links_dependency?(child_aggregate_target, child_pod_target).should.be.true @sut.links_dependency?(child_aggregate_target, child_pod_target).should.be.true
@sut.links_dependency?(child_aggregate_target, parent_pod_target).should.be.true @sut.links_dependency?(child_aggregate_target, parent_pod_target).should.be.true
end end
it 'should link static only transitive dependencies that the parent does not link' do it 'should link static only transitive dependencies that the parent does not link' do
child_pod_target = stub(:name => 'ChildPod', :sandbox => config.sandbox) child_pod_target = stub('child_pod_target', :name => 'ChildPod', :sandbox => config.sandbox)
parent_pod_target = stub(:name => 'ParentPod', :sandbox => config.sandbox, :dependent_targets => [child_pod_target]) parent_pod_target = stub('parent_pod_target', :name => 'ParentPod', :sandbox => config.sandbox, :dependent_targets => [child_pod_target])
parent_target_definition = stub parent_target_definition = stub
child_target_definition = stub(:inheritance => 'search_paths') child_target_definition = stub('child_target_definition', :inheritance => 'search_paths')
parent_aggregate_target = stub(:target_definition => parent_target_definition, :pod_targets => [child_pod_target], :search_paths_aggregate_targets => []) parent_aggregate_target = stub('parent_aggregate_target', :target_definition => parent_target_definition, :pod_targets => [child_pod_target], :search_paths_aggregate_targets => [], :pod_targets_to_link => [child_pod_target])
child_aggregate_target = stub(:target_definition => child_target_definition, :pod_targets => [parent_pod_target, child_pod_target], :search_paths_aggregate_targets => [parent_aggregate_target]) child_aggregate_target = stub('child_aggregate_target', :target_definition => child_target_definition, :pod_targets => [parent_pod_target, child_pod_target], :search_paths_aggregate_targets => [parent_aggregate_target], :pod_targets_to_link => [parent_pod_target])
@sut.links_dependency?(child_aggregate_target, child_pod_target).should.be.false @sut.links_dependency?(child_aggregate_target, child_pod_target).should.be.false
@sut.links_dependency?(child_aggregate_target, parent_pod_target).should.be.true @sut.links_dependency?(child_aggregate_target, parent_pod_target).should.be.true
end end
......
require File.expand_path('../../../../spec_helper', __FILE__)
module Pod
class Installer
class Analyzer
describe PodfileDependencyCache do
describe '.from_podfile' do
it 'returns a warmed cache' do
podfile = Podfile.new do
pod 'A'
target 'T1' do
pod 'B'
target 'T1T' do
inherit! :search_paths
pod 'C'
end
end
target 'T2' do
pod 'B'
target 'T2T' do
inherit! :none
pod 'D'
end
end
end
cache = PodfileDependencyCache.from_podfile(podfile)
cache.podfile_dependencies.should == podfile.dependencies
target_definitions = podfile.target_definition_list
cache.target_definition_list.should == target_definitions
podfile.target_definition_list.each do |td|
cache.target_definition_dependencies(td).should == td.dependencies
end
lambda { cache.target_definition_dependencies(nil) }.should.raise(ArgumentError)
end
end
end
end
end
end
...@@ -598,8 +598,11 @@ module Pod ...@@ -598,8 +598,11 @@ module Pod
it 'fetches the dependencies with external sources' do it 'fetches the dependencies with external sources' do
podfile_state = Installer::Analyzer::SpecsState.new podfile_state = Installer::Analyzer::SpecsState.new
podfile_state.added << 'BananaLib' podfile_state.added << 'BananaLib'
@podfile = Podfile.new do
pod 'BananaLib', :git => 'example.com'
end
@analyzer = Installer::Analyzer.new(@sandbox, @podfile)
@analyzer.stubs(:result).returns(stub(:podfile_state => podfile_state)) @analyzer.stubs(:result).returns(stub(:podfile_state => podfile_state))
@podfile.stubs(:dependencies).returns([Dependency.new('BananaLib', :git => 'example.com')])
ExternalSources::DownloaderSource.any_instance.expects(:fetch) ExternalSources::DownloaderSource.any_instance.expects(:fetch)
@analyzer.send(:fetch_external_sources) @analyzer.send(:fetch_external_sources)
end end
...@@ -607,11 +610,12 @@ module Pod ...@@ -607,11 +610,12 @@ module Pod
it 'does not download the same source multiple times for different subspecs' do it 'does not download the same source multiple times for different subspecs' do
podfile_state = Installer::Analyzer::SpecsState.new podfile_state = Installer::Analyzer::SpecsState.new
podfile_state.added << 'ARAnalytics' podfile_state.added << 'ARAnalytics'
@podfile = Podfile.new do
pod 'ARAnalytics/Mixpanel', :git => 'https://github.com/orta/ARAnalytics', :commit => '6f1a1c314894437e7e5c09572c276e644dbfb64b'
pod 'ARAnalytics/HockeyApp', :git => 'https://github.com/orta/ARAnalytics', :commit => '6f1a1c314894437e7e5c09572c276e644dbfb64b'
end
@analyzer = Installer::Analyzer.new(@sandbox, @podfile)
@analyzer.stubs(:result).returns(stub(:podfile_state => podfile_state)) @analyzer.stubs(:result).returns(stub(:podfile_state => podfile_state))
@podfile.stubs(:dependencies).returns([
Dependency.new('ARAnalytics/Mixpanel', :git => 'https://github.com/orta/ARAnalytics', :commit => '6f1a1c314894437e7e5c09572c276e644dbfb64b'),
Dependency.new('ARAnalytics/HockeyApp', :git => 'https://github.com/orta/ARAnalytics', :commit => '6f1a1c314894437e7e5c09572c276e644dbfb64b'),
])
ExternalSources::DownloaderSource.any_instance.expects(:fetch).once ExternalSources::DownloaderSource.any_instance.expects(:fetch).once
@analyzer.send(:fetch_external_sources) @analyzer.send(:fetch_external_sources)
end end
...@@ -984,7 +988,7 @@ module Pod ...@@ -984,7 +988,7 @@ module Pod
describe 'podfile validation' do describe 'podfile validation' do
before do before do
@sandbox = stub('Sandbox') @sandbox = stub('Sandbox')
@podfile = stub('Podfile') @podfile = Podfile.new
@analyzer = Installer::Analyzer.new(@sandbox, @podfile) @analyzer = Installer::Analyzer.new(@sandbox, @podfile)
end end
......
...@@ -371,6 +371,7 @@ module Pod ...@@ -371,6 +371,7 @@ module Pod
describe '#clean_sandbox' do describe '#clean_sandbox' do
before do before do
@analysis_result = Installer::Analyzer::AnalysisResult.new @analysis_result = Installer::Analyzer::AnalysisResult.new
@analysis_result.podfile_dependency_cache = Installer::Analyzer::PodfileDependencyCache.from_podfile(@installer.podfile)
@analysis_result.specifications = [] @analysis_result.specifications = []
@analysis_result.sandbox_state = Installer::Analyzer::SpecsState.new @analysis_result.sandbox_state = Installer::Analyzer::SpecsState.new
@spec = stub(:name => 'Spec', :test_specification? => false) @spec = stub(:name => 'Spec', :test_specification? => false)
...@@ -563,6 +564,7 @@ module Pod ...@@ -563,6 +564,7 @@ module Pod
describe '#write_lockfiles' do describe '#write_lockfiles' do
before do before do
@analysis_result = Installer::Analyzer::AnalysisResult.new @analysis_result = Installer::Analyzer::AnalysisResult.new
@analysis_result.podfile_dependency_cache = Installer::Analyzer::PodfileDependencyCache.from_podfile(@installer.podfile)
@analysis_result.specifications = [fixture_spec('banana-lib/BananaLib.podspec')] @analysis_result.specifications = [fixture_spec('banana-lib/BananaLib.podspec')]
@analysis_result.specs_by_source = {} @analysis_result.specs_by_source = {}
@installer.stubs(:analysis_result).returns(@analysis_result) @installer.stubs(:analysis_result).returns(@analysis_result)
......
...@@ -159,12 +159,8 @@ module Pod ...@@ -159,12 +159,8 @@ module Pod
#-------------------------------------------------------------------------# #-------------------------------------------------------------------------#
describe 'Resolution' do describe 'Resolution' do
before do def create_resolver(podfile = @podfile, locked_deps = empty_graph)
@podfile = Podfile.new do @resolver = Resolver.new(config.sandbox, podfile, locked_deps, config.sources_manager.all)
platform :ios, '6.0'
pod 'BlocksKit', '1.5.2'
end
@resolver = Resolver.new(config.sandbox, @podfile, empty_graph, config.sources_manager.all)
end end
it 'cross resolves dependencies' do it 'cross resolves dependencies' do
...@@ -174,7 +170,7 @@ module Pod ...@@ -174,7 +170,7 @@ module Pod
pod 'AFQuickLookView', '= 0.1.0' # requires 'AFNetworking', '>= 0.9.0' pod 'AFQuickLookView', '= 0.1.0' # requires 'AFNetworking', '>= 0.9.0'
end end
resolver = Resolver.new(config.sandbox, @podfile, empty_graph, config.sources_manager.all) resolver = create_resolver
specs = resolver.resolve.values.flatten.map(&:spec).map(&:to_s).sort specs = resolver.resolve.values.flatten.map(&:spec).map(&:to_s).sort
specs.should == ['AFNetworking (0.9.1)', 'AFQuickLookView (0.1.0)'] specs.should == ['AFNetworking (0.9.1)', 'AFQuickLookView (0.1.0)']
end end
...@@ -186,7 +182,7 @@ module Pod ...@@ -186,7 +182,7 @@ module Pod
pod 'AFNetworking', '~> 1.2.0' pod 'AFNetworking', '~> 1.2.0'
end end
resolver = Resolver.new(config.sandbox, @podfile, empty_graph, config.sources_manager.all) resolver = create_resolver
specs = resolver.resolve.values.flatten.map(&:spec).map(&:to_s).sort specs = resolver.resolve.values.flatten.map(&:spec).map(&:to_s).sort
specs.should == ['AFNetworking (1.2.1)', 'RestKit (0.20.1)', specs.should == ['AFNetworking (1.2.1)', 'RestKit (0.20.1)',
'RestKit/Core (0.20.1)', 'RestKit/CoreData (0.20.1)', 'RestKit/Core (0.20.1)', 'RestKit/CoreData (0.20.1)',
...@@ -202,7 +198,7 @@ module Pod ...@@ -202,7 +198,7 @@ module Pod
pod 'AFOAuth2Client' # latest version (0.1.2) requires 'AFNetworking', '~> 1.3' pod 'AFOAuth2Client' # latest version (0.1.2) requires 'AFNetworking', '~> 1.3'
end end
resolver = Resolver.new(config.sandbox, @podfile, empty_graph, config.sources_manager.all) resolver = create_resolver
specs = resolver.resolve.values.flatten.map(&:spec).map(&:to_s).sort specs = resolver.resolve.values.flatten.map(&:spec).map(&:to_s).sort
specs.should == ['AFAmazonS3Client (1.0.1)', 'AFNetworking (1.3.4)', specs.should == ['AFAmazonS3Client (1.0.1)', 'AFNetworking (1.3.4)',
'AFOAuth2Client (1.0.0)', 'CargoBay (1.0.0)'] 'AFOAuth2Client (1.0.0)', 'CargoBay (1.0.0)']
...@@ -216,12 +212,17 @@ module Pod ...@@ -216,12 +212,17 @@ module Pod
pod 'AFNetworking', '2.0.1' pod 'AFNetworking', '2.0.1'
end end
resolver = Resolver.new(config.sandbox, @podfile, empty_graph, config.sources_manager.all) resolver = create_resolver
specs = resolver.resolve.values.flatten.map(&:spec).map(&:root).map(&:to_s).uniq.sort specs = resolver.resolve.values.flatten.map(&:spec).map(&:root).map(&:to_s).uniq.sort
specs.should == ['AFNetworking (2.0.1)', 'InstagramKit (3.7)'] specs.should == ['AFNetworking (2.0.1)', 'InstagramKit (3.7)']
end end
it 'holds the context state, such as cached specification sets' do it 'holds the context state, such as cached specification sets' do
@podfile = Podfile.new do
platform :ios, '6.0'
pod 'BlocksKit', '1.5.2'
end
create_resolver
@resolver.resolve @resolver.resolve
cached_sets = @resolver.send(:cached_sets) cached_sets = @resolver.send(:cached_sets)
cached_sets.values.sort_by(&:name).should == [ cached_sets.values.sort_by(&:name).should == [
...@@ -236,7 +237,7 @@ module Pod ...@@ -236,7 +237,7 @@ module Pod
platform :osx, '10.7' platform :osx, '10.7'
pod 'ReactiveCocoa', '0.16.1' # this version is iOS-only pod 'ReactiveCocoa', '0.16.1' # this version is iOS-only
end end
@resolver.stubs(:podfile).returns(@podfile) create_resolver
should.raise Informative do should.raise Informative do
@resolver.resolve @resolver.resolve
end.message.should.match /platform .* not compatible/ end.message.should.match /platform .* not compatible/
...@@ -247,7 +248,7 @@ module Pod ...@@ -247,7 +248,7 @@ module Pod
platform :osx, '10.7' platform :osx, '10.7'
pod 'AFNetworking' # the most recent version requires 10.8 pod 'AFNetworking' # the most recent version requires 10.8
end end
@resolver.stubs(:podfile).returns(@podfile) create_resolver
@resolver.resolve.values.flatten.map(&:spec).map(&:to_s).sort.should == [ @resolver.resolve.values.flatten.map(&:spec).map(&:to_s).sort.should == [
'AFNetworking (1.3.4)', 'AFNetworking (1.3.4)',
] ]
...@@ -270,7 +271,7 @@ module Pod ...@@ -270,7 +271,7 @@ module Pod
platform :ios, '5.0' platform :ios, '5.0'
pod 'lib' pod 'lib'
end end
@resolver.stubs(:podfile).returns(@podfile) create_resolver
@resolver.send(:cached_sets)['lib'] = stub(:all_specifications => [spec]) @resolver.send(:cached_sets)['lib'] = stub(:all_specifications => [spec])
@resolver.resolve.values.flatten.map(&:spec).map(&:to_s).sort.should == [ @resolver.resolve.values.flatten.map(&:spec).map(&:to_s).sort.should == [
'AFNetworking (1.3.4)', 'lib (1.0)', 'lib/Calendar (1.0)', 'lib/Classes (1.0)', 'lib/RequestManager (1.0)' 'AFNetworking (1.3.4)', 'lib (1.0)', 'lib/Calendar (1.0)', 'lib/Classes (1.0)', 'lib/RequestManager (1.0)'
...@@ -282,7 +283,7 @@ module Pod ...@@ -282,7 +283,7 @@ module Pod
platform :osx, '10.7' platform :osx, '10.7'
pod 'AFNetworking', '2.0.0' # requires 10.8 pod 'AFNetworking', '2.0.0' # requires 10.8
end end
@resolver.stubs(:podfile).returns(@podfile) create_resolver
message = should.raise(Informative) { @resolver.resolve }.message message = should.raise(Informative) { @resolver.resolve }.message
message.should.match /required a higher minimum deployment target/ message.should.match /required a higher minimum deployment target/
end end
...@@ -297,13 +298,18 @@ module Pod ...@@ -297,13 +298,18 @@ module Pod
pod 'LocalPod', :path => '../' pod 'LocalPod', :path => '../'
end end
end end
@resolver.stubs(:podfile).returns(@podfile) create_resolver
message = should.raise(Informative) { @resolver.resolve }.message message = should.raise(Informative) { @resolver.resolve }.message
message.should.match /required a higher minimum deployment target/ message.should.match /required a higher minimum deployment target/
end end
it 'raises if unable to find a specification' do it 'raises if unable to find a specification' do
@podfile = Podfile.new do
platform :ios, '6'
pod 'BlocksKit', '1.5.2'
end
Specification.any_instance.stubs(:all_dependencies).returns([Dependency.new('Windows')]) Specification.any_instance.stubs(:all_dependencies).returns([Dependency.new('Windows')])
create_resolver
message = should.raise Informative do message = should.raise Informative do
@resolver.resolve @resolver.resolve
end.message end.message
...@@ -312,6 +318,11 @@ module Pod ...@@ -312,6 +318,11 @@ module Pod
end end
it 'does not raise if all dependencies are supported by the platform of the target definition' do it 'does not raise if all dependencies are supported by the platform of the target definition' do
@podfile = Podfile.new do
platform :ios, '6'
pod 'BlocksKit', '1.5.2'
end
create_resolver
lambda { @resolver.resolve }.should.not.raise lambda { @resolver.resolve }.should.not.raise
end end
...@@ -320,7 +331,7 @@ module Pod ...@@ -320,7 +331,7 @@ module Pod
platform :ios, '7.0' platform :ios, '7.0'
pod 'RestKit', '0.10.3' pod 'RestKit', '0.10.3'
end end
resolver = Resolver.new(config.sandbox, @podfile, empty_graph, config.sources_manager.all) resolver = create_resolver
resolver.resolve.values.flatten.map(&:name).sort.should == %w( resolver.resolve.values.flatten.map(&:name).sort.should == %w(
FileMD5Hash FileMD5Hash
ISO8601DateFormatter ISO8601DateFormatter
...@@ -348,7 +359,7 @@ module Pod ...@@ -348,7 +359,7 @@ module Pod
platform :ios, '7.0' platform :ios, '7.0'
pod 'RestKit', '0.20.0-rc1' pod 'RestKit', '0.20.0-rc1'
end end
resolver = Resolver.new(config.sandbox, @podfile, empty_graph, config.sources_manager.all) resolver = create_resolver
resolver.resolve.values.flatten.map(&:spec).map(&:to_s).sort.should == [ resolver.resolve.values.flatten.map(&:spec).map(&:to_s).sort.should == [
'AFNetworking (1.1.0)', 'AFNetworking (1.1.0)',
'RestKit (0.20.0-rc1)', 'RestKit (0.20.0-rc1)',
...@@ -377,7 +388,7 @@ module Pod ...@@ -377,7 +388,7 @@ module Pod
end end
end end
config.sandbox.expects(:specification).with('MainSpec').returns(spec) config.sandbox.expects(:specification).with('MainSpec').returns(spec)
resolver = Resolver.new(config.sandbox, @podfile, empty_graph, config.sources_manager.all) resolver = create_resolver
specs = resolver.resolve.values.flatten.map(&:name).sort specs = resolver.resolve.values.flatten.map(&:name).sort
specs.should == %w( specs.should == %w(
MainSpec/FirstSubSpec MainSpec/FirstSubSpec/SecondSubSpec MainSpec/FirstSubSpec MainSpec/FirstSubSpec/SecondSubSpec
...@@ -399,7 +410,7 @@ module Pod ...@@ -399,7 +410,7 @@ module Pod
end end
end end
config.sandbox.expects(:specification).with('MainSpec').returns(spec) config.sandbox.expects(:specification).with('MainSpec').returns(spec)
resolver = Resolver.new(config.sandbox, @podfile, empty_graph, config.sources_manager.all) resolver = create_resolver
resolved_specs = resolver.resolve.values.flatten resolved_specs = resolver.resolve.values.flatten
spec_names = resolved_specs.map(&:name).sort spec_names = resolved_specs.map(&:name).sort
spec_names.should == %w( spec_names.should == %w(
...@@ -425,7 +436,7 @@ module Pod ...@@ -425,7 +436,7 @@ module Pod
end end
end end
config.sandbox.expects(:specification).with('MainSpec').returns(spec) config.sandbox.expects(:specification).with('MainSpec').returns(spec)
resolver = Resolver.new(config.sandbox, @podfile, empty_graph, config.sources_manager.all) resolver = create_resolver
resolved_specs = resolver.resolve.values.flatten resolved_specs = resolver.resolve.values.flatten
spec_names = resolved_specs.map(&:name).sort spec_names = resolved_specs.map(&:name).sort
spec_names.should == %w( spec_names.should == %w(
...@@ -453,7 +464,7 @@ module Pod ...@@ -453,7 +464,7 @@ module Pod
end end
end end
config.sandbox.expects(:specification).with('MainSpec').returns(spec) config.sandbox.expects(:specification).with('MainSpec').returns(spec)
resolver = Resolver.new(config.sandbox, @podfile, empty_graph, config.sources_manager.all) resolver = create_resolver
resolved_specs = resolver.resolve.values.flatten resolved_specs = resolver.resolve.values.flatten
spec_names = resolved_specs.map(&:name).sort spec_names = resolved_specs.map(&:name).sort
spec_names.should == %w( spec_names.should == %w(
...@@ -476,7 +487,7 @@ module Pod ...@@ -476,7 +487,7 @@ module Pod
s.platform = :ios s.platform = :ios
end end
config.sandbox.expects(:specification).with('MainSpec').returns(spec) config.sandbox.expects(:specification).with('MainSpec').returns(spec)
resolver = Resolver.new(config.sandbox, @podfile, empty_graph, config.sources_manager.all) resolver = create_resolver
specs = resolver.resolve.values.flatten.map(&:spec).map(&:to_s).sort specs = resolver.resolve.values.flatten.map(&:spec).map(&:to_s).sort
specs.should == [ specs.should == [
'MainSpec (1.2.3-pre)', 'MainSpec (1.2.3-pre)',
...@@ -489,7 +500,7 @@ module Pod ...@@ -489,7 +500,7 @@ module Pod
pod 'JSONKit', '1.4' pod 'JSONKit', '1.4'
pod 'JSONKit', '1.5pre' pod 'JSONKit', '1.5pre'
end end
resolver = Resolver.new(config.sandbox, podfile, empty_graph, config.sources_manager.all) resolver = create_resolver(podfile)
e = lambda { resolver.resolve }.should.raise Informative e = lambda { resolver.resolve }.should.raise Informative
e.message.should.include <<-EOS.strip e.message.should.include <<-EOS.strip
[!] CocoaPods could not find compatible versions for pod "JSONKit": [!] CocoaPods could not find compatible versions for pod "JSONKit":
...@@ -506,7 +517,7 @@ module Pod ...@@ -506,7 +517,7 @@ module Pod
pod 'RestKit', '0.23.3' # dependends on AFNetworking ~> 1.3.0 pod 'RestKit', '0.23.3' # dependends on AFNetworking ~> 1.3.0
pod 'AFNetworking', '> 2' pod 'AFNetworking', '> 2'
end end
resolver = Resolver.new(config.sandbox, podfile, empty_graph, config.sources_manager.all) resolver = create_resolver(podfile)
e = lambda { resolver.resolve }.should.raise Informative e = lambda { resolver.resolve }.should.raise Informative
e.message.should.include <<-EOS.strip e.message.should.include <<-EOS.strip
[!] CocoaPods could not find compatible versions for pod "AFNetworking": [!] CocoaPods could not find compatible versions for pod "AFNetworking":
...@@ -525,7 +536,7 @@ module Pod ...@@ -525,7 +536,7 @@ module Pod
platform :ios platform :ios
pod 'AFNetworking', '999.999.999' pod 'AFNetworking', '999.999.999'
end end
resolver = Resolver.new(config.sandbox, podfile, empty_graph, config.sources_manager.all) resolver = create_resolver(podfile)
e = lambda { resolver.resolve }.should.raise NoSpecFoundError e = lambda { resolver.resolve }.should.raise NoSpecFoundError
e.message.should.include <<-EOS.strip e.message.should.include <<-EOS.strip
[!] CocoaPods could not find compatible versions for pod "AFNetworking": [!] CocoaPods could not find compatible versions for pod "AFNetworking":
...@@ -549,7 +560,7 @@ Note: as of CocoaPods 1.0, `pod repo update` does not happen on `pod install` by ...@@ -549,7 +560,7 @@ Note: as of CocoaPods 1.0, `pod repo update` does not happen on `pod install` by
platform :ios platform :ios
pod 'AFNetworking', '999.999.999' pod 'AFNetworking', '999.999.999'
end end
resolver = Resolver.new(config.sandbox, podfile, empty_graph, config.sources_manager.all) resolver = create_resolver(podfile)
resolver.specs_updated = true resolver.specs_updated = true
e = lambda { resolver.resolve }.should.raise NoSpecFoundError e = lambda { resolver.resolve }.should.raise NoSpecFoundError
e.message.should.include <<-EOS.strip e.message.should.include <<-EOS.strip
...@@ -575,7 +586,7 @@ Note: as of CocoaPods 1.0, `pod repo update` does not happen on `pod install` by ...@@ -575,7 +586,7 @@ Note: as of CocoaPods 1.0, `pod repo update` does not happen on `pod install` by
end end
locked_deps = dependency_graph_from_array([Dependency.new('AFNetworking', '= 1.4')]) locked_deps = dependency_graph_from_array([Dependency.new('AFNetworking', '= 1.4')])
resolver = Resolver.new(config.sandbox, podfile, locked_deps, config.sources_manager.all) resolver = create_resolver(podfile, locked_deps)
e = lambda { resolver.resolve }.should.raise NoSpecFoundError e = lambda { resolver.resolve }.should.raise NoSpecFoundError
e.message.should.include <<-EOS.strip e.message.should.include <<-EOS.strip
[!] CocoaPods could not find compatible versions for pod "AFNetworking": [!] CocoaPods could not find compatible versions for pod "AFNetworking":
...@@ -602,12 +613,12 @@ Note: as of CocoaPods 1.0, `pod repo update` does not happen on `pod install` by ...@@ -602,12 +613,12 @@ Note: as of CocoaPods 1.0, `pod repo update` does not happen on `pod install` by
platform :ios platform :ios
pod 'JSONKit', '<= 1.5pre' pod 'JSONKit', '<= 1.5pre'
end end
resolver = Resolver.new(config.sandbox, podfile, empty_graph, config.sources_manager.all) resolver = create_resolver(podfile)
version = resolver.resolve.values.flatten.first.spec.version version = resolver.resolve.values.flatten.first.spec.version
version.to_s.should == '1.5pre' version.to_s.should == '1.5pre'
locked_deps = dependency_graph_from_array([Dependency.new('JSONKit', '= 1.4')]) locked_deps = dependency_graph_from_array([Dependency.new('JSONKit', '= 1.4')])
resolver = Resolver.new(config.sandbox, podfile, locked_deps, config.sources_manager.all) resolver = create_resolver(podfile, locked_deps)
version = resolver.resolve.values.flatten.first.spec.version version = resolver.resolve.values.flatten.first.spec.version
version.to_s.should == '1.4' version.to_s.should == '1.4'
end end
...@@ -620,7 +631,7 @@ Note: as of CocoaPods 1.0, `pod repo update` does not happen on `pod install` by ...@@ -620,7 +631,7 @@ Note: as of CocoaPods 1.0, `pod repo update` does not happen on `pod install` by
pod 'CocoaLumberjack' pod 'CocoaLumberjack'
end end
locked_deps = dependency_graph_from_array([Dependency.new('CocoaLumberjack', '= 2.0.0-beta2')]) locked_deps = dependency_graph_from_array([Dependency.new('CocoaLumberjack', '= 2.0.0-beta2')])
resolver = Resolver.new(config.sandbox, podfile, locked_deps, config.sources_manager.all) resolver = create_resolver(podfile, locked_deps)
e = lambda { puts resolver.resolve.values.flatten }.should.raise Informative e = lambda { puts resolver.resolve.values.flatten }.should.raise Informative
e.message.should.match(/you were using a pre-release version of `CocoaLumberjack`/) e.message.should.match(/you were using a pre-release version of `CocoaLumberjack`/)
e.message.should.match(/`pod 'CocoaLumberjack', '= 2.0.0-beta2'`/) e.message.should.match(/`pod 'CocoaLumberjack', '= 2.0.0-beta2'`/)
......
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