Commit fccabd9f authored by Eloy Duran's avatar Eloy Duran

Resolve dependencies on subspecs and make the resolver return the specs, instead of sets.

parent 98a447b4
...@@ -36,11 +36,24 @@ module Pod ...@@ -36,11 +36,24 @@ module Pod
(@specification ? @specification == other.specification : @external_spec_source == other.external_spec_source) (@specification ? @specification == other.specification : @external_spec_source == other.external_spec_source)
end end
def subspec_dependency?
@name.include?('/')
end
# In case this is a dependency for a subspec, e.g. 'RestKit/Networking', # In case this is a dependency for a subspec, e.g. 'RestKit/Networking',
# this returns 'RestKit', which is what the Pod::Source needs to know to # this returns 'RestKit', which is what the Pod::Source needs to know to
# retrieve the correct Set from disk. # retrieve the correct Set from disk.
def top_level_spec_name def top_level_spec_name
@name.include?('/') ? @name.split('/').first : @name subspec_dependency? ? @name.split('/').first : @name
end
# Returns a copy of the dependency, but with the name of the top level
# spec. This is used by Pod::Specification::Set to merge dependencies on
# the complete set, irrespective of what spec in the set wil be used.
def to_top_level_spec_dependency
dep = dup
dep.name = top_level_spec_name
dep
end end
def to_s def to_s
......
...@@ -222,8 +222,8 @@ module Pod ...@@ -222,8 +222,8 @@ module Pod
@target_definitions.values.map(&:target_dependencies).flatten @target_definitions.values.map(&:target_dependencies).flatten
end end
def dependency_by_name(name) def dependency_by_top_level_spec_name(name)
dependencies.find { |d| d.name == name } dependencies.find { |d| d.top_level_spec_name == name }
end end
def generate_bridge_support? def generate_bridge_support?
......
...@@ -5,19 +5,31 @@ module Pod ...@@ -5,19 +5,31 @@ module Pod
end end
def resolve def resolve
@sets = [] @sets, @loaded_spec_names, @specs = [], [], []
find_dependency_sets(@specification, @dependencies) find_dependency_sets(@specification, @dependencies)
@sets @specs
end end
def find_dependency_sets(specification, dependencies = nil) def find_dependency_sets(specification, dependencies = nil)
(dependencies || specification.dependencies).each do |dependency| (dependencies || specification.dependencies).each do |dependency|
set = find_dependency_set(dependency) set = find_dependency_set(dependency)
set.required_by(specification) set.required_by(specification)
unless @sets.include?(set) unless @loaded_spec_names.include?(dependency.name)
validate_platform!(set) # Get a reference to the spec that’s actually being loaded.
@sets << set # If it’s a subspec dependency, e.g. 'RestKit/Network', then
find_dependency_sets(set.specification) # find that subspec.
spec = set.specification
if dependency.subspec_dependency?
spec = spec.subspec_by_name(dependency.name)
end
validate_platform!(spec)
# Ensure we don't resolve the same spec twice
@loaded_spec_names << spec.name
@specs << spec
@sets << set unless @sets.include?(set)
find_dependency_sets(spec)
end end
end end
end end
...@@ -30,8 +42,7 @@ module Pod ...@@ -30,8 +42,7 @@ module Pod
end end
end end
def validate_platform!(set) def validate_platform!(spec)
spec = set.specification
unless spec.platform.nil? || spec.platform == @specification.platform unless spec.platform.nil? || spec.platform == @specification.platform
raise Informative, "The platform required by the Podfile (:#{@specification.platform}) " \ raise Informative, "The platform required by the Podfile (:#{@specification.platform}) " \
"does not match that of #{spec} (:#{spec.platform})" "does not match that of #{spec} (:#{spec.platform})"
......
...@@ -42,7 +42,13 @@ module Pod ...@@ -42,7 +42,13 @@ module Pod
end end
def search(dependency) def search(dependency)
pod_sets.find { |set| set.name == dependency.top_level_spec_name } pod_sets.find do |set|
# First match the (top level) name, which does not yet load the spec from disk
set.name == dependency.top_level_spec_name &&
# Now either check if it's a dependency on the top level spec, or if it's not
# check if the requested subspec exists in the top level spec.
(!dependency.subspec_dependency? || !set.specification.subspec_by_name(dependency.name).nil?)
end
end end
def search_by_name(query, full_text_search) def search_by_name(query, full_text_search)
......
...@@ -170,6 +170,19 @@ module Pod ...@@ -170,6 +170,19 @@ module Pod
end end
attr_reader :subspecs attr_reader :subspecs
def subspec_by_name(name)
# Remove this spec's name from the beginning of the name we’re looking for
# and take the first component from the remainder, which is the spec we need
# to find now.
remainder = name[self.name.size+1..-1].split('/')
subspec_name = remainder.shift
subspec = subspecs.find { |s| s.name == "#{self.name}/#{subspec_name}" }
# If this was the last component in the name, then return the subspec,
# otherwise we recursively keep calling subspec_by_name until we reach the
# last one and return that
remainder.empty? ? subspec : subspec.subspec_by_name(name)
end
# These are attributes which are also on a Podfile # These are attributes which are also on a Podfile
# TODO remove this, we no longer allow to install specs as Podfile # TODO remove this, we no longer allow to install specs as Podfile
...@@ -187,8 +200,8 @@ module Pod ...@@ -187,8 +200,8 @@ module Pod
version && version == other.version) version && version == other.version)
end end
def dependency_by_name(name) def dependency_by_top_level_spec_name(name)
@dependencies.find { |d| d.name == name } @dependencies.find { |d| d.top_level_spec_name == name }
end end
def part_of_specification_set def part_of_specification_set
......
...@@ -25,7 +25,7 @@ module Pod ...@@ -25,7 +25,7 @@ module Pod
end end
def required_by(specification) def required_by(specification)
dependency = specification.dependency_by_name(name) dependency = specification.dependency_by_top_level_spec_name(name)
unless @required_by.empty? || dependency.requirement.satisfied_by?(required_version) unless @required_by.empty? || dependency.requirement.satisfied_by?(required_version)
# TODO add graph that shows which dependencies led to this. # TODO add graph that shows which dependencies led to this.
raise Informative, "#{specification} tries to activate `#{dependency}', " \ raise Informative, "#{specification} tries to activate `#{dependency}', " \
...@@ -38,12 +38,12 @@ module Pod ...@@ -38,12 +38,12 @@ module Pod
def dependency def dependency
@required_by.inject(Dependency.new(name)) do |previous, spec| @required_by.inject(Dependency.new(name)) do |previous, spec|
previous.merge(spec.dependency_by_name(name)) previous.merge(spec.dependency_by_top_level_spec_name(name).to_top_level_spec_dependency)
end end
end end
def only_part_of_other_pod? def only_part_of_other_pod?
@required_by.all? { |spec| spec.dependency_by_name(name).only_part_of_other_pod? } @required_by.all? { |spec| spec.dependency_by_top_level_spec_name(name).only_part_of_other_pod? }
end end
def name def name
......
Subproject commit 49cb88232dc6547bfc9751521a38889ec9f9f803 Subproject commit 4d304b8066a9c1d1156412d882de60eeca625659
...@@ -23,6 +23,13 @@ describe "Pod::Dependency" do ...@@ -23,6 +23,13 @@ describe "Pod::Dependency" do
dep.top_level_spec_name.should == 'RestKit' dep.top_level_spec_name.should == 'RestKit'
end end
it "returns a copy of the dependency but for the top level spec, if it's a subspec" do
dep = Pod::Dependency.new('RestKit', '>= 1.2.3')
dep.to_top_level_spec_dependency.should == Pod::Dependency.new('RestKit', '>= 1.2.3')
dep = Pod::Dependency.new('RestKit/Networking', '>= 1.2.3')
dep.to_top_level_spec_dependency.should == Pod::Dependency.new('RestKit', '>= 1.2.3')
end
it "is equal to another dependency if `external_spec_source' is the same" do it "is equal to another dependency if `external_spec_source' is the same" do
dep1 = Pod::Dependency.new('bananas', :git => 'GIT-URL') dep1 = Pod::Dependency.new('bananas', :git => 'GIT-URL')
dep2 = Pod::Dependency.new('bananas') dep2 = Pod::Dependency.new('bananas')
......
...@@ -14,15 +14,15 @@ describe "Pod::Podfile" do ...@@ -14,15 +14,15 @@ describe "Pod::Podfile" do
it "adds dependencies" do it "adds dependencies" do
podfile = Pod::Podfile.new { dependency 'ASIHTTPRequest'; dependency 'SSZipArchive', '>= 0.1' } podfile = Pod::Podfile.new { dependency 'ASIHTTPRequest'; dependency 'SSZipArchive', '>= 0.1' }
podfile.dependencies.size.should == 2 podfile.dependencies.size.should == 2
podfile.dependency_by_name('ASIHTTPRequest').should == Pod::Dependency.new('ASIHTTPRequest') podfile.dependency_by_top_level_spec_name('ASIHTTPRequest').should == Pod::Dependency.new('ASIHTTPRequest')
podfile.dependency_by_name('SSZipArchive').should == Pod::Dependency.new('SSZipArchive', '>= 0.1') podfile.dependency_by_top_level_spec_name('SSZipArchive').should == Pod::Dependency.new('SSZipArchive', '>= 0.1')
end end
it "adds a dependency on a Pod repo outside of a spec repo (the repo is expected to contain a podspec)" do it "adds a dependency on a Pod repo outside of a spec repo (the repo is expected to contain a podspec)" do
podfile = Pod::Podfile.new do podfile = Pod::Podfile.new do
dependency 'SomeExternalPod', :git => 'GIT-URL', :commit => '1234' dependency 'SomeExternalPod', :git => 'GIT-URL', :commit => '1234'
end end
dep = podfile.dependency_by_name('SomeExternalPod') dep = podfile.dependency_by_top_level_spec_name('SomeExternalPod')
dep.external_spec_source.should == { :git => 'GIT-URL', :commit => '1234' } dep.external_spec_source.should == { :git => 'GIT-URL', :commit => '1234' }
end end
...@@ -30,7 +30,7 @@ describe "Pod::Podfile" do ...@@ -30,7 +30,7 @@ describe "Pod::Podfile" do
podfile = Pod::Podfile.new do podfile = Pod::Podfile.new do
dependency 'SomeExternalPod', :podspec => 'http://gist/SomeExternalPod.podspec' dependency 'SomeExternalPod', :podspec => 'http://gist/SomeExternalPod.podspec'
end end
dep = podfile.dependency_by_name('SomeExternalPod') dep = podfile.dependency_by_top_level_spec_name('SomeExternalPod')
dep.external_spec_source.should == { :podspec => 'http://gist/SomeExternalPod.podspec' } dep.external_spec_source.should == { :podspec => 'http://gist/SomeExternalPod.podspec' }
end end
...@@ -40,7 +40,7 @@ describe "Pod::Podfile" do ...@@ -40,7 +40,7 @@ describe "Pod::Podfile" do
s.name = 'SomeExternalPod' s.name = 'SomeExternalPod'
end end
end end
dep = podfile.dependency_by_name('SomeExternalPod') dep = podfile.dependency_by_top_level_spec_name('SomeExternalPod')
dep.specification.name.should == 'SomeExternalPod' dep.specification.name.should == 'SomeExternalPod'
end end
......
...@@ -38,13 +38,10 @@ describe "Pod::Resolver" do ...@@ -38,13 +38,10 @@ describe "Pod::Resolver" do
Pod::Config.instance = @config_before Pod::Config.instance = @config_before
end end
it "returns all sets needed for the dependency" do it "returns all specs needed for the dependency" do
sets = [] specs = Pod::Resolver.new(@podfile).resolve
sets << Pod::Spec::Set.by_pod_dir(fixture('spec-repos/master/Reachability')) specs.map(&:class).uniq.should == [Pod::Specification]
sets << Pod::Spec::Set.by_pod_dir(fixture('spec-repos/master/ASIHTTPRequest')) specs.map(&:name).sort.should == %w{ ASIHTTPRequest ASIWebPageRequest Reachability }
sets << Pod::Spec::Set.by_pod_dir(fixture('spec-repos/master/ASIWebPageRequest'))
resolver = Pod::Resolver.new(@podfile)
resolver.resolve.sort_by(&:name).should == sets.sort_by(&:name)
end end
it "does not raise if all dependencies match the platform of the root spec (Podfile)" do it "does not raise if all dependencies match the platform of the root spec (Podfile)" do
...@@ -71,5 +68,16 @@ describe "Pod::Resolver" do ...@@ -71,5 +68,16 @@ describe "Pod::Resolver" do
resolver.stub_platform = :ios resolver.stub_platform = :ios
lambda { resolver.resolve }.should.raise Pod::Informative lambda { resolver.resolve }.should.raise Pod::Informative
end end
it "resolves subspecs" do
@podfile = Pod::Podfile.new do
platform :ios
dependency 'RestKit/Network'
dependency 'RestKit/ObjectMapping'
end
config.rootspec = @podfile
resolver = Pod::Resolver.new(@podfile)
resolver.resolve.map(&:name).sort.should == %w{ LibComponentLogging-Core LibComponentLogging-NSLog RestKit RestKit/Network RestKit/ObjectMapping }
end
end end
...@@ -21,8 +21,8 @@ describe "Pod::Source" do ...@@ -21,8 +21,8 @@ describe "Pod::Source" do
end end
it "returns a specification set by top level spec name" do it "returns a specification set by top level spec name" do
set = Pod::Source.search(Pod::Dependency.new('JSONKit/SomeSubspec')) set = Pod::Source.search(Pod::Dependency.new('RestKit/Network'))
set.should == Pod::Spec::Set.by_pod_dir(config.repos_dir + 'repo2/JSONKit') set.should == Pod::Spec::Set.by_pod_dir(config.repos_dir + 'repo1/RestKit')
end end
it "raises if a specification set can't be found" do it "raises if a specification set can't be found" do
...@@ -30,4 +30,10 @@ describe "Pod::Source" do ...@@ -30,4 +30,10 @@ describe "Pod::Source" do
Pod::Source.search(Pod::Dependency.new('DoesNotExist')) Pod::Source.search(Pod::Dependency.new('DoesNotExist'))
}.should.raise Pod::Informative }.should.raise Pod::Informative
end end
it "raises if a subspec can't be found" do
lambda {
Pod::Source.search(Pod::Dependency.new('RestKit/DoesNotExist'))
}.should.raise Pod::Informative
end
end end
...@@ -59,7 +59,7 @@ describe "A Pod::Specification loaded from a podspec" do ...@@ -59,7 +59,7 @@ describe "A Pod::Specification loaded from a podspec" do
it "returns the pod's dependencies" do it "returns the pod's dependencies" do
expected = Pod::Dependency.new('monkey', '~> 1.0.1', '< 1.0.9') expected = Pod::Dependency.new('monkey', '~> 1.0.1', '< 1.0.9')
@spec.dependencies.should == [expected] @spec.dependencies.should == [expected]
@spec.dependency_by_name('monkey').should == expected @spec.dependency_by_top_level_spec_name('monkey').should == expected
end end
it "returns the pod's xcconfig settings" do it "returns the pod's xcconfig settings" do
...@@ -318,4 +318,9 @@ describe "A Pod::Specification subspec" do ...@@ -318,4 +318,9 @@ describe "A Pod::Specification subspec" do
@spec.subspecs.first.subspecs.first.summary.should == @spec.summary @spec.subspecs.first.subspecs.first.summary.should == @spec.summary
@spec.subspecs.first.subspecs.first.source.should == @spec.source @spec.subspecs.first.subspecs.first.source.should == @spec.source
end end
it "returns subspecs by name" do
@spec.subspec_by_name('MainSpec/FirstSubSpec').should == @spec.subspecs.first
@spec.subspec_by_name('MainSpec/FirstSubSpec/SecondSubSpec').should == @spec.subspecs.first.subspecs.first
end
end end
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment