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

[WIP][Analyzer] Download external sources before resolution

parent 3cfb3053
...@@ -3,39 +3,46 @@ ...@@ -3,39 +3,46 @@
[Core](https://github.com/CocoaPods/Core/master) [Core](https://github.com/CocoaPods/Core/master)
[Xcodeproj](https://github.com/CocoaPods/Xcodeproj/compare/0.4.0...master) [Xcodeproj](https://github.com/CocoaPods/Xcodeproj/compare/0.4.0...master)
###### Specification DSL ###### __Breaking__
- [__Breaking__] Deprecated `header_mappings` hook. - `requires_arc` is transitioning from `false` to `true`.
- [__Breaking__] Deprecated `exclude_header_search_paths` - Deprecated `header_mappings` hook.
- [__Breaking__] `requires_arc` is transitioning from `false` to `true`. - Deprecated `exclude_header_search_paths`
- [__Breaking__] The support for Rake File list is being deprecated. - The support for Rake File list is being deprecated.
- `preferred_dependency` has been renamed to `default_subspec`. - Support for inline podspecs has been removed.
- Added `exclude_files` attribute. - Subspecs do **not** inherit the files patterns from the parent spec anymore.
- Added `screenshots` attribute - External sources are not supported in specifications anymore.
- Added default values for attributes like `source_files`.
###### DSLs
###### Podfile DSL
- Podfile:
- It is not needed to specify the platform anymore (unless not integrating) - 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 ###### 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 - The workspace is written only if needed greatly reducing the occasions in
which Xcode asks to revert. which Xcode asks to revert.
- Specification hooks are only called when the specification is installed.
- The Lockfile is sorted reducing the SCM noise. - 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. - Added Podfile, Frameworks, and Resources to the Pods project.
[#647](https://github.com/CocoaPods/CocoaPods/issues/647) [#647](https://github.com/CocoaPods/CocoaPods/issues/647)
[#588](https://github.com/CocoaPods/CocoaPods/issues/588) [#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. - Adds new subcommand `pod spec cat NAME` to print a spec file to standard output.
- It is now possible to specify default values for the configuration in `~/.cocoapods/config.yaml` ([example]()). - Specification hooks are only called when the specification is installed.
- CocoaPods now checks the checksums of the installed specifications and reinstalls them if needed. - 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. - Added new command `pod ipc` to provide support for inter process communication.
###### Bug fixes ###### Bug fixes
...@@ -45,9 +52,8 @@ ...@@ -45,9 +52,8 @@
###### Codebase ###### Codebase
- Major clean up and refactor of the whole code base, with great reduction of - Major clean up and refactor of the whole code base.
the technical debt. - Extracted the core classes into
- Extracted the models of into
[CocoaPods-Core](https://github.com/CocoaPods/Core) gem. [CocoaPods-Core](https://github.com/CocoaPods/Core) gem.
- Extracted command-line command & option handling into - Extracted command-line command & option handling into
[CLAide](https://github.com/CocoaPods/CLAide). [CLAide](https://github.com/CocoaPods/CLAide).
......
...@@ -70,36 +70,17 @@ module Pod ...@@ -70,36 +70,17 @@ module Pod
public public
# @!group Specifications # @!group Fetching
# @return [Specification] returns the specification, either from the # Fetches the external source from the remote according to the params.
# 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.
# #
def specification_from_local(sandbox) # @param [Sandbox] sandbox
sandbox.specification(name) # the sandbox where the specification should be stored.
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.
# #
# @raise If not specification could be found. # @return [void]
# #
def specification_from_external(sandbox) def fetch(sandbox)
copy_external_source_into_sandbox(sandbox) raise "Abstract method"
spec = specification_from_local(sandbox)
unless spec
raise Informative, "No podspec found for `#{name}` in #{description}"
end
spec
end end
#--------------------------------------# #--------------------------------------#
...@@ -115,7 +96,7 @@ module Pod ...@@ -115,7 +96,7 @@ module Pod
# #
# @return [void] # @return [void]
# #
def copy_external_source_into_sandbox(sandbox) def fetch(sandbox)
raise "Abstract method" raise "Abstract method"
end end
...@@ -131,22 +112,25 @@ module Pod ...@@ -131,22 +112,25 @@ module Pod
# @! Subclasses helpers # @! Subclasses helpers
# Pre-downloads a Pod passing the options to the downloader and informing # Pre-downloads a Pod passing the options to the downloader and informing
# the sandbox. # the sandbox.
# #
# @param [Sandbox] 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] # @return [void]
# #
def pre_download(sandbox) 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 = sandbox.root + name
target.rmtree if target.exist? target.rmtree if target.exist?
downloader = Downloader.for_target(target, params) downloader = Downloader.for_target(target, params)
downloader.download downloader.download
sandbox.store_podspec(name, target + "#{name}.podspec", true) store_podspec(sandbox, target + "#{name}.podspec")
sandbox.store_pre_downloaded_pod(name) sandbox.store_pre_downloaded_pod(name)
if downloader.options_specific? if downloader.options_specific?
source = params source = params
...@@ -157,6 +141,27 @@ module Pod ...@@ -157,6 +141,27 @@ module Pod
end end
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 end
#-------------------------------------------------------------------------# #-------------------------------------------------------------------------#
...@@ -171,13 +176,9 @@ module Pod ...@@ -171,13 +176,9 @@ module Pod
# #
class GitSource < AbstractExternalSource class GitSource < 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) pre_download(sandbox)
end end
...@@ -205,13 +206,9 @@ module Pod ...@@ -205,13 +206,9 @@ module Pod
# #
class SvnSource < AbstractExternalSource 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 def fetch(sandbox)
# as pre-downloaded indicating to the installer that only clean
# operations are needed.
#
def copy_external_source_into_sandbox(sandbox)
pre_download(sandbox) pre_download(sandbox)
end end
...@@ -239,13 +236,9 @@ module Pod ...@@ -239,13 +236,9 @@ module Pod
# #
class MercurialSource < AbstractExternalSource class MercurialSource < 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) pre_download(sandbox)
end end
...@@ -265,14 +258,14 @@ module Pod ...@@ -265,14 +258,14 @@ module Pod
# #
class PodspecSource < AbstractExternalSource class PodspecSource < AbstractExternalSource
# @see AbstractExternalSource#copy_external_source_into_sandbox # @see AbstractExternalSource#fetch
# #
def copy_external_source_into_sandbox(sandbox) def fetch(sandbox)
UI.info("->".green + " Fetching podspec for `#{name}` from: #{params[:podspec]}") do UI.titled_section("Fetching podspec for `#{name}` #{description}", { :verbose_prefix => "-> " }) do
path = params[:podspec] path = params[:podspec]
path = Pathname.new(path).expand_path if path.to_s.start_with?("~") path = Pathname.new(path).expand_path if path.to_s.start_with?("~")
require 'open-uri' require 'open-uri'
open(path) { |io| sandbox.store_podspec(name, io.read, true) } open(path) { |io| store_podspec(sandbox, io.read) }
end end
end end
...@@ -292,11 +285,14 @@ module Pod ...@@ -292,11 +285,14 @@ module Pod
# #
class LocalSource < AbstractExternalSource class LocalSource < AbstractExternalSource
# @see AbstractExternalSource#copy_external_source_into_sandbox # @see AbstractExternalSource#fetch
# #
def copy_external_source_into_sandbox(sandbox) def fetch(sandbox)
sandbox.store_podspec(name, pod_spec_path, true) UI.titled_section("Fetching podspec for `#{name}` #{description}", { :verbose_prefix => "-> " }) do
sandbox.store_local_path(name, params[:local]) podspec = pod_spec_path
store_podspec(sandbox, podspec)
sandbox.store_local_path(name, podspec.dirname)
end
end end
# @see AbstractExternalSource#description # @see AbstractExternalSource#description
...@@ -305,29 +301,6 @@ module Pod ...@@ -305,29 +301,6 @@ module Pod
"from `#{params[:local]}`" "from `#{params[:local]}`"
end 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 private
......
...@@ -88,7 +88,7 @@ module Pod ...@@ -88,7 +88,7 @@ module Pod
end end
def resolve_dependencies def resolve_dependencies
UI.section "Resolving dependencies" do UI.section "Analyzing dependencies" do
analyze analyze
detect_pods_to_install detect_pods_to_install
prepare_for_legacy_compatibility prepare_for_legacy_compatibility
...@@ -173,22 +173,8 @@ module Pod ...@@ -173,22 +173,8 @@ module Pod
# #
def detect_pods_to_install def detect_pods_to_install
names = [] 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 += analysis_result.sandbox_state.added + analysis_result.sandbox_state.changed
names += sandbox.predownloaded_pods
names = names.map { |name| Specification.root_name(name) } names = names.map { |name| Specification.root_name(name) }
names = names.flatten.uniq names = names.flatten.uniq
@names_of_pods_to_install = names @names_of_pods_to_install = names
...@@ -231,11 +217,7 @@ module Pod ...@@ -231,11 +217,7 @@ module Pod
def create_file_accessors def create_file_accessors
libraries.each do |library| libraries.each do |library|
library.specs.each do |spec| library.specs.each do |spec|
if spec.local? pod_root = sandbox.pod_dir(spec.root.name)
pod_root = Pathname.new(spec.source[:local]).expand_path
else
pod_root = sandbox.pod_dir(spec.root.name)
end
path_list = Sandbox::PathList.new(pod_root) path_list = Sandbox::PathList.new(pod_root)
file_accessor = Sandbox::FileAccessor.new(path_list, spec.consumer(library.platform)) file_accessor = Sandbox::FileAccessor.new(path_list, spec.consumer(library.platform))
library.file_accessors ||= [] library.file_accessors ||= []
......
...@@ -52,6 +52,7 @@ module Pod ...@@ -52,6 +52,7 @@ module Pod
@locked_dependencies = generate_version_locking_dependencies @locked_dependencies = generate_version_locking_dependencies
@result.libraries = generated_libraries @result.libraries = generated_libraries
fetch_external_sources
@result.specs_by_target = resolve_dependencies @result.specs_by_target = resolve_dependencies
@result.specifications = generate_specifications @result.specifications = generate_specifications
@result.sandbox_state = generate_sandbox_state @result.sandbox_state = generate_sandbox_state
...@@ -134,7 +135,9 @@ module Pod ...@@ -134,7 +135,9 @@ module Pod
end end
pods_state pods_state
else else
SpecsState.new({}) state = SpecsState.new
state.added.concat(podfile.dependencies.map(&:root_name).uniq)
state
end end
end end
...@@ -211,6 +214,36 @@ module Pod ...@@ -211,6 +214,36 @@ module Pod
end end
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. # Converts the Podfile in a list of specifications grouped by target.
# #
# @note In this step the specs are added to the libraries. # @note In this step the specs are added to the libraries.
...@@ -235,19 +268,8 @@ module Pod ...@@ -235,19 +268,8 @@ module Pod
def resolve_dependencies def resolve_dependencies
specs_by_target = nil 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 UI.section "Resolving dependencies of #{UI.path podfile.defined_in_file}" do
resolver = Resolver.new(sandbox, podfile, locked_dependencies) 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 specs_by_target = resolver.resolve
end end
...@@ -270,28 +292,6 @@ module Pod ...@@ -270,28 +292,6 @@ module Pod
# Computes the state of the sandbox respect to the resolved # Computes the state of the sandbox respect to the resolved
# specifications. # 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 # @return [SpecsState] the representation of the state of the manifest
# specifications. # specifications.
# #
...@@ -383,6 +383,7 @@ module Pod ...@@ -383,6 +383,7 @@ module Pod
# @return [Array<PBXNativeTarget>] Returns the user’s targets, excluding # @return [Array<PBXNativeTarget>] Returns the user’s targets, excluding
# aggregate targets. # aggregate targets.
#
def native_targets(user_project) def native_targets(user_project)
user_project.targets.reject do |target| user_project.targets.reject do |target|
target.is_a? Xcodeproj::Project::Object::PBXAggregateTarget target.is_a? Xcodeproj::Project::Object::PBXAggregateTarget
......
...@@ -5,6 +5,27 @@ module Pod ...@@ -5,6 +5,27 @@ module Pod
# Analyze the sandbox to detect which Pods should be removed, and which # Analyze the sandbox to detect which Pods should be removed, and which
# ones should be reinstalled. # 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 class SandboxAnalyzer
# @return [Sandbox] The sandbox to analyze. # @return [Sandbox] The sandbox to analyze.
...@@ -129,7 +150,6 @@ module Pod ...@@ -129,7 +150,6 @@ module Pod
return true if folder_empty?(pod) return true if folder_empty?(pod)
if update_mode if update_mode
return true if spec.version.head? return true if spec.version.head?
# return true if sandbox.external_source?(pod) TODO
end end
return false return false
end end
...@@ -171,7 +191,7 @@ module Pod ...@@ -171,7 +191,7 @@ module Pod
specs.select { |s| s.root.name == pod }.map(&:name).uniq specs.select { |s| s.root.name == pod }.map(&:name).uniq
end 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). # sandbox manifest (includes subspecs).
# #
# @param [String] pod # @param [String] pod
......
...@@ -54,7 +54,7 @@ module Pod ...@@ -54,7 +54,7 @@ module Pod
# #
def relativize(path) def relativize(path)
unless path.absolute? 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 end
result = path.relative_path_from(root) result = path.relative_path_from(root)
......
...@@ -38,29 +38,8 @@ module Pod ...@@ -38,29 +38,8 @@ module Pod
@sandbox = sandbox @sandbox = sandbox
@podfile = podfile @podfile = podfile
@locked_dependencies = locked_dependencies @locked_dependencies = locked_dependencies
@allow_pre_downloads = true
end 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 public
...@@ -134,7 +113,7 @@ module Pod ...@@ -134,7 +113,7 @@ module Pod
private private
# !@ Helpers # @!group Private helpers
# Resolves recursively the dependencies of a specification and stores them # Resolves recursively the dependencies of a specification and stores them
# in the @cached_specs ivar. # in the @cached_specs ivar.
...@@ -188,23 +167,23 @@ module Pod ...@@ -188,23 +167,23 @@ module Pod
end end
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 # @param [Dependency] dependency
# the dependency for which the set is needed. # 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. # @return [Set] the cached set for a given dependency.
# #
def find_cached_set(dependency) def find_cached_set(dependency)
name = dependency.root_name name = dependency.root_name
unless cached_sets[name] unless cached_sets[name]
if dependency.external_source 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 else
set = cached_sources.search(dependency) set = cached_sources.search(dependency)
end end
...@@ -213,33 +192,6 @@ module Pod ...@@ -213,33 +192,6 @@ module Pod
cached_sets[name] cached_sets[name]
end 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. # Ensures that a specification is compatible with the platform of a target.
# #
# @raise If the specification is not supported by the target. # @raise If the specification is not supported by the target.
......
$ pod install --no-update --no-doc --verbose --no-color 2>&1 $ pod install --no-update --no-doc --verbose --no-color 2>&1
Resolving dependencies Analyzing dependencies
Finding Podfile changes Finding Podfile changes
A JSONKit A JSONKit
......
$ pod install --no-update --no-doc --verbose --no-color 2>&1 $ 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 of `Podfile`
Resolving dependencies for target `default' (iOS 4.3) Resolving dependencies for target `default' (iOS 4.3)
- PodTest (from `PodTest-hg-source`) - 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_1 (= 1.0)
- PodTest/subspec_2 (= 1.0) - PodTest/subspec_2 (= 1.0)
......
$ pod install --no-update --no-doc --verbose --no-color 2>&1 $ 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 of `Podfile`
Resolving dependencies for target `default' (iOS 4.3) Resolving dependencies for target `default' (iOS 4.3)
......
$ pod install --no-update --no-doc --verbose --no-color 2>&1 $ pod install --no-update --no-doc --verbose --no-color 2>&1
Resolving dependencies Analyzing dependencies
Resolving dependencies of `Podfile` Resolving dependencies of `Podfile`
Resolving dependencies for target `SampleApp_2' (iOS 6.0) Resolving dependencies for target `SampleApp_2' (iOS 6.0)
......
$ pod install --no-update --no-doc --verbose --no-color 2>&1 $ pod install --no-update --no-doc --verbose --no-color 2>&1
Resolving dependencies Analyzing dependencies
Resolving dependencies of `Podfile` Resolving dependencies of `Podfile`
Resolving dependencies for target `default' (iOS 6.0) Resolving dependencies for target `default' (iOS 6.0)
......
$ pod install --no-update --no-doc --verbose --no-color 2>&1 $ pod install --no-update --no-doc --verbose --no-color 2>&1
Resolving dependencies Analyzing dependencies
Resolving dependencies of `Podfile` Resolving dependencies of `Podfile`
Resolving dependencies for target `default' (iOS 6.0) Resolving dependencies for target `default' (iOS 6.0)
......
$ pod install --no-update --no-doc --verbose --no-color 2>&1 $ 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 of `Podfile`
Resolving dependencies for target `default' (iOS 6.0) Resolving dependencies for target `default' (iOS 6.0)
- Reachability (from `Reachability.podspec`) - Reachability (from `Reachability.podspec`)
-> Fetching podspec for `Reachability` from: Reachability.podspec
Comparing resolved specification to the sandbox manifest Comparing resolved specification to the sandbox manifest
A Reachability A Reachability
......
$ pod install --no-update --no-doc --verbose --no-color 2>&1 $ pod install --no-update --no-doc --verbose --no-color 2>&1
Resolving dependencies Analyzing dependencies
Finding Podfile changes Finding Podfile changes
R JSONKit R JSONKit
......
$ pod install --no-update --no-doc --verbose --no-color 2>&1 $ 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 of `Podfile`
Resolving dependencies for target `default' (iOS 6.0) Resolving dependencies for target `default' (iOS 6.0)
- Reachability (from `Reachability.podspec`) - Reachability (from `Reachability.podspec`)
-> Fetching podspec for `Reachability` from: Reachability.podspec
Comparing resolved specification to the sandbox manifest Comparing resolved specification to the sandbox manifest
A Reachability A Reachability
......
$ pod install --no-update --no-doc --verbose --no-color 2>&1 $ 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 of `Podfile`
Resolving dependencies for target `OS X App' (OS X 10.6) Resolving dependencies for target `OS X App' (OS X 10.6)
- PodTest/subspec_2 (from `PodTest-hg-source`) - 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 `default' (iOS 6.1)
Resolving dependencies for target `iOS App' (iOS 4.3) Resolving dependencies for target `iOS App' (iOS 4.3)
- PodTest/subspec_1 (from `PodTest-hg-source`) - PodTest/subspec_1 (from `PodTest-hg-source`)
......
$ pod update --no-update --no-doc --verbose --no-color 2>&1 $ pod update --no-update --no-doc --verbose --no-color 2>&1
Resolving dependencies Analyzing dependencies
Finding Podfile changes Finding Podfile changes
- Reachability - Reachability
......
...@@ -320,10 +320,6 @@ describe "Integration take 2" do ...@@ -320,10 +320,6 @@ describe "Integration take 2" do
check "install --no-update --no-doc", "install_multiple_targets" check "install --no-update --no-doc", "install_multiple_targets"
end 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 describe "Installs a Pod with different subspecs activated across different targets" do
check "install --no-update --no-doc", "install_subspecs" check "install --no-update --no-doc", "install_subspecs"
end end
......
...@@ -39,35 +39,10 @@ module Pod ...@@ -39,35 +39,10 @@ module Pod
dependency_1.should.not.be == dependency_3 dependency_1.should.not.be == dependency_3
end end
it "returns the specification from the sandbox if available" do it "fetches the specification from the remote stores it in the sandbox" do
config.sandbox.store_podspec('Reachability', fixture('integration/Reachability/Reachability.podspec')) config.sandbox.specification('Reachability').should == nil
@external_source.expects(:specification_from_external).never @external_source.fetch(config.sandbox)
@external_source.specification(config.sandbox).name.should == 'Reachability' config.sandbox.specification('Reachability').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?
end end
end end
...@@ -104,13 +79,13 @@ module Pod ...@@ -104,13 +79,13 @@ module Pod
end end
it "creates a copy of the podspec" do 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 = config.sandbox.root + 'Local Podspecs/Reachability.podspec'
path.should.exist? path.should.exist?
end end
it "marks a LocalPod as downloaded" do 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"] config.sandbox.predownloaded_pods.should == ["Reachability"]
end end
...@@ -129,13 +104,13 @@ module Pod ...@@ -129,13 +104,13 @@ module Pod
end end
it "creates a copy of the podspec" do 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 = config.sandbox.root + 'Local Podspecs/SvnSource.podspec'
path.should.exist? path.should.exist?
end end
it "marks a LocalPod as downloaded" do 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"] config.sandbox.predownloaded_pods.should == ["SvnSource"]
end end
...@@ -154,13 +129,13 @@ module Pod ...@@ -154,13 +129,13 @@ module Pod
end end
it "creates a copy of the podspec" do 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 = config.sandbox.root + 'Local Podspecs/MercurialSource.podspec'
path.should.exist? path.should.exist?
end end
it "marks a LocalPod as downloaded" do 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"] config.sandbox.predownloaded_pods.should == ["MercurialSource"]
end end
...@@ -180,7 +155,7 @@ module Pod ...@@ -180,7 +155,7 @@ module Pod
end end
it "creates a copy of the podspec" do 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 = config.sandbox.root + 'Local Podspecs/Reachability.podspec'
path.should.exist? path.should.exist?
end end
...@@ -202,7 +177,7 @@ module Pod ...@@ -202,7 +177,7 @@ module Pod
end end
it "creates a copy of the podspec" do 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 = config.sandbox.root + 'Local Podspecs/Reachability.podspec'
path.should.exist? path.should.exist?
end end
...@@ -212,7 +187,7 @@ module Pod ...@@ -212,7 +187,7 @@ module Pod
end end
it "marks the Pod as local in the sandbox" do 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 == { config.sandbox.local_pods.should == {
"Reachability" => fixture('integration/Reachability').to_s "Reachability" => fixture('integration/Reachability').to_s
} }
......
...@@ -89,8 +89,10 @@ module Pod ...@@ -89,8 +89,10 @@ module Pod
@analyzer.send(:pod_changed?, 'BananaLib').should == true @analyzer.send(:pod_changed?, 'BananaLib').should == true
end 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
end end
......
...@@ -3,7 +3,7 @@ require File.expand_path('../../../spec_helper', __FILE__) ...@@ -3,7 +3,7 @@ require File.expand_path('../../../spec_helper', __FILE__)
# @return [Analyzer] the sample analyzer. # @return [Analyzer] the sample analyzer.
# #
def create_analyzer def create_analyzer
podfile = Pod::Podfile.new do @podfile = Pod::Podfile.new do
platform :ios, '6.0' platform :ios, '6.0'
xcodeproj 'SampleProject/SampleProject' xcodeproj 'SampleProject/SampleProject'
pod 'JSONKit', '1.5pre' pod 'JSONKit', '1.5pre'
...@@ -20,7 +20,7 @@ def create_analyzer ...@@ -20,7 +20,7 @@ def create_analyzer
lockfile = Pod::Lockfile.new(hash) lockfile = Pod::Lockfile.new(hash)
SpecHelper.create_sample_app_copy_from_fixture('SampleProject') 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 end
#-----------------------------------------------------------------------------# #-----------------------------------------------------------------------------#
...@@ -111,6 +111,37 @@ module Pod ...@@ -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 it "resolves the dependencies" do
@analyzer.analyze.specifications.map(&:to_s).should == [ @analyzer.analyze.specifications.map(&:to_s).should == [
"AFNetworking (1.0.1)", "AFNetworking (1.0.1)",
...@@ -120,7 +151,7 @@ module Pod ...@@ -120,7 +151,7 @@ module Pod
] ]
end 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 @analyzer.allow_pre_downloads = true
podspec = @analyzer.sandbox.root + 'Local Podspecs/JSONKit.podspec' podspec = @analyzer.sandbox.root + 'Local Podspecs/JSONKit.podspec'
podspec.dirname.mkpath podspec.dirname.mkpath
...@@ -138,28 +169,6 @@ module Pod ...@@ -138,28 +169,6 @@ module Pod
] ]
end 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 it "computes the state of the Sandbox respect to the resolved dependencies" do
......
...@@ -128,60 +128,22 @@ module Pod ...@@ -128,60 +128,22 @@ module Pod
end end
it "includes the added Pods" do 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.send(:detect_pods_to_install)
@installer.names_of_pods_to_install.should == ['Added-Pod'] @installer.names_of_pods_to_install.should == ['added-pod']
end end
it "includes the changed Pods" do 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.send(:detect_pods_to_install)
@installer.names_of_pods_to_install.should == ['Changed-Pod'] @installer.names_of_pods_to_install.should == ['changed-pod']
end end
it "includes head pods in update mode" do it "includes the pre-downloaded Pods" do
spec = Spec.new do |s| @analysis_result.sandbox_state.add_name('unchanged-pods', :unchanged)
s.name = 'Head-Pod' config.sandbox.stubs(:predownloaded_pods).returns(['pre-downloaded-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
@installer.send(:detect_pods_to_install) @installer.send(:detect_pods_to_install)
@installer.names_of_pods_to_install.should == ['Head-Pod'] @installer.names_of_pods_to_install.should == ['pre-downloaded-pod']
end
xit "includes pods whose root folder is empty" do
end end
end end
......
...@@ -24,20 +24,6 @@ module Pod ...@@ -24,20 +24,6 @@ module Pod
@resolver.locked_dependencies.should == [Dependency.new('BlocksKit', '1.5.2')] @resolver.locked_dependencies.should == [Dependency.new('BlocksKit', '1.5.2')]
end 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 it "resolves the specification of the podfile" do
...@@ -63,6 +49,8 @@ module Pod ...@@ -63,6 +49,8 @@ module Pod
it "it resolves specifications from external sources" do it "it resolves specifications from external sources" do
podspec = fixture('integration/Reachability/Reachability.podspec') podspec = fixture('integration/Reachability/Reachability.podspec')
spec = Specification.from_file(podspec)
config.sandbox.expects(:specification).with('Reachability').returns(spec)
podfile = Podfile.new do podfile = Podfile.new do
platform :ios platform :ios
pod "Reachability", :podspec => podspec pod "Reachability", :podspec => podspec
...@@ -182,7 +170,7 @@ module Pod ...@@ -182,7 +170,7 @@ module Pod
fss.subspec 'SecondSubSpec' fss.subspec 'SecondSubSpec'
end end
end end
ExternalSources::GitSource.any_instance.stubs(:specification).returns(spec) config.sandbox.expects(:specification).with('MainSpec').returns(spec)
resolver = Resolver.new(config.sandbox, @podfile) resolver = Resolver.new(config.sandbox, @podfile)
specs = resolver.resolve.values.flatten.map(&:name).sort specs = resolver.resolve.values.flatten.map(&:name).sort
specs.should == %w{ MainSpec/FirstSubSpec MainSpec/FirstSubSpec/SecondSubSpec } specs.should == %w{ MainSpec/FirstSubSpec MainSpec/FirstSubSpec/SecondSubSpec }
...@@ -227,35 +215,6 @@ module Pod ...@@ -227,35 +215,6 @@ module Pod
end end
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