Commit d99e21ac authored by Samuel E. Giddins's avatar Samuel E. Giddins

Merge pull request #2513 from CocoaPods/podfile-source-url

Allow the specification of a source URL in a Podfile
parents d132d9d7 539744f8
...@@ -4,6 +4,28 @@ To install or update CocoaPods see this [guide](http://docs.cocoapods.org/guides ...@@ -4,6 +4,28 @@ To install or update CocoaPods see this [guide](http://docs.cocoapods.org/guides
## Master ## Master
##### Breaking
* Add support for loading podspecs from *only* specific spec-repos via
`sources`. By default, when there are no sources specified in a Podfile all
source repos will be used. This has always been the case.
However, this implicit use of sources is now deprecated.
Once you specify specific sources, **no** repos wil be included by
default. For example:
source 'https://banana.com/corp/private-spec-repo.git'
source 'https://github.com/CocoaPods/Specs.git'
Any source URLs specified that have not yet been added will be cloned before
resolution begins.
[François Benaiteau](https://github.com/netbe)
[Fabio Pelosin](https://github.com/fabiopelosin)
[Samuel Giddins](https://github.com/segiddins)
[#1143](https://github.com/CocoaPods/CocoaPods/pull/1143)
[Core#19](https://github.com/CocoaPods/Core/pull/19)
[Core#170](https://github.com/CocoaPods/Core/issues/170)
[#2515](https://github.com/CocoaPods/CocoaPods/issues/2515)
##### Bug Fixes ##### Bug Fixes
* Works around an Xcode issue where linting would fail even though `xcodebuild` * Works around an Xcode issue where linting would fail even though `xcodebuild`
......
...@@ -7,7 +7,7 @@ GIT ...@@ -7,7 +7,7 @@ GIT
GIT GIT
remote: https://github.com/CocoaPods/Core.git remote: https://github.com/CocoaPods/Core.git
revision: afe219baa5a4854067145825d0c141e43eee0e6a revision: b9dcb24367e8215637cdee840af58a9f0bf62568
branch: master branch: master
specs: specs:
cocoapods-core (0.34.0.rc2) cocoapods-core (0.34.0.rc2)
......
...@@ -318,12 +318,6 @@ module Pod ...@@ -318,12 +318,6 @@ module Pod
def resolve_dependencies def resolve_dependencies
specs_by_target = nil specs_by_target = nil
UI.section "Resolving dependencies of #{UI.path podfile.defined_in_file}" do UI.section "Resolving dependencies of #{UI.path podfile.defined_in_file}" do
if podfile.sources.empty?
sources = SourcesManager.master
else
sources = SourcesManager.sources(podfile.sources)
end
resolver = Resolver.new(sandbox, podfile, locked_dependencies, sources) resolver = Resolver.new(sandbox, podfile, locked_dependencies, sources)
specs_by_target = resolver.resolve specs_by_target = resolver.resolve
end end
...@@ -367,6 +361,33 @@ module Pod ...@@ -367,6 +361,33 @@ module Pod
private private
# Returns the sources used to query for specifications
#
# @note Currently, this defaults to {SourcesManager.all} when no
# Podfile sources are defined, but this implicit declaration of
# sources is deprecated.
#
# @return [Array<Source>] the sources to be used in finding
# specifications, as specified by the {#podfile}.
#
def sources
@sources ||= begin
sources = podfile.sources
if sources.empty?
SourcesManager.all.tap do |all|
UI.warn all.reduce("The use of implicit sources has been " \
"deprecated. To replicate the previous behavior, add the " \
"following to your Podfile:") \
{ |w, s| w << "\nsource '#{s.url}'" }
end
else
sources.map do |url|
SourcesManager.find_or_create_source_with_url(url)
end
end
end
end
# @!group Analysis sub-steps # @!group Analysis sub-steps
# Returns the path of the user project that the {TargetDefinition} # Returns the path of the user project that the {TargetDefinition}
......
...@@ -23,6 +23,30 @@ module Pod ...@@ -23,6 +23,30 @@ module Pod
dirs.map { |repo| Source.new(repo) } dirs.map { |repo| Source.new(repo) }
end end
# Returns the source whose {Source#url} is equal to `url`, adding the repo
# in a manner similarly to `pod repo add` if it is not found.
#
# @raise If no source with the given `url` could be created,
#
# @return [Source] The source whose {Source#url} is equal to `url`,
#
# @param [String] url
# The URL of the source.
#
def find_or_create_source_with_url(url)
unless source = source_with_url(url)
name = name_for_url(url)
Command::Repo::Add.new(CLAide::ARGV.new([name, url])).run
source = source_with_url(url)
end
unless source
raise Informative, "Unable to add a source with url `#{url}` named " \
"`#{name}`.\nYou can add it manually via `pod repo add NAME " \
"#{url}`.\n\n#{output}"
end
source
end
# @return [Array<Source>] The list of all the sources known to this # @return [Array<Source>] The list of all the sources known to this
# installation of CocoaPods. # installation of CocoaPods.
# #
...@@ -31,7 +55,7 @@ module Pod ...@@ -31,7 +55,7 @@ module Pod
dirs.map { |repo| Source.new(repo) } dirs.map { |repo| Source.new(repo) }
end end
# @return [Source] The CocoaPods Master Repo source. # @return [Array<Source>] The CocoaPods Master Repo source.
# #
def master def master
sources(['master']) sources(['master'])
...@@ -343,6 +367,57 @@ module Pod ...@@ -343,6 +367,57 @@ module Pod
raise Informative, "Unable to find the `#{name}` repo." raise Informative, "Unable to find the `#{name}` repo."
end end
end end
# @return [Source] The source whose {Source#url} is equal to `url`.
#
# @param [String] url
# The URL of the source.
#
def source_with_url(url)
url = url.downcase
aggregate.sources.find { |s| s.url.downcase == url }
end
# Returns a suitable repository name for `url`.
#
# @example A GitHub.com URL
#
# name_for_url('https://github.com/Artsy/Specs.git')
# # "artsy"
# name_for_url('https://github.com/Artsy/Specs.git')
# # "artsy-1"
#
# @example A non-Github.com URL
#
# name_for_url('https://sourceforge.org/Artsy/Specs.git')
# # sourceforge-artsy-specs
#
# @param [#to_s] url
# The URL of the source.
#
# @return [String] A suitable repository name for `url`.
#
def name_for_url(url)
case url.downcase
when %r{github.com(:|/)cocoapods/specs}
base = 'master'
when %r{github.com(:|/)(.+)/(.+)}
base = Regexp.last_match[2]
else
raise Informative,
"`#{url}` is not a valid URL." unless url =~ URI.regexp
url = URI(url.downcase)
base = url.host.split('.')[-2] +
url.path.gsub(/.git$/, '').split('/').join('-')
end
name = base
infinity = 1.0 / 0
(1..infinity).each do |i|
break unless source_dir(name).exist?
name = "#{base}-#{i}"
end
name
end
end end
end end
end end
...@@ -465,6 +465,49 @@ module Pod ...@@ -465,6 +465,49 @@ module Pod
e.message.should.match /Targets with different platforms/ e.message.should.match /Targets with different platforms/
end end
end end
#--------------------------------------#
describe '#sources' do
describe 'when there are no explicit sources' do
it 'defaults to all sources' do
@analyzer.send(:sources).map(&:url).should ==
SourcesManager.all.map(&:url)
end
it 'prints a warning about the deprecation of implicit sources' do
@analyzer.send(:sources)
UI.warnings.should.match /implicit(.+)sources(.+)deprecated/
end
it 'prints a warning about how to add explicit sources' do
@analyzer.send(:sources)
UI.warnings.should.
match %r{^source 'https://github.com/CocoaPods/Specs.git'$}
end
end
describe 'when there are explicit sources' do
it 'raises if no specs repo with that URL could be added' do
podfile = Podfile.new do
source 'not-a-git-repo'
end
@analyzer.instance_variable_set(:@podfile, podfile)
should.raise Informative do
@analyzer.send(:sources)
end.message.should.match /not a valid URL/
end
it 'fetches a specs repo that is specified by the podfile' do
podfile = Podfile.new do
source 'https://github.com/artsy/Specs.git'
end
@analyzer.instance_variable_set(:@podfile, podfile)
SourcesManager.expects(:find_or_create_source_with_url).once
@analyzer.send(:sources)
end
end
end
end end
end end
end end
...@@ -101,6 +101,62 @@ module Pod ...@@ -101,6 +101,62 @@ module Pod
path = SourcesManager.search_index_path.to_s path = SourcesManager.search_index_path.to_s
path.should.match %r{Library/Caches/CocoaPods/search_index.yaml} path.should.match %r{Library/Caches/CocoaPods/search_index.yaml}
end end
describe 'managing sources by URL' do
describe 'generating a repo name from a URL' do
it 'uses `master` for the master CocoaPods repository' do
url = 'https://github.com/CocoaPods/Specs.git'
Pathname.any_instance.stubs(:exist?).
returns(false).then.returns(true)
SourcesManager.send(:name_for_url, url).should == 'master'
url = 'git@github.com:CocoaPods/Specs.git'
Pathname.any_instance.stubs(:exist?).
returns(false).then.returns(true)
SourcesManager.send(:name_for_url, url).should == 'master'
end
it 'uses the organization name for github.com URLs' do
url = 'https://github.com/segiddins/banana.git'
SourcesManager.send(:name_for_url, url).should == 'segiddins'
end
it 'uses a combination of host and path for other URLs' do
url = 'https://sourceforge.org/Artsy/Specs.git'
SourcesManager.send(:name_for_url, url).
should == 'sourceforge-artsy-specs'
end
it 'appends a number to the name if the base name dir exists' do
url = 'https://github.com/segiddins/banana.git'
Pathname.any_instance.stubs(:exist?).
returns(true).then.returns(false)
SourcesManager.send(:name_for_url, url).should == 'segiddins-1'
url = 'https://sourceforge.org/Artsy/Specs.git'
Pathname.any_instance.stubs(:exist?).
returns(true).then.returns(false)
SourcesManager.send(:name_for_url, url).
should == 'sourceforge-artsy-specs-1'
end
end
describe 'finding or creating a source by URL' do
it 'returns an existing matching source' do
Source.any_instance.stubs(:url).returns('url')
SourcesManager.expects(:name_for_url).never
SourcesManager.find_or_create_source_with_url('url').url.
should == 'url'
end
it 'runs `pod repo add` when there is no matching source' do
Command::Repo::Add.any_instance.stubs(:run).once
SourcesManager.stubs(:source_with_url).returns(nil).then.returns('Source')
SourcesManager.find_or_create_source_with_url('https://banana.com/local/specs.git').
should == 'Source'
end
end
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