Commit b455a333 authored by Fabio Pelosin's avatar Fabio Pelosin

[Set] Support for multiple sources.

Closes #85
parent a07d93d1
...@@ -5,17 +5,21 @@ ...@@ -5,17 +5,21 @@
###### Enhancements ###### Enhancements
- Pod `install` will update the specs repo only if needed. - Pod `install` will update the specs repo only if needed.
[#533](https://github.com/CocoaPods/CocoaPods/issues/533) [#533](https://github.com/CocoaPods/CocoaPods/issues/533)
- CocoaPods now searches for the highest version of a Pod on
all the repos.
[#85](https://github.com/CocoaPods/CocoaPods/issues/85)
- Added a pre install hook to the Podfile and to root specifications. - Added a pre install hook to the Podfile and to root specifications.
[#486](https://github.com/CocoaPods/CocoaPods/issues/486) [#486](https://github.com/CocoaPods/CocoaPods/issues/486)
- Support for `header_mappings_dir` attribute in subspecs. - Support for `header_mappings_dir` attribute in subspecs.
- Refactored UI. - Refactored UI.
- Added support for Podfiles named `Podfile.cocoapods` which allows to associate an editor application in Mac OS X. - Added support for Podfiles named `Podfile.cocoapods` which allows to
associate an editor application in Mac OS X.
[#528](https://github.com/CocoaPods/CocoaPods/issues/528) [#528](https://github.com/CocoaPods/CocoaPods/issues/528)
- Added config option to disable the new version available message. - Added config option to disable the new version available message.
[#448](https://github.com/CocoaPods/CocoaPods/issues/448) [#448](https://github.com/CocoaPods/CocoaPods/issues/448)
- Added support for extracting `.tar.bz2` files - Added support for extracting `.tar.bz2` files
[#522](https://github.com/CocoaPods/CocoaPods/issues/522) [#522](https://github.com/CocoaPods/CocoaPods/issues/522)
- Improved feedback for errors of repo subcommand. - Improved feedback for errors of repo subcommands.
[#505](https://github.com/CocoaPods/CocoaPods/issues/505) [#505](https://github.com/CocoaPods/CocoaPods/issues/505)
......
...@@ -209,7 +209,7 @@ module Pod ...@@ -209,7 +209,7 @@ module Pod
end end
end end
# Ensures that a spec is compatible with platform of a target. # Ensures that a spec is compatible with the platform of a target.
# #
# @raises If the spec is not supported by the target. # @raises If the spec is not supported by the target.
# #
......
module Pod module Pod
class Source
class Aggregate
def all
@sources ||= dirs.map { |repo| Source.new(repo) }
end
def dirs # The {Source} class is responsible to manage a collection of podspecs.
if ENV['CP_MASTER_REPO_DIR'] #
[Pathname.new(ENV['CP_MASTER_REPO_DIR'])] # @note The backing store of the podspecs collection is an implementation detail
else # abstraced from the rest of CocoaPods.
repos_dir = Config.instance.repos_dir #
unless repos_dir.exist? # @note The default implementation uses a git repo as a backing store, where the
raise Informative, "No spec repos found in `#{repos_dir}'. " \ # podspecs are namespaces as:
"To fetch the `master' repo run: $ pod setup" #
end # #{POD_NAME}/#{VERSION}/#{POD_NAME}.podspec
repos_dir.children.select(&:directory?) #
end # @todo For better abstranction the sources should be responsible to update themselves.
end #
class Source
def all_sets # @return [Pathname] The location of the repo.
all.map(&:pod_sets).flatten #
end attr_reader :repo
def search(dependency) # @param [Pathname] repo @see repo.
all.map { |s| s.search(dependency) }.compact.first || #
raise(Informative, "[!] Unable to find a pod named `#{dependency.name}'".red) def initialize(repo)
@repo = repo
end end
def search_by_name(query, full_text_search) # @return [String] the name of the repo.
result = all.map { |s| s.search_by_name(query, full_text_search) }.flatten #
if result.empty? def name
extra = ", author, summary, or description" if full_text_search @repo.basename.to_s
raise(Informative, "Unable to find a pod with name" \
"#{extra} matching `#{query}'")
end
result
end
end end
def self.all # @!group Quering the source
Aggregate.new.all
end
def self.all_sets # @return [Array<String>] The name of all the Pods.
Aggregate.new.all_sets #
def pods
@repo.children.map do |child|
child.basename.to_s if child.directory? && child.basename.to_s != '.git'
end.compact
end end
def self.search(dependency) # @return [Array<Sets>] The sets of all the Pods.
Aggregate.new.search(dependency) #
def pod_sets
pods.map { |pod| Specification::Set.new(pod, self) }
end end
def self.search_by_name(name, full_text_search) # @return [Array<Version>] All the available versions for the Pod, sorted
Aggregate.new.search_by_name(name, full_text_search) # from highest to lowest.
#
# @param [String] name The name of the Pod.
#
def versions(name)
pod_dir = repo + name
pod_dir.children.map do |v|
basename = v.basename.to_s
Version.new(basename) if v.directory? && basename[0,1] != '.'
end.compact.sort.reverse
end end
attr_reader :repo # @return [Specification] The specification for a given version of Pod.
#
def initialize(repo) # @param [String] name The name of the Pod.
@repo = repo #
# @param [Version,String] version
# The version for the specification.
#
def specification(name, version)
specification_path = repo + name + version.to_s + "#{name}.podspec"
Specification.from_file(specification_path)
end end
def name # @!group Searching the source
@repo.basename.to_s
end
def pod_sets
@repo.children.map do |child|
if child.directory? && child.basename.to_s != '.git'
Specification::Set.new(child)
end
end.compact
end
# @return [Set] A set for a given dependency. The set is identified by the
# name of the dependency and takes into account subspecs.
#
def search(dependency) def search(dependency)
pod_sets.find do |set| pod_sets.find do |set|
# First match the (top level) name, which does not yet load the spec from disk # First match the (top level) name, which does not yet load the spec from disk
...@@ -82,7 +86,19 @@ module Pod ...@@ -82,7 +86,19 @@ module Pod
end end
end end
def search_by_name(query, full_text_search) # @return [Array<Set>] The sets that contain the search term.
#
# @param [String] query The search term.
#
# @param [Bool] full_text_search Whether the search should be limited to
# the name of the Pod or should include
# also the author, the summary, and the
# description.
#
# @note Full text search requires to load the specification for each pod,
# hence is considerably slower.
#
def search_by_name(query, full_text_search = false)
pod_sets.map do |set| pod_sets.map do |set|
text = if full_text_search text = if full_text_search
s = set.specification s = set.specification
...@@ -93,5 +109,102 @@ module Pod ...@@ -93,5 +109,102 @@ module Pod
set if text.downcase.include?(query.downcase) set if text.downcase.include?(query.downcase)
end.compact end.compact
end end
# The {Source::Aggregate} manages all the sources available to CocoaPods.
#
class Aggregate
# @return [Array<Source>] All the sources.
#
def all
@sources ||= dirs.map { |repo| Source.new(repo) }.sort_by(&:name)
end
# @return [Array<String>] The names of all the pods available.
#
def all_pods
all.map(&:pods).flatten.uniq
end
# @return [Array<Set>] The sets for all the pods available.
#
def all_sets
all_pods.map do |pod|
sources = all.select{ |s| s.pods.include?(pod) }.compact
Specification::Set.new(pod, sources)
end
end
# @return [Set] A set for a given dependency including all the Sources
# that countain the Pod.
#
# @raises If no source including the set can be foud.
#
# @see Source#search
#
def search(dependency)
sources = all.select { |s| !s.search(dependency).nil? }
raise(Informative, "[!] Unable to find a pod named `#{dependency.name}'".red) if sources.empty?
Specification::Set.new(dependency.top_level_spec_name, sources)
end
# @return [Array<Set>] The sets that contain the search term.
#
# @raises If no source including the set can be foud.
#
# @see Source#search_by_name
#
def search_by_name(query, full_text_search = false)
pods_by_source = {}
result = []
all.each { |s| pods_by_source[s] = s.search_by_name(query, full_text_search).map(&:name) }
pod_names = pods_by_source.values.flatten.uniq
pod_names.each do |pod|
sources = pods_by_source.select{ |source, pods| pods.include?(pod) }.keys
result << Specification::Set.new(pod, sources)
end
if result.empty?
extra = ", author, summary, or description" if full_text_search
raise(Informative, "Unable to find a pod with name" \
"#{extra} matching `#{query}'")
end
result
end
# @return [Array<Pathname>] The directories where the sources are stored.
#
# @raises If the repos dir doesn't exits.
#
def dirs
if ENV['CP_MASTER_REPO_DIR']
[Pathname.new(ENV['CP_MASTER_REPO_DIR'])]
else
repos_dir = Config.instance.repos_dir
unless repos_dir.exist?
raise Informative, "No spec repos found in `#{repos_dir}'. " \
"To fetch the `master' repo run: $ pod setup"
end
repos_dir.children.select(&:directory?)
end
end
end
# @!group Shortcuts
def self.all
Aggregate.new.all
end
def self.all_sets
Aggregate.new.all_sets
end
def self.search(dependency)
Aggregate.new.search(dependency)
end
def self.search_by_name(name, full_text_search = false)
Aggregate.new.search_by_name(name, full_text_search)
end
end end
end end
...@@ -2,72 +2,139 @@ require 'active_support/core_ext/array/conversions' ...@@ -2,72 +2,139 @@ require 'active_support/core_ext/array/conversions'
module Pod module Pod
class Specification class Specification
# A Specification::Set is resposible of handling all the specifications of
# a Pod. This class stores the information of the dependencies that reuired
# a Pod in the resolution process.
#
# @note The alpahbetical order of the sets is used to select a specification
# if multiple are available for a given version.
#
# @note The set class is not and should be not aware of the backing store
# of a Source.
#
class Set class Set
attr_reader :pod_dir
def initialize(pod_dir) # @return [String] The name of the Pod.
@pod_dir = pod_dir #
attr_reader :name
# @return [Array<Source>] The sources that contain the specifications for
# the available versions of a Pod.
#
attr_reader :sources
# @param [String] name The name of the Pod.
#
# @param [Array<Source>,Source] sources
# The sources that contain a Pod.
#
def initialize(name, sources)
@name = name
sources = sources.is_a?(Array) ? sources : [sources]
@sources = sources.sort_by(&:name)
@required_by = [] @required_by = []
@dependencies = [] @dependencies = []
end end
# @return [void] Stores a dependency on the Pod.
#
# @param [Dependency] dependency A dependency that requires the Pod.
#
# @param [String] dependent_name The name of the owner of the
# dependency. It is used only to display
# the Pod::Informative.
#
# @raises If the versions requirement of the dependency are not
# compatible with the previously stored dependencies.
#
def required_by(dependency, dependent_name) def required_by(dependency, dependent_name)
unless @required_by.empty? || dependency.requirement.satisfied_by?(Gem::Version.new(required_version.to_s)) unless @required_by.empty? || dependency.requirement.satisfied_by?(Gem::Version.new(required_version.to_s))
raise Informative, "#{dependent_name} tries to activate `#{dependency}', " \ raise Informative, "#{dependent_name} tries to activate `#{dependency}', but already activated version `#{required_version}' by #{@required_by.to_sentence}."
"but already activated version `#{required_version}' " \
"by #{@required_by.to_sentence}."
end end
@specification = nil @specification = nil
@required_by << dependent_name @required_by << dependent_name
@dependencies << dependency @dependencies << dependency
end end
def specification_by_name(name) # @return [Dependency] A dependency including all the versions
specification.top_level_parent.subspec_by_name(name) # requirements of the stored dependencies.
end #
def dependency def dependency
@dependencies.inject(Dependency.new(name)) do |previous, dependency| @dependencies.inject(Dependency.new(name)) do |previous, dependency|
previous.merge(dependency.to_top_level_spec_dependency) previous.merge(dependency.to_top_level_spec_dependency)
end end
end end
def name # @return [Specification] The specification for the given subspec name,
@pod_dir.basename.to_s # from {specification}.
end #
# @param [String] name The name of the specification. It can be the
def specification_path # name of the top level parent or the name of a
@pod_dir + required_version.to_s + "#{name}.podspec" # subspec.
#
# @see specification
#
def specification_by_name(name)
specification.top_level_parent.subspec_by_name(name)
end end
# @return [Specification] The top level specification of the Pod for the
# {required_version}.
#
# @note If multiple sources have a specification for the
# {required_version} The alpahbetical order of their names is used
# to disambiguate.
#
def specification def specification
@specification ||= Specification.from_file(specification_path) unless @specification
sources = versions_by_source.select { |_, versions| versions.include?(required_version) }.keys
source = sources.sort_by(&:name).first
@specification = source.specification(name, required_version)
end
@specification
end end
# Return the first version that matches the current dependency. # @return [Version] The highest version that satisfies {dependency}.
#
def required_version def required_version
versions.find { |v| dependency.match?(name, v) } || versions.find { |v| dependency.match?(name, v) } ||
raise(Informative, "Required version (#{dependency}) not found for `#{name}'.\nAvailable versions: #{versions.join(', ')}") raise(Informative, "Required version (#{dependency}) not found for `#{name}'.\nAvailable versions: #{versions.join(', ')}")
end end
# @return [Array<Version>] All the available versions for the Pod, sorted
# from highest to lowest.
#
def versions
versions_by_source.values.flatten.uniq.sort.reverse
end
# @return [Hash{Source => Version}] All the available versions for the
# Pod groupped by source.
#
def versions_by_source
result = {}
sources.each do |source|
result[source] = source.versions(name)
end
result
end
def ==(other) def ==(other)
self.class === other && @pod_dir == other.pod_dir self.class === other && @name == other.name && @sources.map(&:name) == other.sources.map(&:name)
end end
def to_s def to_s
"#<#{self.class.name} for `#{name}' with required version `#{required_version}' at `#{@pod_dir}'>" "#<#{self.class.name} for `#{name}' with required version `#{required_version}' available at `#{sources.map(&:name) * ', '}'>"
end end
alias_method :inspect, :to_s alias_method :inspect, :to_s
# Returns Pod::Version instances, for each version directory, sorted from # The Set::External class handles Pods from external sources. Pods from
# highest version to lowest. # external sources don't use the {Pod::Sources} and are intialized by a
def versions # given specification.
@pod_dir.children.map do |v| #
basename = v.basename.to_s # @note External sources *don't* support subspecs.
Version.new(basename) if v.directory? && basename[0,1] != '.' #
end.compact.sort.reverse
end
class External < Set class External < Set
def initialize(specification) def initialize(specification)
@specification = specification @specification = specification
...@@ -80,7 +147,7 @@ module Pod ...@@ -80,7 +147,7 @@ module Pod
end end
def ==(other) def ==(other)
self.class === other && name == other.name self.class === other && @specification == other.specification
end end
def required_by(dependency, dependent_name) def required_by(dependency, dependent_name)
......
...@@ -78,7 +78,7 @@ module Pod ...@@ -78,7 +78,7 @@ module Pod
def compute_creation_date(set, save = true) def compute_creation_date(set, save = true)
date = get_value(set, :creation_date) date = get_value(set, :creation_date)
unless date unless date
Dir.chdir(set.pod_dir.dirname) do Dir.chdir(set.sources.first.repo) do
date = Time.at(`git log --first-parent --format=%ct #{set.name}`.split("\n").last.to_i) date = Time.at(`git log --first-parent --format=%ct #{set.name}`.split("\n").last.to_i)
end end
set_value(set, :creation_date, date) set_value(set, :creation_date, date)
......
Pod::Spec.new do |s|
s.name = 'BananaLib'
s.version = '1.0'
s.authors = 'Banana Corp', { 'Monkey Boy' => 'monkey@banana-corp.local' }
s.homepage = 'http://banana-corp.local/banana-lib.html'
s.summary = 'Chunky bananas!'
s.description = 'Full of chunky bananas.'
s.source = { :git => 'http://banana-corp.local/banana-lib.git', :tag => 'v1.0' }
s.source_files = 'Classes/*.{h,m}', 'Vendor'
s.xcconfig = { 'OTHER_LDFLAGS' => '-framework SystemConfiguration' }
s.clean_paths = "sub-dir"
s.prefix_header_file = 'Classes/BananaLib.pch'
s.resources = "Resources/*.png"
s.dependency 'monkey', '~> 1.0.1', '< 1.0.9'
s.license = {
:type => 'MIT',
:file => 'LICENSE',
:text => 'Permission is hereby granted ...'
}
s.documentation = {
:html => 'http://banana-corp.local/banana-lib/docs.html',
:appledoc => [
'--project-company', 'Banana Corp',
'--company-id', 'com.banana',
]
}
end
Pod::Spec.new do |s|
s.name = 'JSONKit'
s.version = '1.4'
s.license = 'BSD / Apache License, Version 2.0'
s.summary = 'A Very High Performance Objective-C JSON Library.'
s.homepage = 'https://github.com/johnezang/JSONKit'
s.author = 'John Engelhart'
s.source = { :git => 'https://github.com/johnezang/JSONKit.git', :tag => 'v1.4' }
s.source_files = 'JSONKit.*'
end
Pod::Spec.new do |s|
s.name = 'JSONKit'
s.version = '999.999.999'
s.license = 'BSD / Apache License, Version 2.0'
s.summary = 'A Very High Performance Objective-C JSON Library.'
s.homepage = 'https://github.com/johnezang/JSONKit'
s.author = 'John Engelhart'
s.source = { :git => 'https://github.com/johnezang/JSONKit.git', :commit => '0aff3deb5e1bb2bbc88a83fd71c8ad5550185cce' }
s.source_files = 'JSONKit.*'
s.compiler_flags = '-Wno-deprecated-objc-isa-usage', '-Wno-format'
end
...@@ -3,19 +3,10 @@ require File.expand_path('../../../spec_helper', __FILE__) ...@@ -3,19 +3,10 @@ require File.expand_path('../../../spec_helper', __FILE__)
describe "Pod::Command::List" do describe "Pod::Command::List" do
extend SpecHelper::TemporaryRepos extend SpecHelper::TemporaryRepos
before do
config.repos_dir = fixture('spec-repos')
end
def command(arguments = argv) def command(arguments = argv)
command = Pod::Command::List.new(arguments) command = Pod::Command::List.new(arguments)
end end
it "runs with correct parameters" do
lambda { command.run }.should.not.raise
lambda { command(argv('new')).run }.should.not.raise
end
it "complains for wrong parameters" do it "complains for wrong parameters" do
lambda { command(argv('wrong')).run }.should.raise Pod::Command::Help lambda { command(argv('wrong')).run }.should.raise Pod::Command::Help
lambda { command(argv('--wrong')).run }.should.raise Pod::Command::Help lambda { command(argv('--wrong')).run }.should.raise Pod::Command::Help
...@@ -24,8 +15,7 @@ describe "Pod::Command::List" do ...@@ -24,8 +15,7 @@ describe "Pod::Command::List" do
it "presents the known pods" do it "presents the known pods" do
list = command() list = command()
list.run list.run
[ [ /ZBarSDK/,
/ZBarSDK/,
/TouchJSON/, /TouchJSON/,
/SDURLCache/, /SDURLCache/,
/MagicalRecord/, /MagicalRecord/,
......
...@@ -5,6 +5,10 @@ describe Pod::Command::Push do ...@@ -5,6 +5,10 @@ describe Pod::Command::Push do
extend SpecHelper::TemporaryDirectory extend SpecHelper::TemporaryDirectory
extend SpecHelper::TemporaryRepos extend SpecHelper::TemporaryRepos
before do
config.repos_dir = SpecHelper.tmp_repos_path
end
def master_repo def master_repo
fixture('spec-repos/master') fixture('spec-repos/master')
end end
......
require File.expand_path('../../../spec_helper', __FILE__) require File.expand_path('../../../spec_helper', __FILE__)
describe "Pod::Command::Repo" do describe "Pod::Command::Repo" do
before do
config.repos_dir = SpecHelper.tmp_repos_path
end
describe "In general" do describe "In general" do
extend SpecHelper::Command extend SpecHelper::Command
extend SpecHelper::TemporaryDirectory extend SpecHelper::TemporaryDirectory
......
...@@ -6,6 +6,10 @@ describe "Pod::Command::Setup" do ...@@ -6,6 +6,10 @@ describe "Pod::Command::Setup" do
extend SpecHelper::TemporaryDirectory extend SpecHelper::TemporaryDirectory
extend SpecHelper::TemporaryRepos extend SpecHelper::TemporaryRepos
before do
config.repos_dir = SpecHelper.tmp_repos_path
end
it "runs with correct parameters" do it "runs with correct parameters" do
lambda { run_command('setup') }.should.not.raise lambda { run_command('setup') }.should.not.raise
end end
......
...@@ -5,7 +5,7 @@ describe Pod::UI do ...@@ -5,7 +5,7 @@ describe Pod::UI do
extend SpecHelper::Command extend SpecHelper::Command
before do before do
@set = Pod::Spec::Set.new(fixture('spec-repos/master/CocoaLumberjack')) @set = Pod::Source.search_by_name('CocoaLumberjack').first
Pod::Specification::Statistics.instance.cache_file = nil Pod::Specification::Statistics.instance.cache_file = nil
end end
...@@ -34,7 +34,7 @@ describe Pod::UI do ...@@ -34,7 +34,7 @@ describe Pod::UI do
end end
it "should print at least one subspec" do it "should print at least one subspec" do
@set = Pod::Spec::Set.new(fixture('spec-repos/master/RestKit')) @set = Pod::Source.search_by_name('RestKit').first
Pod::UI.pod(@set) Pod::UI.pod(@set)
output = Pod::UI.output output = Pod::UI.output
output.should.include? "RestKit/Network" output.should.include? "RestKit/Network"
......
...@@ -303,7 +303,7 @@ else ...@@ -303,7 +303,7 @@ else
lockfile_contents = { lockfile_contents = {
'PODS' => [ 'PODS' => [
'JSONKit (1.5pre)', 'JSONKit (999.999.999)',
'Reachability (3.0.0)', 'Reachability (3.0.0)',
'SSZipArchive (0.1.1)', 'SSZipArchive (0.1.1)',
], ],
......
...@@ -8,7 +8,7 @@ module Bacon ...@@ -8,7 +8,7 @@ module Bacon
::Pod::Config.instance = nil ::Pod::Config.instance = nil
::Pod::Config.instance.tap do |c| ::Pod::Config.instance.tap do |c|
ENV['VERBOSE_SPECS'] ? c.verbose = true : c.silent = true ENV['VERBOSE_SPECS'] ? c.verbose = true : c.silent = true
c.repos_dir = SpecHelper.tmp_repos_path c.repos_dir = fixture('spec-repos')
c.project_root = SpecHelper.temporary_directory c.project_root = SpecHelper.temporary_directory
c.doc_install = false c.doc_install = false
c.generate_docs = false c.generate_docs = false
......
...@@ -7,7 +7,6 @@ module Pod ...@@ -7,7 +7,6 @@ module Pod
@podfile = Podfile.new do @podfile = Podfile.new do
platform :ios platform :ios
pod 'BlocksKit' pod 'BlocksKit'
# pod 'ASIWebPageRequest'
end end
@resolver = Resolver.new(@podfile, nil, stub('sandbox')) @resolver = Resolver.new(@podfile, nil, stub('sandbox'))
end end
...@@ -15,9 +14,9 @@ module Pod ...@@ -15,9 +14,9 @@ module Pod
it "holds the context state, such as cached specification sets" do it "holds the context state, such as cached specification sets" do
@resolver.resolve @resolver.resolve
@resolver.cached_sets.values.sort_by(&:name).should == [ @resolver.cached_sets.values.sort_by(&:name).should == [
Spec::Set.new(config.repos_dir + 'master/A2DynamicDelegate'), Pod::Source.search_by_name('A2DynamicDelegate').first,
Spec::Set.new(config.repos_dir + 'master/BlocksKit'), Pod::Source.search_by_name('BlocksKit').first,
Spec::Set.new(config.repos_dir + 'master/libffi'), Pod::Source.search_by_name('libffi').first
].sort_by(&:name) ].sort_by(&:name)
end end
...@@ -35,7 +34,7 @@ module Pod ...@@ -35,7 +34,7 @@ module Pod
end end
it "raises once any of the dependencies does not match the platform of its podfile target" do it "raises once any of the dependencies does not match the platform of its podfile target" do
set = Spec::Set.new(config.repos_dir + 'master/BlocksKit') set = Pod::Source.search_by_name('BlocksKit').first
@resolver.cached_sets['BlocksKit'] = set @resolver.cached_sets['BlocksKit'] = set
def set.stub_platform=(platform); @stubbed_platform = platform; end def set.stub_platform=(platform); @stubbed_platform = platform; end
...@@ -55,7 +54,7 @@ module Pod ...@@ -55,7 +54,7 @@ module Pod
end end
it "raises once any of the dependencies does not have a deployment_target compatible with its podfile target" do it "raises once any of the dependencies does not have a deployment_target compatible with its podfile target" do
set = Spec::Set.new(config.repos_dir + 'master/BlocksKit') set = Pod::Source.search_by_name('BlocksKit').first
@resolver.cached_sets['BlocksKit'] = set @resolver.cached_sets['BlocksKit'] = set
@podfile.platform :ios, "4.0" @podfile.platform :ios, "4.0"
...@@ -371,7 +370,7 @@ module Pod ...@@ -371,7 +370,7 @@ module Pod
it "identifies the pods that can be updated" do it "identifies the pods that can be updated" do
installed = @resolver.resolve.values.flatten.map(&:to_s) installed = @resolver.resolve.values.flatten.map(&:to_s)
installed.should.include? "JSONKit (1.5pre)" installed.should.include? "JSONKit (999.999.999)"
@resolver.should_install?("JSONKit").should.be.true @resolver.should_install?("JSONKit").should.be.true
end end
......
require File.expand_path('../../spec_helper', __FILE__) require File.expand_path('../../spec_helper', __FILE__)
describe "Pod::Source" do describe "Pod::Source" do
extend SpecHelper::Command
extend SpecHelper::TemporaryDirectory
extend SpecHelper::TemporaryRepos
before do before do
add_repo('repo1', fixture('spec-repos/master')) @source = Pod::Source.new(fixture('spec-repos/master'))
(config.repos_dir + 'repo1/JSONKit').rmtree end
add_repo('repo2', fixture('spec-repos/master'))
(config.repos_dir + 'repo2/Reachability').rmtree it "return its name" do
@source.name.should == 'master'
end
it "returns the sets of all the available Pods" do
set_names = @source.pod_sets.map(&:name)
set_names.should.include('JSONKit')
set_names.should.include('Reachability')
end
it "returns the available versions of a Pod" do
@source.versions('Reachability').map(&:to_s).should == %w| 3.0.0 2.0.5 2.0.4 |
end
it "returns the specification of a given version of a Pod" do
spec = @source.specification('Reachability', Pod::Version.new('3.0.0'))
spec.name.should == 'Reachability'
spec.version.should.to_s == '3.0.0'
end
it "properly configures the sources of a set in seach by name" do
source = Pod::Source.new(fixture('spec-repos/test_repo'))
sets = source.search_by_name('monkey', true)
sets.count.should == 1
set = sets.first
set.name.should == 'BananaLib'
set.sources.map(&:name).should == %w| test_repo |
end end
it "returns a specification set by name from any spec repo" do describe "Pod::Source::Aggregate" do
set = Pod::Source.search(Pod::Dependency.new('Reachability')) # BananaLib is available only in test_repo.
set.should == Pod::Spec::Set.new(config.repos_dir + 'repo1/Reachability') # JSONKit is in test repo has version 1.4 (duplicated) and the 999.999.999.
set = Pod::Source.search(Pod::Dependency.new('JSONKit'))
set.should == Pod::Spec::Set.new(config.repos_dir + 'repo2/JSONKit') it "returns all the sources" do
Pod::Source.all.map(&:name).should == %w| master test_repo |
end
it "returns the name of all the available pods" do
pod_names = Pod::Source::Aggregate.new.all_pods
pod_names.should.include('JSONKit')
pod_names.should.include('BananaLib')
end
it "returns all the available sets with the sources configured" do
sets = Pod::Source.all_sets
banana_sets = sets.select{ |set| set.name == 'BananaLib' }
banana_sets.count.should == 1
banana_sets.first.sources.map(&:name).should == %w| test_repo |
json_set = sets.select{ |set| set.name == 'JSONKit' }
json_set.count.should == 1
json_set.first.sources.map(&:name).should == %w| master test_repo |
end end
it "returns a specification set by top level spec name" do it "searches the sets by dependency" do
(config.repos_dir + 'repo2/RestKit').rmtree dep = Pod::Dependency.new('JSONKit')
set = Pod::Source.search(Pod::Dependency.new('RestKit/Network')) set = Pod::Source.search(dep)
set.should == Pod::Spec::Set.new(config.repos_dir + 'repo1/RestKit') set.name.should == 'JSONKit'
set.sources.map(&:name).should == %w| master test_repo |
end
it "searches the sets specifing a dependency on a subspec" do
dep = Pod::Dependency.new('RestKit/JSON')
set = Pod::Source.search(dep)
set.name.should == 'RestKit'
set.sources.map(&:name).should == %w| master |
end end
it "raises if a specification set can't be found" do it "raises if a specification set can't be found" do
lambda { lambda {
Pod::Source.search(Pod::Dependency.new('DoesNotExist')) dep = Pod::Dependency.new('DoesNotExist')
set = Pod::Source.search(dep)
}.should.raise Pod::Informative }.should.raise Pod::Informative
end end
it "raises if a subspec can't be found" do it "raises if a subspec can't be found" do
lambda { lambda {
Pod::Source.search(Pod::Dependency.new('RestKit/DoesNotExist')) dep = Pod::Dependency.new('RestKit/DoesNotExist')
set = Pod::Source.search(dep)
}.should.raise Pod::Informative }.should.raise Pod::Informative
end end
it "return the names of the repos" do it "searches the sets by name" do
Pod::Source.all.map(&:name).should == %w| repo1 repo2 | sets = Pod::Source.search_by_name('JSONKit')
sets.count.should == 1
set = sets.first
set.name.should == 'JSONKit'
set.sources.map(&:name).should == %w| master test_repo |
end
it "properly configures the sources of a set in search by name" do
sets = Pod::Source.search_by_name('BananaLib')
sets.count.should == 1
set = sets.first
set.name.should == 'BananaLib'
set.sources.map(&:name).should == %w| test_repo |
end
end end
end end
require File.expand_path('../../../spec_helper', __FILE__) require File.expand_path('../../../spec_helper', __FILE__)
describe "Pod::Specification::Set" do describe "Pod::Specification::Set" do
describe "In general" do
before do before do
@set = Pod::Spec::Set.new(fixture('spec-repos/master/CocoaLumberjack')) @source = Pod::Source.new(fixture('spec-repos/master'))
@set = Pod::Spec::Set.new('CocoaLumberjack', @source)
end end
it "returns the name of the pod" do it "returns the name of the pod" do
...@@ -29,6 +32,11 @@ describe "Pod::Specification::Set" do ...@@ -29,6 +32,11 @@ describe "Pod::Specification::Set" do
lambda { @set.required_version }.should.raise Pod::Informative lambda { @set.required_version }.should.raise Pod::Informative
end end
it "can returns test if it is equal to another set" do
@set.should == Pod::Spec::Set.new('CocoaLumberjack', @source)
@set.should != Pod::Spec::Set.new('RestKit', @source)
end
before do before do
@set.required_by(Pod::Dependency.new('CocoaLumberjack', '< 1.2.1'), 'Spec') @set.required_by(Pod::Dependency.new('CocoaLumberjack', '< 1.2.1'), 'Spec')
end end
...@@ -37,10 +45,6 @@ describe "Pod::Specification::Set" do ...@@ -37,10 +45,6 @@ describe "Pod::Specification::Set" do
@set.required_version.should == Pod::Version.new('1.2') @set.required_version.should == Pod::Version.new('1.2')
end end
it "returns the path to the specification for the required version" do
@set.specification_path.should == fixture('spec-repos/master/CocoaLumberjack/1.2/CocoaLumberjack.podspec')
end
it "returns the specification for the required version" do it "returns the specification for the required version" do
@set.specification.should == Pod::Spec.new { |s| s.name = 'CocoaLumberjack'; s.version = '1.2' } @set.specification.should == Pod::Spec.new { |s| s.name = 'CocoaLumberjack'; s.version = '1.2' }
end end
...@@ -54,4 +58,52 @@ describe "Pod::Specification::Set" do ...@@ -54,4 +58,52 @@ describe "Pod::Specification::Set" do
spec = Pod::Dependency.new('CocoaLumberjack', '1.2.1') spec = Pod::Dependency.new('CocoaLumberjack', '1.2.1')
lambda { @set.required_by(spec, 'Spec') }.should.raise Pod::Informative lambda { @set.required_by(spec, 'Spec') }.should.raise Pod::Informative
end end
end
describe "Concerning multiple sources" do
before do
# JSONKit is in test repo has version 1.4 (duplicated) and the 999.999.999.
@set = Pod::Source.search_by_name('JSONKit').first
end
it "returns all the available versions sorted from biggest to lowest" do
@set.versions.map(&:to_s).should == %w| 999.999.999 1.5pre 1.4 |
end
it "returns all the available versions by source sorted from bigest to lowest" do
hash = {}
@set.versions_by_source.each { |source, versions| hash[source.name] = versions.map(&:to_s) }
hash['master'].should == %w| 1.5pre 1.4 |
hash['test_repo'].should == %w| 999.999.999 1.4 |
hash.keys.should == %w| master test_repo |
end
it "returns the specification from the `master` source for the required version" do
dep = Pod::Dependency.new('JSONKit', '1.5pre')
@set.required_by(dep, 'Spec')
spec = @set.specification
spec.name.should == 'JSONKit'
spec.version.to_s.should == '1.5pre'
spec.defined_in_file.should == fixture('spec-repos/master/JSONKit/1.5pre/JSONKit.podspec')
end
it "returns the specification from `test_repo` source for the required version" do
dep = Pod::Dependency.new('JSONKit', '999.999.999')
@set.required_by(dep, 'Spec')
spec = @set.specification
spec.name.should == 'JSONKit'
spec.version.to_s.should == '999.999.999'
spec.defined_in_file.should == fixture('spec-repos/test_repo/JSONKit/999.999.999/JSONKit.podspec')
end
it "prefers sources by alphabetical order" do
dep = Pod::Dependency.new('JSONKit', '1.4')
@set.required_by(dep, 'Spec')
spec = @set.specification
spec.name.should == 'JSONKit'
spec.version.to_s.should == '1.4'
spec.defined_in_file.should == fixture('spec-repos/master/JSONKit/1.4/JSONKit.podspec')
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