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