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
(@specification ? @specification == other.specification : @external_spec_source == other.external_spec_source)
end
def subspec_dependency?
@name.include?('/')
end
# 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
# retrieve the correct Set from disk.
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
def to_s
......
......@@ -222,8 +222,8 @@ module Pod
@target_definitions.values.map(&:target_dependencies).flatten
end
def dependency_by_name(name)
dependencies.find { |d| d.name == name }
def dependency_by_top_level_spec_name(name)
dependencies.find { |d| d.top_level_spec_name == name }
end
def generate_bridge_support?
......
......@@ -5,19 +5,31 @@ module Pod
end
def resolve
@sets = []
@sets, @loaded_spec_names, @specs = [], [], []
find_dependency_sets(@specification, @dependencies)
@sets
@specs
end
def find_dependency_sets(specification, dependencies = nil)
(dependencies || specification.dependencies).each do |dependency|
set = find_dependency_set(dependency)
set.required_by(specification)
unless @sets.include?(set)
validate_platform!(set)
@sets << set
find_dependency_sets(set.specification)
unless @loaded_spec_names.include?(dependency.name)
# Get a reference to the spec that’s actually being loaded.
# If it’s a subspec dependency, e.g. 'RestKit/Network', then
# 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
......@@ -30,8 +42,7 @@ module Pod
end
end
def validate_platform!(set)
spec = set.specification
def validate_platform!(spec)
unless spec.platform.nil? || spec.platform == @specification.platform
raise Informative, "The platform required by the Podfile (:#{@specification.platform}) " \
"does not match that of #{spec} (:#{spec.platform})"
......
......@@ -42,7 +42,13 @@ module Pod
end
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
def search_by_name(query, full_text_search)
......
......@@ -170,6 +170,19 @@ module Pod
end
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
# TODO remove this, we no longer allow to install specs as Podfile
......@@ -187,8 +200,8 @@ module Pod
version && version == other.version)
end
def dependency_by_name(name)
@dependencies.find { |d| d.name == name }
def dependency_by_top_level_spec_name(name)
@dependencies.find { |d| d.top_level_spec_name == name }
end
def part_of_specification_set
......
......@@ -25,7 +25,7 @@ module Pod
end
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)
# TODO add graph that shows which dependencies led to this.
raise Informative, "#{specification} tries to activate `#{dependency}', " \
......@@ -38,12 +38,12 @@ module Pod
def dependency
@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
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
def name
......
Subproject commit 49cb88232dc6547bfc9751521a38889ec9f9f803
Subproject commit 4d304b8066a9c1d1156412d882de60eeca625659
......@@ -23,6 +23,13 @@ describe "Pod::Dependency" do
dep.top_level_spec_name.should == 'RestKit'
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
dep1 = Pod::Dependency.new('bananas', :git => 'GIT-URL')
dep2 = Pod::Dependency.new('bananas')
......
......@@ -14,15 +14,15 @@ describe "Pod::Podfile" do
it "adds dependencies" do
podfile = Pod::Podfile.new { dependency 'ASIHTTPRequest'; dependency 'SSZipArchive', '>= 0.1' }
podfile.dependencies.size.should == 2
podfile.dependency_by_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('ASIHTTPRequest').should == Pod::Dependency.new('ASIHTTPRequest')
podfile.dependency_by_top_level_spec_name('SSZipArchive').should == Pod::Dependency.new('SSZipArchive', '>= 0.1')
end
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
dependency 'SomeExternalPod', :git => 'GIT-URL', :commit => '1234'
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' }
end
......@@ -30,7 +30,7 @@ describe "Pod::Podfile" do
podfile = Pod::Podfile.new do
dependency 'SomeExternalPod', :podspec => 'http://gist/SomeExternalPod.podspec'
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' }
end
......@@ -40,7 +40,7 @@ describe "Pod::Podfile" do
s.name = 'SomeExternalPod'
end
end
dep = podfile.dependency_by_name('SomeExternalPod')
dep = podfile.dependency_by_top_level_spec_name('SomeExternalPod')
dep.specification.name.should == 'SomeExternalPod'
end
......
......@@ -38,13 +38,10 @@ describe "Pod::Resolver" do
Pod::Config.instance = @config_before
end
it "returns all sets needed for the dependency" do
sets = []
sets << Pod::Spec::Set.by_pod_dir(fixture('spec-repos/master/Reachability'))
sets << Pod::Spec::Set.by_pod_dir(fixture('spec-repos/master/ASIHTTPRequest'))
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)
it "returns all specs needed for the dependency" do
specs = Pod::Resolver.new(@podfile).resolve
specs.map(&:class).uniq.should == [Pod::Specification]
specs.map(&:name).sort.should == %w{ ASIHTTPRequest ASIWebPageRequest Reachability }
end
it "does not raise if all dependencies match the platform of the root spec (Podfile)" do
......@@ -71,5 +68,16 @@ describe "Pod::Resolver" do
resolver.stub_platform = :ios
lambda { resolver.resolve }.should.raise Pod::Informative
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
......@@ -21,8 +21,8 @@ describe "Pod::Source" do
end
it "returns a specification set by top level spec name" do
set = Pod::Source.search(Pod::Dependency.new('JSONKit/SomeSubspec'))
set.should == Pod::Spec::Set.by_pod_dir(config.repos_dir + 'repo2/JSONKit')
set = Pod::Source.search(Pod::Dependency.new('RestKit/Network'))
set.should == Pod::Spec::Set.by_pod_dir(config.repos_dir + 'repo1/RestKit')
end
it "raises if a specification set can't be found" do
......@@ -30,4 +30,10 @@ describe "Pod::Source" do
Pod::Source.search(Pod::Dependency.new('DoesNotExist'))
}.should.raise Pod::Informative
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
......@@ -59,7 +59,7 @@ describe "A Pod::Specification loaded from a podspec" do
it "returns the pod's dependencies" do
expected = Pod::Dependency.new('monkey', '~> 1.0.1', '< 1.0.9')
@spec.dependencies.should == [expected]
@spec.dependency_by_name('monkey').should == expected
@spec.dependency_by_top_level_spec_name('monkey').should == expected
end
it "returns the pod's xcconfig settings" 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.source.should == @spec.source
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
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