Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

[Set] Support for multiple sources.

Closes #85
  • Loading branch information...
commit b455a333095a902080e43b3a185655d2e61c39c3 1 parent a07d93d
Fabio Pelosin fabiopelosin authored
8 CHANGELOG.md
View
@@ -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)
2  lib/cocoapods/resolver.rb
View
@@ -209,7 +209,7 @@ def find_dependency_specs(dependent_specification, dependencies, target_definiti
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.
#
227 lib/cocoapods/source.rb
View
@@ -1,77 +1,81 @@
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 @@ def search(dependency)
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 @@ def search_by_name(query, full_text_search)
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
135 lib/cocoapods/specification/set.rb
View
@@ -2,77 +2,144 @@
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 @@ def name
end
def ==(other)
- self.class === other && name == other.name
+ self.class === other && @specification == other.specification
end
def required_by(dependency, dependent_name)
2  lib/cocoapods/specification/statistics.rb
View
@@ -78,7 +78,7 @@ def save_cache
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)
27 spec/fixtures/spec-repos/test_repo/BananaLib/1.0/BananaLib.podspec
View
@@ -0,0 +1,27 @@
+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
11 spec/fixtures/spec-repos/test_repo/JSONKit/1.4/JSONKit.podspec
View
@@ -0,0 +1,11 @@
+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
12 spec/fixtures/spec-repos/test_repo/JSONKit/999.999.999/JSONKit.podspec
View
@@ -0,0 +1,12 @@
+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
12 spec/functional/command/list_spec.rb
View
@@ -3,19 +3,10 @@
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 @@ def command(arguments = argv)
it "presents the known pods" do
list = command()
list.run
- [
- /ZBarSDK/,
+ [ /ZBarSDK/,
/TouchJSON/,
/SDURLCache/,
/MagicalRecord/,
4 spec/functional/command/push_spec.rb
View
@@ -5,6 +5,10 @@
extend SpecHelper::TemporaryDirectory
extend SpecHelper::TemporaryRepos
+ before do
+ config.repos_dir = SpecHelper.tmp_repos_path
+ end
+
def master_repo
fixture('spec-repos/master')
end
5 spec/functional/command/repo_spec.rb
View
@@ -1,6 +1,11 @@
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
4 spec/functional/command/setup_spec.rb
View
@@ -6,6 +6,10 @@
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
4 spec/functional/user_interface_spec.rb
View
@@ -5,7 +5,7 @@
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 @@
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"
2  spec/integration_spec.rb
View
@@ -303,7 +303,7 @@ def should_xcodebuild(target_definition)
lockfile_contents = {
'PODS' => [
- 'JSONKit (1.5pre)',
+ 'JSONKit (999.999.999)',
'Reachability (3.0.0)',
'SSZipArchive (0.1.1)',
],
2  spec/spec_helper/config.rb
View
@@ -8,7 +8,7 @@ class Context
::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
13 spec/unit/resolver_spec.rb
View
@@ -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 @@ def set.specification; spec = super; spec.platform = @stubbed_platform; spec; en
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 @@ def set.specification; spec = super; spec.platform = @stubbed_platform; spec; en
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
117 spec/unit/source_spec.rb
View
@@ -1,43 +1,106 @@
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
134 spec/unit/specification/set_spec.rb
View
@@ -1,57 +1,109 @@
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

1 comment on commit b455a33

Eloy Durán
Owner

Awesome work, also on all the docs.

Please sign in to comment.
Something went wrong with that request. Please try again.