Commit f88e26c1 authored by Eloy Duran's avatar Eloy Duran

[HEAD] Move logic from Specification to Installer/Downloader.

Closes #392.

Incidentally touched ALL THE FILES.
parent a24b4ba3
...@@ -6,8 +6,8 @@ require 'open-uri' ...@@ -6,8 +6,8 @@ require 'open-uri'
module Pod module Pod
class Dependency < Gem::Dependency class Dependency < Gem::Dependency
attr_reader :external_source, :bleeding attr_reader :external_source, :head
alias :bleeding? :bleeding alias :head? :head
attr_accessor :specification attr_accessor :specification
def initialize(*name_and_version_requirements, &block) def initialize(*name_and_version_requirements, &block)
...@@ -19,22 +19,28 @@ module Pod ...@@ -19,22 +19,28 @@ module Pod
elsif !name_and_version_requirements.empty? && block.nil? elsif !name_and_version_requirements.empty? && block.nil?
if name_and_version_requirements.last.is_a?(Hash) if name_and_version_requirements.last.is_a?(Hash)
@external_source = ExternalSources.from_params(name_and_version_requirements[0].split('/').first, name_and_version_requirements.pop) @external_source = ExternalSources.from_params(name_and_version_requirements[0].split('/').first, name_and_version_requirements.pop)
elsif name_and_version_requirements.last.is_a?(Symbol)
symbol = name_and_version_requirements.pop elsif (symbol = name_and_version_requirements.last).is_a?(Symbol) && symbol == :head
if symbol == :bleeding name_and_version_requirements.pop
@bleeding = true @head = true
else
raise Informative, "Unrecognized symbol `#{symbol}' for dependency `#{name_and_version_requirements[0]}'"
end
end end
super(*name_and_version_requirements) super(*name_and_version_requirements)
if head? && !latest_version?
raise Informative, "A `:head' dependency may not specify version requirements."
end
else else
raise Informative, "A dependency needs either a name and version requirements, " \ raise Informative, "A dependency needs either a name and version requirements, " \
"a source hash, or a block which defines a podspec." "a source hash, or a block which defines a podspec."
end end
end end
def latest_version?
versions = @version_requirements.requirements.map(&:last)
versions == [Gem::Version.new('0')]
end
def ==(other) def ==(other)
super && (@specification ? @specification == other.specification : @external_source == other.external_source) super && (@specification ? @specification == other.specification : @external_source == other.external_source)
end end
...@@ -76,9 +82,9 @@ module Pod ...@@ -76,9 +82,9 @@ module Pod
elsif @version_requirements != Gem::Requirement.default elsif @version_requirements != Gem::Requirement.default
version << @version_requirements.to_s version << @version_requirements.to_s
end end
result = @name result = @name.dup
result = result + " (#{version})" unless version.empty? result += " (#{version})" unless version.empty?
result = result + " [BLEEDING]" if bleeding? result += " [HEAD]" if head?
result result
end end
......
...@@ -23,7 +23,7 @@ module Pod ...@@ -23,7 +23,7 @@ module Pod
else else
download_head download_head
end end
removed_cached_repos_if_needed prune_cache
end end
def create_cache def create_cache
...@@ -33,7 +33,7 @@ module Pod ...@@ -33,7 +33,7 @@ module Pod
clone(url, cache_path) clone(url, cache_path)
end end
def removed_cached_repos_if_needed def prune_cache
return unless caches_dir.exist? return unless caches_dir.exist?
Dir.chdir(caches_dir) do Dir.chdir(caches_dir) do
repos = Pathname.new(caches_dir).children.select { |c| c.directory? }.sort_by(&:ctime) repos = Pathname.new(caches_dir).children.select { |c| c.directory? }.sort_by(&:ctime)
......
...@@ -48,18 +48,17 @@ module Pod ...@@ -48,18 +48,17 @@ module Pod
pods.each do |pod| pods.each do |pod|
unless config.silent? unless config.silent?
marker = config.verbose ? "\n-> ".green : '' marker = config.verbose ? "\n-> ".green : ''
if pod.top_specification.preferred_dependency if subspec_name = pod.top_specification.preferred_dependency
name = "#{pod.top_specification.name}/#{pod.top_specification.preferred_dependency} (#{pod.top_specification.version})" name = "#{pod.top_specification.name}/#{subspec_name} (#{pod.top_specification.version})"
name << "[BLEEDING]" if pod.top_specification.bleeding?
else else
name = pod.to_s name = pod.to_s
end end
name << " [HEAD]" if pod.top_specification.version.head?
puts marker << ( pod.exists? ? "Using #{name}" : "Installing #{name}".green ) puts marker << ( pod.exists? ? "Using #{name}" : "Installing #{name}".green )
end end
unless pod.exists? unless pod.exists?
downloader = Downloader.for_pod(pod) download_pod(pod)
downloader.download
# The docs need to be generated before cleaning because # The docs need to be generated before cleaning because
# the documentation is created for all the subspecs. # the documentation is created for all the subspecs.
generate_docs(pod) generate_docs(pod)
...@@ -68,6 +67,19 @@ module Pod ...@@ -68,6 +67,19 @@ module Pod
end end
end end
def download_pod(pod)
downloader = Downloader.for_pod(pod)
# Force the `bleeding edge' version if necessary.
if pod.top_specification.version.head?
if downloader.respond_to?(:download_head)
downloader.download_head
else
end
else
downloader.download
end
end
#TODO: move to generator ? #TODO: move to generator ?
def generate_docs(pod) def generate_docs(pod)
doc_generator = Generator::Documentation.new(pod) doc_generator = Generator::Documentation.new(pod)
......
...@@ -64,8 +64,9 @@ module Pod ...@@ -64,8 +64,9 @@ module Pod
spec = set.specification_by_name(dependency.name) spec = set.specification_by_name(dependency.name)
@loaded_specs << spec.name @loaded_specs << spec.name
@specs[spec.name] = spec @specs[spec.name] = spec
# Configure the specification
spec.activate_platform(target_definition.platform) spec.activate_platform(target_definition.platform)
spec.bleeding = dependency.bleeding? spec.version.head = dependency.head?
# And recursively load the dependencies of the spec. # And recursively load the dependencies of the spec.
find_dependency_specs(spec, spec.dependencies, target_definition) if spec.dependencies find_dependency_specs(spec, spec.dependencies, target_definition) if spec.dependencies
end end
......
...@@ -180,14 +180,6 @@ module Pod ...@@ -180,14 +180,6 @@ module Pod
@platform = Platform.new(*platform) @platform = Platform.new(*platform)
end end
# @!method bleeding
#
# @return [BOOL] returns wheter the specification is in bleeding mode.
#
attr_accessor :bleeding
alias_method :bleeding?, :bleeding
# If not platform is specified all the platforms are returned. # If not platform is specified all the platforms are returned.
def available_platforms def available_platforms
platform.nil? ? @define_for_platforms.map { |platform| Platform.new(platform, deployment_target(platform)) } : [ platform ] platform.nil? ? @define_for_platforms.map { |platform| Platform.new(platform, deployment_target(platform)) } : [ platform ]
...@@ -196,6 +188,7 @@ module Pod ...@@ -196,6 +188,7 @@ module Pod
### Top level attributes. These attributes represent the unique features of pod and can't be specified by subspecs. ### Top level attributes. These attributes represent the unique features of pod and can't be specified by subspecs.
top_attr_accessor :defined_in_file top_attr_accessor :defined_in_file
top_attr_accessor :source
top_attr_accessor :homepage top_attr_accessor :homepage
top_attr_accessor :summary top_attr_accessor :summary
top_attr_accessor :documentation top_attr_accessor :documentation
...@@ -205,23 +198,6 @@ module Pod ...@@ -205,23 +198,6 @@ module Pod
top_attr_reader :description, lambda { |instance, ivar| ivar || instance.summary } top_attr_reader :description, lambda { |instance, ivar| ivar || instance.summary }
top_attr_writer :description, lambda { |d| d.strip_heredoc } top_attr_writer :description, lambda { |d| d.strip_heredoc }
# @!method source
#
# @abstract
# Returns the source of the pod. If the specification is set in bleeding mode
# and the source is a git repository the head of master will be returned.
#
top_attr_writer :source
top_attr_reader :source, lambda { |instance, ivar|
if instance.bleeding?
raise Informative, 'Bleeding is supported only for git repos' unless ivar[:git]
{ :git => ivar[:git] }
else
ivar
end
}
# @!method license # @!method license
# #
# @abstract # @abstract
...@@ -374,15 +350,14 @@ module Pod ...@@ -374,15 +350,14 @@ module Pod
attr_reader :subspecs attr_reader :subspecs
def recursive_subspecs def recursive_subspecs
unless @recursive_subspecs @recursive_subspecs ||= begin
mapper = lambda do |spec| mapper = lambda do |spec|
spec.subspecs.map do |subspec| spec.subspecs.map do |subspec|
[subspec, *mapper.call(subspec)] [subspec, *mapper.call(subspec)]
end.flatten end.flatten
end end
@recursive_subspecs = mapper.call self mapper.call(self)
end end
@recursive_subspecs
end end
def subspec_by_name(name) def subspec_by_name(name)
...@@ -463,9 +438,7 @@ module Pod ...@@ -463,9 +438,7 @@ module Pod
end end
def to_s def to_s
result = "#{name} (#{version})" "#{name} (#{version})"
result << " [BLEEDING]" if bleeding?
result
end end
def inspect def inspect
......
...@@ -4,6 +4,8 @@ require 'rubygems/version' ...@@ -4,6 +4,8 @@ require 'rubygems/version'
module Pod module Pod
class Version < Gem::Version class Version < Gem::Version
attr_accessor :head
alias_method :head?, :head
end end
end end
This diff is collapsed.
require File.expand_path('../../spec_helper', __FILE__) require File.expand_path('../../spec_helper', __FILE__)
describe "Pod::Dependency" do module Pod
it "merges dependencies (taken from newer RubyGems version)" do describe Dependency do
dep1 = Pod::Dependency.new('bananas', '>= 1.8') it "merges dependencies (taken from newer RubyGems version)" do
dep2 = Pod::Dependency.new('bananas', '1.9') dep1 = Dependency.new('bananas', '>= 1.8')
dep1.merge(dep2).should == Pod::Dependency.new('bananas', '>= 1.8', '1.9') dep2 = Dependency.new('bananas', '1.9')
end dep1.merge(dep2).should == Dependency.new('bananas', '>= 1.8', '1.9')
end
it "returns the name of the dependency, or the name of the pod of which this is a subspec" do it "returns the name of the dependency, or the name of the pod of which this is a subspec" do
dep = Pod::Dependency.new('RestKit') dep = Dependency.new('RestKit')
dep.top_level_spec_name.should == 'RestKit' dep.top_level_spec_name.should == 'RestKit'
dep = Pod::Dependency.new('RestKit/Networking') dep = Dependency.new('RestKit/Networking')
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 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 = Dependency.new('RestKit', '>= 1.2.3')
dep.to_top_level_spec_dependency.should == Pod::Dependency.new('RestKit', '>= 1.2.3') dep.to_top_level_spec_dependency.should == Dependency.new('RestKit', '>= 1.2.3')
dep = Pod::Dependency.new('RestKit/Networking', '>= 1.2.3') dep = Dependency.new('RestKit/Networking', '>= 1.2.3')
dep.to_top_level_spec_dependency.should == Pod::Dependency.new('RestKit', '>= 1.2.3') dep.to_top_level_spec_dependency.should == Dependency.new('RestKit', '>= 1.2.3')
end end
it "is equal to another dependency if `external_source' is the same" do it "is equal to another dependency if `external_source' is the same" do
dep1 = Pod::Dependency.new('bananas', :git => 'GIT-URL') dep1 = Dependency.new('bananas', :git => 'GIT-URL')
dep2 = Pod::Dependency.new('bananas') dep2 = Dependency.new('bananas')
dep1.should.not == dep2 dep1.should.not == dep2
dep3 = Pod::Dependency.new('bananas', :git => 'GIT-URL') dep3 = Dependency.new('bananas', :git => 'GIT-URL')
dep1.should == dep3 dep1.should == dep3
end end
it "is equal to another dependency if `specification' is equal" do it "is equal to another dependency if `specification' is equal" do
dep1 = Pod::Dependency.new { |s| s.name = 'bananas'; s.version = '1' } dep1 = Dependency.new { |s| s.name = 'bananas'; s.version = '1' }
dep2 = Pod::Dependency.new('bananas') dep2 = Dependency.new('bananas')
dep1.should.not == dep2 dep1.should.not == dep2
dep2 = Pod::Dependency.new { |s| s.name = 'bananas'; s.version = '1' } dep2 = Dependency.new { |s| s.name = 'bananas'; s.version = '1' }
dep1.should == dep2 dep1.should == dep2
end end
it 'raises if created without either valid name/version/external requirements or a block' do it 'raises if created without either valid name/version/external requirements or a block' do
lambda { Pod::Dependency.new }.should.raise Pod::Informative lambda { Dependency.new }.should.raise Informative
end end
end
describe "Pod::Dependency", "defined with a block" do describe "defined with a block" do
before do before do
@dependency = Pod::Dependency.new do |spec| @dependency = Dependency.new do |spec|
spec.name = "my-custom-spec" spec.name = "my-custom-spec"
spec.version = "1.0.3" spec.version = "1.0.3"
end
end
it 'it identifies itself as an inline dependency' do
@dependency.should.be.inline
end
it 'attaches a custom spec to the dependency, configured by the block' do
@dependency.specification.name.should == "my-custom-spec"
end
end end
end
it 'it identifies itself as an inline dependency' do
@dependency.should.be.inline
end
it 'attaches a custom spec to the dependency, configured by the block' do
@dependency.specification.name.should == "my-custom-spec"
end
end
describe "Pod::Dependency", "with a hash of external source settings" do describe "with a hash of external source settings" do
before do before do
@dependency = Pod::Dependency.new("cocoapods", :git => "git://github.com/cocoapods/cocoapods") @dependency = Dependency.new("cocoapods", :git => "git://github.com/cocoapods/cocoapods")
end end
it 'it identifies itself as an external dependency' do it 'identifies itself as an external dependency' do
@dependency.should.be.external @dependency.should.be.external
end
end
describe "with flags" do
it "identifies itself as a `bleeding edge' dependency" do
dependency = Dependency.new("cocoapods", :head)
dependency.should.be.head
dependency.to_s.should == "cocoapods [HEAD]"
end
it "only supports the `:head' option on the last version of a pod" do
should.raise Informative do
Dependency.new("cocoapods", "1.2.3", :head)
end
end
it "raises if an invalid flag is given" do
should.raise ArgumentError do
Dependency.new("cocoapods", :foot)
end
end
end
end end
end end
require File.expand_path('../../spec_helper', __FILE__) require File.expand_path('../../spec_helper', __FILE__)
def stub_pod_with_source(source_options) def stub_pod_with_source(source_options)
specification = stub( specification = stub(:source => source_options)
:source => source_options
)
stub('pod') do stub('pod') do
stubs(:root).returns(temporary_sandbox.root) stubs(:root).returns(temporary_sandbox.root)
stubs(:top_specification).returns(specification) stubs(:top_specification).returns(specification)
end end
end end
describe "Pod::Downloader" do module Pod
it "returns a git downloader with parsed options" do describe Downloader do
pod = Pod::LocalPod.new(fixture_spec('banana-lib/BananaLib.podspec'), temporary_sandbox, Pod::Platform.ios) it "returns a git downloader with parsed options" do
downloader = Pod::Downloader.for_pod(pod) pod = LocalPod.new(fixture_spec('banana-lib/BananaLib.podspec'), temporary_sandbox, Platform.ios)
downloader.should.be.instance_of Pod::Downloader::Git downloader = Downloader.for_pod(pod)
downloader.url.should == 'http://banana-corp.local/banana-lib.git' downloader.should.be.instance_of Downloader::Git
downloader.options.should == { :tag => 'v1.0' } downloader.url.should == 'http://banana-corp.local/banana-lib.git'
downloader.options.should == { :tag => 'v1.0' }
end
it 'returns a github downloader when the :git URL is on github' do
pod = LocalPod.new(fixture_spec('banana-lib/BananaLib.podspec'), temporary_sandbox, Platform.ios)
pod.top_specification.stubs(:source).returns(:git => "git://github.com/CocoaPods/CocoaPods")
downloader = Downloader.for_pod(pod)
downloader.should.be.instance_of Downloader::GitHub
end
end end
it 'returns a github downloader when the :git URL is on github' do describe Downloader::GitHub do
pod = Pod::LocalPod.new(fixture_spec('banana-lib/BananaLib.podspec'), temporary_sandbox, Pod::Platform.ios) it 'can convert public HTTP repository URLs to the tarball URL' do
pod.top_specification.stubs(:source).returns(:git => "git://github.com/CocoaPods/CocoaPods") downloader = Downloader.for_pod(stub_pod_with_source(
downloader = Pod::Downloader.for_pod(pod) :git => "https://github.com/CocoaPods/CocoaPods.git"
downloader.should.be.instance_of Pod::Downloader::GitHub ))
downloader.tarball_url_for('master').should == "https://github.com/CocoaPods/CocoaPods/tarball/master"
end
it 'can convert private HTTP repository URLs to the tarball URL' do
downloader = Downloader.for_pod(stub_pod_with_source(
:git => "https://lukeredpath@github.com/CocoaPods/CocoaPods.git"
))
downloader.tarball_url_for('master').should == "https://github.com/CocoaPods/CocoaPods/tarball/master"
end
it 'can convert private SSH repository URLs to the tarball URL' do
downloader = Downloader.for_pod(stub_pod_with_source(
:git => "git@github.com:CocoaPods/CocoaPods.git"
))
downloader.tarball_url_for('master').should == "https://github.com/CocoaPods/CocoaPods/tarball/master"
end
it 'can convert public git protocol repository URLs to the tarball URL' do
downloader = Downloader.for_pod(stub_pod_with_source(
:git => "git://github.com/CocoaPods/CocoaPods.git"
))
downloader.tarball_url_for('master').should == "https://github.com/CocoaPods/CocoaPods/tarball/master"
end
end end
end end
describe Pod::Downloader::GitHub do
it 'can convert public HTTP repository URLs to the tarball URL' do
downloader = Pod::Downloader.for_pod(stub_pod_with_source(
:git => "https://github.com/CocoaPods/CocoaPods.git"
))
downloader.tarball_url_for('master').should == "https://github.com/CocoaPods/CocoaPods/tarball/master"
end
it 'can convert private HTTP repository URLs to the tarball URL' do
downloader = Pod::Downloader.for_pod(stub_pod_with_source(
:git => "https://lukeredpath@github.com/CocoaPods/CocoaPods.git"
))
downloader.tarball_url_for('master').should == "https://github.com/CocoaPods/CocoaPods/tarball/master"
end
it 'can convert private SSH repository URLs to the tarball URL' do
downloader = Pod::Downloader.for_pod(stub_pod_with_source(
:git => "git@github.com:CocoaPods/CocoaPods.git"
))
downloader.tarball_url_for('master').should == "https://github.com/CocoaPods/CocoaPods/tarball/master"
end
it 'can convert public git protocol repository URLs to the tarball URL' do
downloader = Pod::Downloader.for_pod(stub_pod_with_source(
:git => "git://github.com/CocoaPods/CocoaPods.git"
))
downloader.tarball_url_for('master').should == "https://github.com/CocoaPods/CocoaPods/tarball/master"
end
end
require File.expand_path('../../spec_helper', __FILE__) require File.expand_path('../../spec_helper', __FILE__)
describe "Pod::Installer" do module Pod
before do describe Installer do
config.repos_dir = fixture('spec-repos')
config.project_pods_root = fixture('integration')
end
describe "by default" do
before do before do
podfile = Pod::Podfile.new do config.repos_dir = fixture('spec-repos')
platform :ios config.project_pods_root = fixture('integration')
xcodeproj 'MyProject'
pod 'JSONKit'
end
@xcconfig = Pod::Installer.new(podfile).target_installers.first.xcconfig.to_hash
end end
it "sets the header search paths where installed Pod headers can be found" do describe "by default" do
@xcconfig['ALWAYS_SEARCH_USER_PATHS'].should == 'YES' before do
end podfile = Podfile.new do
platform :ios
xcodeproj 'MyProject'
pod 'JSONKit'
end
@xcconfig = Installer.new(podfile).target_installers.first.xcconfig.to_hash
end
it "configures the project to load all members that implement Objective-c classes or categories from the static library" do it "sets the header search paths where installed Pod headers can be found" do
@xcconfig['OTHER_LDFLAGS'].should == '-ObjC' @xcconfig['ALWAYS_SEARCH_USER_PATHS'].should == 'YES'
end end
it "configures the project to load all members that implement Objective-c classes or categories from the static library" do
@xcconfig['OTHER_LDFLAGS'].should == '-ObjC'
end
it "sets the PODS_ROOT build variable" do it "sets the PODS_ROOT build variable" do
@xcconfig['PODS_ROOT'].should.not == nil @xcconfig['PODS_ROOT'].should.not == nil
end
end end
end
it "generates a BridgeSupport metadata file from all the pod headers" do it "generates a BridgeSupport metadata file from all the pod headers" do
podfile = Pod::Podfile.new do podfile = Podfile.new do
platform :osx platform :osx
pod 'ASIHTTPRequest' pod 'ASIHTTPRequest'
end
installer = Installer.new(podfile)
pods = installer.specifications.map do |spec|
LocalPod.new(spec, installer.sandbox, podfile.target_definitions[:default].platform)
end
expected = pods.map { |pod| pod.header_files }.flatten.map { |header| config.project_pods_root + header }
expected.size.should > 0
installer.target_installers.first.bridge_support_generator_for(pods, installer.sandbox).headers.should == expected
end end
installer = Pod::Installer.new(podfile)
pods = installer.specifications.map do |spec| it "omits empty target definitions" do
Pod::LocalPod.new(spec, installer.sandbox, podfile.target_definitions[:default].platform) podfile = Podfile.new do
platform :ios
target :not_empty do
pod 'JSONKit'
end
end
installer = Installer.new(podfile)
installer.target_installers.map(&:target_definition).map(&:name).should == [:not_empty]
end end
expected = pods.map { |pod| pod.header_files }.flatten.map { |header| config.project_pods_root + header }
expected.size.should > 0
installer.target_installers.first.bridge_support_generator_for(pods, installer.sandbox).headers.should == expected
end
it "omits empty target definitions" do it "adds the user's build configurations" do
podfile = Pod::Podfile.new do path = fixture('SampleProject/SampleProject.xcodeproj')
platform :ios podfile = Podfile.new do
target :not_empty do platform :ios
pod 'JSONKit' xcodeproj path, 'App Store' => :release
end end
installer = Installer.new(podfile)
installer.project.build_configurations.map(&:name).sort.should == ['App Store', 'Debug', 'Release', 'Test']
end end
installer = Pod::Installer.new(podfile)
installer.target_installers.map(&:target_definition).map(&:name).should == [:not_empty]
end
it "adds the user's build configurations" do it "forces downloading of the `bleeding edge' version of a pod" do
path = fixture('SampleProject/SampleProject.xcodeproj') podfile = Podfile.new do
podfile = Pod::Podfile.new do platform :ios
platform :ios pod 'JSONKit', :head
xcodeproj path, 'App Store' => :release end
installer = Installer.new(podfile)
pod = installer.pods.first
downloader = stub('Downloader')
Downloader.stubs(:for_pod).returns(downloader)
downloader.expects(:download_head)
installer.download_pod(pod)
end end
installer = Pod::Installer.new(podfile)
installer.project.build_configurations.map(&:name).sort.should == ['App Store', 'Debug', 'Release', 'Test']
end end
end end
This diff is collapsed.
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