Commit b165493d authored by Marius Rackwitz's avatar Marius Rackwitz

[Analyzer] Fix transitive dependency selection

parent 82145472
...@@ -305,48 +305,68 @@ module Pod ...@@ -305,48 +305,68 @@ module Pod
generate_pod_target(target_definitions, variant.specs, :scope_suffix => suffixes[variant]) generate_pod_target(target_definitions, variant.specs, :scope_suffix => suffixes[variant])
end end
end end
all_specs = specs_by_target.values.flatten.uniq
pod_targets_by_name = pod_targets.group_by(&:pod_name).each_with_object({}) do |(name, values), hash|
# Sort the target by the number of activated subspecs, so that
# we prefer a minimal target as transitive dependency.
hash[name] = values.sort_by { |pt| pt.specs.count }
end
pod_targets.each do |target|
dependencies = transitive_dependencies_for_specs(target.specs, target.platform, all_specs).group_by(&:root)
target.dependent_targets = dependencies.map do |root_spec, deps|
pod_targets_by_name[root_spec.name].find do |t|
next false if t.platform.symbolic_name != target.platform.symbolic_name ||
t.requires_frameworks? != target.requires_frameworks?
spec_names = t.specs.map(&:name)
deps.all? { |dep| spec_names.include?(dep.name) }
end
end
end
else else
dedupe_cache = {} dedupe_cache = {}
pod_targets = specs_by_target.flat_map do |target_definition, specs| specs_by_target.flat_map do |target_definition, specs|
grouped_specs = specs.group_by.group_by(&:root).values.uniq grouped_specs = specs.group_by(&:root).values.uniq
grouped_specs.flat_map do |pod_specs| pod_targets = grouped_specs.flat_map do |pod_specs|
generate_pod_target([target_definition], pod_specs).scoped(dedupe_cache) generate_pod_target([target_definition], pod_specs).scoped(dedupe_cache)
end end
pod_targets.each do |target|
dependencies = transitive_dependencies_for_specs(target.specs, target.platform, specs).group_by(&:root)
target.dependent_targets = pod_targets.reject { |t| dependencies[t.root_spec].nil? }
end end
end end
pod_targets.each do |target|
target.dependent_targets = transitive_dependencies_for_pod_target(target, pod_targets)
end end
end end
# Finds the names of the Pods upon which the given target _transitively_ # Returns the specs upon which the given specs _transitively_ depend.
# depends.
# #
# @note: This is implemented in the analyzer, because we don't have to # @note: This is implemented in the analyzer, because we don't have to
# care about the requirements after dependency resolution. # care about the requirements after dependency resolution.
# #
# @param [PodTarget] pod_target # @param [Array<Specification>] specs
# The pod target, whose dependencies should be returned. # The specs, whose dependencies should be returned.
# #
# @param [Array<PodTarget>] targets # @param [Platform] platform
# All pod targets, which are integrated alongside. # The platform for which the dependencies should be returned.
# #
# @return [Array<PodTarget>] # @param [Array<Specification>] all_specs
# All specifications which are installed alongside.
# #
def transitive_dependencies_for_pod_target(pod_target, targets) # @return [Array<Specification>]
if targets.any? #
dependent_targets = pod_target.dependencies.flat_map do |dep| def transitive_dependencies_for_specs(specs, platform, all_specs)
next [] if pod_target.pod_name == dep return [] if specs.empty? || all_specs.empty?
targets.select { |t| t.pod_name == dep } dependent_specs = specs.flat_map do |spec|
end spec.consumer(platform).dependencies.flat_map do |dependency|
remaining_targets = targets - dependent_targets all_specs.find do |s|
dependent_targets += dependent_targets.flat_map do |target| next false if specs.include?(s)
transitive_dependencies_for_pod_target(target, remaining_targets) s.name == dependency.name
end
dependent_targets.uniq
else
[]
end end
end.compact
end.uniq
remaining_specs = all_specs - dependent_specs
dependent_specs + transitive_dependencies_for_specs(dependent_specs, platform, remaining_specs)
end end
# Create a target for each spec group # Create a target for each spec group
......
...@@ -4,6 +4,11 @@ module Pod ...@@ -4,6 +4,11 @@ module Pod
describe Installer::Analyzer do describe Installer::Analyzer do
describe 'Analysis' do describe 'Analysis' do
before do before do
repos = [fixture('spec-repos/test_repo'), fixture('spec-repos/master')]
aggregate = Pod::Source::Aggregate.new(repos)
Pod::SourcesManager.stubs(:aggregate).returns(aggregate)
aggregate.sources.first.stubs(:url).returns(SpecHelper.test_repo_url)
@podfile = Pod::Podfile.new do @podfile = Pod::Podfile.new do
platform :ios, '6.0' platform :ios, '6.0'
project 'SampleProject/SampleProject' project 'SampleProject/SampleProject'
...@@ -162,7 +167,8 @@ module Pod ...@@ -162,7 +167,8 @@ module Pod
target.platform.to_s.should == 'iOS 6.0' target.platform.to_s.should == 'iOS 6.0'
end end
it 'generates the set of dependent pod targets' do describe 'dependent pod targets' do
it 'picks transitive dependencies up' do
@podfile = Pod::Podfile.new do @podfile = Pod::Podfile.new do
platform :ios, '8.0' platform :ios, '8.0'
project 'SampleProject/SampleProject' project 'SampleProject/SampleProject'
...@@ -172,8 +178,9 @@ module Pod ...@@ -172,8 +178,9 @@ module Pod
end end
end end
@analyzer = Pod::Installer::Analyzer.new(config.sandbox, @podfile, nil) @analyzer = Pod::Installer::Analyzer.new(config.sandbox, @podfile, nil)
@analyzer.analyze.targets.count.should == 1 result = @analyzer.analyze
target = @analyzer.analyze.targets.first result.targets.count.should == 1
target = result.targets.first
restkit_target = target.pod_targets.find { |pt| pt.pod_name == 'RestKit' } restkit_target = target.pod_targets.find { |pt| pt.pod_name == 'RestKit' }
restkit_target.dependent_targets.map(&:pod_name).sort.should == %w( restkit_target.dependent_targets.map(&:pod_name).sort.should == %w(
AFNetworking AFNetworking
...@@ -185,14 +192,38 @@ module Pod ...@@ -185,14 +192,38 @@ module Pod
restkit_target.dependent_targets.all?(&:scoped).should.be.true restkit_target.dependent_targets.all?(&:scoped).should.be.true
end end
describe 'deduplication' do it 'picks the right variants up when there are multiple' do
before do @podfile = Pod::Podfile.new do
repos = [fixture('spec-repos/test_repo'), fixture('spec-repos/master')] source SpecHelper.test_repo_url
aggregate = Pod::Source::Aggregate.new(repos) platform :ios, '8.0'
Pod::SourcesManager.stubs(:aggregate).returns(aggregate) project 'SampleProject/SampleProject'
aggregate.sources.first.stubs(:url).returns(SpecHelper.test_repo_url)
# The order of target definitions is important for this test.
target 'TestRunner' do
pod 'OrangeFramework'
pod 'matryoshka/Foo'
end end
target 'SampleProject' do
pod 'OrangeFramework'
end
end
@analyzer = Pod::Installer::Analyzer.new(config.sandbox, @podfile, nil)
result = @analyzer.analyze
result.targets.count.should == 2
pod_target = result.targets[0].pod_targets.find { |pt| pt.pod_name == 'OrangeFramework' }
pod_target.dependent_targets.count == 1
pod_target.dependent_targets.first.specs.map(&:name).should == %w(
matryoshka
matryoshka/Outer
matryoshka/Outer/Inner
)
end
end
describe 'deduplication' do
it 'deduplicate targets if possible' do it 'deduplicate targets if possible' do
podfile = Pod::Podfile.new do podfile = Pod::Podfile.new do
source SpecHelper.test_repo_url source SpecHelper.test_repo_url
......
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