Commit 4a37f7ee authored by Fabio Pelosin's avatar Fabio Pelosin

[WIP][Analyzer] Download external sources before resolution

parent 3cfb3053
......@@ -3,39 +3,46 @@
[Core](https://github.com/CocoaPods/Core/master)
[Xcodeproj](https://github.com/CocoaPods/Xcodeproj/compare/0.4.0...master)
###### Specification DSL
- [__Breaking__] Deprecated `header_mappings` hook.
- [__Breaking__] Deprecated `exclude_header_search_paths`
- [__Breaking__] `requires_arc` is transitioning from `false` to `true`.
- [__Breaking__] The support for Rake File list is being deprecated.
- `preferred_dependency` has been renamed to `default_subspec`.
- Added `exclude_files` attribute.
- Added `screenshots` attribute
- Added default values for attributes like `source_files`.
###### Podfile DSL
- It is not needed to specify the platform anymore (unless not integrating)
###### __Breaking__
- `requires_arc` is transitioning from `false` to `true`.
- Deprecated `header_mappings` hook.
- Deprecated `exclude_header_search_paths`
- The support for Rake File list is being deprecated.
- Support for inline podspecs has been removed.
- Subspecs do **not** inherit the files patterns from the parent spec anymore.
- External sources are not supported in specifications anymore.
###### DSLs
- Podfile:
- It is not needed to specify the platform anymore (unless not integrating)
as CocoaPods now can infer the platform from the integrated targets.
- Specification:
- `preferred_dependency` has been renamed to `default_subspec`.
- Added `exclude_files` attribute.
- Added `screenshots` attribute
- Added default values for attributes like `source_files`.
###### Enhancements
- Subspecs now do not inherit the files patterns from the parent spec.
- Released preview [documentation](docs.cocoapods.org).
- CocoaPods now has support for working in teams and not committing the Pods folder.
- Simplified installation: no specific version of ruby gems is required anymore.
- The workspace is written only if needed greatly reducing the occasions in
which Xcode asks to revert.
- Specification hooks are only called when the specification is installed.
- The Lockfile is sorted reducing the SCM noise.
- Simplified installation: no specific version of ruby gems is required anymore.
- Released preview [documentation](docs.cocoapods.org).
- CocoaPods now has support for working in teams and not committing the Pods folder.
- CocoaPods now can infer the platform from the integrated targets.
- Adds new subcommand `pod spec cat NAME` to print a spec file to standard output.
- Added Podfile, Frameworks, and Resources to the Pods project.
[#647](https://github.com/CocoaPods/CocoaPods/issues/647)
[#588](https://github.com/CocoaPods/CocoaPods/issues/588)
- The `--no-clean` option of the `pod spec lint` command now displays the Pods project for inspection.
- It is now possible to specify default values for the configuration in `~/.cocoapods/config.yaml` ([example]()).
- CocoaPods now checks the checksums of the installed specifications and reinstalls them if needed.
- Adds new subcommand `pod spec cat NAME` to print a spec file to standard output.
- Specification hooks are only called when the specification is installed.
- The `--no-clean` option of the `pod spec lint` command now displays the Pods
project for inspection.
- It is now possible to specify default values for the configuration in
`~/.cocoapods/config.yaml` ([see](https://github.com/CocoaPods/CocoaPods/blob/master/lib/cocoapods/config.rb#L17)).
- CocoaPods now checks the checksums of the installed specifications and
reinstalls them if needed.
- Added new command `pod ipc` to provide support for inter process communication.
###### Bug fixes
......@@ -45,9 +52,8 @@
###### Codebase
- Major clean up and refactor of the whole code base, with great reduction of
the technical debt.
- Extracted the models of into
- Major clean up and refactor of the whole code base.
- Extracted the core classes into
[CocoaPods-Core](https://github.com/CocoaPods/Core) gem.
- Extracted command-line command & option handling into
[CLAide](https://github.com/CocoaPods/CLAide).
......
......@@ -70,36 +70,17 @@ module Pod
public
# @!group Specifications
# @!group Fetching
# @return [Specification] returns the specification, either from the
# sandbox or by fetching the remote source, associated with the
# external source.
#
def specification(sandbox)
specification_from_local(sandbox) || specification_from_external(sandbox)
end
# @return [Specification] returns the specification associated with the
# external source if available in the sandbox.
# Fetches the external source from the remote according to the params.
#
def specification_from_local(sandbox)
sandbox.specification(name)
end
# @return [Specification] returns the specification associated with the
# external source after fetching it from the remote source, even
# if is already present in the sandbox.
# @param [Sandbox] sandbox
# the sandbox where the specification should be stored.
#
# @raise If not specification could be found.
# @return [void]
#
def specification_from_external(sandbox)
copy_external_source_into_sandbox(sandbox)
spec = specification_from_local(sandbox)
unless spec
raise Informative, "No podspec found for `#{name}` in #{description}"
end
spec
def fetch(sandbox)
raise "Abstract method"
end
#--------------------------------------#
......@@ -115,7 +96,7 @@ module Pod
#
# @return [void]
#
def copy_external_source_into_sandbox(sandbox)
def fetch(sandbox)
raise "Abstract method"
end
......@@ -131,22 +112,25 @@ module Pod
# @! Subclasses helpers
# Pre-downloads a Pod passing the options to the downloader and informing
# the sandbox.
#
# @param [Sandbox] sandbox
# the sandbox where the Pod should be downloaded.
# The sandbox where the Pod should be downloaded.
#
# @note To prevent a double download of the repository the pod is
# marked as pre-downloaded indicating to the installer that only
# clean operations are needed.
#
# @return [void]
#
def pre_download(sandbox)
UI.info("->".green + " Pre-downloading: `#{name}`") do
UI.titled_section("Pre-downloading: `#{name}` #{description}", { :verbose_prefix => "-> " }) do
target = sandbox.root + name
target.rmtree if target.exist?
downloader = Downloader.for_target(target, params)
downloader.download
sandbox.store_podspec(name, target + "#{name}.podspec", true)
store_podspec(sandbox, target + "#{name}.podspec")
sandbox.store_pre_downloaded_pod(name)
if downloader.options_specific?
source = params
......@@ -157,6 +141,27 @@ module Pod
end
end
# Stores the podspec in the sandbox and marks it as from an external
# source.
#
# @param [Sandbox] sandbox
# The sandbox where the specification should be stored.
#
# @param [Pathname, String] spec
# The path of the specification or its contents.
#
# @note All the concrete implementations of #{fetch} should invoke this
# method.
#
# @note The sandbox ensures that the podspec exists and that the names
# match.
#
# @return [void]
#
def store_podspec(sandbox, spec)
sandbox.store_podspec(name, spec, true)
end
end
#-------------------------------------------------------------------------#
......@@ -171,13 +176,9 @@ module Pod
#
class GitSource < AbstractExternalSource
# @see AbstractExternalSource#copy_external_source_into_sandbox
#
# @note To prevent a double download of the repository the pod is marked
# as pre-downloaded indicating to the installer that only clean
# operations are needed.
# @see AbstractExternalSource#fetch
#
def copy_external_source_into_sandbox(sandbox)
def fetch(sandbox)
pre_download(sandbox)
end
......@@ -205,13 +206,9 @@ module Pod
#
class SvnSource < AbstractExternalSource
# @see AbstractExternalSource#copy_external_source_into_sandbox
# @see AbstractExternalSource#fetch
#
# @note To prevent a double download of the repository the pod is marked
# as pre-downloaded indicating to the installer that only clean
# operations are needed.
#
def copy_external_source_into_sandbox(sandbox)
def fetch(sandbox)
pre_download(sandbox)
end
......@@ -239,13 +236,9 @@ module Pod
#
class MercurialSource < AbstractExternalSource
# @see AbstractExternalSource#copy_external_source_into_sandbox
#
# @note To prevent a double download of the repository the pod is marked
# as pre-downloaded indicating to the installer that only clean
# operations are needed.
# @see AbstractExternalSource#fetch
#
def copy_external_source_into_sandbox(sandbox)
def fetch(sandbox)
pre_download(sandbox)
end
......@@ -265,14 +258,14 @@ module Pod
#
class PodspecSource < AbstractExternalSource
# @see AbstractExternalSource#copy_external_source_into_sandbox
# @see AbstractExternalSource#fetch
#
def copy_external_source_into_sandbox(sandbox)
UI.info("->".green + " Fetching podspec for `#{name}` from: #{params[:podspec]}") do
def fetch(sandbox)
UI.titled_section("Fetching podspec for `#{name}` #{description}", { :verbose_prefix => "-> " }) do
path = params[:podspec]
path = Pathname.new(path).expand_path if path.to_s.start_with?("~")
require 'open-uri'
open(path) { |io| sandbox.store_podspec(name, io.read, true) }
open(path) { |io| store_podspec(sandbox, io.read) }
end
end
......@@ -292,11 +285,14 @@ module Pod
#
class LocalSource < AbstractExternalSource
# @see AbstractExternalSource#copy_external_source_into_sandbox
# @see AbstractExternalSource#fetch
#
def copy_external_source_into_sandbox(sandbox)
sandbox.store_podspec(name, pod_spec_path, true)
sandbox.store_local_path(name, params[:local])
def fetch(sandbox)
UI.titled_section("Fetching podspec for `#{name}` #{description}", { :verbose_prefix => "-> " }) do
podspec = pod_spec_path
store_podspec(sandbox, podspec)
sandbox.store_local_path(name, podspec.dirname)
end
end
# @see AbstractExternalSource#description
......@@ -305,29 +301,6 @@ module Pod
"from `#{params[:local]}`"
end
# @see AbstractExternalSource#specification_from_local
#
# @note The LocalSource class always fetches podspecs from the external
# source to provide always the freshest specification. Otherwise,
# once installed, the podspec would be updated only by `pod
# update`.
#
def specification_from_local(sandbox)
specification_from_external(sandbox)
end
# @see AbstractExternalSource#specification_from_local
#
# @note The LocalSource overrides the source of the specification to
# point to the local path.
#
def specification_from_external(sandbox)
copy_external_source_into_sandbox(sandbox)
spec = Specification.from_file(pod_spec_path)
spec.source = params
spec
end
#--------------------------------------#
private
......
......@@ -88,7 +88,7 @@ module Pod
end
def resolve_dependencies
UI.section "Resolving dependencies" do
UI.section "Analyzing dependencies" do
analyze
detect_pods_to_install
prepare_for_legacy_compatibility
......@@ -173,22 +173,8 @@ module Pod
#
def detect_pods_to_install
names = []
analysis_result.specifications.each do |spec|
root_name = spec.root.name
if update_mode
if spec.version.head? # || resolver.pods_from_external_sources.include?(root_name) TODO
names << root_name
end
end
unless sandbox.pod_dir(root_name).exist?
names << root_name
end
end
names += analysis_result.sandbox_state.added + analysis_result.sandbox_state.changed
names += sandbox.predownloaded_pods
names = names.map { |name| Specification.root_name(name) }
names = names.flatten.uniq
@names_of_pods_to_install = names
......@@ -231,11 +217,7 @@ module Pod
def create_file_accessors
libraries.each do |library|
library.specs.each do |spec|
if spec.local?
pod_root = Pathname.new(spec.source[:local]).expand_path
else
pod_root = sandbox.pod_dir(spec.root.name)
end
pod_root = sandbox.pod_dir(spec.root.name)
path_list = Sandbox::PathList.new(pod_root)
file_accessor = Sandbox::FileAccessor.new(path_list, spec.consumer(library.platform))
library.file_accessors ||= []
......
......@@ -52,6 +52,7 @@ module Pod
@locked_dependencies = generate_version_locking_dependencies
@result.libraries = generated_libraries
fetch_external_sources
@result.specs_by_target = resolve_dependencies
@result.specifications = generate_specifications
@result.sandbox_state = generate_sandbox_state
......@@ -134,7 +135,9 @@ module Pod
end
pods_state
else
SpecsState.new({})
state = SpecsState.new
state.added.concat(podfile.dependencies.map(&:root_name).uniq)
state
end
end
......@@ -211,6 +214,36 @@ module Pod
end
end
# If modifications to the sandbox are allowed external sources are
# fetched. In update mode all the external sources are refreshed while in
# normal mode they refreshed only if added or changed in the Podfile.
#
# TODO Specs, comments, and fix UI
#
def fetch_external_sources
return unless allow_pre_downloads?
deps_to_fetch = []
deps_to_fetch_if_needed = []
deps_with_external_source = podfile.dependencies.select { |dep| dep.external_source }
if update_mode?
deps_to_fetch = deps_with_external_source
else
pods_to_fetch = result.podfile_state.added + result.podfile_state.changed
deps_to_fetch = deps_with_external_source.select { |dep| pods_to_fetch.include?(dep.root_name) }
deps_to_fetch_if_needed = deps_with_external_source.select { |dep| result.podfile_state.unchanged.include?(dep.root_name) }
deps_to_fetch += deps_to_fetch_if_needed.select { |dep| sandbox.specification(dep.root_name).nil? || !dep.external_source[:local].nil? }
end
unless deps_to_fetch.empty?
UI.section "Fetching external sources" do
deps_to_fetch.uniq.sort.each do |dependency|
source = ExternalSources.from_dependency(dependency, podfile.defined_in_file)
source.fetch(sandbox)
end
end
end
end
# Converts the Podfile in a list of specifications grouped by target.
#
# @note In this step the specs are added to the libraries.
......@@ -235,19 +268,8 @@ module Pod
def resolve_dependencies
specs_by_target = nil
podfile_state = result.podfile_state
if allow_pre_downloads?
changed_pods = podfile_state.added + podfile_state.changed + podfile_state.deleted
changed_pods.each do |pod_name|
podspec = sandbox.specification_path(pod_name)
podspec.delete if podspec
end
end
UI.section "Resolving dependencies of #{UI.path podfile.defined_in_file}" do
resolver = Resolver.new(sandbox, podfile, locked_dependencies)
resolver.update_external_specs = update_mode?
resolver.allow_pre_downloads = allow_pre_downloads?
specs_by_target = resolver.resolve
end
......@@ -270,28 +292,6 @@ module Pod
# Computes the state of the sandbox respect to the resolved
# specifications.
#
# The logic is the following:
#
# Added
# - If not present in the sandbox lockfile.
#
# Changed
# - The version of the Pod changed.
# - The specific installed (sub)specs of the same Pod changed.
# - The SHA of the specification file changed.
#
# Removed
# - If a specification is present in the lockfile but not in the resolved
# specs.
#
# Unchanged
# - If none of the above conditions match.
#
# @todo [CocoaPods > 0.18] Version 0.17 falls back to the lockfile of
# the Podfile for the sandbox manifest to prevent the full
# re-installation for upgrading users (this was the old behaviour
# pre sandbox manifest) of all the pods. Drop in 0.18.
#
# @return [SpecsState] the representation of the state of the manifest
# specifications.
#
......@@ -383,6 +383,7 @@ module Pod
# @return [Array<PBXNativeTarget>] Returns the user’s targets, excluding
# aggregate targets.
#
def native_targets(user_project)
user_project.targets.reject do |target|
target.is_a? Xcodeproj::Project::Object::PBXAggregateTarget
......
......@@ -5,6 +5,27 @@ module Pod
# Analyze the sandbox to detect which Pods should be removed, and which
# ones should be reinstalled.
#
# The logic is the following:
#
# Added
# - If not present in the sandbox lockfile.
# - The directory of the Pod doesn't exits.
#
# Changed
# - The version of the Pod changed.
# - The SHA of the specification file changed.
# - The specific installed (sub)specs of the same Pod changed.
# - The specification is in head mode or from an external source and the
# installation process is in update mode.
# - The directory of the Pod is empty.
#
# Removed
# - If a specification is present in the lockfile but not in the resolved
# specs.
#
# Unchanged
# - If none of the above conditions match.
#
class SandboxAnalyzer
# @return [Sandbox] The sandbox to analyze.
......@@ -129,7 +150,6 @@ module Pod
return true if folder_empty?(pod)
if update_mode
return true if spec.version.head?
# return true if sandbox.external_source?(pod) TODO
end
return false
end
......@@ -171,7 +191,7 @@ module Pod
specs.select { |s| s.root.name == pod }.map(&:name).uniq
end
# @return [Array<String>] The name of the specifications stored in the
# @return [Array<String>] The name of the specifications stored in the
# sandbox manifest (includes subspecs).
#
# @param [String] pod
......
......@@ -54,7 +54,7 @@ module Pod
#
def relativize(path)
unless path.absolute?
raise Informative, "Attempt to add relative path to the Pods project"
raise StandardError, "[Bug] Attempt to add relative path `#{path}` to the Pods project"
end
result = path.relative_path_from(root)
......
......@@ -38,29 +38,8 @@ module Pod
@sandbox = sandbox
@podfile = podfile
@locked_dependencies = locked_dependencies
@allow_pre_downloads = true
end
# @return [Bool] Whether the resolver should update the external specs
# in the resolution process. This option is used for detecting
# changes in with the Podfile without affecting the existing Pods
# installation
#
# @note This option is used by `pod outdated`.
#
attr_accessor :update_external_specs
alias_method :update_external_specs?, :update_external_specs
# @return [Bool] Whether pre-downloads should be allowed. Pre-downloads
# change the state of the sandbox and should be allowed only during
# installations. Defaults to true.
#
# @note Enabling this if the Podfile and the sandbox are not in sync
# might result in an exception.
#
attr_accessor :allow_pre_downloads
alias_method :allow_pre_downloads?, :allow_pre_downloads
#-------------------------------------------------------------------------#
public
......@@ -134,7 +113,7 @@ module Pod
private
# !@ Helpers
# @!group Private helpers
# Resolves recursively the dependencies of a specification and stores them
# in the @cached_specs ivar.
......@@ -188,23 +167,23 @@ module Pod
end
end
# Loads or returns a previously initialized {Set} for the given dependency.
# Loads or returns a previously initialized for the Pod of the given
# dependency.
#
# @param [Dependency] dependency
# the dependency for which the set is needed.
#
# @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.
#
# @return [Set] the cached set for a given dependency.
#
def find_cached_set(dependency)
name = dependency.root_name
unless cached_sets[name]
if dependency.external_source
set = set_from_external_source(dependency)
spec = sandbox.specification(dependency.root_name)
unless spec
raise StandardError, "[Bug] Unable to find the specification for `#{dependency}`."
end
set = Specification::Set::External.new(spec)
else
set = cached_sources.search(dependency)
end
......@@ -213,33 +192,6 @@ module Pod
cached_sets[name]
end
# Returns a new set created from an external source
#
# @param [Dependency] dependency
# The dependency with the external source for which the set is
# needed.
#
# @return [Set] the set for the dependency.
#
def set_from_external_source(dependency)
source = ExternalSources.from_dependency(dependency, podfile.defined_in_file)
if allow_pre_downloads?
if update_external_specs?
spec = source.specification_from_external(sandbox)
else
spec = source.specification(sandbox)
end
else
spec = sandbox.specification(dependency.name)
unless spec
raise Informative, "Unable to find the specification for " \
"`#{dependency}`. Running `pod install` should fix the issue."
end
end
Specification::Set::External.new(spec)
end
# Ensures that a specification is compatible with the platform of a target.
#
# @raise If the specification is not supported by the target.
......
$ pod install --no-update --no-doc --verbose --no-color 2>&1
Resolving dependencies
Analyzing dependencies
Finding Podfile changes
A JSONKit
......
$ pod install --no-update --no-doc --verbose --no-color 2>&1
Resolving dependencies
Analyzing dependencies
Fetching external sources
-> Pre-downloading: `PodTest` from `PodTest-hg-source`
> Mercurial download
$ /usr/local/bin/hg clone "PodTest-hg-source" "ROOT/tmp/install_external_source/Pods/PodTest"
updating to branch default
5 files updated, 0 files merged, 0 files removed, 0 files unresolved
Resolving dependencies of `Podfile`
Resolving dependencies for target `default' (iOS 4.3)
- PodTest (from `PodTest-hg-source`)
-> Pre-downloading: `PodTest`
> Mercurial download
$ /usr/local/bin/hg clone "PodTest-hg-source" "ROOT/tmp/install_external_source/Pods/PodTest"
updating to branch default
5 files updated, 0 files merged, 0 files removed, 0 files unresolved
- PodTest/subspec_1 (= 1.0)
- PodTest/subspec_2 (= 1.0)
......
$ pod install --no-update --no-doc --verbose --no-color 2>&1
Resolving dependencies
Analyzing dependencies
Fetching external sources
-> Fetching podspec for `Reachability` from `Reachability`
Resolving dependencies of `Podfile`
Resolving dependencies for target `default' (iOS 4.3)
......
$ pod install --no-update --no-doc --verbose --no-color 2>&1
Resolving dependencies
Analyzing dependencies
Resolving dependencies of `Podfile`
Resolving dependencies for target `SampleApp_2' (iOS 6.0)
......
$ pod install --no-update --no-doc --verbose --no-color 2>&1
Resolving dependencies
Analyzing dependencies
Resolving dependencies of `Podfile`
Resolving dependencies for target `default' (iOS 6.0)
......
$ pod install --no-update --no-doc --verbose --no-color 2>&1
Resolving dependencies
Analyzing dependencies
Resolving dependencies of `Podfile`
Resolving dependencies for target `default' (iOS 6.0)
......
$ pod install --no-update --no-doc --verbose --no-color 2>&1
Resolving dependencies
Analyzing dependencies
Fetching external sources
-> Fetching podspec for `Reachability` from `Reachability.podspec`
Resolving dependencies of `Podfile`
Resolving dependencies for target `default' (iOS 6.0)
- Reachability (from `Reachability.podspec`)
-> Fetching podspec for `Reachability` from: Reachability.podspec
Comparing resolved specification to the sandbox manifest
A Reachability
......
$ pod install --no-update --no-doc --verbose --no-color 2>&1
Resolving dependencies
Analyzing dependencies
Finding Podfile changes
R JSONKit
......
$ pod install --no-update --no-doc --verbose --no-color 2>&1
Resolving dependencies
Analyzing dependencies
Fetching external sources
-> Fetching podspec for `Reachability` from `Reachability.podspec`
Resolving dependencies of `Podfile`
Resolving dependencies for target `default' (iOS 6.0)
- Reachability (from `Reachability.podspec`)
-> Fetching podspec for `Reachability` from: Reachability.podspec
Comparing resolved specification to the sandbox manifest
A Reachability
......
$ pod install --no-update --no-doc --verbose --no-color 2>&1
Resolving dependencies
Analyzing dependencies
Fetching external sources
-> Pre-downloading: `PodTest` from `PodTest-hg-source`
> Mercurial download
$ /usr/local/bin/hg clone "PodTest-hg-source" "ROOT/tmp/install_subspecs/Pods/PodTest"
updating to branch default
5 files updated, 0 files merged, 0 files removed, 0 files unresolved
-> Pre-downloading: `PodTest` from `PodTest-hg-source`
> Mercurial download
$ /usr/local/bin/hg clone "PodTest-hg-source" "ROOT/tmp/install_subspecs/Pods/PodTest"
updating to branch default
5 files updated, 0 files merged, 0 files removed, 0 files unresolved
Resolving dependencies of `Podfile`
Resolving dependencies for target `OS X App' (OS X 10.6)
- PodTest/subspec_2 (from `PodTest-hg-source`)
-> Pre-downloading: `PodTest`
> Mercurial download
$ /usr/local/bin/hg clone "PodTest-hg-source" "ROOT/tmp/install_subspecs/Pods/PodTest"
updating to branch default
5 files updated, 0 files merged, 0 files removed, 0 files unresolved
Resolving dependencies for target `default' (iOS 6.1)
Resolving dependencies for target `iOS App' (iOS 4.3)
- PodTest/subspec_1 (from `PodTest-hg-source`)
......
$ pod update --no-update --no-doc --verbose --no-color 2>&1
Resolving dependencies
Analyzing dependencies
Finding Podfile changes
- Reachability
......
......@@ -320,10 +320,6 @@ describe "Integration take 2" do
check "install --no-update --no-doc", "install_multiple_targets"
end
# TODO This test should reflect a bug of CP 0.16: the clean phase
# considers only the subspecs of only one target. However there is another
# issue and Pod from external sources are not cleaned.
#
describe "Installs a Pod with different subspecs activated across different targets" do
check "install --no-update --no-doc", "install_subspecs"
end
......
......@@ -39,35 +39,10 @@ module Pod
dependency_1.should.not.be == dependency_3
end
it "returns the specification from the sandbox if available" do
config.sandbox.store_podspec('Reachability', fixture('integration/Reachability/Reachability.podspec'))
@external_source.expects(:specification_from_external).never
@external_source.specification(config.sandbox).name.should == 'Reachability'
end
it "fetches the remote if needed to return the specification" do
@external_source.specification(config.sandbox).name.should == 'Reachability'
end
it "returns the specification as stored in the sandbox if available" do
@external_source.specification_from_external(config.sandbox)
@external_source.specification_from_local(config.sandbox).name.should == 'Reachability'
end
it "returns nil if the specification requested from local is not available in the sandbox" do
@external_source.specification_from_local(config.sandbox).should.be.nil
end
it "returns the specification fetching it from the external source in any case" do
@external_source.specification_from_external(config.sandbox).name.should == 'Reachability'
end
it "stores the specification in the sandbox after fetching it from the remote" do
path = config.sandbox.root + 'Local Podspecs/Reachability.podspec'
path.should.not.exist?
@external_source.specification_from_external(config.sandbox).name.should == 'Reachability'
path = config.sandbox.root + 'Local Podspecs/Reachability.podspec'
path.should.exist?
it "fetches the specification from the remote stores it in the sandbox" do
config.sandbox.specification('Reachability').should == nil
@external_source.fetch(config.sandbox)
config.sandbox.specification('Reachability').name.should == 'Reachability'
end
end
......@@ -104,13 +79,13 @@ module Pod
end
it "creates a copy of the podspec" do
@external_source.copy_external_source_into_sandbox(config.sandbox)
@external_source.fetch(config.sandbox)
path = config.sandbox.root + 'Local Podspecs/Reachability.podspec'
path.should.exist?
end
it "marks a LocalPod as downloaded" do
@external_source.copy_external_source_into_sandbox(config.sandbox)
@external_source.fetch(config.sandbox)
config.sandbox.predownloaded_pods.should == ["Reachability"]
end
......@@ -129,13 +104,13 @@ module Pod
end
it "creates a copy of the podspec" do
@external_source.copy_external_source_into_sandbox(config.sandbox)
@external_source.fetch(config.sandbox)
path = config.sandbox.root + 'Local Podspecs/SvnSource.podspec'
path.should.exist?
end
it "marks a LocalPod as downloaded" do
@external_source.copy_external_source_into_sandbox(config.sandbox)
@external_source.fetch(config.sandbox)
config.sandbox.predownloaded_pods.should == ["SvnSource"]
end
......@@ -154,13 +129,13 @@ module Pod
end
it "creates a copy of the podspec" do
@external_source.copy_external_source_into_sandbox(config.sandbox)
@external_source.fetch(config.sandbox)
path = config.sandbox.root + 'Local Podspecs/MercurialSource.podspec'
path.should.exist?
end
it "marks a LocalPod as downloaded" do
@external_source.copy_external_source_into_sandbox(config.sandbox)
@external_source.fetch(config.sandbox)
config.sandbox.predownloaded_pods.should == ["MercurialSource"]
end
......@@ -180,7 +155,7 @@ module Pod
end
it "creates a copy of the podspec" do
@external_source.copy_external_source_into_sandbox(config.sandbox)
@external_source.fetch(config.sandbox)
path = config.sandbox.root + 'Local Podspecs/Reachability.podspec'
path.should.exist?
end
......@@ -202,7 +177,7 @@ module Pod
end
it "creates a copy of the podspec" do
@external_source.copy_external_source_into_sandbox(config.sandbox)
@external_source.fetch(config.sandbox)
path = config.sandbox.root + 'Local Podspecs/Reachability.podspec'
path.should.exist?
end
......@@ -212,7 +187,7 @@ module Pod
end
it "marks the Pod as local in the sandbox" do
@external_source.copy_external_source_into_sandbox(config.sandbox)
@external_source.fetch(config.sandbox)
config.sandbox.local_pods.should == {
"Reachability" => fixture('integration/Reachability').to_s
}
......
......@@ -89,8 +89,10 @@ module Pod
@analyzer.send(:pod_changed?, 'BananaLib').should == true
end
xit "considers changed a Pod fetched from an external source if in update mode" do
it "doesn't consider changed a Pod whose specification is in head mode if not in update mode" do
@spec.version.head = true
@analyzer.stubs(:update_mode).returns(false)
@analyzer.send(:pod_changed?, 'BananaLib').should == false
end
end
......
......@@ -3,7 +3,7 @@ require File.expand_path('../../../spec_helper', __FILE__)
# @return [Analyzer] the sample analyzer.
#
def create_analyzer
podfile = Pod::Podfile.new do
@podfile = Pod::Podfile.new do
platform :ios, '6.0'
xcodeproj 'SampleProject/SampleProject'
pod 'JSONKit', '1.5pre'
......@@ -20,7 +20,7 @@ def create_analyzer
lockfile = Pod::Lockfile.new(hash)
SpecHelper.create_sample_app_copy_from_fixture('SampleProject')
analyzer = Pod::Installer::Analyzer.new(config.sandbox, podfile, lockfile)
analyzer = Pod::Installer::Analyzer.new(config.sandbox, @podfile, lockfile)
end
#-----------------------------------------------------------------------------#
......@@ -111,6 +111,37 @@ module Pod
#--------------------------------------#
it "fetches the dependencies with external sources" do
podfile_state = Installer::Analyzer::SpecsState.new
podfile_state.added << "BananaLib"
@analyzer.stubs(:result).returns(stub(:podfile_state => podfile_state))
@podfile.stubs(:dependencies).returns([Dependency.new('BananaLib', :git => "example.com")])
ExternalSources::GitSource.any_instance.expects(:fetch)
@analyzer.send(:fetch_external_sources)
end
xit "it fetches the specification from either the sandbox or from the remote be default" do
dependency = Dependency.new('Name', :git => 'www.example.com')
ExternalSources::GitSource.any_instance.expects(:specification_from_external).returns(Specification.new).once
@resolver.send(:set_from_external_source, dependency)
end
xit "it fetches the specification from the remote if in update mode" do
dependency = Dependency.new('Name', :git => 'www.example.com')
ExternalSources::GitSource.any_instance.expects(:specification).returns(Specification.new).once
@resolver.update_external_specs = false
@resolver.send(:set_from_external_source, dependency)
end
xit "it fetches the specification only from the sandbox if pre-downloads are disabled" do
dependency = Dependency.new('Name', :git => 'www.example.com')
Sandbox.any_instance.expects(:specification).returns(Specification.new).once
@resolver.allow_pre_downloads = true
@resolver.send(:set_from_external_source, dependency)
end
#--------------------------------------#
it "resolves the dependencies" do
@analyzer.analyze.specifications.map(&:to_s).should == [
"AFNetworking (1.0.1)",
......@@ -120,7 +151,7 @@ module Pod
]
end
it "removes the specifications of the changed pods to prevent confusion in the resolution process" do
xit "removes the specifications of the changed pods to prevent confusion in the resolution process" do
@analyzer.allow_pre_downloads = true
podspec = @analyzer.sandbox.root + 'Local Podspecs/JSONKit.podspec'
podspec.dirname.mkpath
......@@ -138,28 +169,6 @@ module Pod
]
end
it "instructs the resolver to not update external sources by default" do
Resolver.any_instance.expects(:update_external_specs=).with(false)
@analyzer.analyze
end
it "instructs the resolver to update external sources if in update mode" do
Resolver.any_instance.expects(:update_external_specs=).with(true)
@analyzer.update_mode = true
@analyzer.analyze
end
it "allow pre downloads in the resolver by default" do
Resolver.any_instance.expects(:allow_pre_downloads=).with(true)
@analyzer.analyze
end
it "allow pre downloads in the resolver by default" do
Resolver.any_instance.expects(:allow_pre_downloads=).with(false)
@analyzer.allow_pre_downloads = false
@analyzer.analyze
end
#--------------------------------------#
it "computes the state of the Sandbox respect to the resolved dependencies" do
......
......@@ -128,60 +128,22 @@ module Pod
end
it "includes the added Pods" do
@analysis_result.sandbox_state.add_name('Added-Pod', :added)
@analysis_result.sandbox_state.add_name('added-pod', :added)
@installer.send(:detect_pods_to_install)
@installer.names_of_pods_to_install.should == ['Added-Pod']
@installer.names_of_pods_to_install.should == ['added-pod']
end
it "includes the changed Pods" do
@analysis_result.sandbox_state.add_name('Changed-Pod', :changed)
@analysis_result.sandbox_state.add_name('changed-pod', :changed)
@installer.send(:detect_pods_to_install)
@installer.names_of_pods_to_install.should == ['Changed-Pod']
@installer.names_of_pods_to_install.should == ['changed-pod']
end
it "includes head pods in update mode" do
spec = Spec.new do |s|
s.name = 'Head-Pod'
end
spec.version.head = true
@analysis_result.specifications = [spec]
@installer.update_mode = true
@installer.send(:detect_pods_to_install)
@installer.names_of_pods_to_install.should == ['Head-Pod']
end
it "doesn't includes head pods if not in update mode" do
spec = Spec.new do |s|
s.name = 'Head-Pod'
end
spec.version.head = true
@analysis_result.specifications = [spec]
@installer.update_mode = false
@installer.send(:detect_pods_to_install)
@installer.names_of_pods_to_install.should == []
end
xit "includes pods from external sources in update mode" do
end
xit "doesn't includes pods from external sources if not in update mode" do
end
it "includes pods whose root folder doesn't exists" do
Pathname.any_instance.stubs(:exist?).returns(false)
spec = Spec.new do |s|
s.name = 'Head-Pod'
end
@analysis_result.specifications = [spec]
@installer.update_mode = false
it "includes the pre-downloaded Pods" do
@analysis_result.sandbox_state.add_name('unchanged-pods', :unchanged)
config.sandbox.stubs(:predownloaded_pods).returns(['pre-downloaded-pod'])
@installer.send(:detect_pods_to_install)
@installer.names_of_pods_to_install.should == ['Head-Pod']
end
xit "includes pods whose root folder is empty" do
@installer.names_of_pods_to_install.should == ['pre-downloaded-pod']
end
end
......
......@@ -24,20 +24,6 @@ module Pod
@resolver.locked_dependencies.should == [Dependency.new('BlocksKit', '1.5.2')]
end
it "allows to specify whether the external sources should be updated against the remote" do
@resolver.update_external_specs = true
@resolver.update_external_specs.should.be.true
end
it "allows to specify whether the sandbox can be modified and pre-downloads are allowed" do
@resolver.allow_pre_downloads = false
@resolver.allow_pre_downloads.should.be.false
end
it "allows pre-downloads by default" do
@resolver.allow_pre_downloads.should.be.true
end
#--------------------------------------#
it "resolves the specification of the podfile" do
......@@ -63,6 +49,8 @@ module Pod
it "it resolves specifications from external sources" do
podspec = fixture('integration/Reachability/Reachability.podspec')
spec = Specification.from_file(podspec)
config.sandbox.expects(:specification).with('Reachability').returns(spec)
podfile = Podfile.new do
platform :ios
pod "Reachability", :podspec => podspec
......@@ -182,7 +170,7 @@ module Pod
fss.subspec 'SecondSubSpec'
end
end
ExternalSources::GitSource.any_instance.stubs(:specification).returns(spec)
config.sandbox.expects(:specification).with('MainSpec').returns(spec)
resolver = Resolver.new(config.sandbox, @podfile)
specs = resolver.resolve.values.flatten.map(&:name).sort
specs.should == %w{ MainSpec/FirstSubSpec MainSpec/FirstSubSpec/SecondSubSpec }
......@@ -227,35 +215,6 @@ module Pod
end
end
#-------------------------------------------------------------------------#
describe "#set_from_external_source" do
before do
podfile = Podfile.new("#{temporary_directory}/Podfile") { }
@resolver = Resolver.new(config.sandbox, podfile)
end
it "it fetches the specification from either the sandbox or from the remote be default" do
dependency = Dependency.new('Name', :git => 'www.example.com')
ExternalSources::GitSource.any_instance.expects(:specification_from_external).returns(Specification.new).once
@resolver.send(:set_from_external_source, dependency)
end
it "it fetches the specification from the remote if in update mode" do
dependency = Dependency.new('Name', :git => 'www.example.com')
ExternalSources::GitSource.any_instance.expects(:specification).returns(Specification.new).once
@resolver.update_external_specs = false
@resolver.send(:set_from_external_source, dependency)
end
it "it fetches the specification only from the sandbox if pre-downloads are disabled" do
dependency = Dependency.new('Name', :git => 'www.example.com')
Sandbox.any_instance.expects(:specification).returns(Specification.new).once
@resolver.allow_pre_downloads = true
@resolver.send(:set_from_external_source, dependency)
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