Commit eb272e33 authored by Dimitris Koutsogiorgas's avatar Dimitris Koutsogiorgas Committed by Dimitris Koutsogiorgas

Remove analyzer `attr_accessor` properties

parent 4f8ffc7b
...@@ -241,15 +241,13 @@ module Pod ...@@ -241,15 +241,13 @@ module Pod
# @return [void] # @return [void]
# #
def analyze(analyzer = create_analyzer) def analyze(analyzer = create_analyzer)
analyzer.update = update
@analysis_result = analyzer.analyze @analysis_result = analyzer.analyze
@aggregate_targets = analyzer.result.targets @aggregate_targets = @analysis_result.targets
end end
def create_analyzer(plugin_sources = nil) def create_analyzer(plugin_sources = nil)
Analyzer.new(sandbox, podfile, lockfile, plugin_sources).tap do |analyzer| Analyzer.new(sandbox, podfile, lockfile, plugin_sources, has_dependencies?, update).tap do |analyzer|
analyzer.installation_options = installation_options analyzer.installation_options = installation_options
analyzer.has_dependencies = has_dependencies?
end end
end end
...@@ -684,9 +682,9 @@ module Pod ...@@ -684,9 +682,9 @@ module Pod
plugin_sources = run_source_provider_hooks plugin_sources = run_source_provider_hooks
analyzer = create_analyzer(plugin_sources) analyzer = create_analyzer(plugin_sources)
analyze(analyzer) analyze(analyzer)
if analyzer.podfile_needs_install?(analyzer.result) if analysis_result.podfile_needs_install?
raise Pod::Informative, 'The Podfile has changed, you must run `pod install`' raise Pod::Informative, 'The Podfile has changed, you must run `pod install`'
elsif analyzer.sandbox_needs_install?(analyzer.result) elsif analysis_result.sandbox_needs_install?
raise Pod::Informative, 'The `Pods` directory is out-of-date, you must run `pod install`' raise Pod::Informative, 'The `Pods` directory is out-of-date, you must run `pod install`'
end end
......
...@@ -19,42 +19,51 @@ module Pod ...@@ -19,42 +19,51 @@ module Pod
autoload :TargetInspectionResult, 'cocoapods/installer/analyzer/target_inspection_result' autoload :TargetInspectionResult, 'cocoapods/installer/analyzer/target_inspection_result'
autoload :TargetInspector, 'cocoapods/installer/analyzer/target_inspector' autoload :TargetInspector, 'cocoapods/installer/analyzer/target_inspector'
# @return [Sandbox] The sandbox where the Pods should be installed. # @return [Sandbox] The sandbox to use for this analysis.
# #
attr_reader :sandbox attr_reader :sandbox
# @return [Podfile] The Podfile specification that contains the # @return [Podfile] The Podfile specification that contains the information of the Pods that should be installed.
# information of the Pods that should be installed.
# #
attr_reader :podfile attr_reader :podfile
# @return [Lockfile] The Lockfile that stores the information about the # @return [Lockfile] The Lockfile, if available, that stores the information about the Pods previously installed.
# Pods previously installed on any machine.
# #
attr_reader :lockfile attr_reader :lockfile
# @return [Array<Source>] Sources provided by plugins # @return [Array<Source>] Sources provided by plugins or `nil`.
# #
attr_reader :plugin_sources attr_reader :plugin_sources
# @return [Bool] Whether the analysis has dependencies and thus sources must be configured.
#
# @note This is used by the `pod lib lint` command to prevent update of specs when not needed.
#
attr_reader :has_dependencies
alias_method :has_dependencies?, :has_dependencies
# @return [Hash, Boolean, nil] Pods that have been requested to be updated or true if all Pods should be updated.
# This can be false if no pods should be updated.
#
attr_reader :pods_to_update
# Initialize a new instance # Initialize a new instance
# #
# @param [Sandbox] sandbox @see #sandbox # @param [Sandbox] sandbox @see #sandbox
# @param [Podfile] podfile @see #podfile # @param [Podfile] podfile @see #podfile
# @param [Lockfile] lockfile @see #lockfile # @param [Lockfile] lockfile @see #lockfile
# @param [Array<Source>] plugin_sources @see #plugin_sources # @param [Array<Source>] plugin_sources @see #plugin_sources
# @param [Boolean] has_dependencies @see #has_dependencies
# @param [Hash, Boolean, nil] pods_to_update @see #pods_to_update
# #
def initialize(sandbox, podfile, lockfile = nil, plugin_sources = nil) def initialize(sandbox, podfile, lockfile = nil, plugin_sources = nil, has_dependencies = true,
pods_to_update = false)
@sandbox = sandbox @sandbox = sandbox
@podfile = podfile @podfile = podfile
@lockfile = lockfile @lockfile = lockfile
@plugin_sources = plugin_sources @plugin_sources = plugin_sources
@has_dependencies = has_dependencies
@update = false @pods_to_update = pods_to_update
@allow_pre_downloads = true
@has_dependencies = true
@test_pod_target_analyzer_cache = {}
@test_pod_target_key = Struct.new(:name, :pod_targets)
@podfile_dependency_cache = PodfileDependencyCache.from_podfile(podfile) @podfile_dependency_cache = PodfileDependencyCache.from_podfile(podfile)
@result = nil @result = nil
end end
...@@ -74,122 +83,109 @@ module Pod ...@@ -74,122 +83,109 @@ module Pod
return @result if @result return @result if @result
validate_podfile! validate_podfile!
validate_lockfile_version! validate_lockfile_version!
@result = AnalysisResult.new
@result.podfile_dependency_cache = @podfile_dependency_cache
if installation_options.integrate_targets? if installation_options.integrate_targets?
@result.target_inspections = inspect_targets_to_integrate target_inspections = inspect_targets_to_integrate
else else
verify_platforms_specified! verify_platforms_specified!
target_inspections = {}
end end
@result.podfile_state = generate_podfile_state podfile_state = generate_podfile_state
store_existing_checkout_options store_existing_checkout_options
fetch_external_sources if allow_fetches fetch_external_sources(podfile_state) if allow_fetches
@locked_dependencies = generate_version_locking_dependencies locked_dependencies = generate_version_locking_dependencies(podfile_state)
resolver_specs_by_target = resolve_dependencies resolver_specs_by_target = resolve_dependencies(locked_dependencies)
validate_platforms(resolver_specs_by_target) validate_platforms(resolver_specs_by_target)
@result.specifications = generate_specifications(resolver_specs_by_target) specifications = generate_specifications(resolver_specs_by_target)
@result.targets = generate_targets(resolver_specs_by_target) targets = generate_targets(resolver_specs_by_target, target_inspections)
@result.sandbox_state = generate_sandbox_state sandbox_state = generate_sandbox_state(specifications)
@result.specs_by_target = resolver_specs_by_target.each_with_object({}) do |rspecs_by_target, hash| specs_by_target = resolver_specs_by_target.each_with_object({}) do |rspecs_by_target, hash|
hash[rspecs_by_target[0]] = rspecs_by_target[1].map(&:spec) hash[rspecs_by_target[0]] = rspecs_by_target[1].map(&:spec)
end end
@result.specs_by_source = Hash[resolver_specs_by_target.values.flatten(1).group_by(&:source).map { |source, specs| [source, specs.map(&:spec).uniq] }] specs_by_source = Hash[resolver_specs_by_target.values.flatten(1).group_by(&:source).map do |source, specs|
sources.each { |s| @result.specs_by_source[s] ||= [] } [source, specs.map(&:spec).uniq]
@result end]
sources.each { |s| specs_by_source[s] ||= [] }
@result = AnalysisResult.new(podfile_state, specs_by_target, specs_by_source, specifications, sandbox_state,
targets, @podfile_dependency_cache)
end end
attr_accessor :result # Updates the git source repositories.
# @return [Bool] Whether an installation should be performed or this
# CocoaPods project is already up to date.
# #
def needs_install? def update_repositories
analysis_result = analyze(false) sources.each do |source|
podfile_needs_install?(analysis_result) || sandbox_needs_install?(analysis_result) if source.git?
config.sources_manager.update(source.name, true)
else
UI.message "Skipping `#{source.name}` update because the repository is not a git source repository."
end
end
@specs_updated = true
end end
# @param [AnalysisResult] analysis_result # Returns the sources used to query for specifications.
# the analysis result to check for changes
#
# @return [Bool] Whether the podfile has changes respect to the lockfile.
# #
def podfile_needs_install?(analysis_result) # When no explicit Podfile sources or plugin sources are defined, this defaults to the master spec repository.
state = analysis_result.podfile_state
needing_install = state.added + state.changed + state.deleted
!needing_install.empty?
end
# @param [AnalysisResult] analysis_result
# the analysis result to check for changes
# #
# @return [Bool] Whether the sandbox is in synch with the lockfile. # @return [Array<Source>] the sources to be used in finding specifications, as specified by the podfile or all
# sources.
# #
def sandbox_needs_install?(analysis_result) def sources
state = analysis_result.sandbox_state @sources ||= begin
needing_install = state.added + state.changed + state.deleted sources = podfile.sources
!needing_install.empty? plugin_sources = @plugin_sources || []
# Add any sources specified using the :source flag on individual dependencies.
dependency_sources = @podfile_dependency_cache.podfile_dependencies.map(&:podspec_repo).compact
all_dependencies_have_sources = dependency_sources.count == @podfile_dependency_cache.podfile_dependencies.count
if all_dependencies_have_sources
sources = dependency_sources
elsif has_dependencies? && sources.empty? && plugin_sources.empty?
sources = ['https://github.com/CocoaPods/Specs.git']
else
sources += dependency_sources
end
result = sources.uniq.map do |source_url|
config.sources_manager.find_or_create_source_with_url(source_url)
end
unless plugin_sources.empty?
result.insert(0, *plugin_sources)
end
result
end
end end
#-----------------------------------------------------------------------# #-----------------------------------------------------------------------#
# @!group Configuration private
# @return [Hash, Boolean, nil] Pods that have been requested to be # @!group Configuration
# updated or true if all Pods should be updated
#
attr_accessor :update
# @return [Bool] Whether the version of the dependencies which did not # @return [Bool] Whether the version of the dependencies which did not
# change in the Podfile should be locked. # change in the Podfile should be locked.
# #
def update_mode? def update_mode?
update != nil pods_to_update != nil
end end
# @return [Symbol] Whether and how the dependencies in the Podfile # @return [Symbol] Whether and how the dependencies in the Podfile
# should be updated. # should be updated.
# #
def update_mode def update_mode
if !update if !pods_to_update
:none :none
elsif update == true elsif pods_to_update == true
:all :all
elsif !update[:pods].nil? elsif !pods_to_update[:pods].nil?
:selected :selected
end end
end end
# @return [Bool] Whether the analysis allows pre-downloads and thus
# modifications to the sandbox.
#
# @note This flag should not be used in installations.
#
# @note This is used by the `pod outdated` command to prevent
# modification of the sandbox in the resolution process.
#
attr_accessor :allow_pre_downloads
alias_method :allow_pre_downloads?, :allow_pre_downloads
# @return [Bool] Whether the analysis has dependencies and thus
# sources must be configured.
#
# @note This is used by the `pod lib lint` command to prevent
# update of specs when not needed.
#
attr_accessor :has_dependencies
alias_method :has_dependencies?, :has_dependencies
#-----------------------------------------------------------------------# #-----------------------------------------------------------------------#
private
# @return [Bool] Whether the analysis has updated sources repositories.
#
attr_accessor :specs_updated
alias_method :specs_updated?, :specs_updated
def validate_podfile! def validate_podfile!
validator = Installer::PodfileValidator.new(podfile, @podfile_dependency_cache) validator = Installer::PodfileValidator.new(podfile, @podfile_dependency_cache)
validator.validate validator.validate
...@@ -225,6 +221,8 @@ module Pod ...@@ -225,6 +221,8 @@ module Pod
# the name of the Pod (root name of the dependencies) and doesn't # the name of the Pod (root name of the dependencies) and doesn't
# group them by target definition. # group them by target definition.
# #
# @return [SpecState]
#
def generate_podfile_state def generate_podfile_state
if lockfile if lockfile
pods_state = nil pods_state = nil
...@@ -241,23 +239,6 @@ module Pod ...@@ -241,23 +239,6 @@ module Pod
end end
end end
public
# Updates the git source repositories.
#
def update_repositories
sources.each do |source|
if source.git?
config.sources_manager.update(source.name, true)
else
UI.message "Skipping `#{source.name}` update because the repository is not a git source repository."
end
end
@specs_updated = true
end
private
# Copies the pod_targets of any of the app embedded aggregate targets into # Copies the pod_targets of any of the app embedded aggregate targets into
# their potential host aggregate target, if that potential host aggregate target's # their potential host aggregate target, if that potential host aggregate target's
# user_target hosts any of the app embedded aggregate targets' user_targets # user_target hosts any of the app embedded aggregate targets' user_targets
...@@ -383,13 +364,16 @@ module Pod ...@@ -383,13 +364,16 @@ module Pod
# mapping of targets to resolved specs (containing information about test usage) # mapping of targets to resolved specs (containing information about test usage)
# aggregate targets # aggregate targets
# #
# @param [Array<TargetInspection>] target_inspections
# the user target inspections used to construct the aggregate and pod targets.
#
# @return [Array<AggregateTarget>] the list of aggregate targets generated. # @return [Array<AggregateTarget>] the list of aggregate targets generated.
# #
def generate_targets(resolver_specs_by_target) def generate_targets(resolver_specs_by_target, target_inspections)
resolver_specs_by_target = resolver_specs_by_target.reject { |td, _| td.abstract? } resolver_specs_by_target = resolver_specs_by_target.reject { |td, _| td.abstract? }
pod_targets = generate_pod_targets(resolver_specs_by_target) pod_targets = generate_pod_targets(resolver_specs_by_target, target_inspections)
aggregate_targets = resolver_specs_by_target.keys.map do |target_definition| aggregate_targets = resolver_specs_by_target.keys.map do |target_definition|
generate_target(target_definition, pod_targets, resolver_specs_by_target) generate_target(target_definition, target_inspections, pod_targets, resolver_specs_by_target)
end end
if installation_options.integrate_targets? if installation_options.integrate_targets?
# Copy embedded target pods that cannot have their pods embedded as frameworks to # Copy embedded target pods that cannot have their pods embedded as frameworks to
...@@ -420,6 +404,9 @@ module Pod ...@@ -420,6 +404,9 @@ module Pod
# @param [TargetDefinition] target_definition # @param [TargetDefinition] target_definition
# the target definition for the user target. # the target definition for the user target.
# #
# @param [Array<TargetInspection>] target_inspections
# the user target inspections used to construct the aggregate and pod targets.
#
# @param [Array<PodTarget>] pod_targets # @param [Array<PodTarget>] pod_targets
# the pod targets, which were generated. # the pod targets, which were generated.
# #
...@@ -428,9 +415,9 @@ module Pod ...@@ -428,9 +415,9 @@ module Pod
# #
# @return [AggregateTarget] # @return [AggregateTarget]
# #
def generate_target(target_definition, pod_targets, resolver_specs_by_target) def generate_target(target_definition, target_inspections, pod_targets, resolver_specs_by_target)
if installation_options.integrate_targets? if installation_options.integrate_targets?
target_inspection = result.target_inspections[target_definition] target_inspection = target_inspections[target_definition]
raise "missing inspection: #{target_definition.name}" unless target_inspection raise "missing inspection: #{target_definition.name}" unless target_inspection
user_project = target_inspection.project user_project = target_inspection.project
client_root = user_project.path.dirname.realpath client_root = user_project.path.dirname.realpath
...@@ -478,7 +465,9 @@ module Pod ...@@ -478,7 +465,9 @@ module Pod
pod_targets.each do |pod_target| pod_targets.each do |pod_target|
next unless pod_target.target_definitions.include?(target_definition) next unless pod_target.target_definitions.include?(target_definition)
next unless resolver_specs_by_target[target_definition].any? { |resolver_spec| !resolver_spec.used_by_tests_only? && pod_target.specs.include?(resolver_spec.spec) } next unless resolver_specs_by_target[target_definition].any? do |resolver_spec|
!resolver_spec.used_by_tests_only? && pod_target.specs.include?(resolver_spec.spec)
end
pod_name = pod_target.pod_name pod_name = pod_target.pod_name
...@@ -515,9 +504,12 @@ module Pod ...@@ -515,9 +504,12 @@ module Pod
# @param [Hash{Podfile::TargetDefinition => Array<ResolvedSpecification>}] resolver_specs_by_target # @param [Hash{Podfile::TargetDefinition => Array<ResolvedSpecification>}] resolver_specs_by_target
# the resolved specifications grouped by target. # the resolved specifications grouped by target.
# #
# @param [Array<TargetInspection>] target_inspections
# the user target inspections used to construct the aggregate and pod targets.
#
# @return [Array<PodTarget>] # @return [Array<PodTarget>]
# #
def generate_pod_targets(resolver_specs_by_target) def generate_pod_targets(resolver_specs_by_target, target_inspections)
if installation_options.deduplicate_targets? if installation_options.deduplicate_targets?
distinct_targets = resolver_specs_by_target.each_with_object({}) do |dependency, hash| distinct_targets = resolver_specs_by_target.each_with_object({}) do |dependency, hash|
target_definition, dependent_specs = *dependency target_definition, dependent_specs = *dependency
...@@ -534,7 +526,7 @@ module Pod ...@@ -534,7 +526,7 @@ module Pod
pod_targets = distinct_targets.flat_map do |_root, target_definitions_by_variant| pod_targets = distinct_targets.flat_map do |_root, target_definitions_by_variant|
suffixes = PodVariantSet.new(target_definitions_by_variant.keys).scope_suffixes suffixes = PodVariantSet.new(target_definitions_by_variant.keys).scope_suffixes
target_definitions_by_variant.flat_map do |variant, target_definitions| target_definitions_by_variant.flat_map do |variant, target_definitions|
generate_pod_target(target_definitions, variant.specs + variant.test_specs, :scope_suffix => suffixes[variant]) generate_pod_target(target_definitions, target_inspections, variant.specs + variant.test_specs, :scope_suffix => suffixes[variant])
end end
end end
...@@ -559,7 +551,7 @@ module Pod ...@@ -559,7 +551,7 @@ module Pod
resolver_specs_by_target.flat_map do |target_definition, specs| resolver_specs_by_target.flat_map do |target_definition, specs|
grouped_specs = specs.group_by(&:root).values.uniq grouped_specs = specs.group_by(&:root).values.uniq
pod_targets = grouped_specs.flat_map do |pod_specs| pod_targets = grouped_specs.flat_map do |pod_specs|
generate_pod_target([target_definition], pod_specs.map(&:spec)).scoped(dedupe_cache) generate_pod_target([target_definition], target_inspections, pod_specs.map(&:spec)).scoped(dedupe_cache)
end end
pod_targets.each do |target| pod_targets.each do |target|
...@@ -628,6 +620,9 @@ module Pod ...@@ -628,6 +620,9 @@ module Pod
# @param [TargetDefinitions] target_definitions # @param [TargetDefinitions] target_definitions
# the aggregate target # the aggregate target
# #
# @param [Array<TargetInspection>] target_inspections
# the user target inspections used to construct the aggregate and pod targets.
#
# @param [Array<Specification>] specs # @param [Array<Specification>] specs
# the specifications of an equal root. # the specifications of an equal root.
# #
...@@ -636,9 +631,9 @@ module Pod ...@@ -636,9 +631,9 @@ module Pod
# #
# @return [PodTarget] # @return [PodTarget]
# #
def generate_pod_target(target_definitions, specs, scope_suffix: nil) def generate_pod_target(target_definitions, target_inspections, specs, scope_suffix: nil)
if installation_options.integrate_targets? if installation_options.integrate_targets?
target_inspections = result.target_inspections.select { |t, _| target_definitions.include?(t) }.values target_inspections = target_inspections.select { |t, _| target_definitions.include?(t) }.values
user_build_configurations = target_inspections.map(&:build_configurations).reduce({}, &:merge) user_build_configurations = target_inspections.map(&:build_configurations).reduce({}, &:merge)
archs = target_inspections.flat_map(&:archs).compact.uniq.sort archs = target_inspections.flat_map(&:archs).compact.uniq.sort
else else
...@@ -707,21 +702,24 @@ module Pod ...@@ -707,21 +702,24 @@ module Pod
# is in update mode, to prevent it from upgrading the Pods that weren't # is in update mode, to prevent it from upgrading the Pods that weren't
# changed in the {Podfile}. # changed in the {Podfile}.
# #
# @param [SpecState] podfile_state
# the state of the podfile for which dependencies have or have not changed, added, deleted or updated.
#
# @return [Molinillo::DependencyGraph<Dependency>] the dependencies # @return [Molinillo::DependencyGraph<Dependency>] the dependencies
# generated by the lockfile that prevent the resolver to update # generated by the lockfile that prevent the resolver to update
# a Pod. # a Pod.
# #
def generate_version_locking_dependencies def generate_version_locking_dependencies(podfile_state)
if update_mode == :all || !lockfile if update_mode == :all || !lockfile
LockingDependencyAnalyzer.unlocked_dependency_graph LockingDependencyAnalyzer.unlocked_dependency_graph
else else
pods_to_update = result.podfile_state.changed + result.podfile_state.deleted deleted_and_changed = podfile_state.changed + podfile_state.deleted
pods_to_update += update[:pods] if update_mode == :selected deleted_and_changed += pods_to_update[:pods] if update_mode == :selected
local_pod_names = @podfile_dependency_cache.podfile_dependencies.select(&:local?).map(&:root_name) local_pod_names = @podfile_dependency_cache.podfile_dependencies.select(&:local?).map(&:root_name)
pods_to_unlock = local_pod_names.to_set.delete_if do |pod_name| pods_to_unlock = local_pod_names.to_set.delete_if do |pod_name|
sandbox.specification(pod_name).checksum == lockfile.checksum(pod_name) sandbox.specification(pod_name).checksum == lockfile.checksum(pod_name)
end end
LockingDependencyAnalyzer.generate_version_locking_dependencies(lockfile, pods_to_update, pods_to_unlock) LockingDependencyAnalyzer.generate_version_locking_dependencies(lockfile, deleted_and_changed, pods_to_unlock)
end end
end end
...@@ -740,16 +738,17 @@ module Pod ...@@ -740,16 +738,17 @@ module Pod
# compatible with the version reported by the podspec of the # compatible with the version reported by the podspec of the
# external source the resolver will raise. # external source the resolver will raise.
# #
# @param [SpecState] podfile_state
# the state of the podfile for which dependencies have or have not changed, added, deleted or updated.
#
# @return [void] # @return [void]
# #
def fetch_external_sources def fetch_external_sources(podfile_state)
return unless allow_pre_downloads?
verify_no_pods_with_different_sources! verify_no_pods_with_different_sources!
unless dependencies_to_fetch.empty? unless dependencies_to_fetch(podfile_state).empty?
UI.section 'Fetching external sources' do UI.section 'Fetching external sources' do
dependencies_to_fetch.sort.each do |dependency| dependencies_to_fetch(podfile_state).sort.each do |dependency|
fetch_external_source(dependency, !pods_to_fetch.include?(dependency.root_name)) fetch_external_source(dependency, !pods_to_fetch(podfile_state).include?(dependency.root_name))
end end
end end
end end
...@@ -775,7 +774,7 @@ module Pod ...@@ -775,7 +774,7 @@ module Pod
source.fetch(sandbox) source.fetch(sandbox)
end end
def dependencies_to_fetch def dependencies_to_fetch(podfile_state)
@deps_to_fetch ||= begin @deps_to_fetch ||= begin
deps_to_fetch = [] deps_to_fetch = []
deps_with_external_source = @podfile_dependency_cache.podfile_dependencies.select(&:external_source) deps_with_external_source = @podfile_dependency_cache.podfile_dependencies.select(&:external_source)
...@@ -783,8 +782,8 @@ module Pod ...@@ -783,8 +782,8 @@ module Pod
if update_mode == :all if update_mode == :all
deps_to_fetch = deps_with_external_source deps_to_fetch = deps_with_external_source
else else
deps_to_fetch = deps_with_external_source.select { |dep| pods_to_fetch.include?(dep.root_name) } deps_to_fetch = deps_with_external_source.select { |dep| pods_to_fetch(podfile_state).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_if_needed = deps_with_external_source.select { |dep| podfile_state.unchanged.include?(dep.root_name) }
deps_to_fetch += deps_to_fetch_if_needed.select do |dep| deps_to_fetch += deps_to_fetch_if_needed.select do |dep|
sandbox.specification_path(dep.root_name).nil? || sandbox.specification_path(dep.root_name).nil? ||
!dep.external_source[:path].nil? || !dep.external_source[:path].nil? ||
...@@ -803,13 +802,13 @@ module Pod ...@@ -803,13 +802,13 @@ module Pod
locked_checkout_options != sandbox_checkout_options locked_checkout_options != sandbox_checkout_options
end end
def pods_to_fetch def pods_to_fetch(podfile_state)
@pods_to_fetch ||= begin @pods_to_fetch ||= begin
pods_to_fetch = result.podfile_state.added + result.podfile_state.changed pods_to_fetch = podfile_state.added + podfile_state.changed
if update_mode == :selected if update_mode == :selected
pods_to_fetch += update[:pods] pods_to_fetch += pods_to_update[:pods]
elsif update_mode == :all elsif update_mode == :all
pods_to_fetch += result.podfile_state.unchanged + result.podfile_state.deleted pods_to_fetch += podfile_state.unchanged + podfile_state.deleted
end end
pods_to_fetch += @podfile_dependency_cache.podfile_dependencies. pods_to_fetch += @podfile_dependency_cache.podfile_dependencies.
select { |dep| Hash(dep.external_source).key?(:podspec) && sandbox.specification_path(dep.root_name).nil? }. select { |dep| Hash(dep.external_source).key?(:podspec) && sandbox.specification_path(dep.root_name).nil? }.
...@@ -845,7 +844,7 @@ module Pod ...@@ -845,7 +844,7 @@ module Pod
# @return [Hash{TargetDefinition => Array<Spec>}] the specifications # @return [Hash{TargetDefinition => Array<Spec>}] the specifications
# grouped by target. # grouped by target.
# #
def resolve_dependencies def resolve_dependencies(locked_dependencies)
duplicate_dependencies = @podfile_dependency_cache.podfile_dependencies.group_by(&:name). duplicate_dependencies = @podfile_dependency_cache.podfile_dependencies.group_by(&:name).
select { |_name, dependencies| dependencies.count > 1 } select { |_name, dependencies| dependencies.count > 1 }
duplicate_dependencies.each do |name, dependencies| duplicate_dependencies.each do |name, dependencies|
...@@ -855,7 +854,7 @@ module Pod ...@@ -855,7 +854,7 @@ module Pod
resolver_specs_by_target = nil resolver_specs_by_target = nil
UI.section "Resolving dependencies of #{UI.path(podfile.defined_in_file) || 'Podfile'}" do UI.section "Resolving dependencies of #{UI.path(podfile.defined_in_file) || 'Podfile'}" do
resolver = Resolver.new(sandbox, podfile, locked_dependencies, sources, specs_updated?) resolver = Pod::Resolver.new(sandbox, podfile, locked_dependencies, sources, @specs_updated)
resolver_specs_by_target = resolver.resolve resolver_specs_by_target = resolver.resolve
resolver_specs_by_target.values.flatten(1).map(&:spec).each(&:validate_cocoapods_version) resolver_specs_by_target.values.flatten(1).map(&:spec).each(&:validate_cocoapods_version)
end end
...@@ -865,7 +864,7 @@ module Pod ...@@ -865,7 +864,7 @@ module Pod
# Warns for any specification that is incompatible with its target. # Warns for any specification that is incompatible with its target.
# #
# @param [Hash{TargetDefinition => Array<Spec>}] resolver_specs_by_target # @param [Hash{TargetDefinition => Array<Spec>}] resolver_specs_by_target
# the specifications grouped by target. # the resolved specifications grouped by target.
# #
# @return [Hash{TargetDefinition => Array<Spec>}] the specifications # @return [Hash{TargetDefinition => Array<Spec>}] the specifications
# grouped by target. # grouped by target.
...@@ -885,6 +884,9 @@ module Pod ...@@ -885,6 +884,9 @@ module Pod
# Returns the list of all the resolved specifications. # Returns the list of all the resolved specifications.
# #
# @param [Hash{TargetDefinition => Array<Spec>}] resolver_specs_by_target
# the resolved specifications grouped by target.
#
# @return [Array<Specification>] the list of the specifications. # @return [Array<Specification>] the list of the specifications.
# #
def generate_specifications(resolver_specs_by_target) def generate_specifications(resolver_specs_by_target)
...@@ -897,10 +899,10 @@ module Pod ...@@ -897,10 +899,10 @@ module Pod
# @return [SpecsState] the representation of the state of the manifest # @return [SpecsState] the representation of the state of the manifest
# specifications. # specifications.
# #
def generate_sandbox_state def generate_sandbox_state(specifications)
sandbox_state = nil sandbox_state = nil
UI.section 'Comparing resolved specification to the sandbox manifest' do UI.section 'Comparing resolved specification to the sandbox manifest' do
sandbox_analyzer = SandboxAnalyzer.new(sandbox, result.specifications, update_mode?) sandbox_analyzer = SandboxAnalyzer.new(sandbox, specifications, update_mode?)
sandbox_state = sandbox_analyzer.analyze sandbox_state = sandbox_analyzer.analyze
sandbox_state.print sandbox_state.print
end end
...@@ -909,58 +911,6 @@ module Pod ...@@ -909,58 +911,6 @@ module Pod
#-----------------------------------------------------------------------# #-----------------------------------------------------------------------#
# @!group Analysis internal products
# @return [Molinillo::DependencyGraph<Dependency>] the dependencies
# generated by the lockfile that prevent the resolver to update a
# Pod.
#
attr_reader :locked_dependencies
#-----------------------------------------------------------------------#
public
# Returns the sources used to query for specifications
#
# When no explicit Podfile sources or plugin sources are defined, this
# defaults to the master spec repository.
# available sources ({config.sources_manager.all}).
#
# @return [Array<Source>] the sources to be used in finding
# specifications, as specified by the {#podfile} or all sources.
#
def sources
@sources ||= begin
sources = podfile.sources
plugin_sources = @plugin_sources || []
# Add any sources specified using the :source flag on individual dependencies.
dependency_sources = @podfile_dependency_cache.podfile_dependencies.map(&:podspec_repo).compact
all_dependencies_have_sources = dependency_sources.count == @podfile_dependency_cache.podfile_dependencies.count
if all_dependencies_have_sources
sources = dependency_sources
elsif has_dependencies? && sources.empty? && plugin_sources.empty?
sources = ['https://github.com/CocoaPods/Specs.git']
else
sources += dependency_sources
end
result = sources.uniq.map do |source_url|
config.sources_manager.find_or_create_source_with_url(source_url)
end
unless plugin_sources.empty?
result.insert(0, *plugin_sources)
end
result
end
end
#-----------------------------------------------------------------------#
private
# @!group Analysis sub-steps # @!group Analysis sub-steps
# Checks whether the platform is specified if not integrating # Checks whether the platform is specified if not integrating
......
module Pod module Pod
class Installer class Installer
class Analyzer class Analyzer
# A simple container produced after a analysis is completed by the {Analyzer}.
#
class AnalysisResult class AnalysisResult
# @return [SpecsState] the states of the Podfile specs. # @return [SpecsState] the states of the Podfile specs.
# #
attr_accessor :podfile_state attr_reader :podfile_state
# @return [Hash{TargetDefinition => Array<Specification>}] the # @return [Hash{TargetDefinition => Array<Specification>}] the specifications grouped by target.
# specifications grouped by target.
# #
attr_accessor :specs_by_target attr_reader :specs_by_target
# @return [Hash{Source => Array<Specification>}] the # @return [Hash{Source => Array<Specification>}] the specifications grouped by spec repo source.
# specifications grouped by spec repo source.
# #
attr_accessor :specs_by_source attr_reader :specs_by_source
# @return [Array<Specification>] the specifications of the resolved # @return [Array<Specification>] the specifications of the resolved version of Pods that should be installed.
# version of Pods that should be installed.
# #
attr_accessor :specifications attr_reader :specifications
# @return [SpecsState] the states of the {Sandbox} respect the resolved # @return [SpecsState] the states of the {Sandbox} respect the resolved specifications.
# specifications.
# #
attr_accessor :sandbox_state attr_accessor :sandbox_state
# @return [Array<AggregateTarget>] The aggregate targets created for each # @return [Array<AggregateTarget>] The aggregate targets created for each {TargetDefinition} from the {Podfile}.
# {TargetDefinition} from the {Podfile}.
# #
attr_accessor :targets attr_reader :targets
# @return [Hash{TargetDefinition => Array<TargetInspectionResult>}] the # @return [PodfileDependencyCache] the cache of all dependencies in the podfile.
# results of inspecting the user targets
# #
attr_accessor :target_inspections attr_reader :podfile_dependency_cache
# @return [PodfileDependencyCache] the cache of all dependencies in the def initialize(podfile_state, specs_by_target, specs_by_source, specifications, sandbox_state, targets,
# podfile. podfile_dependency_cache)
# @podfile_state = podfile_state
attr_accessor :podfile_dependency_cache @specs_by_target = specs_by_target
@specs_by_source = specs_by_source
@specifications = specifications
@sandbox_state = sandbox_state
@targets = targets
@podfile_dependency_cache = podfile_dependency_cache
end
# @return [Hash{String=>Symbol}] A hash representing all the user build # @return [Hash{String=>Symbol}] A hash representing all the user build
# configurations across all integration targets. Each key # configurations across all integration targets. Each key
...@@ -51,6 +53,29 @@ module Pod ...@@ -51,6 +53,29 @@ module Pod
result.merge(target.user_build_configurations) result.merge(target.user_build_configurations)
end end
end end
# @return [Bool] Whether an installation should be performed or this
# CocoaPods project is already up to date.
#
def needs_install?
podfile_needs_install? || sandbox_needs_install?
end
# @return [Bool] Whether the podfile has changes respect to the lockfile.
#
def podfile_needs_install?
state = podfile_state
needing_install = state.added.length + state.changed.length + state.deleted.length
needing_install > 0
end
# @return [Bool] Whether the sandbox is in synch with the lockfile.
#
def sandbox_needs_install?
state = sandbox_state
needing_install = state.added.length + state.changed.length + state.deleted.length
needing_install > 0
end
end end
end end
end end
......
...@@ -20,7 +20,9 @@ module Pod ...@@ -20,7 +20,9 @@ module Pod
@sources = [] @sources = []
end end
# @param [Source] Source object to be added to the installer # @param [Source] source object to be added to the installer
#
# @return [void]
# #
def add_source(source) def add_source(source)
unless source.nil? unless source.nil?
......
...@@ -40,17 +40,15 @@ module Pod ...@@ -40,17 +40,15 @@ module Pod
end end
it 'returns whether an installation should be performed' do it 'returns whether an installation should be performed' do
@analyzer.needs_install?.should.be.true @analyzer.analyze.needs_install?.should.be.true
end end
it 'returns whether the Podfile has changes' do it 'returns whether the Podfile has changes' do
analysis_result = @analyzer.analyze(false) @analyzer.analyze(false).podfile_needs_install?.should.be.true
@analyzer.podfile_needs_install?(analysis_result).should.be.true
end end
it 'returns whether the sandbox is not in sync with the lockfile' do it 'returns whether the sandbox is not in sync with the lockfile' do
analysis_result = @analyzer.analyze(false) @analyzer.analyze(false).sandbox_needs_install?.should.be.true
@analyzer.sandbox_needs_install?(analysis_result).should.be.true
end end
#--------------------------------------# #--------------------------------------#
...@@ -469,22 +467,22 @@ module Pod ...@@ -469,22 +467,22 @@ module Pod
#--------------------------------------# #--------------------------------------#
it 'locks the version of the dependencies which did not change in the Podfile' do it 'locks the version of the dependencies which did not change in the Podfile' do
@analyzer.analyze podfile_state = @analyzer.send(:generate_podfile_state)
@analyzer.send(:locked_dependencies).map(&:payload).map(&:to_s). @analyzer.send(:generate_version_locking_dependencies, podfile_state).map(&:payload).map(&:to_s).should ==
should == ['JSONKit (= 1.5pre)', 'SVPullToRefresh (= 0.4)'] ['JSONKit (= 1.5pre)', 'SVPullToRefresh (= 0.4)']
end end
it 'does not lock the dependencies in update mode' do it 'does not lock the dependencies in update mode' do
@analyzer.update = true @analyzer.stubs(:pods_to_update).returns(true)
@analyzer.analyze podfile_state = @analyzer.send(:generate_podfile_state)
@analyzer.send(:locked_dependencies).to_a.map(&:payload).should == [] @analyzer.send(:generate_version_locking_dependencies, podfile_state).to_a.map(&:payload).should == []
end end
it 'unlocks dependencies in a case-insensitive manner' do it 'unlocks dependencies in a case-insensitive manner' do
@analyzer.update = { :pods => %w(JSONKit) } @analyzer.stubs(:pods_to_update).returns(:pods => %w(JSONKit))
@analyzer.analyze podfile_state = @analyzer.send(:generate_podfile_state)
@analyzer.send(:locked_dependencies).map(&:payload).map(&:to_s). @analyzer.send(:generate_version_locking_dependencies, podfile_state).map(&:payload).map(&:to_s).should ==
should == ['SVPullToRefresh (= 0.4)'] ['SVPullToRefresh (= 0.4)']
end end
it 'unlocks all dependencies with the same root name in update mode' do it 'unlocks all dependencies with the same root name in update mode' do
...@@ -511,9 +509,8 @@ module Pod ...@@ -511,9 +509,8 @@ module Pod
hash['SPEC CHECKSUMS'] = {} hash['SPEC CHECKSUMS'] = {}
hash['COCOAPODS'] = Pod::VERSION hash['COCOAPODS'] = Pod::VERSION
lockfile = Pod::Lockfile.new(hash) lockfile = Pod::Lockfile.new(hash)
analyzer = Installer::Analyzer.new(config.sandbox, podfile, lockfile) analyzer = Installer::Analyzer.new(config.sandbox, podfile, lockfile, nil, true, :pods => %w(AFNetworking))
analyzer.update = { :pods => %w(AFNetworking) }
analyzer.analyze.specifications. analyzer.analyze.specifications.
find { |s| s.name == 'AFNetworking' }. find { |s| s.name == 'AFNetworking' }.
version.to_s.should == '2.6.3' version.to_s.should == '2.6.3'
...@@ -602,9 +599,8 @@ module Pod ...@@ -602,9 +599,8 @@ module Pod
pod 'BananaLib', :git => 'example.com' pod 'BananaLib', :git => 'example.com'
end end
@analyzer = Installer::Analyzer.new(@sandbox, @podfile) @analyzer = Installer::Analyzer.new(@sandbox, @podfile)
@analyzer.stubs(:result).returns(stub(:podfile_state => podfile_state))
ExternalSources::DownloaderSource.any_instance.expects(:fetch) ExternalSources::DownloaderSource.any_instance.expects(:fetch)
@analyzer.send(:fetch_external_sources) @analyzer.send(:fetch_external_sources, podfile_state)
end end
it 'does not download the same source multiple times for different subspecs' do it 'does not download the same source multiple times for different subspecs' do
...@@ -615,9 +611,8 @@ module Pod ...@@ -615,9 +611,8 @@ module Pod
pod 'ARAnalytics/HockeyApp', :git => 'https://github.com/orta/ARAnalytics', :commit => '6f1a1c314894437e7e5c09572c276e644dbfb64b' pod 'ARAnalytics/HockeyApp', :git => 'https://github.com/orta/ARAnalytics', :commit => '6f1a1c314894437e7e5c09572c276e644dbfb64b'
end end
@analyzer = Installer::Analyzer.new(@sandbox, @podfile) @analyzer = Installer::Analyzer.new(@sandbox, @podfile)
@analyzer.stubs(:result).returns(stub(:podfile_state => podfile_state))
ExternalSources::DownloaderSource.any_instance.expects(:fetch).once ExternalSources::DownloaderSource.any_instance.expects(:fetch).once
@analyzer.send(:fetch_external_sources) @analyzer.send(:fetch_external_sources, podfile_state)
end end
xit 'it fetches the specification from either the sandbox or from the remote by default' do xit 'it fetches the specification from either the sandbox or from the remote by default' do
...@@ -1103,82 +1098,95 @@ module Pod ...@@ -1103,82 +1098,95 @@ module Pod
@analyzer.send(:checkout_requires_update?, @dependency).should == true @analyzer.send(:checkout_requires_update?, @dependency).should == true
end end
before do
@analyzer.result = Installer::Analyzer::AnalysisResult.new
@analyzer.result.podfile_state = Installer::Analyzer::SpecsState.new
end
it 'uses lockfile checkout options when no source exists in the sandbox' do it 'uses lockfile checkout options when no source exists in the sandbox' do
@analyzer.result.podfile_state.unchanged << 'BananaLib'
@sandbox_manifest.send(:checkout_options_data).delete('BananaLib') @sandbox_manifest.send(:checkout_options_data).delete('BananaLib')
downloader = stub('DownloaderSource') downloader = stub('DownloaderSource')
ExternalSources.stubs(:from_params).with(@lockfile_checkout_options, @dependency, @podfile.defined_in_file, true).returns(downloader) ExternalSources.stubs(:from_params).with(@lockfile_checkout_options, @dependency, @podfile.defined_in_file,
true).returns(downloader)
podfile_state = Installer::Analyzer::SpecsState.new
podfile_state.unchanged << 'BananaLib'
downloader.expects(:fetch) downloader.expects(:fetch)
@analyzer.send(:fetch_external_sources) @analyzer.send(:fetch_external_sources, podfile_state)
end end
it 'uses lockfile checkout options when a different checkout exists in the sandbox' do it 'uses lockfile checkout options when a different checkout exists in the sandbox' do
@analyzer.result.podfile_state.unchanged << 'BananaLib'
@sandbox_manifest.send(:checkout_options_data)['BananaLib'] = @lockfile_checkout_options.merge(:commit => 'other commit') @sandbox_manifest.send(:checkout_options_data)['BananaLib'] = @lockfile_checkout_options.merge(:commit => 'other commit')
podfile_state = Installer::Analyzer::SpecsState.new
podfile_state.unchanged << 'BananaLib'
downloader = stub('DownloaderSource') downloader = stub('DownloaderSource')
ExternalSources.stubs(:from_params).with(@lockfile_checkout_options, @dependency, @podfile.defined_in_file, true).returns(downloader) ExternalSources.stubs(:from_params).with(@lockfile_checkout_options, @dependency, @podfile.defined_in_file,
true).returns(downloader)
downloader.expects(:fetch) downloader.expects(:fetch)
@analyzer.send(:fetch_external_sources) @analyzer.send(:fetch_external_sources, podfile_state)
end end
it 'ignores lockfile checkout options when the podfile state has changed' do it 'ignores lockfile checkout options when the podfile state has changed' do
@analyzer.result.podfile_state.changed << 'BananaLib' podfile_state = Installer::Analyzer::SpecsState.new
podfile_state.changed << 'BananaLib'
downloader = stub('DownloaderSource') downloader = stub('DownloaderSource')
ExternalSources.stubs(:from_params).with(@dependency.external_source, @dependency, @podfile.defined_in_file, true).returns(downloader) ExternalSources.stubs(:from_params).with(@dependency.external_source, @dependency, @podfile.defined_in_file,
true).returns(downloader)
downloader.expects(:fetch) downloader.expects(:fetch)
@analyzer.send(:fetch_external_sources) @analyzer.send(:fetch_external_sources, podfile_state)
end end
it 'ignores lockfile checkout options when updating selected pods' do it 'ignores lockfile checkout options when updating selected pods' do
@analyzer.result.podfile_state.unchanged << 'BananaLib' podfile_state = Installer::Analyzer::SpecsState.new
@analyzer.stubs(:update).returns(:pods => %w(BananaLib)) podfile_state.unchanged << 'BananaLib'
@analyzer.stubs(:pods_to_update).returns(:pods => %w(BananaLib))
downloader = stub('DownloaderSource') downloader = stub('DownloaderSource')
ExternalSources.stubs(:from_params).with(@dependency.external_source, @dependency, @podfile.defined_in_file, true).returns(downloader) ExternalSources.stubs(:from_params).with(@dependency.external_source, @dependency, @podfile.defined_in_file,
true).returns(downloader)
downloader.expects(:fetch) downloader.expects(:fetch)
@analyzer.send(:fetch_external_sources) @analyzer.send(:fetch_external_sources, podfile_state)
end end
it 'ignores lockfile checkout options when updating all pods' do it 'ignores lockfile checkout options when updating all pods' do
@analyzer.result.podfile_state.unchanged << 'BananaLib' podfile_state = Installer::Analyzer::SpecsState.new
@analyzer.stubs(:update).returns(true) podfile_state.unchanged << 'BananaLib'
@analyzer.stubs(:pods_to_update).returns(true)
downloader = stub('DownloaderSource') downloader = stub('DownloaderSource')
ExternalSources.stubs(:from_params).with(@dependency.external_source, @dependency, @podfile.defined_in_file, true).returns(downloader) ExternalSources.stubs(:from_params).with(@dependency.external_source, @dependency, @podfile.defined_in_file,
true).returns(downloader)
downloader.expects(:fetch) downloader.expects(:fetch)
@analyzer.send(:fetch_external_sources) @analyzer.send(:fetch_external_sources, podfile_state)
end end
it 'does not use the cache when the podfile instructs not to clean' do it 'does not use the cache when the podfile instructs not to clean' do
@analyzer.result.podfile_state.unchanged << 'BananaLib' podfile_state = Installer::Analyzer::SpecsState.new
podfile_state.unchanged << 'BananaLib'
@sandbox_manifest.send(:checkout_options_data).delete('BananaLib') @sandbox_manifest.send(:checkout_options_data).delete('BananaLib')
downloader = stub('DownloaderSource') downloader = stub('DownloaderSource')
ExternalSources.stubs(:from_params).with(@lockfile_checkout_options, @dependency, @podfile.defined_in_file, false).returns(downloader) ExternalSources.stubs(:from_params).with(@lockfile_checkout_options, @dependency, @podfile.defined_in_file,
false).returns(downloader)
downloader.expects(:fetch) downloader.expects(:fetch)
@analyzer.installation_options.clean = false @analyzer.installation_options.clean = false
@analyzer.send(:fetch_external_sources) @analyzer.send(:fetch_external_sources, podfile_state)
end end
it 'does not re-fetch the external source when the sandbox has the correct revision of the source' do it 'does not re-fetch the external source when the sandbox has the correct revision of the source' do
@analyzer.result.podfile_state.unchanged << 'BananaLib' podfile_state = Installer::Analyzer::SpecsState.new
podfile_state.unchanged << 'BananaLib'
@analyzer.expects(:fetch_external_source).never @analyzer.expects(:fetch_external_source).never
@analyzer.send(:fetch_external_sources) @analyzer.send(:fetch_external_sources, podfile_state)
end end
end end
end end
......
...@@ -63,8 +63,10 @@ module Pod ...@@ -63,8 +63,10 @@ module Pod
aggregate_targets = [@ios_target, @osx_target] aggregate_targets = [@ios_target, @osx_target]
@analysis_result = Pod::Installer::Analyzer::AnalysisResult.new @analysis_result = Pod::Installer::Analyzer::AnalysisResult.new(Pod::Installer::Analyzer::SpecsState.new,
@analysis_result.targets = aggregate_targets {}, {}, [],
Pod::Installer::Analyzer::SpecsState.new,
aggregate_targets, nil)
@installation_options = Pod::Installer::InstallationOptions.new @installation_options = Pod::Installer::InstallationOptions.new
......
...@@ -192,7 +192,6 @@ module Pod ...@@ -192,7 +192,6 @@ module Pod
analyzer = Installer::Analyzer.new(config.sandbox, @installer.podfile, @installer.lockfile) analyzer = Installer::Analyzer.new(config.sandbox, @installer.podfile, @installer.lockfile)
analyzer.stubs(:analyze).returns(result) analyzer.stubs(:analyze).returns(result)
analyzer.stubs(:result).returns(result)
@installer.stubs(:create_analyzer).returns(analyzer) @installer.stubs(:create_analyzer).returns(analyzer)
@installer.send(:analyze) @installer.send(:analyze)
...@@ -336,10 +335,8 @@ module Pod ...@@ -336,10 +335,8 @@ module Pod
it 'configures the analyzer to use update mode if appropriate' do it 'configures the analyzer to use update mode if appropriate' do
@installer.update = true @installer.update = true
Installer::Analyzer.any_instance.expects(:update=).with(true) analyzer = @installer.send(:create_analyzer)
@installer.send(:analyze) analyzer.pods_to_update.should.be.true
@installer.aggregate_targets.map(&:name).sort.should == ['Pods-SampleProject', 'Pods-SampleProjectTests']
@installer.pod_targets.map(&:name).sort.should == ['JSONKit']
end end
end end
...@@ -369,13 +366,13 @@ module Pod ...@@ -369,13 +366,13 @@ module Pod
describe '#clean_sandbox' do describe '#clean_sandbox' do
before do before do
@analysis_result = Installer::Analyzer::AnalysisResult.new @analysis_result = Installer::Analyzer::AnalysisResult.new(Pod::Installer::Analyzer::SpecsState.new, {}, {},
@analysis_result.podfile_dependency_cache = Installer::Analyzer::PodfileDependencyCache.from_podfile(@installer.podfile) [], Pod::Installer::Analyzer::SpecsState.new, [],
@analysis_result.specifications = [] Installer::Analyzer::PodfileDependencyCache.from_podfile(@installer.podfile))
@analysis_result.sandbox_state = Installer::Analyzer::SpecsState.new
@spec = stub(:name => 'Spec', :test_specification? => false) @spec = stub(:name => 'Spec', :test_specification? => false)
@spec.stubs(:root => @spec) @spec.stubs(:root => @spec)
@pod_targets = [PodTarget.new(config.sandbox, false, {}, [], Platform.ios, [@spec], [fixture_target_definition], nil)] @pod_targets = [PodTarget.new(config.sandbox, false, {}, [], Platform.ios, [@spec],
[fixture_target_definition], nil)]
@installer.stubs(:analysis_result).returns(@analysis_result) @installer.stubs(:analysis_result).returns(@analysis_result)
@installer.stubs(:pod_targets).returns(@pod_targets) @installer.stubs(:pod_targets).returns(@pod_targets)
@installer.stubs(:aggregate_targets).returns([]) @installer.stubs(:aggregate_targets).returns([])
...@@ -421,7 +418,9 @@ module Pod ...@@ -421,7 +418,9 @@ module Pod
end end
it 'deletes the target support file dirs of the removed aggregate targets' do it 'deletes the target support file dirs of the removed aggregate targets' do
aggregate_target = AggregateTarget.new(config.sandbox, false, {}, [], Platform.ios, fixture_target_definition('MyApp'), config.sandbox.root.dirname, nil, nil, {}) aggregate_target = AggregateTarget.new(config.sandbox, false, {}, [], Platform.ios,
fixture_target_definition('MyApp'), config.sandbox.root.dirname, nil,
nil, {})
@installer.stubs(:aggregate_targets).returns([aggregate_target]) @installer.stubs(:aggregate_targets).returns([aggregate_target])
FileUtils.mkdir_p(config.sandbox.target_support_files_root) FileUtils.mkdir_p(config.sandbox.target_support_files_root)
FileUtils.mkdir_p(@installer.aggregate_targets.first.support_files_dir) FileUtils.mkdir_p(@installer.aggregate_targets.first.support_files_dir)
...@@ -434,7 +433,9 @@ module Pod ...@@ -434,7 +433,9 @@ module Pod
end end
it 'does not delete the target support file dirs for non removed aggregate targets' do it 'does not delete the target support file dirs for non removed aggregate targets' do
aggregate_target = AggregateTarget.new(config.sandbox, false, {}, [], Platform.ios, fixture_target_definition('MyApp'), config.sandbox.root.dirname, nil, nil, {}) aggregate_target = AggregateTarget.new(config.sandbox, false, {}, [], Platform.ios,
fixture_target_definition('MyApp'), config.sandbox.root.dirname, nil,
nil, {})
@installer.stubs(:aggregate_targets).returns([aggregate_target]) @installer.stubs(:aggregate_targets).returns([aggregate_target])
FileUtils.mkdir_p(config.sandbox.target_support_files_root) FileUtils.mkdir_p(config.sandbox.target_support_files_root)
FileUtils.mkdir_p(@installer.aggregate_targets.first.support_files_dir) FileUtils.mkdir_p(@installer.aggregate_targets.first.support_files_dir)
...@@ -469,7 +470,8 @@ module Pod ...@@ -469,7 +470,8 @@ module Pod
it 'correctly configures the Pod source installer' do it 'correctly configures the Pod source installer' do
spec = fixture_spec('banana-lib/BananaLib.podspec') spec = fixture_spec('banana-lib/BananaLib.podspec')
pod_target = PodTarget.new(config.sandbox, false, {}, [], Platform.ios, [spec], [fixture_target_definition], nil) pod_target = PodTarget.new(config.sandbox, false, {}, [], Platform.ios, [spec], [fixture_target_definition],
nil)
pod_target.stubs(:platform).returns(:ios) pod_target.stubs(:platform).returns(:ios)
@installer.stubs(:pod_targets).returns([pod_target]) @installer.stubs(:pod_targets).returns([pod_target])
@installer.instance_variable_set(:@installed_specs, []) @installer.instance_variable_set(:@installed_specs, [])
...@@ -479,7 +481,8 @@ module Pod ...@@ -479,7 +481,8 @@ module Pod
it 'maintains the list of the installed specs' do it 'maintains the list of the installed specs' do
spec = fixture_spec('banana-lib/BananaLib.podspec') spec = fixture_spec('banana-lib/BananaLib.podspec')
pod_target = PodTarget.new(config.sandbox, false, {}, [], Platform.ios, [spec], [fixture_target_definition], nil) pod_target = PodTarget.new(config.sandbox, false, {}, [], Platform.ios, [spec], [fixture_target_definition],
nil)
pod_target.stubs(:platform).returns(:ios) pod_target.stubs(:platform).returns(:ios)
@installer.stubs(:pod_targets).returns([pod_target, pod_target]) @installer.stubs(:pod_targets).returns([pod_target, pod_target])
@installer.instance_variable_set(:@installed_specs, []) @installer.instance_variable_set(:@installed_specs, [])
...@@ -494,9 +497,9 @@ module Pod ...@@ -494,9 +497,9 @@ module Pod
spec.version = Version.new('2.0') spec.version = Version.new('2.0')
manifest = Lockfile.new('SPEC REPOS' => { 'source1' => ['RestKit'] }) manifest = Lockfile.new('SPEC REPOS' => { 'source1' => ['RestKit'] })
manifest.stubs(:version).with('RestKit').returns(Version.new('1.0')) manifest.stubs(:version).with('RestKit').returns(Version.new('1.0'))
analysis_result = Installer::Analyzer::AnalysisResult.new analysis_result = Installer::Analyzer::AnalysisResult.new(Pod::Installer::Analyzer::SpecsState.new, {},
analysis_result.specifications = [spec] { Source.new('source1') => [spec] }, [spec],
analysis_result.specs_by_source = { Source.new('source1') => [spec] } Pod::Installer::Analyzer::SpecsState.new, [], nil)
@installer.stubs(:analysis_result).returns(analysis_result) @installer.stubs(:analysis_result).returns(analysis_result)
@installer.sandbox.stubs(:manifest).returns(manifest) @installer.sandbox.stubs(:manifest).returns(manifest)
@installer.stubs(:root_specs).returns([spec]) @installer.stubs(:root_specs).returns([spec])
...@@ -515,9 +518,9 @@ module Pod ...@@ -515,9 +518,9 @@ module Pod
spec.version = Version.new('1.0') spec.version = Version.new('1.0')
manifest = Lockfile.new('SPEC REPOS' => { 'source1' => ['RestKit'] }) manifest = Lockfile.new('SPEC REPOS' => { 'source1' => ['RestKit'] })
manifest.stubs(:version).with('RestKit').returns(Version.new('1.0')) manifest.stubs(:version).with('RestKit').returns(Version.new('1.0'))
analysis_result = Installer::Analyzer::AnalysisResult.new analysis_result = Installer::Analyzer::AnalysisResult.new(Pod::Installer::Analyzer::SpecsState.new, {},
analysis_result.specifications = [spec] { Source.new('source2') => [spec] }, [spec],
analysis_result.specs_by_source = { Source.new('source2') => [spec] } Pod::Installer::Analyzer::SpecsState.new, [], nil)
@installer.stubs(:analysis_result).returns(analysis_result) @installer.stubs(:analysis_result).returns(analysis_result)
@installer.sandbox.stubs(:manifest).returns(manifest) @installer.sandbox.stubs(:manifest).returns(manifest)
@installer.stubs(:root_specs).returns([spec]) @installer.stubs(:root_specs).returns([spec])
...@@ -536,9 +539,9 @@ module Pod ...@@ -536,9 +539,9 @@ module Pod
spec.version = Version.new('3.0') spec.version = Version.new('3.0')
manifest = Lockfile.new('SPEC REPOS' => { 'source1' => ['RestKit'] }) manifest = Lockfile.new('SPEC REPOS' => { 'source1' => ['RestKit'] })
manifest.stubs(:version).with('RestKit').returns(Version.new('2.0')) manifest.stubs(:version).with('RestKit').returns(Version.new('2.0'))
analysis_result = Installer::Analyzer::AnalysisResult.new analysis_result = Installer::Analyzer::AnalysisResult.new(Pod::Installer::Analyzer::SpecsState.new, {},
analysis_result.specifications = [spec] { Source.new('source2') => [spec] }, [spec],
analysis_result.specs_by_source = { Source.new('source2') => [spec] } Pod::Installer::Analyzer::SpecsState.new, [], nil)
@installer.stubs(:analysis_result).returns(analysis_result) @installer.stubs(:analysis_result).returns(analysis_result)
@installer.sandbox.stubs(:manifest).returns(manifest) @installer.sandbox.stubs(:manifest).returns(manifest)
@installer.stubs(:root_specs).returns([spec]) @installer.stubs(:root_specs).returns([spec])
...@@ -552,7 +555,8 @@ module Pod ...@@ -552,7 +555,8 @@ module Pod
it 'raises when it attempts to install pod source with no target supporting it' do it 'raises when it attempts to install pod source with no target supporting it' do
spec = fixture_spec('banana-lib/BananaLib.podspec') spec = fixture_spec('banana-lib/BananaLib.podspec')
pod_target = PodTarget.new(config.sandbox, false, {}, [], Platform.ios, [spec], [fixture_target_definition], nil) pod_target = PodTarget.new(config.sandbox, false, {}, [], Platform.ios, [spec], [fixture_target_definition],
nil)
pod_target.stubs(:platform).returns(:ios) pod_target.stubs(:platform).returns(:ios)
@installer.stubs(:pod_targets).returns([pod_target]) @installer.stubs(:pod_targets).returns([pod_target])
should.raise Informative do should.raise Informative do
...@@ -563,7 +567,8 @@ module Pod ...@@ -563,7 +567,8 @@ module Pod
it 'prints a warning for installed pods that included script phases' do it 'prints a warning for installed pods that included script phases' do
spec = fixture_spec('coconut-lib/CoconutLib.podspec') spec = fixture_spec('coconut-lib/CoconutLib.podspec')
spec.test_specs.first.script_phase = { :name => 'Hello World', :script => 'echo "Hello World"' } spec.test_specs.first.script_phase = { :name => 'Hello World', :script => 'echo "Hello World"' }
pod_target = PodTarget.new(config.sandbox, false, {}, [], Platform.ios, [spec, *spec.test_specs], [fixture_target_definition], nil) pod_target = PodTarget.new(config.sandbox, false, {}, [], Platform.ios, [spec, *spec.test_specs],
[fixture_target_definition], nil)
pod_target.stubs(:platform).returns(:ios) pod_target.stubs(:platform).returns(:ios)
sandbox_state = Installer::Analyzer::SpecsState.new sandbox_state = Installer::Analyzer::SpecsState.new
sandbox_state.added << 'CoconutLib' sandbox_state.added << 'CoconutLib'
...@@ -578,7 +583,8 @@ module Pod ...@@ -578,7 +583,8 @@ module Pod
it 'does not print a warning for already installed pods that include script phases' do it 'does not print a warning for already installed pods that include script phases' do
spec = fixture_spec('coconut-lib/CoconutLib.podspec') spec = fixture_spec('coconut-lib/CoconutLib.podspec')
spec.test_specs.first.script_phase = { :name => 'Hello World', :script => 'echo "Hello World"' } spec.test_specs.first.script_phase = { :name => 'Hello World', :script => 'echo "Hello World"' }
pod_target = PodTarget.new(config.sandbox, false, {}, [], Platform.ios, [spec, *spec.test_specs], [fixture_target_definition], nil) pod_target = PodTarget.new(config.sandbox, false, {}, [], Platform.ios, [spec, *spec.test_specs],
[fixture_target_definition], nil)
pod_target.stubs(:platform).returns(:ios) pod_target.stubs(:platform).returns(:ios)
sandbox_state = Installer::Analyzer::SpecsState.new sandbox_state = Installer::Analyzer::SpecsState.new
sandbox_state.unchanged << 'CoconutLib' sandbox_state.unchanged << 'CoconutLib'
...@@ -608,10 +614,11 @@ module Pod ...@@ -608,10 +614,11 @@ module Pod
describe 'Generating pods project' do describe 'Generating pods project' do
describe '#write_lockfiles' do describe '#write_lockfiles' do
before do before do
@analysis_result = Installer::Analyzer::AnalysisResult.new podfile_dependency_cache = Installer::Analyzer::PodfileDependencyCache.from_podfile(@installer.podfile)
@analysis_result.podfile_dependency_cache = Installer::Analyzer::PodfileDependencyCache.from_podfile(@installer.podfile) @analysis_result = Installer::Analyzer::AnalysisResult.new(Pod::Installer::Analyzer::SpecsState.new, {}, {},
@analysis_result.specifications = [fixture_spec('banana-lib/BananaLib.podspec')] [fixture_spec('banana-lib/BananaLib.podspec')],
@analysis_result.specs_by_source = {} Pod::Installer::Analyzer::SpecsState.new, [],
podfile_dependency_cache)
@installer.stubs(:analysis_result).returns(@analysis_result) @installer.stubs(:analysis_result).returns(@analysis_result)
end end
...@@ -638,7 +645,8 @@ module Pod ...@@ -638,7 +645,8 @@ module Pod
describe 'Integrating client projects' do describe 'Integrating client projects' do
it 'integrates the client projects' do it 'integrates the client projects' do
target = AggregateTarget.new(config.sandbox, false, {}, [], Platform.ios, fixture_target_definition, config.sandbox.root.dirname, nil, nil, {}) target = AggregateTarget.new(config.sandbox, false, {}, [], Platform.ios, fixture_target_definition,
config.sandbox.root.dirname, nil, nil, {})
@installer.stubs(:aggregate_targets).returns([target]) @installer.stubs(:aggregate_targets).returns([target])
Installer::UserProjectIntegrator.any_instance.expects(:integrate!) Installer::UserProjectIntegrator.any_instance.expects(:integrate!)
@installer.send(:integrate_user_project) @installer.send(:integrate_user_project)
......
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