Commit 1baebf67 authored by Fabio Pelosin's avatar Fabio Pelosin

[Resolver] Clean-up and specs update.

parent ff745f82
...@@ -5,186 +5,253 @@ module Pod ...@@ -5,186 +5,253 @@ module Pod
# #
# Its current implementation is naive, in the sense that it can't do full # Its current implementation is naive, in the sense that it can't do full
# automatic resolves like Bundler: # automatic resolves like Bundler:
# # [how-does-bundler-bundle](http://patshaughnessy.net/2011/9/24/how-does-bundler-bundle)
# http://patshaughnessy.net/2011/9/24/how-does-bundler-bundle
# #
# Another important aspect to keep in mind of the current implementation # Another important aspect to keep in mind of the current implementation
# is that the order of the dependencies matters. # is that the order of the dependencies matters.
# #
class Resolver class Resolver
include Config::Mixin include Config::Mixin
# @return [Sandbox] The Sandbox used by the resolver to find external # @return [Sandbox] the Sandbox used by the resolver to find external
# dependencies. # dependencies.
# #
attr_reader :sandbox attr_reader :sandbox
# @return [Podfile] The Podfile used by the resolver. # @return [Podfile] the Podfile used by the resolver.
# #
attr_reader :podfile attr_reader :podfile
# @return [Array<Dependency>] The list of dependencies locked to a specific # @return [Array<Dependency>] the list of dependencies locked to a specific
# version. # version.
# #
attr_reader :locked_dependencies attr_reader :locked_dependencies
# @return [Bool] Whether the resolver should update the external specs # @return [Bool] whether the resolver should update the external specs
# in the resolution process. This option is used for detecting changes # in the resolution process. This option is used for detecting
# in with the Podfile without affecting the existing Pods installation # changes in with the Podfile without affecting the existing Pods
# (see `pod outdated`). # installation
#
# @note This option is used by `pod outdated`.
# #
# @TODO: This implementation is not clean, because if the spec doesn't # @TODO: This implementation is not clean, because if the spec doesn't
# exists the sandbox will actually download it and result modified. # exists the sandbox will actually download and modify the
# installation.
# #
attr_accessor :update_external_specs attr_accessor :update_external_specs
# @param [Sandbox] sandbox @see sandbox
# @param [Podfile] podfile @see podfile
# @param [Array<Dependency>] locked_dependencies @see locked_dependencies
#
def initialize(sandbox, podfile, locked_dependencies = []) def initialize(sandbox, podfile, locked_dependencies = [])
@sandbox = sandbox @sandbox = sandbox
@podfile = podfile @podfile = podfile
@locked_dependencies = locked_dependencies @locked_dependencies = locked_dependencies
end end
# @return [Hash{Podfile::TargetDefinition => Array<Specification>}] #-------------------------------------------------------------------------#
# Returns the resolved specifications grouped by target.
#
attr_reader :specs_by_target
# @return [Array<Specification>] All The specifications loaded by the # @!group Resolution
# resolver.
#
def specs
@cached_specs.values.uniq
end
# @return [Array<Strings>] The name of the pods that have an public
# external source.
#
# @TODO: Add an attribute to the specification class?
#
attr_reader :pods_from_external_sources
# Identifies the specifications that should be installed.
#
# @return [Hash{TargetDefinition => Array<Specification>}] specs_by_target # @return [Hash{TargetDefinition => Array<Specification>}] specs_by_target
# Identifies the specifications that should be installed according # the specifications that need to be installed grouped by target
# whether the resolver is in update mode or not. # definition.
# #
def resolve def resolve
@cached_sources = Source::Aggregate.new(config.repos_dir) @cached_sources = Source::Aggregate.new(config.repos_dir)
@cached_sets = {} @cached_sets = {}
@cached_specs = {} @cached_specs = {}
@specs_by_target = {} @specs_by_target = {}
@pods_from_external_sources = [] # @pods_from_external_sources = []
podfile.target_definitions.values.each do |target_definition| podfile.target_definitions.values.each do |target|
UI.section "Resolving dependencies for target `#{target_definition.name}' (#{target_definition.platform})" do UI.section "Resolving dependencies for target `#{target.name}' (#{target.platform})" do
@loaded_specs = [] @loaded_specs = []
find_dependency_specs(podfile, target_definition.dependencies, target_definition) find_dependency_specs(podfile, target.dependencies, target)
@specs_by_target[target_definition] = @cached_specs.values_at(*@loaded_specs).sort_by(&:name) specs = cached_specs.values_at(*@loaded_specs).sort_by(&:name)
specs_by_target[target] = specs
end end
end end
@cached_specs.values.sort_by(&:name) cached_specs.values.sort_by(&:name)
@specs_by_target specs_by_target
end end
#-----------------------------------------------------------------------# # @return [Hash{Podfile::TargetDefinition => Array<Specification>}]
# returns the resolved specifications grouped by target.
#
# @note The returned specifications can be subspecs.
#
attr_reader :specs_by_target
private # @return [Array<Specification>] All the specifications resolved.
#
def specs
specs_by_target.values.flatten.uniq
end
# @return [Array<Set>] A cache of the sets used to resolve the dependencies. # @return [Array<Strings>] The name of the pods that have an
# external source.
#
# TODO: Not sure if needed.
# #
attr_reader :cached_sets # attr_reader :pods_from_external_sources
#-------------------------------------------------------------------------#
# !@ Resolution context
private
# @return [Source::Aggregate] A cache of the sources needed to find the # @return [Source::Aggregate] A cache of the sources needed to find the
# podspecs. # podspecs.
# #
attr_reader :cached_sources # TODO: Cache the sources globally?
#
attr_accessor :cached_sources
# @return [void] Resolves recursively the dependencies of a specification # @return [Hash<String => Set>] A cache that keeps tracks of the sets
# and stores them in @cached_specs # loaded by the resolution process.
# #
# @param [Specification] dependent_specification # @note Sets keep track of the TODO:
# The specification whose dependencies are being resolved. #
attr_accessor :cached_sets
#
#
attr_accessor :cached_specs
#
#
attr_writer :specs_by_target
#-------------------------------------------------------------------------#
# !@ Resolution helpers
private
# Resolves recursively the dependencies of a specification and stores them
# in the @cached_specs ivar.
#
# @param [Podfile, Specification] dependent_spec
# the specification whose dependencies are being resolved.
# #
# @param [Array<Dependency>] dependencies # @param [Array<Dependency>] dependencies
# The dependencies of the specification. # the dependencies of the specification.
# #
# @param [TargetDefinition] target_definition # @param [TargetDefinition] target_definition
# The target definition that owns the specification. # the target definition that owns the specification.
#
# @note If there is a locked dependency with the same name of a
# given dependency the locked one is used in place of the
# dependency of the specification. In this way it is possible to
# not updated the installed pods without without introducing
# dependencies in other target definitions.
# TODO: Just add the requirement to the set?
# TODO: Use root name?
#
# @note The recursive process checks if a dependency has already been
# loaded to prevent an infinite loop. For this reason the
# @loaded_specs ivar must be cleaned when changing target
# definition.
#
# #
def find_dependency_specs(dependent_specification, dependencies, target_definition) # TODO: The set class should be aware whether it is in head mode.
#
# @return [void]
#
def find_dependency_specs(dependent_spec, dependencies, target_definition)
dependencies.each do |dependency| dependencies.each do |dependency|
# Replace the dependency with a more specific one if the pod is already locked_dep = locked_dependencies.find { |ld| ld.name == dependency.name }
# installed.
# @TODO: check for compatibility?
locked_dep = locked_dependencies.find { |locked| locked.name == dependency.name }
dependency = locked_dep if locked_dep dependency = locked_dep if locked_dep
UI.message("- #{dependency}", '', 2) do UI.message("- #{dependency}", '', 2) do
set = find_cached_set(dependency, target_definition.platform) set = find_cached_set(dependency, target_definition.platform)
set.required_by(dependency, dependent_specification.to_s) set.required_by(dependency, dependent_spec.to_s)
# Ensure we don't resolve the same spec twice for one target unless @loaded_specs.include?(dependency.name)
if @loaded_specs.include?(dependency.name)
validate_platform(@cached_specs[dependency.name], target_definition)
else
spec = set.specification.subspec_by_name(dependency.name) spec = set.specification.subspec_by_name(dependency.name)
@pods_from_external_sources << spec.pod_name if dependency.external?
@loaded_specs << spec.name @loaded_specs << spec.name
@cached_specs[spec.name] = spec cached_specs[spec.name] = spec
# Configure the specification # @pods_from_external_sources << spec.root_name if dependency.external?
validate_platform(spec, target_definition)
spec.activate_platform(target_definition.platform) spec.activate_platform(target_definition.platform)
spec.version.head = dependency.head? spec.version.head = dependency.head?
# And recursively load the dependencies of the spec.
find_dependency_specs(spec, spec.dependencies, target_definition)
validate_platform(spec, target_definition) find_dependency_specs(spec, spec.dependencies, target_definition)
end end
end end
end end
end end
# @return [Set] The cached set for a given dependency. # Loads or returns a previously initialized {Set} for the given dependency.
#
# @param [Dependency] dependency
# the dependency for which the set is needed.
# TODO: check dependency.specification
# #
# If the update_external_specs flag is activated the dependencies with # @param [Platform] platform
# external sources are always resolved against the remote. Otherwise the # the platform on which the dependency is needed this is used by
# specification is retrieved from the sandbox that fetches the external # the sandbox to locate external sources.
# source only if needed. # TODO why?
#
# @note If the {#update_external_specs} flag is activated the
# dependencies with external sources are always resolved against
# the remote. Otherwise the specification is retrieved from the
# sandbox that fetches the external source only if needed.
#
# TODO If the set is loaded from a normal source and then from an
# external one that information is lost.
#
# @return [Set] the cached set for a given dependency.
# #
def find_cached_set(dependency, platform) def find_cached_set(dependency, platform)
set_name = dependency.name.split('/').first name = dependency.root_name
@cached_sets[set_name] ||= begin unless cached_sets[name]
if dependency.specification if dependency.specification
Specification::Set::External.new(dependency.specification) set = Specification::Set::External.new(dependency.specification)
elsif external_source = dependency.external_source elsif dependency.external_source
if update_external_specs set = set_from_external_source(dependency, platform)
external_source = ExternalSources.from_dependency(dependency)
spec = external_source.specification_from_external(@sandbox, platform)
else else
external_source = ExternalSources.from_dependency(dependency) set = cached_sources.search(dependency)
spec = external_source.specification_from_sandbox(@sandbox, platform)
end end
set = Specification::Set::External.new(spec) cached_sets[name] = set
if dependency.subspec_dependency?
@cached_sets[dependency.root_name] ||= set
end end
set cached_sets[name]
else
cached_sources.search(dependency)
end end
# Returns a new set created from an external source
#
def set_from_external_source(dependency, platform)
source = ExternalSources.from_dependency(dependency)
spec = if update_external_specs
source.specification_from_external(@sandbox, platform)
else
source.specification_from_sandbox(@sandbox, platform)
end end
set = Specification::Set::External.new(spec)
set
end end
# @return [void] Ensures that a spec is compatible with the platform of a # Ensures that a spec is compatible with the platform of a target.
# target.
# #
# @raises If the spec is not supported by the target. # @raises If the spec is not supported by the target.
# #
# @return [void]
#
def validate_platform(spec, target) def validate_platform(spec, target)
unless spec.available_platforms.any? { |platform| target.platform.supports?(platform) } unless spec.available_platforms.any? { |p| target.platform.supports?(p) }
raise Informative, "The platform of the target `#{target.name}' "\ raise Informative, "The platform of the target `#{target.name}` " \
"(#{target.platform}) is not compatible with `#{spec}' which " \ "(#{target.platform}) is not compatible with `#{spec}` which has " \
"has a minimum requirement of #{spec.available_platforms.join(' - ')}." "a minimum requirement of #{spec.available_platforms.join(' - ')}."
end end
end end
end end
......
...@@ -2,90 +2,104 @@ require File.expand_path('../../spec_helper', __FILE__) ...@@ -2,90 +2,104 @@ require File.expand_path('../../spec_helper', __FILE__)
module Pod module Pod
describe Resolver do describe Resolver do
describe "In general" do
before do before do
config.repos_dir = fixture('spec-repos') config.repos_dir = fixture('spec-repos')
@podfile = Podfile.new do @podfile = Podfile.new do
platform :ios platform :ios
pod 'BlocksKit', '1.5.2' pod 'BlocksKit', '1.5.2'
end end
@resolver = Resolver.new(config.sandbox, @podfile) locked_deps = [Dependency.new('BlocksKit', '1.5.2')]
@resolver = Resolver.new(config.sandbox, @podfile, locked_deps)
end end
it "holds the context state, such as cached specification sets" do it "returns the sandbox" do
@resolver.resolve @resolver.sandbox.should == config.sandbox
cached_sets = @resolver.send(:cached_sets)
cached_sets.values.sort_by(&:name).should == [
Source.search_by_name('A2DynamicDelegate').first,
Source.search_by_name('BlocksKit').first,
Source.search_by_name('libffi').first
].sort_by(&:name)
end end
it "returns all specs needed for the dependency" do it "returns the podfile" do
specs = @resolver.resolve.values.flatten @resolver.podfile.should == @podfile
specs.map(&:class).uniq.should == [Specification]
specs.map(&:name).sort.should == %w{ A2DynamicDelegate BlocksKit libffi }
end end
it "does not raise if all dependencies match the platform of the root spec (Podfile)" do it "returns the locked dependencies" do
@podfile.platform :ios, '6.0' @resolver.locked_dependencies.should == [Dependency.new('BlocksKit', '1.5.2')]
lambda { @resolver.resolve }.should.not.raise
@podfile.platform :osx, '10.7'
lambda { @resolver.resolve }.should.not.raise
end end
it "raises once any of the dependencies does not match the platform of its podfile target" do it "allows to specify whether the external sources should be updated against the remote" do
set = Source.search_by_name('BlocksKit').first # TODO
cached_sets = @resolver.send(:cached_sets) @resolver.update_external_specs = true
@resolver.stubs(:cached_sets).returns({'BlocksKit' => set}) @resolver.update_external_specs.should.be.true
end
def set.stub_platform=(platform); @stubbed_platform = platform; end #--------------------------------------#
def set.specification; spec = super; spec.platform = @stubbed_platform; spec; end
@podfile.platform :ios it "resolves the specification of the podfile" do
set.stub_platform = :ios target_definition = @podfile.target_definitions[:default]
lambda { @resolver.resolve }.should.not.raise specs = @resolver.resolve[target_definition]
set.stub_platform = :osx specs.map(&:to_s).should == [
lambda { @resolver.resolve }.should.raise Pod::StandardError "A2DynamicDelegate (2.0.2)",
"BlocksKit (1.5.2)",
"libffi (3.0.11)"
]
end
@podfile.platform :osx it "returns the resolved specifications grouped by target definition" do
set.stub_platform = :osx @resolver.resolve
lambda { @resolver.resolve }.should.not.raise target_definition = @podfile.target_definitions[:default]
set.stub_platform = :ios specs = @resolver.specs_by_target[target_definition]
lambda { @resolver.resolve }.should.raise Pod::StandardError specs.map(&:to_s).should == [
"A2DynamicDelegate (2.0.2)",
"BlocksKit (1.5.2)",
"libffi (3.0.11)"
]
end end
it "raises once any of the dependencies does not have a deployment_target compatible with its podfile target" do it "returns all the resolved specifications" do
set = Source.search_by_name('BlocksKit').first @resolver.resolve
@resolver.stubs(:cached_sets).returns({'BlocksKit' => set}) @resolver.specs.map(&:class).uniq.should == [Specification]
@podfile.platform :ios, "4.0" @resolver.specs.map(&:to_s).should == [
"A2DynamicDelegate (2.0.2)",
"BlocksKit (1.5.2)",
"libffi (3.0.11)"
]
end
Specification.any_instance.stubs(:available_platforms).returns([ Platform.new(:ios, '4.0'), Platform.new(:osx, '10.7') ]) xit "returns the specifications that originated from external sources" do
lambda { @resolver.resolve }.should.not.raise
Specification.any_instance.stubs(:available_platforms).returns([ Platform.new(:ios, '5.0'), Platform.new(:osx, '10.7') ])
lambda { @resolver.resolve }.should.raise Pod::StandardError
end end
end
#-------------------------------------------------------------------------#
it "resolves subspecs" do describe "Resolution" do
before do
config.repos_dir = fixture('spec-repos')
@podfile = Podfile.new do @podfile = Podfile.new do
platform :ios platform :ios, '6.0'
pod 'RestKit/Network' pod 'BlocksKit', '1.5.2'
pod 'RestKit/ObjectMapping/XML'
end end
resolver = Resolver.new(@podfile, nil, stub('sandbox')) @resolver = Resolver.new(config.sandbox, @podfile)
resolver.resolve.values.flatten.map(&:name).sort.should == %w{ end
FileMD5Hash
ISO8601DateFormatter
LibComponentLogging-Core it "holds the context state, such as cached specification sets" do
LibComponentLogging-NSLog @resolver.resolve
NSData+Base64 cached_sets = @resolver.send(:cached_sets)
RestKit/Network cached_sets.values.sort_by(&:name).should == [
RestKit/ObjectMapping/XML Source.search_by_name('A2DynamicDelegate').first,
SOCKit Source.search_by_name('BlocksKit').first,
XMLReader Source.search_by_name('libffi').first
cocoa-oauth ].sort_by(&:name)
} end
it "raises once any of the dependencies does not match the platform of its podfile target" do
Specification.any_instance.stubs(:available_platforms).returns([Platform.new(:ios, '999')])
e = lambda { @resolver.resolve }.should.raise Informative
e.message.should.match(/platform .* not compatible/)
end
it "does not raise if all dependencies are supported by the platform of the target definition" do
lambda { @resolver.resolve }.should.not.raise
end end
it "includes all the subspecs of a specification node" do it "includes all the subspecs of a specification node" do
...@@ -93,7 +107,7 @@ module Pod ...@@ -93,7 +107,7 @@ module Pod
platform :ios platform :ios
pod 'RestKit' pod 'RestKit'
end end
resolver = Resolver.new(@podfile, nil, stub('sandbox')) resolver = Resolver.new(config.sandbox, @podfile)
resolver.resolve.values.flatten.map(&:name).sort.should == %w{ resolver.resolve.values.flatten.map(&:name).sort.should == %w{
FileMD5Hash FileMD5Hash
ISO8601DateFormatter ISO8601DateFormatter
...@@ -112,58 +126,6 @@ module Pod ...@@ -112,58 +126,6 @@ module Pod
} }
end end
# TODO inline podspecs are deprecated
xit "it includes only the main subspec of a specification node" do
spec = Spec.new do |s|
s.name = 'RestKit'
s.version = '9999990.10.0'
s.preferred_dependency = 'JSON'
s.subspec 'JSON' do |js|
js.dependency 'RestKit/Network'
js.dependency 'RestKit/UI'
js.dependency 'RestKit/ObjectMapping/JSON'
js.dependency 'RestKit/ObjectMapping/CoreData'
end
s.subspec 'Network' do |ns|
ns.dependency 'LibComponentLogging-NSLog', '>= 1.0.4'
end
s.subspec 'UI'
s.subspec 'ObjectMapping' do |os|
os.subspec 'JSON'
os.subspec 'XML'
os.subspec 'CoreData'
end
end
@podfile = Podfile.new do
platform :ios
pod 'RestKit'
end
Set.any_instance.stubs(:specification).returns(spec)
resolver = Resolver.new(@podfile, nil, stub('sandbox'))
resolver.find_cached_set()
specs = resolver.resolve.values.flatten.map(&:name).sort
specs.should.not.include 'RestKit/ObjectMapping/XML'
spec = resolver.specs_by_target.values.first.first
spec.name.should == 'test'
spec.version.should == '9999990.10.0'
specs.should == %w{
LibComponentLogging-Core
LibComponentLogging-NSLog
RestKit
RestKit/JSON
RestKit/Network
RestKit/ObjectMapping/CoreData
RestKit/ObjectMapping/JSON
RestKit/UI
}
end
it "resolves subspecs with external constraints" do it "resolves subspecs with external constraints" do
@podfile = Podfile.new do @podfile = Podfile.new do
platform :ios platform :ios
...@@ -185,7 +147,7 @@ module Pod ...@@ -185,7 +147,7 @@ module Pod
end end
end end
ExternalSources::GitSource.any_instance.stubs(:specification_from_sandbox).returns(spec) ExternalSources::GitSource.any_instance.stubs(:specification_from_sandbox).returns(spec)
resolver = Resolver.new(@podfile, nil, stub('sandbox')) resolver = Resolver.new(config.sandbox, @podfile)
resolver.resolve.values.flatten.map(&:name).sort.should == %w{ MainSpec/FirstSubSpec MainSpec/FirstSubSpec/SecondSubSpec } resolver.resolve.values.flatten.map(&:name).sort.should == %w{ MainSpec/FirstSubSpec MainSpec/FirstSubSpec/SecondSubSpec }
end end
...@@ -195,257 +157,253 @@ module Pod ...@@ -195,257 +157,253 @@ module Pod
pod 'FileMD5Hash' pod 'FileMD5Hash'
pod 'JSONKit', :head pod 'JSONKit', :head
end end
resolver = Resolver.new(podfile, nil, stub('sandbox')) resolver = Resolver.new(config.sandbox, podfile)
filemd5hash, jsonkit = resolver.resolve.values.first.sort_by(&:name) filemd5hash, jsonkit = resolver.resolve.values.first.sort_by(&:name)
filemd5hash.version.should.not.be.head filemd5hash.version.should.not.be.head
jsonkit.version.should.be.head jsonkit.version.should.be.head
end end
it "accepts a nil lockfile" do
lambda { Resolver.new(@podfile, nil, stub('sandbox'))}.should.not.raise
end
it "raises if it finds two conflicting dependencies" do it "raises if it finds two conflicting dependencies" do
podfile = Podfile.new do podfile = Podfile.new do
platform :ios platform :ios
pod 'JSONKit', "1.4" pod 'JSONKit', "1.4"
pod 'JSONKit', "1.5pre" pod 'JSONKit', "1.5pre"
end end
resolver = Resolver.new(podfile, nil, stub('sandbox')) resolver = Resolver.new(config.sandbox, podfile)
lambda {resolver.resolve}.should.raise Pod::StandardError e = lambda {resolver.resolve}.should.raise Pod::StandardError
e.message.should.match(/already activated version/)
end
# describe "Concerning Installation mode" do
# before do
# config.repos_dir = fixture('spec-repos')
# @podfile = Podfile.new do
# platform :ios
# pod 'BlocksKit', '1.5.2'
# pod 'JSONKit'
# end
# @specs = [
# Specification.new do |s|
# s.name = "BlocksKit"
# s.version = "1.5.2"
# end,
# Specification.new do |s|
# s.name = "JSONKit"
# s.version = "1.4"
# end ]
# @specs.each { |s| s.activate_platform(:ios) }
# @resolver = Resolver.new(@podfile, @lockfile, stub('sandbox'))
# end
# it "doesn't install pods still compatible with the Podfile" do
# @resolver.resolve
# @resolver.should_install?("BlocksKit").should.be.false
# @resolver.should_install?("JSONKit").should.be.false
# end
# it "doesn't update the version of pods still compatible with the Podfile" do
# installed = @resolver.resolve.values.flatten.map(&:to_s)
# installed.should.include? "JSONKit (1.4)"
# end
# it "doesn't include pods removed from the Podfile" do
# podfile = Podfile.new { platform :ios; pod 'JSONKit' }
# @resolver = Resolver.new(podfile, @lockfile, stub('sandbox'))
# @resolver.resolve.values.flatten.map(&:name).should == %w{ JSONKit }
# end
# it "reinstalls pods updated in the Podfile" do
# podfile = Podfile.new do
# platform :ios
# pod 'JSONKit', '1.5pre'
# pod 'BlocksKit', '1.5.2'
# end
# @resolver = Resolver.new(podfile, @lockfile, stub('sandbox'))
# installed = @resolver.resolve.values.flatten.map(&:to_s)
# installed.should.include? "BlocksKit (1.5.2)"
# installed.should.include? "JSONKit (1.5pre)"
# end
# it "installs pods added to the Podfile" do
# podfile = Podfile.new do
# platform :ios
# pod 'JSONKit'
# pod 'BlocksKit'
# pod 'libPusher', '1.3' # New pod
# end
# @resolver = Resolver.new(podfile, @lockfile, stub('sandbox'))
# installed = @resolver.resolve.values.flatten.map(&:to_s)
# installed.should.include? "libPusher (1.3)"
# end
# it "handles head pods" do
# podfile = Podfile.new do
# platform :ios
# pod 'JSONKit', :head # Existing pod switched to head mode
# pod 'libPusher', :head # New pod
# end
# @resolver = Resolver.new(podfile, @lockfile, stub('sandbox'))
# @resolver.resolve
# @resolver.should_install?("JSONKit").should.be.true
# @resolver.should_install?("libPusher").should.be.true
# end
# it "handles pods from external dependencies" do
# podfile = Podfile.new do
# platform :ios
# pod 'libPusher', :git => 'GIT-URL'
# end
# spec = Spec.new do |s|
# s.name = 'libPusher'
# s.version = '1.3'
# end
# ExternalSources::GitSource.any_instance.stubs(:specification_from_sandbox).returns(spec)
# @resolver = Resolver.new(podfile, @lockfile, stub('sandbox'))
# @resolver.resolve
# @resolver.should_install?("JSONKit").should.be.false
# end
# it "doesn't updates the repos if there no change in the pods" do
# podfile = Podfile.new do
# platform :ios
# pod 'BlocksKit'
# pod 'JSONKit'
# end
# config.skip_repo_update = false
# Command::Repo.any_instance.expects(:run).never
# @resolver = Resolver.new(podfile, @lockfile, stub('sandbox'))
# @resolver.resolve
# end
# it "updates the repos if there is a new pod" do
# podfile = Podfile.new do
# platform :ios
# pod 'BlocksKit'
# pod 'JSONKit'
# pod 'libPusher' # New pod
# end
# config.skip_repo_update = false
# Command::Repo::Update.any_instance.expects(:run).once
# @resolver = Resolver.new(podfile, @lockfile, stub('sandbox'))
# @resolver.resolve
# end
# it "doesn't update the repos if config indicate to skip it in any case" do
# podfile = Podfile.new do
# platform :ios
# pod 'BlocksKit'
# pod 'JSONKit', :head #changed to head
# pod 'libPusher' # New pod
# end
# config.skip_repo_update = true
# Command::Repo::Update.any_instance.expects(:run).never
# @resolver = Resolver.new(podfile, @lockfile, stub('sandbox'))
# @resolver.resolve
# end
# it "updates the repos if there is a new pod" do
# podfile = Podfile.new do
# platform :ios
# pod 'BlocksKit'
# pod 'JSONKit', :head #changed to head
# end
# config.skip_repo_update = false
# Command::Repo::Update.any_instance.expects(:run).once
# @resolver = Resolver.new(podfile, @lockfile, stub('sandbox'))
# @resolver.resolve
# end
# end
# describe "Concerning Update mode" do
# before do
# config.repos_dir = fixture('spec-repos')
# previous_podfile = Podfile.new do
# platform :ios
# pod 'JSONKit'
# pod 'libPusher'
# end
# @specs = [
# Specification.new do |s|
# s.name = "libPusher"
# s.version = "1.3"
# end,
# Specification.new do |s|
# s.name = "JSONKit"
# s.version = "1.4"
# end ]
# @specs.each { |s| s.activate_platform(:ios) }
# @lockfile = Lockfile.generate(previous_podfile, @specs)
# @podfile = Podfile.new do
# platform :ios
# pod 'BlocksKit', '1.5.2'
# pod 'JSONKit'
# pod 'libPusher'
# end
# @resolver = Resolver.new(@podfile, @lockfile, stub('sandbox'))
# @resolver.update_mode = true
# end
# it "identifies the pods that can be updated" do
# installed = @resolver.resolve.values.flatten.map(&:to_s)
# installed.should.include? "JSONKit (999.999.999)"
# @resolver.should_install?("JSONKit").should.be.true
# end
# it "respects the constraints of the podfile" do
# podfile = Podfile.new do
# platform :ios
# pod 'BlocksKit', '1.5.2'
# pod 'JSONKit', '1.4'
# end
# @resolver = Resolver.new(podfile, @lockfile, stub('sandbox'))
# @resolver.update_mode = true
# installed = @resolver.resolve.values.flatten.map(&:to_s)
# installed.should.include? "JSONKit (1.4)"
# @resolver.should_install?("JSONKit").should.be.false
# end
# it "installs new pods" do
# installed = @resolver.resolve.values.flatten.map(&:to_s)
# installed.join(' ').should.include?('BlocksKit')
# @resolver.should_install?("BlocksKit").should.be.true
# end
# it "it always suggests to update pods in head mode" do
# podfile = Podfile.new do
# platform :ios
# pod 'libPusher', :head
# end
# @resolver = Resolver.new(podfile, @lockfile, stub('sandbox'))
# @resolver.update_mode = true
# @resolver.resolve
# @resolver.should_install?("libPusher").should.be.true
# end
# it "always updates the repos even if there is change in the pods" do
# podfile = Podfile.new do
# platform :ios
# pod 'JSONKit'
# pod 'libPusher'
# end
# config.skip_repo_update = false
# Command::Repo::Update.any_instance.expects(:run).once
# @resolver = Resolver.new(podfile, @lockfile, stub('sandbox'))
# @resolver.update_mode = true
# @resolver.resolve
# end
# # TODO: stub the specification resolution for the sandbox
# xit "it always suggests to update pods from external sources" do
# podfile = Podfile.new do
# platform :ios
# pod 'libPusher', :git => "example.com"
# end
# @resolver = Resolver.new(podfile, @lockfile, stub('sandbox'))
# @resolver.update_mode = true
# @resolver.resolve
# @resolver.should_install?("libPusher").should.be.true
# end
# end
end end
describe "Concerning Installation mode" do
before do
config.repos_dir = fixture('spec-repos')
@podfile = Podfile.new do
platform :ios
pod 'BlocksKit', '1.5.2'
pod 'JSONKit'
end
@specs = [
Specification.new do |s|
s.name = "BlocksKit"
s.version = "1.5.2"
end,
Specification.new do |s|
s.name = "JSONKit"
s.version = "1.4"
end ]
@specs.each { |s| s.activate_platform(:ios) }
@lockfile = Lockfile.generate(@podfile, @specs)
@resolver = Resolver.new(@podfile, @lockfile, stub('sandbox'))
end
it "doesn't install pods still compatible with the Podfile" do
@resolver.resolve
@resolver.should_install?("BlocksKit").should.be.false
@resolver.should_install?("JSONKit").should.be.false
end
it "doesn't update the version of pods still compatible with the Podfile" do
installed = @resolver.resolve.values.flatten.map(&:to_s)
installed.should.include? "JSONKit (1.4)"
end
it "doesn't include pods removed from the Podfile" do
podfile = Podfile.new { platform :ios; pod 'JSONKit' }
@resolver = Resolver.new(podfile, @lockfile, stub('sandbox'))
@resolver.resolve.values.flatten.map(&:name).should == %w{ JSONKit }
end
it "reinstalls pods updated in the Podfile" do
podfile = Podfile.new do
platform :ios
pod 'JSONKit', '1.5pre'
pod 'BlocksKit', '1.5.2'
end
@resolver = Resolver.new(podfile, @lockfile, stub('sandbox'))
installed = @resolver.resolve.values.flatten.map(&:to_s)
installed.should.include? "BlocksKit (1.5.2)"
installed.should.include? "JSONKit (1.5pre)"
end
it "installs pods added to the Podfile" do
podfile = Podfile.new do
platform :ios
pod 'JSONKit'
pod 'BlocksKit'
pod 'libPusher', '1.3' # New pod
end
@resolver = Resolver.new(podfile, @lockfile, stub('sandbox'))
installed = @resolver.resolve.values.flatten.map(&:to_s)
installed.should.include? "libPusher (1.3)"
end
it "handles head pods" do
podfile = Podfile.new do
platform :ios
pod 'JSONKit', :head # Existing pod switched to head mode
pod 'libPusher', :head # New pod
end
@resolver = Resolver.new(podfile, @lockfile, stub('sandbox'))
@resolver.resolve
@resolver.should_install?("JSONKit").should.be.true
@resolver.should_install?("libPusher").should.be.true
end
it "handles pods from external dependencies" do
podfile = Podfile.new do
platform :ios
pod 'libPusher', :git => 'GIT-URL'
end
spec = Spec.new do |s|
s.name = 'libPusher'
s.version = '1.3'
end
ExternalSources::GitSource.any_instance.stubs(:specification_from_sandbox).returns(spec)
@resolver = Resolver.new(podfile, @lockfile, stub('sandbox'))
@resolver.resolve
@resolver.should_install?("JSONKit").should.be.false
end
it "doesn't updates the repos if there no change in the pods" do
podfile = Podfile.new do
platform :ios
pod 'BlocksKit'
pod 'JSONKit'
end
config.skip_repo_update = false
Command::Repo.any_instance.expects(:run).never
@resolver = Resolver.new(podfile, @lockfile, stub('sandbox'))
@resolver.resolve
end
it "updates the repos if there is a new pod" do
podfile = Podfile.new do
platform :ios
pod 'BlocksKit'
pod 'JSONKit'
pod 'libPusher' # New pod
end
config.skip_repo_update = false
Command::Repo::Update.any_instance.expects(:run).once
@resolver = Resolver.new(podfile, @lockfile, stub('sandbox'))
@resolver.resolve
end
it "doesn't update the repos if config indicate to skip it in any case" do
podfile = Podfile.new do
platform :ios
pod 'BlocksKit'
pod 'JSONKit', :head #changed to head
pod 'libPusher' # New pod
end
config.skip_repo_update = true
Command::Repo::Update.any_instance.expects(:run).never
@resolver = Resolver.new(podfile, @lockfile, stub('sandbox'))
@resolver.resolve
end
it "updates the repos if there is a new pod" do
podfile = Podfile.new do
platform :ios
pod 'BlocksKit'
pod 'JSONKit', :head #changed to head
end
config.skip_repo_update = false
Command::Repo::Update.any_instance.expects(:run).once
@resolver = Resolver.new(podfile, @lockfile, stub('sandbox'))
@resolver.resolve
end
end
describe "Concerning Update mode" do
before do
config.repos_dir = fixture('spec-repos')
previous_podfile = Podfile.new do
platform :ios
pod 'JSONKit'
pod 'libPusher'
end
@specs = [
Specification.new do |s|
s.name = "libPusher"
s.version = "1.3"
end,
Specification.new do |s|
s.name = "JSONKit"
s.version = "1.4"
end ]
@specs.each { |s| s.activate_platform(:ios) }
@lockfile = Lockfile.generate(previous_podfile, @specs)
@podfile = Podfile.new do
platform :ios
pod 'BlocksKit', '1.5.2'
pod 'JSONKit'
pod 'libPusher'
end
@resolver = Resolver.new(@podfile, @lockfile, stub('sandbox'))
@resolver.update_mode = true
end
it "identifies the pods that can be updated" do
installed = @resolver.resolve.values.flatten.map(&:to_s)
installed.should.include? "JSONKit (999.999.999)"
@resolver.should_install?("JSONKit").should.be.true
end
it "respects the constraints of the podfile" do
podfile = Podfile.new do
platform :ios
pod 'BlocksKit', '1.5.2'
pod 'JSONKit', '1.4'
end
@resolver = Resolver.new(podfile, @lockfile, stub('sandbox'))
@resolver.update_mode = true
installed = @resolver.resolve.values.flatten.map(&:to_s)
installed.should.include? "JSONKit (1.4)"
@resolver.should_install?("JSONKit").should.be.false
end
it "installs new pods" do
installed = @resolver.resolve.values.flatten.map(&:to_s)
installed.join(' ').should.include?('BlocksKit')
@resolver.should_install?("BlocksKit").should.be.true
end
it "it always suggests to update pods in head mode" do
podfile = Podfile.new do
platform :ios
pod 'libPusher', :head
end
@resolver = Resolver.new(podfile, @lockfile, stub('sandbox'))
@resolver.update_mode = true
@resolver.resolve
@resolver.should_install?("libPusher").should.be.true
end
it "always updates the repos even if there is change in the pods" do
podfile = Podfile.new do
platform :ios
pod 'JSONKit'
pod 'libPusher'
end
config.skip_repo_update = false
Command::Repo::Update.any_instance.expects(:run).once
@resolver = Resolver.new(podfile, @lockfile, stub('sandbox'))
@resolver.update_mode = true
@resolver.resolve
end
# TODO: stub the specification resolution for the sandbox
xit "it always suggests to update pods from external sources" do
podfile = Podfile.new do
platform :ios
pod 'libPusher', :git => "example.com"
end
@resolver = Resolver.new(podfile, @lockfile, stub('sandbox'))
@resolver.update_mode = true
@resolver.resolve
@resolver.should_install?("libPusher").should.be.true
end
end
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