Commit b455a333 authored by Fabio Pelosin's avatar Fabio Pelosin

[Set] Support for multiple sources.

Closes #85
parent a07d93d1
......@@ -5,17 +5,21 @@
###### Enhancements
- Pod `install` will update the specs repo only if needed.
[#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.
[#486](https://github.com/CocoaPods/CocoaPods/issues/486)
- Support for `header_mappings_dir` attribute in subspecs.
- 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)
- Added config option to disable the new version available message.
[#448](https://github.com/CocoaPods/CocoaPods/issues/448)
- Added support for extracting `.tar.bz2` files
[#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)
......
......@@ -209,7 +209,7 @@ module Pod
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.
#
......
module Pod
class Source
class Aggregate
def all
@sources ||= dirs.map { |repo| Source.new(repo) }
end
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
def all_sets
all.map(&:pod_sets).flatten
end
# The {Source} class is responsible to manage a collection of podspecs.
#
# @note The backing store of the podspecs collection is an implementation detail
# abstraced from the rest of CocoaPods.
#
# @note The default implementation uses a git repo as a backing store, where the
# podspecs are namespaces as:
#
# #{POD_NAME}/#{VERSION}/#{POD_NAME}.podspec
#
# @todo For better abstranction the sources should be responsible to update themselves.
#
class Source
def search(dependency)
all.map { |s| s.search(dependency) }.compact.first ||
raise(Informative, "[!] Unable to find a pod named `#{dependency.name}'".red)
end
# @return [Pathname] The location of the repo.
#
attr_reader :repo
def search_by_name(query, full_text_search)
result = all.map { |s| s.search_by_name(query, full_text_search) }.flatten
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
# @param [Pathname] repo @see repo.
#
def initialize(repo)
@repo = repo
end
def self.all
Aggregate.new.all
# @return [String] the name of the repo.
#
def name
@repo.basename.to_s
end
def self.all_sets
Aggregate.new.all_sets
end
# @!group Quering the source
def self.search(dependency)
Aggregate.new.search(dependency)
# @return [Array<String>] The name of all the Pods.
#
def pods
@repo.children.map do |child|
child.basename.to_s if child.directory? && child.basename.to_s != '.git'
end.compact
end
def self.search_by_name(name, full_text_search)
Aggregate.new.search_by_name(name, full_text_search)
# @return [Array<Sets>] The sets of all the Pods.
#
def pod_sets
pods.map { |pod| Specification::Set.new(pod, self) }
end
attr_reader :repo
def initialize(repo)
@repo = repo
# @return [Array<Version>] All the available versions for the Pod, sorted
# 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
def name
@repo.basename.to_s
# @return [Specification] The specification for a given version of Pod.
#
# @param [String] name The name of the Pod.
#
# @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
def pod_sets
@repo.children.map do |child|
if child.directory? && child.basename.to_s != '.git'
Specification::Set.new(child)
end
end.compact
end
# @!group Searching the source
# @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)
pod_sets.find do |set|
# First match the (top level) name, which does not yet load the spec from disk
......@@ -82,7 +86,19 @@ module Pod
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|
text = if full_text_search
s = set.specification
......@@ -93,5 +109,102 @@ module Pod
set if text.downcase.include?(query.downcase)
end.compact
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
......@@ -2,77 +2,144 @@ require 'active_support/core_ext/array/conversions'
module Pod
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
attr_reader :pod_dir
def initialize(pod_dir)
@pod_dir = pod_dir
@required_by = []
# @return [String] The name of the Pod.
#
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 = []
@dependencies = []
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)
unless @required_by.empty? || dependency.requirement.satisfied_by?(Gem::Version.new(required_version.to_s))
raise Informative, "#{dependent_name} tries to activate `#{dependency}', " \
"but already activated version `#{required_version}' " \
"by #{@required_by.to_sentence}."
raise Informative, "#{dependent_name} tries to activate `#{dependency}', but already activated version `#{required_version}' by #{@required_by.to_sentence}."
end
@specification = nil
@required_by << dependent_name
@required_by << dependent_name
@dependencies << dependency
end
def specification_by_name(name)
specification.top_level_parent.subspec_by_name(name)
end
# @return [Dependency] A dependency including all the versions
# requirements of the stored dependencies.
#
def dependency
@dependencies.inject(Dependency.new(name)) do |previous, dependency|
previous.merge(dependency.to_top_level_spec_dependency)
end
end
def name
@pod_dir.basename.to_s
end
def specification_path
@pod_dir + required_version.to_s + "#{name}.podspec"
# @return [Specification] The specification for the given subspec name,
# from {specification}.
#
# @param [String] name The name of the specification. It can be the
# name of the top level parent or the name of a
# subspec.
#
# @see specification
#
def specification_by_name(name)
specification.top_level_parent.subspec_by_name(name)
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
@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
# Return the first version that matches the current dependency.
# @return [Version] The highest version that satisfies {dependency}.
#
def required_version
versions.find { |v| dependency.match?(name, v) } ||
raise(Informative, "Required version (#{dependency}) not found for `#{name}'.\nAvailable versions: #{versions.join(', ')}")
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)
self.class === other && @pod_dir == other.pod_dir
self.class === other && @name == other.name && @sources.map(&:name) == other.sources.map(&:name)
end
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
alias_method :inspect, :to_s
# Returns Pod::Version instances, for each version directory, sorted from
# highest version to lowest.
def versions
@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
# The Set::External class handles Pods from external sources. Pods from
# external sources don't use the {Pod::Sources} and are intialized by a
# given specification.
#
# @note External sources *don't* support subspecs.
#
class External < Set
def initialize(specification)
@specification = specification
@required_by = []
@dependencies = []
@required_by = []
@dependencies = []
end
def name
......@@ -80,7 +147,7 @@ module Pod
end
def ==(other)
self.class === other && name == other.name
self.class === other && @specification == other.specification
end
def required_by(dependency, dependent_name)
......
......@@ -78,7 +78,7 @@ module Pod
def compute_creation_date(set, save = true)
date = get_value(set, :creation_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)
end
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__)
describe "Pod::Command::List" do
extend SpecHelper::TemporaryRepos
before do
config.repos_dir = fixture('spec-repos')
end
def command(arguments = argv)
command = Pod::Command::List.new(arguments)
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
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
it "presents the known pods" do
list = command()
list.run
[
/ZBarSDK/,
[ /ZBarSDK/,
/TouchJSON/,
/SDURLCache/,
/MagicalRecord/,
......
......@@ -5,6 +5,10 @@ describe Pod::Command::Push do
extend SpecHelper::TemporaryDirectory
extend SpecHelper::TemporaryRepos
before do
config.repos_dir = SpecHelper.tmp_repos_path
end
def master_repo
fixture('spec-repos/master')
end
......
require File.expand_path('../../../spec_helper', __FILE__)
describe "Pod::Command::Repo" do
before do
config.repos_dir = SpecHelper.tmp_repos_path
end
describe "In general" do
extend SpecHelper::Command
extend SpecHelper::TemporaryDirectory
......
......@@ -6,6 +6,10 @@ describe "Pod::Command::Setup" do
extend SpecHelper::TemporaryDirectory
extend SpecHelper::TemporaryRepos
before do
config.repos_dir = SpecHelper.tmp_repos_path
end
it "runs with correct parameters" do
lambda { run_command('setup') }.should.not.raise
end
......
......@@ -5,7 +5,7 @@ describe Pod::UI do
extend SpecHelper::Command
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
end
......@@ -34,7 +34,7 @@ describe Pod::UI do
end
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)
output = Pod::UI.output
output.should.include? "RestKit/Network"
......
......@@ -303,7 +303,7 @@ else
lockfile_contents = {
'PODS' => [
'JSONKit (1.5pre)',
'JSONKit (999.999.999)',
'Reachability (3.0.0)',
'SSZipArchive (0.1.1)',
],
......
......@@ -8,7 +8,7 @@ module Bacon
::Pod::Config.instance = nil
::Pod::Config.instance.tap do |c|
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.doc_install = false
c.generate_docs = false
......
......@@ -7,7 +7,6 @@ module Pod
@podfile = Podfile.new do
platform :ios
pod 'BlocksKit'
# pod 'ASIWebPageRequest'
end
@resolver = Resolver.new(@podfile, nil, stub('sandbox'))
end
......@@ -15,9 +14,9 @@ module Pod
it "holds the context state, such as cached specification sets" do
@resolver.resolve
@resolver.cached_sets.values.sort_by(&:name).should == [
Spec::Set.new(config.repos_dir + 'master/A2DynamicDelegate'),
Spec::Set.new(config.repos_dir + 'master/BlocksKit'),
Spec::Set.new(config.repos_dir + 'master/libffi'),
Pod::Source.search_by_name('A2DynamicDelegate').first,
Pod::Source.search_by_name('BlocksKit').first,
Pod::Source.search_by_name('libffi').first
].sort_by(&:name)
end
......@@ -35,7 +34,7 @@ module Pod
end
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
def set.stub_platform=(platform); @stubbed_platform = platform; end
......@@ -55,7 +54,7 @@ module Pod
end
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
@podfile.platform :ios, "4.0"
......@@ -371,7 +370,7 @@ module Pod
it "identifies the pods that can be updated" do
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
end
......
require File.expand_path('../../spec_helper', __FILE__)
describe "Pod::Source" do
extend SpecHelper::Command
extend SpecHelper::TemporaryDirectory
extend SpecHelper::TemporaryRepos
before do
add_repo('repo1', fixture('spec-repos/master'))
(config.repos_dir + 'repo1/JSONKit').rmtree
add_repo('repo2', fixture('spec-repos/master'))
(config.repos_dir + 'repo2/Reachability').rmtree
@source = Pod::Source.new(fixture('spec-repos/master'))
end
it "return its name" do
@source.name.should == 'master'
end
it "returns a specification set by name from any spec repo" do
set = Pod::Source.search(Pod::Dependency.new('Reachability'))
set.should == Pod::Spec::Set.new(config.repos_dir + 'repo1/Reachability')
set = Pod::Source.search(Pod::Dependency.new('JSONKit'))
set.should == Pod::Spec::Set.new(config.repos_dir + 'repo2/JSONKit')
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 a specification set by top level spec name" do
(config.repos_dir + 'repo2/RestKit').rmtree
set = Pod::Source.search(Pod::Dependency.new('RestKit/Network'))
set.should == Pod::Spec::Set.new(config.repos_dir + 'repo1/RestKit')
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 "raises if a specification set can't be found" do
lambda {
Pod::Source.search(Pod::Dependency.new('DoesNotExist'))
}.should.raise Pod::Informative
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 "raises if a subspec can't be found" do
lambda {
Pod::Source.search(Pod::Dependency.new('RestKit/DoesNotExist'))
}.should.raise Pod::Informative
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
it "return the names of the repos" do
Pod::Source.all.map(&:name).should == %w| repo1 repo2 |
describe "Pod::Source::Aggregate" do
# BananaLib is available only in test_repo.
# JSONKit is in test repo has version 1.4 (duplicated) and the 999.999.999.
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
it "searches the sets by dependency" do
dep = Pod::Dependency.new('JSONKit')
set = Pod::Source.search(dep)
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
it "raises if a specification set can't be found" do
lambda {
dep = Pod::Dependency.new('DoesNotExist')
set = Pod::Source.search(dep)
}.should.raise Pod::Informative
end
it "raises if a subspec can't be found" do
lambda {
dep = Pod::Dependency.new('RestKit/DoesNotExist')
set = Pod::Source.search(dep)
}.should.raise Pod::Informative
end
it "searches the sets by name" do
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
require File.expand_path('../../../spec_helper', __FILE__)
describe "Pod::Specification::Set" do
before do
@set = Pod::Spec::Set.new(fixture('spec-repos/master/CocoaLumberjack'))
end
it "returns the name of the pod" do
@set.name.should == 'CocoaLumberjack'
end
describe "In general" do
before do
@source = Pod::Source.new(fixture('spec-repos/master'))
@set = Pod::Spec::Set.new('CocoaLumberjack', @source)
end
it "returns the versions available for this pod ordered from highest to lowest" do
@set.versions.should == %w[1.6 1.3.3 1.3.2 1.3.1 1.3 1.2.3 1.2.2 1.2.1 1.2 1.1 1.0].map { |v| Pod::Version.new(v) }
end
it "returns the name of the pod" do
@set.name.should == 'CocoaLumberjack'
end
it "checks if the dependency of the specification is compatible with existing requirements" do
@set.required_by(Pod::Dependency.new('CocoaLumberjack', '1.2'), 'Spec')
@set.required_by(Pod::Dependency.new('CocoaLumberjack', '< 1.2.1'), 'Spec')
@set.required_by(Pod::Dependency.new('CocoaLumberjack', '> 1.1'), 'Spec')
@set.required_by(Pod::Dependency.new('CocoaLumberjack', '~> 1.2.0'), 'Spec')
@set.required_by(Pod::Dependency.new('CocoaLumberjack'), 'Spec')
lambda {
@set.required_by(Pod::Dependency.new('CocoaLumberjack', '< 1.0' ), 'Spec')
}.should.raise Pod::Informative
end
it "returns the versions available for this pod ordered from highest to lowest" do
@set.versions.should == %w[1.6 1.3.3 1.3.2 1.3.1 1.3 1.2.3 1.2.2 1.2.1 1.2 1.1 1.0].map { |v| Pod::Version.new(v) }
end
it "raises if the required version doesn't exist" do
@set.required_by(Pod::Dependency.new('CocoaLumberjack', '< 1.0'), 'Spec')
lambda { @set.required_version }.should.raise Pod::Informative
end
it "checks if the dependency of the specification is compatible with existing requirements" do
@set.required_by(Pod::Dependency.new('CocoaLumberjack', '1.2'), 'Spec')
@set.required_by(Pod::Dependency.new('CocoaLumberjack', '< 1.2.1'), 'Spec')
@set.required_by(Pod::Dependency.new('CocoaLumberjack', '> 1.1'), 'Spec')
@set.required_by(Pod::Dependency.new('CocoaLumberjack', '~> 1.2.0'), 'Spec')
@set.required_by(Pod::Dependency.new('CocoaLumberjack'), 'Spec')
lambda {
@set.required_by(Pod::Dependency.new('CocoaLumberjack', '< 1.0' ), 'Spec')
}.should.raise Pod::Informative
end
before do
@set.required_by(Pod::Dependency.new('CocoaLumberjack', '< 1.2.1'), 'Spec')
end
it "raises if the required version doesn't exist" do
@set.required_by(Pod::Dependency.new('CocoaLumberjack', '< 1.0'), 'Spec')
lambda { @set.required_version }.should.raise Pod::Informative
end
it "returns the version required for the dependency" do
@set.required_version.should == Pod::Version.new('1.2')
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
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
before do
@set.required_by(Pod::Dependency.new('CocoaLumberjack', '< 1.2.1'), 'Spec')
end
it "returns the specification for the required version" do
@set.specification.should == Pod::Spec.new { |s| s.name = 'CocoaLumberjack'; s.version = '1.2' }
end
it "returns the version required for the dependency" do
@set.required_version.should == Pod::Version.new('1.2')
end
it "ignores dotfiles when getting the version directories" do
`touch #{fixture('spec-repos/master/CocoaLumberjack/.DS_Store')}`
lambda { @set.versions }.should.not.raise
it "returns the specification for the required version" do
@set.specification.should == Pod::Spec.new { |s| s.name = 'CocoaLumberjack'; s.version = '1.2' }
end
it "ignores dotfiles when getting the version directories" do
`touch #{fixture('spec-repos/master/CocoaLumberjack/.DS_Store')}`
lambda { @set.versions }.should.not.raise
end
it "raises if a version is incompatible with the activated version" do
spec = Pod::Dependency.new('CocoaLumberjack', '1.2.1')
lambda { @set.required_by(spec, 'Spec') }.should.raise Pod::Informative
end
end
it "raises if a version is incompatible with the activated version" do
spec = Pod::Dependency.new('CocoaLumberjack', '1.2.1')
lambda { @set.required_by(spec, 'Spec') }.should.raise Pod::Informative
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
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