Unverified Commit ec89a4e3 authored by Samuel Giddins's avatar Samuel Giddins Committed by GitHub

Merge pull request #7326 from CocoaPods/seg-resolver-multi-source-ordering

 [Resolver] Fix multi-source resolution
parents 937f86f9 9a14419b
...@@ -22,6 +22,11 @@ To install release candidates run `[sudo] gem install cocoapods --pre` ...@@ -22,6 +22,11 @@ To install release candidates run `[sudo] gem install cocoapods --pre`
[Dimitris Koutsogiorgas](https://github.com/dnkoutso) [Dimitris Koutsogiorgas](https://github.com/dnkoutso)
[#7292](https://github.com/CocoaPods/CocoaPods/pull/7292) [#7292](https://github.com/CocoaPods/CocoaPods/pull/7292)
* Fix resolution when multiple sources provide the same pods, and there are
(potential) dependencies between the sources.
[Samuel Giddins](https://github.com/segiddins)
[#7031](https://github.com/CococaPods/CocoaPods/issues/7031)
## 1.4.0.rc.1 (2017-12-16) ## 1.4.0.rc.1 (2017-12-16)
##### Enhancements ##### Enhancements
......
...@@ -351,8 +351,7 @@ module Pod ...@@ -351,8 +351,7 @@ module Pod
all_specifications(installation_options.warn_for_multiple_pod_sources). all_specifications(installation_options.warn_for_multiple_pod_sources).
select { |s| requirement.satisfied_by? s.version }. select { |s| requirement.satisfied_by? s.version }.
map { |s| s.subspec_by_name(dependency.name, false, true) }. map { |s| s.subspec_by_name(dependency.name, false, true) }.
compact. compact
reverse
end end
# @return [Set] Loads or returns a previously initialized set for the Pod # @return [Set] Loads or returns a previously initialized set for the Pod
...@@ -508,7 +507,7 @@ module Pod ...@@ -508,7 +507,7 @@ module Pod
end, end,
) )
end end
raise type, message raise type.new(message).tap { |e| e.set_backtrace(error.backtrace) }
end end
# Returns whether the given spec is platform-compatible with the dependency # Returns whether the given spec is platform-compatible with the dependency
......
...@@ -37,12 +37,12 @@ module Pod ...@@ -37,12 +37,12 @@ module Pod
end end
end end
# returns the highest versioned spec last
def all_specifications(warn_for_multiple_pod_sources) def all_specifications(warn_for_multiple_pod_sources)
@all_specifications ||= begin @all_specifications ||= begin
sources_by_version = {} sources_by_version = {}
versions_by_source.each do |source, versions| versions_by_source.each do |source, versions|
versions.each { |v| (sources_by_version[v] ||= []) << source } versions.each { |v| (sources_by_version[v] ||= []) << source }
sources_by_version
end end
if warn_for_multiple_pod_sources if warn_for_multiple_pod_sources
...@@ -56,8 +56,11 @@ module Pod ...@@ -56,8 +56,11 @@ module Pod
end end
end end
versions_by_source.flat_map do |source, versions| # sort versions from high to low
versions.map { |version| LazySpecification.new(name, version, source) } sources_by_version.sort_by(&:first).flat_map do |version, sources|
# within each version, we want the prefered (first-specified) source
# to be the _last_ one
sources.reverse_each.map { |source| LazySpecification.new(name, version, source) }
end end
end end
end end
......
...@@ -13,6 +13,68 @@ end ...@@ -13,6 +13,68 @@ end
module Pod module Pod
describe Resolver do describe Resolver do
class MockSource < Source
attr_reader :name
def initialize(name, &blk)
@name = name
@_pods_by_name = Hash.new { |h, k| h[k] = [] }
@_current_pod = nil
instance_eval(&blk)
super('/mock/repo')
end
def pod(name, version = nil, platform: [[:ios, '9.0']], test_spec: false, &_blk)
cp = @_current_pod
Pod::Specification.new(cp, name, test_spec) do |spec|
@_current_pod = spec
if cp
cp.subspecs << spec
else
spec.version = version
end
platform.each { |pl, dt| spec.send(pl).deployment_target = dt }
yield spec if block_given?
end
@_pods_by_name[name] << @_current_pod if cp.nil?
ensure
@_current_pod = cp
end
def test_spec(name: 'Tests', &blk)
pod(name, :test_spec => true, &blk)
end
def all_specs
@_pods_by_name.values.flatten(1)
end
def pods
@_pods_by_name.keys
end
def search(query)
query = query.root_name if query.is_a?(Dependency)
set(query) if @_pods_by_name.key?(query)
end
def specification(name, version)
@_pods_by_name[name].find { |s| s.version == Pod::Version.new(version) }
end
def versions(name)
@_pods_by_name[name].map(&:version)
end
def specification_path(name, version)
pod_path(name).join(version.to_s, "#{name}.podspec")
end
def specs_dir
repo
end
end
describe 'In general' do describe 'In general' do
before do before do
@podfile = Podfile.new do @podfile = Podfile.new do
...@@ -675,6 +737,54 @@ Note: as of CocoaPods 1.0, `pod repo update` does not happen on `pod install` by ...@@ -675,6 +737,54 @@ Note: as of CocoaPods 1.0, `pod repo update` does not happen on `pod install` by
UI.warnings.should.match /multiple specifications/ UI.warnings.should.match /multiple specifications/
end end
it 'chooses the first source in a complicated scenario' do
test_repo1 = MockSource.new('test_repo1') do
pod 'Core', '1.0.0' do
test_spec
end
pod 'Core', '1.0.1' do
test_spec
end
pod 'Data', '1.0.0' do |s|
s.dependency 'Core', '~> 1.0'
test_spec { |ts| ts.dependency 'Testing', '~> 1.0' }
end
pod 'Data', '1.0.1' do |s|
s.dependency 'Core', '~> 1.0'
test_spec { |ts| ts.dependency 'Testing', '~> 1.0' }
end
pod 'Testing', '1.0.0' do |s|
s.dependency 'Core'
end
pod 'Testing', '1.0.1' do |s|
s.dependency 'Core'
end
end
test_repo2 = MockSource.new('test_repo2') do
pod 'Core', '1.0.1' do
test_spec
end
pod 'Data', '1.0.1' do |s|
s.dependency 'Core', '~> 1.0'
test_spec { |ts| ts.dependency 'Testing', '~> 1.0' }
end
pod 'Testing', '1.0.1' do |s|
s.dependency 'Core'
end
end
sources = [test_repo1, test_repo2]
podfile = Podfile.new do
platform :ios, '9.0'
pod 'Data/Tests', '~> 1.0'
pod 'Data', '~> 1.0'
end
resolver = Resolver.new(config.sandbox, podfile, empty_graph, sources)
resolver.resolve.values.flatten.map { |rs| rs.spec.to_s }.sort.
should == ['Core (1.0.1)', 'Data (1.0.1)', 'Data/Tests (1.0.1)', 'Testing (1.0.1)']
end
it 'does not warn when multiple sources contain a pod but a dependency ' \ it 'does not warn when multiple sources contain a pod but a dependency ' \
'has an explicit source specified' do 'has an explicit source specified' do
test_repo_url = config.sources_manager.source_with_name_or_url('test_repo').url test_repo_url = config.sources_manager.source_with_name_or_url('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