class Pod::Installer::Analyzer

Analyzes the Podfile, the Lockfile, and the sandbox manifest to generate the information relative to a CocoaPods installation.

Constants

IOS_64_BIT_ONLY_PROJECT_VERSION

@return [Integer] The Xcode object version until which 64-bit architectures should be manually specified

Xcode 10 will automatically select the correct architectures based on deployment target

IOS_64_BIT_ONLY_VERSION

@return [String] The version of iOS which requires binaries with only 64-bit architectures

Attributes

has_dependencies[R]

@return [Boolean] 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.

has_dependencies?[R]

@return [Boolean] 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.

installation_options[R]

@return [InstallationOptions] the installation options specified by the Podfile

lockfile[R]

@return [Lockfile, nil] The Lockfile, if available, that stores the information about the Pods previously installed.

plugin_sources[R]

@return [Array<Source>] Sources provided by plugins or ‘nil`.

podfile[R]

@return [Podfile] The Podfile specification that contains the information of the Pods that should be installed.

pods_to_update[R]

@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.
sandbox[R]

@return [Sandbox] The sandbox to use for this analysis.

sources_manager[R]

@return [Source::Manager] the sources manager to use when resolving dependencies

Public Class Methods

new(sandbox, podfile, lockfile = nil, plugin_sources = nil, has_dependencies = true, pods_to_update = false, sources_manager = Source::Manager.new(config.repos_dir)) click to toggle source

Initialize a new instance

@param [Sandbox] sandbox @see sandbox @param [Podfile] podfile @see podfile @param [Lockfile, nil] lockfile @see lockfile @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 @param [Source::Manager] sources_manager @see sources_manager

# File lib/cocoapods/installer/analyzer.rb, line 76
def initialize(sandbox, podfile, lockfile = nil, plugin_sources = nil, has_dependencies = true,
               pods_to_update = false, sources_manager = Source::Manager.new(config.repos_dir))
  @sandbox  = sandbox
  @podfile  = podfile
  @lockfile = lockfile
  @plugin_sources = plugin_sources
  @has_dependencies = has_dependencies
  @pods_to_update = pods_to_update
  @installation_options = podfile.installation_options
  @podfile_dependency_cache = PodfileDependencyCache.from_podfile(podfile)
  @sources_manager = sources_manager
  @path_lists = {}
  @result = nil
end

Private Class Methods

requires_64_bit_archs?(platform, object_version) click to toggle source

@param [Platform] platform

The platform to build against

@param [String, Nil] object_version

The user project's object version, or nil if not available

@return [Boolean] Whether the platform requires 64-bit architectures

# File lib/cocoapods/installer/analyzer.rb, line 1142
def requires_64_bit_archs?(platform, object_version)
  return false unless platform
  case platform.name
  when :osx
    true
  when :ios
    if (version = object_version)
      platform.deployment_target >= IOS_64_BIT_ONLY_VERSION && version.to_i < IOS_64_BIT_ONLY_PROJECT_VERSION
    else
      platform.deployment_target >= IOS_64_BIT_ONLY_VERSION
    end
  when :watchos
    false
  when :tvos
    false
  end
end

Public Instance Methods

analyze(allow_fetches = true) click to toggle source

Performs the analysis.

The Podfile and the Lockfile provide the information necessary to compute which specification should be installed. The manifest of the sandbox returns which specifications are installed.

@param [Boolean] allow_fetches

whether external sources may be fetched

@return [AnalysisResult]

# File lib/cocoapods/installer/analyzer.rb, line 102
def analyze(allow_fetches = true)
  return @result if @result
  validate_podfile!
  validate_lockfile_version!
  if installation_options.integrate_targets?
    target_inspections = inspect_targets_to_integrate
  else
    verify_platforms_specified!
    target_inspections = {}
  end
  podfile_state = generate_podfile_state

  store_existing_checkout_options
  if allow_fetches == :outdated
    # special-cased -- we're only really resolving for outdated, rather than doing a full analysis
  elsif allow_fetches == true
    fetch_external_sources(podfile_state)
  elsif !dependencies_to_fetch(podfile_state).all?(&:local?)
    raise Informative, 'Cannot analyze without fetching dependencies since the sandbox is not up-to-date. Run `pod install` to ensure all dependencies have been fetched.' \
      "\n    The missing dependencies are:\n    \t#{dependencies_to_fetch(podfile_state).reject(&:local?).join("\n    \t")}"
  end

  locked_dependencies = generate_version_locking_dependencies(podfile_state)
  resolver_specs_by_target = resolve_dependencies(locked_dependencies)
  validate_platforms(resolver_specs_by_target)
  specifications = generate_specifications(resolver_specs_by_target)
  aggregate_targets, pod_targets = generate_targets(resolver_specs_by_target, target_inspections)
  sandbox_state = generate_sandbox_state(specifications)
  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)
  end
  specs_by_source = Hash[resolver_specs_by_target.values.flatten(1).group_by(&:source).map do |source, specs|
    [source, specs.map(&:spec).uniq]
  end]
  sources.each { |s| specs_by_source[s] ||= [] }
  @result = AnalysisResult.new(podfile_state, specs_by_target, specs_by_source, specifications, sandbox_state,
                               aggregate_targets, pod_targets, @podfile_dependency_cache)
end
sources() click to toggle source

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.

@return [Array<Source>] the sources to be used in finding specifications, as specified by the podfile or all

sources.
# File lib/cocoapods/installer/analyzer.rb, line 161
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_dependencies.map(&:podspec_repo).compact
    all_dependencies_have_sources = dependency_sources.count == podfile_dependencies.count

    if all_dependencies_have_sources
      sources = dependency_sources
    elsif has_dependencies? && sources.empty? && plugin_sources.empty?
      sources = [Pod::TrunkSource::TRUNK_REPO_URL] + dependency_sources
    else
      sources += dependency_sources
    end

    result = sources.uniq.map do |source_url|
      sources_manager.find_or_create_source_with_url(source_url)
    end
    unless plugin_sources.empty?
      result.insert(0, *plugin_sources)
      plugin_sources.each do |source|
        sources_manager.add_source(source)
      end
    end
    result
  end
end
update_repositories() click to toggle source

Updates the git source repositories.

# File lib/cocoapods/installer/analyzer.rb, line 143
def update_repositories
  sources.each do |source|
    if source.updateable?
      sources_manager.update(source.name, true)
    else
      UI.message "Skipping `#{source.name}` update because the repository is not an updateable repository."
    end
  end
  @specs_updated = true
end

Private Instance Methods

analyze_host_targets_in_podfile(aggregate_targets, embedded_aggregate_targets) click to toggle source

Raises an error if there are embedded targets in the Podfile, but their host targets have not been declared in the Podfile. As it finds host targets, it collection information on host target types.

@param [Array<AggregateTarget>] aggregate_targets the generated

aggregate targets

@param [Array<AggregateTarget>] embedded_aggregate_targets the aggregate targets

representing the embedded targets to be integrated
# File lib/cocoapods/installer/analyzer.rb, line 336
def analyze_host_targets_in_podfile(aggregate_targets, embedded_aggregate_targets)
  target_definitions_by_uuid = {}
  cli_host_with_dynamic_linkage = []
  cli_product_type = 'com.apple.product-type.tool'
  # Collect aggregate target definitions by uuid to later lookup host target
  # definitions and verify their compatibility with their embedded targets
  aggregate_targets.each do |target|
    target.user_targets.each do |user_target|
      target_definition = target.target_definition
      target_definitions_by_uuid[user_target.uuid] = target_definition
      if user_target.product_type == cli_product_type && target_definition.build_type.linkage == :dynamic
        cli_host_with_dynamic_linkage << user_target
      end
    end
  end
  aggregate_target_user_projects = aggregate_targets.map(&:user_project)
  embedded_targets_missing_hosts = []
  host_uuid_to_embedded_target_definitions = {}
  # Search all of the known user projects for each embedded target's hosts
  embedded_aggregate_targets.each do |target|
    host_uuids = aggregate_target_user_projects.product(target.user_targets).flat_map do |user_project, user_target|
      user_project.host_targets_for_embedded_target(user_target).map(&:uuid)
    end
    # For each host, keep track of its embedded target definitions
    # to later verify each embedded target's compatiblity with its host,
    # ignoring the hosts that aren't known to CocoaPods (no target
    # definitions in the Podfile)
    host_uuids.each do |uuid|
      (host_uuid_to_embedded_target_definitions[uuid] ||= []) << target.target_definition if target_definitions_by_uuid.key? uuid
    end
    # If none of the hosts are known to CocoaPods (no target definitions
    # in the Podfile), add it to the list of targets missing hosts
    embedded_targets_missing_hosts << target unless host_uuids.any? do |uuid|
      target_definitions_by_uuid.key? uuid
    end
  end

  unless cli_host_with_dynamic_linkage.empty?
    UI.warn "The Podfile contains command line tool target(s) (#{cli_host_with_dynamic_linkage.map(&:name).to_sentence}) which are attempting to integrate dynamic frameworks or libraries." \
      "\n" \
      'This may not behave as expected, because command line tools are usually distributed as a single binary and cannot contain their own dynamic dependencies.'
  end

  unless embedded_targets_missing_hosts.empty?
    embedded_targets_missing_hosts_product_types = Set.new embedded_targets_missing_hosts.flat_map(&:user_targets).map(&:symbol_type)
    target_names = embedded_targets_missing_hosts.map do |target|
      target.name.sub('Pods-', '') # Make the target names more recognizable to the user
    end.join ', '
    #  If the targets missing hosts are only frameworks, then this is likely
    #  a project for doing framework development. In that case, just warn that
    #  the frameworks that these targets depend on won't be integrated anywhere
    if embedded_targets_missing_hosts_product_types.subset?(Set.new([:framework, :static_library]))
      UI.warn "The Podfile contains framework or static library targets (#{target_names}), for which the Podfile does not contain host targets (targets which embed the framework)." \
        "\n" \
        'If this project is for doing framework development, you can ignore this message. Otherwise, add a target to the Podfile that embeds these frameworks to make this message go away (e.g. a test target).'
    else
      raise Informative, "Unable to find host target(s) for #{target_names}. Please add the host targets for the embedded targets to the Podfile." \
                          "\n" \
                          'Certain kinds of targets require a host target. A host target is a "parent" target which embeds a "child" target. These are example types of targets that need a host target:' \
                          "\n- Framework" \
                          "\n- App Extension" \
                          "\n- Watch OS 1 Extension" \
                          "\n- Messages Extension (except when used with a Messages Application)"
    end
  end

  target_mismatches = []
  host_uuid_to_embedded_target_definitions.each do |uuid, target_definitions|
    host_target_definition = target_definitions_by_uuid[uuid]
    target_definitions.each do |target_definition|
      unless host_target_definition.uses_frameworks? == target_definition.uses_frameworks?
        target_mismatches << "- #{host_target_definition.name} (#{host_target_definition.uses_frameworks?}) and #{target_definition.name} (#{target_definition.uses_frameworks?}) do not both set use_frameworks!."
      end
    end
  end

  unless target_mismatches.empty?
    heading = 'Unable to integrate the following embedded targets with their respective host targets (a host target is a "parent" target which embeds a "child" target like a framework or extension):'
    raise Informative, heading + "\n\n" + target_mismatches.sort.uniq.join("\n")
  end
end
checkout_requires_update?(dependency) click to toggle source
# File lib/cocoapods/installer/analyzer.rb, line 1021
def checkout_requires_update?(dependency)
  return true unless lockfile && sandbox.manifest
  locked_checkout_options = lockfile.checkout_options_for_pod_named(dependency.root_name)
  sandbox_checkout_options = sandbox.manifest.checkout_options_for_pod_named(dependency.root_name)
  locked_checkout_options != sandbox_checkout_options
end
compute_pod_target_dependencies(pod_targets, all_specs) click to toggle source

Compute the dependencies for the set of pod targets.

@param [Array<PodTarget>] pod_targets

pod targets.

@param [Hash{String => Array<Specification>}] all_specs

specifications grouped by name.

@return [Array<PodTarget>]

# File lib/cocoapods/installer/analyzer.rb, line 679
def compute_pod_target_dependencies(pod_targets, all_specs)
  pod_targets_by_name = pod_targets.group_by(&:pod_name).each_with_object({}) do |(name, values), hash|
    # Sort the target by the number of activated subspecs, so that
    # we prefer a minimal target as transitive dependency.
    hash[name] = values.sort_by { |pt| pt.specs.count }
  end

  pod_targets.each do |target|
    dependencies_by_config = dependencies_for_specs(target.library_specs, target.platform, all_specs)
    target.dependent_targets_by_config = Hash[dependencies_by_config.map { |k, v| [k, filter_dependencies(v, pod_targets_by_name, target)] }]

    target.test_dependent_targets_by_spec_name_by_config = target.test_specs.each_with_object({}) do |test_spec, hash|
      test_dependencies_by_config = dependencies_for_specs([test_spec], target.platform, all_specs)
      test_dependencies_by_config.each { |config, deps| deps.delete_if { |k, _| dependencies_by_config[config].key? k } }
      hash[test_spec.name] = Hash[test_dependencies_by_config.map { |k, v| [k, filter_dependencies(v, pod_targets_by_name, target)] }]
    end

    target.app_dependent_targets_by_spec_name_by_config = target.app_specs.each_with_object({}) do |app_spec, hash|
      app_dependencies_by_config = dependencies_for_specs([app_spec], target.platform, all_specs)
      app_dependencies_by_config.each { |config, deps| deps.delete_if { |k, _| dependencies_by_config[config].key? k } }
      hash[app_spec.name] = Hash[app_dependencies_by_config.map { |k, v| [k, filter_dependencies(v, pod_targets_by_name, target)] }]
    end

    target.test_app_hosts_by_spec = target.test_specs.each_with_object({}) do |test_spec, hash|
      next unless app_host_name = test_spec.consumer(target.platform).app_host_name
      app_host_spec = pod_targets_by_name[Specification.root_name(app_host_name)].flat_map(&:app_specs).find do |pt|
        pt.name == app_host_name
      end
      app_host_dependencies = { app_host_spec.root => [app_host_spec] }
      hash[test_spec] = [app_host_spec, filter_dependencies(app_host_dependencies, pod_targets_by_name, target).first]
    end
  end
end
create_file_accessors(specs, platform) click to toggle source

Creates the file accessors for a given pod.

@param [Array<Specification>] specs

the specs to map each file accessor to.

@param [Platform] platform

the platform to use when generating each file accessor.

@return [Array<FileAccessor>]

# File lib/cocoapods/installer/analyzer.rb, line 831
def create_file_accessors(specs, platform)
  name = specs.first.name
  pod_root = sandbox.pod_dir(name)
  path_list = @path_lists.fetch(pod_root) do |root|
    path_list = Sandbox::PathList.new(root)
    @path_lists[root] = path_list
  end
  specs.map do |spec|
    Sandbox::FileAccessor.new(path_list, spec.consumer(platform))
  end
end
dependencies_for_specs(specs, platform, all_specs) click to toggle source

Returns the specs upon which the given specs directly depend.

@note: This is implemented in the analyzer, because we don’t have to

care about the requirements after dependency resolution.

@param [Array<Specification>] specs

The specs, whose dependencies should be returned.

@param [Platform] platform

The platform for which the dependencies should be returned.

@param [Hash{String => Array<Specification>}] all_specs

All specifications which are installed alongside.

@return [Hash{Symbol => Set<Specification>}]

# File lib/cocoapods/installer/analyzer.rb, line 745
def dependencies_for_specs(specs, platform, all_specs)
  dependent_specs = {
    :debug => Set.new,
    :release => Set.new,
  }

  if !specs.empty? && !all_specs.empty?
    specs.each do |s|
      s.dependencies(platform).each do |dep|
        all_specs[dep.name].each do |spec|
          if spec.non_library_specification?
            if s.test_specification? && spec.name == s.consumer(platform).app_host_name && spec.app_specification?
              # This needs to be handled separately, since we _don't_ want to treat this as a "normal" dependency
              next
            end
            raise Informative, "`#{s}` depends upon `#{spec}`, which is a `#{spec.spec_type}` spec."
          end

          dependent_specs.each do |config, set|
            next unless s.dependency_whitelisted_for_configuration?(dep, config)
            set << spec
          end
        end
      end
    end
  end

  Hash[dependent_specs.map { |k, v| [k, (v - specs).group_by(&:root)] }].freeze
end
dependencies_to_fetch(podfile_state) click to toggle source
# File lib/cocoapods/installer/analyzer.rb, line 1000
def dependencies_to_fetch(podfile_state)
  @deps_to_fetch ||= begin
    deps_to_fetch = []
    deps_with_external_source = podfile_dependencies.select(&:external_source)

    if update_mode == :all
      deps_to_fetch = deps_with_external_source
    else
      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| podfile_state.unchanged.include?(dep.root_name) }
      deps_to_fetch += deps_to_fetch_if_needed.select do |dep|
        sandbox.specification_path(dep.root_name).nil? ||
          !dep.external_source[:path].nil? ||
          !sandbox.pod_dir(dep.root_name).directory? ||
          checkout_requires_update?(dep)
      end
    end
    deps_to_fetch.uniq(&:root_name)
  end
end
determine_build_type(spec, target_definition_build_type) click to toggle source

Calculates and returns the BuildType to use for the given spec. If the spec specifies ‘static_framework` then it is honored as long as the host BuildType also requires its pods to be integrated as frameworks.

@param [Specification] spec

the spec to determine the #BuildType for.

@param [BuildType] target_definition_build_type

The desired #BuildType by the target definition that integrates this target. If the pod target spec does
not specify explicitly a `static_framework` #BuildType then the one from the target definition is used.

@return [BuildType]

# File lib/cocoapods/installer/analyzer.rb, line 911
def determine_build_type(spec, target_definition_build_type)
  if target_definition_build_type.framework?
    root_spec = spec.root
    root_spec.static_framework ? BuildType.static_framework : target_definition_build_type
  else
    BuildType.static_library
  end
end
determine_platform(specs, target_definitions, build_type) click to toggle source

Calculates and returns the platform to use for the given list specs and target definitions.

@note The platform is only determined by all library specs and ignores non library ones. Subspecs are always

integrated in the same target as the root spec therefore the max deployment target is always returned
across the specs passed.

@param [Array<Specification>] specs

the specs to inspect and calculate the platform for.

@param [Array<TargetDefinition>] target_definitions

the target definitions these specs are part of.

@param [BuildType] build_type

the #BuildType used for calculating the platform.

@return [Platform]

# File lib/cocoapods/installer/analyzer.rb, line 860
def determine_platform(specs, target_definitions, build_type)
  library_specs = specs.select(&:library_specification?)
  platform_name = target_definitions.first.platform.name
  default = Podfile::TargetDefinition::PLATFORM_DEFAULTS[platform_name]
  deployment_target = library_specs.map do |library_spec|
    Version.new(library_spec.deployment_target(platform_name) || default)
  end.max
  if platform_name == :ios && build_type.framework?
    minimum = Version.new('8.0')
    deployment_target = [deployment_target, minimum].max
  end
  Platform.new(platform_name, deployment_target)
end
determine_swift_version(spec, target_definitions) click to toggle source

Determines the Swift version for the given spec within a list of target definitions. If the pod author has provided a set of Swift versions supported by their pod then the max Swift version is chosen, unless the target definitions specify explicit requirements for supported Swift versions. Otherwise the Swift version is derived by the target definitions that integrate this pod.

@param [Specification] spec

the specs to inspect and determine what Swift version to use.

@param [Array<TargetDefinition>] target_definitions

the target definitions the spec is part of.

@return [String, nil] the computed Swift version or ‘nil` if the Swift version could not be determined.

# File lib/cocoapods/installer/analyzer.rb, line 887
def determine_swift_version(spec, target_definitions)
  if spec.swift_versions.empty?
    target_definitions.map(&:swift_version).compact.uniq.first
  else
    spec.swift_versions.sort.reverse_each.find do |swift_version|
      target_definitions.all? do |td|
        td.supports_swift_version?(swift_version)
      end
    end.to_s
  end
end
embedded_target_pod_targets_by_host(aggregate_target, embedded_aggregate_targets, libraries_only) click to toggle source

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 user_target hosts any of the app embedded aggregate targets’ user_targets

@param [AggregateTarget] aggregate_target the aggregate target whose user_target

might host one or more of the embedded aggregate targets' user_targets

@param [Array<AggregateTarget>] embedded_aggregate_targets the aggregate targets

representing the embedded targets to be integrated

@param [Boolean] libraries_only if true, only library-type embedded

targets are considered, otherwise, all other types are have
their pods copied to their host targets as well (extensions, etc.)

@return [Hash{String=>Array<PodTarget>}] the additional pod targets to include to the host

keyed by their configuration.
# File lib/cocoapods/installer/analyzer.rb, line 293
def embedded_target_pod_targets_by_host(aggregate_target, embedded_aggregate_targets, libraries_only)
  return {} if aggregate_target.requires_host_target?
  aggregate_user_target_uuids = Set.new(aggregate_target.user_targets.map(&:uuid))
  embedded_pod_targets_by_build_config = Hash.new([].freeze)
  embedded_aggregate_targets.each do |embedded_aggregate_target|
    # Skip non libraries in library-only mode
    next if libraries_only && !embedded_aggregate_target.library?
    next if aggregate_target.search_paths_aggregate_targets.include?(embedded_aggregate_target)
    next unless embedded_aggregate_target.user_targets.any? do |embedded_user_target|
      # You have to ask the host target's project for the host targets of
      # the embedded target, as opposed to asking user_project for the
      # embedded targets of the host target. The latter doesn't work when
      # the embedded target lives in a sub-project. The lines below get
      # the host target uuids for the embedded target and checks to see if
      # those match to any of the user_target uuids in the aggregate_target.
      host_target_uuids = Set.new(aggregate_target.user_project.host_targets_for_embedded_target(embedded_user_target).map(&:uuid))
      !aggregate_user_target_uuids.intersection(host_target_uuids).empty?
    end
    embedded_aggregate_target.user_build_configurations.each_key do |configuration_name|
      pod_target_names = Set.new(aggregate_target.pod_targets_for_build_configuration(configuration_name).map(&:name))
      embedded_pod_targets = embedded_aggregate_target.pod_targets_for_build_configuration(configuration_name).select do |pod_target|
        if !pod_target_names.include?(pod_target.name) &&
           aggregate_target.pod_targets.none? { |aggregate_pod_target| (pod_target.specs - aggregate_pod_target.specs).empty? } &&
           (libraries_only || pod_target.build_as_dynamic?)
          pod_target.name
        end
      end
      embedded_pod_targets_by_build_config[configuration_name] += embedded_pod_targets
    end
  end
  embedded_pod_targets_by_build_config
end
fetch_external_source(dependency, use_lockfile_options) click to toggle source
# File lib/cocoapods/installer/analyzer.rb, line 991
def fetch_external_source(dependency, use_lockfile_options)
  source = if use_lockfile_options && lockfile && checkout_options = lockfile.checkout_options_for_pod_named(dependency.root_name)
             ExternalSources.from_params(checkout_options, dependency, podfile.defined_in_file, installation_options.clean?)
           else
             ExternalSources.from_dependency(dependency, podfile.defined_in_file, installation_options.clean?)
           end
  source.fetch(sandbox)
end
fetch_external_sources(podfile_state) click to toggle source

Fetches the podspecs of external sources if modifications to the sandbox are allowed.

@note In update mode all the external sources are refreshed while in

normal mode they are refreshed only if added or changed in the
Podfile. Moreover, in normal specifications for unchanged Pods
which are missing or are generated from an local source are
fetched as well.

@note It is possible to perform this step before the resolution

process because external sources identify a single specific
version (checkout). If the other dependencies are not
compatible with the version reported by the podspec of the
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]

# File lib/cocoapods/installer/analyzer.rb, line 969
def fetch_external_sources(podfile_state)
  verify_no_pods_with_different_sources!
  deps = dependencies_to_fetch(podfile_state)
  pods = pods_to_fetch(podfile_state)
  return if deps.empty?
  UI.section 'Fetching external sources' do
    deps.sort.each do |dependency|
      fetch_external_source(dependency, !pods.include?(dependency.root_name))
    end
  end
end
filter_dependencies(dependencies, pod_targets_by_name, target) click to toggle source
# File lib/cocoapods/installer/analyzer.rb, line 713
def filter_dependencies(dependencies, pod_targets_by_name, target)
  dependencies.map do |root_spec, deps|
    pod_targets_by_name[root_spec.name].find do |t|
      next false if t.platform.symbolic_name != target.platform.symbolic_name ||
        # In the case of variants we must ensure that the platform this target is meant for is the same
        # as the one we are interested in.
        t.target_definitions.first.platform != target.target_definitions.first.platform ||
        # rather than target type or requires_frameworks? since we want to group by what was specified in that
        # _target definition_.
        t.build_as_framework? != target.build_as_framework?
      spec_names = t.specs.map(&:name)
      deps.all? { |dep| spec_names.include?(dep.name) }
    end
  end
end
filter_pod_targets_for_target_definition(target_definition, pod_targets_by_target_definition, build_configurations) click to toggle source

Returns a filtered list of pod targets that should or should not be part of the target definition. Pod targets used by tests only are filtered.

@param [TargetDefinition] target_definition

the target definition to use as the base for filtering

@param [Hash{TargetDefinition => Array<PodTarget>}] pod_targets_by_target_definition

the pod targets grouped by target.

@param [Array<String>] build_configurations

The list of all build configurations the targets will be built for.

@return [Hash{String => Array<PodTarget>}]

the filtered list of pod targets, grouped by build configuration.
# File lib/cocoapods/installer/analyzer.rb, line 564
def filter_pod_targets_for_target_definition(target_definition, pod_targets_by_target_definition,
                                             build_configurations)
  pod_targets_by_build_config = Hash.new([].freeze)
  build_configurations.each { |config| pod_targets_by_build_config[config] = [] }

  dependencies_by_root_name = @podfile_dependency_cache.target_definition_dependencies(target_definition).group_by(&:root_name)

  pod_targets_by_target_definition[target_definition].each do |pod_target|
    pod_name = pod_target.pod_name
    dependencies = dependencies_by_root_name[pod_name] || []

    build_configurations.each do |configuration_name|
      whitelists = dependencies.map do |dependency|
        target_definition.pod_whitelisted_for_configuration?(dependency.name, configuration_name)
      end.uniq

      case whitelists
      when [], [true] then nil
      when [false] then next
      else
        raise Informative, "The subspecs of `#{pod_name}` are linked to " \
          "different build configurations for the `#{target_definition}` " \
          'target. CocoaPods does not currently support subspecs across ' \
          'different build configurations.'
      end

      pod_targets_by_build_config[configuration_name] << pod_target
    end
  end

  pod_targets_by_build_config
end
generate_aggregate_target(target_definition, target_inspections, pod_targets_by_target_definition) click to toggle source

Setup the aggregate target for a single user target

@param [TargetDefinition] target_definition

the target definition for the user target.

@param [Hash{TargetDefinition => TargetInspectionResult}] target_inspections

the user target inspections used to construct the aggregate and pod targets.

@param [Hash{TargetDefinition => Array<PodTarget>}] pod_targets_by_target_definition

the pod targets grouped by target.

@return [AggregateTarget]

# File lib/cocoapods/installer/analyzer.rb, line 500
def generate_aggregate_target(target_definition, target_inspections, pod_targets_by_target_definition)
  if installation_options.integrate_targets?
    target_inspection = target_inspections[target_definition]
    raise "missing inspection for #{target_definition.inspect}" unless target_inspection
    target_requires_64_bit = Analyzer.requires_64_bit_archs?(target_definition.platform, target_inspection.project.object_version)
    user_project = target_inspection.project
    client_root = target_inspection.client_root
    user_target_uuids = target_inspection.project_target_uuids
    user_build_configurations = target_inspection.build_configurations
    archs = target_requires_64_bit ? ['$(ARCHS_STANDARD_64_BIT)'] : target_inspection.archs
  else
    target_requires_64_bit = Analyzer.requires_64_bit_archs?(target_definition.platform, nil)
    user_project = nil
    client_root = config.installation_root.realpath
    user_target_uuids = []
    user_build_configurations = target_definition.build_configurations || Target::DEFAULT_BUILD_CONFIGURATIONS
    archs = target_requires_64_bit ? ['$(ARCHS_STANDARD_64_BIT)'] : []
  end
  platform = target_definition.platform
  build_configurations = user_build_configurations.keys.concat(target_definition.all_whitelisted_configurations).uniq
  pod_targets_for_build_configuration = filter_pod_targets_for_target_definition(target_definition,
                                                                                 pod_targets_by_target_definition,
                                                                                 build_configurations)
  build_type = target_definition.uses_frameworks? ? BuildType.static_framework : BuildType.static_library
  AggregateTarget.new(sandbox, build_type, user_build_configurations, archs, platform, target_definition,
                      client_root, user_project, user_target_uuids, pod_targets_for_build_configuration)
end
generate_pod_target(target_definitions, build_type, target_inspections, specs, scope_suffix: nil, swift_version: nil) click to toggle source

Create a target for each spec group

@param [Array<TargetDefinition>] target_definitions

the target definitions of the pod target

@param [BuildType] build_type

the BuildType to use for this pod target.

@param [Hash{TargetDefinition => TargetInspectionResult}] target_inspections

the user target inspections used to construct the aggregate and pod targets.

@param [Array<Specification>] specs

the specifications of an equal root.

@param [String] scope_suffix

@see PodTarget#scope_suffix

@param [String] swift_version

@see PodTarget#swift_version

@return [PodTarget]

# File lib/cocoapods/installer/analyzer.rb, line 797
def generate_pod_target(target_definitions, build_type, target_inspections, specs, scope_suffix: nil,
                        swift_version: nil)
  target_inspections = target_inspections.select { |t, _| target_definitions.include?(t) }.values
  object_version = target_inspections.map { |ti| ti.project.object_version }.min
  target_requires_64_bit = target_definitions.all? { |td| Analyzer.requires_64_bit_archs?(td.platform, object_version) }
  if !target_inspections.empty?
    user_build_configurations = target_inspections.map(&:build_configurations).reduce({}, &:merge)
    archs = if target_requires_64_bit
              ['$(ARCHS_STANDARD_64_BIT)']
            else
              target_inspections.flat_map(&:archs).compact.uniq.sort
            end
  else
    user_build_configurations = Target::DEFAULT_BUILD_CONFIGURATIONS.merge(
      target_definitions.map { |td| td.build_configurations || {} }.reduce({}, &:merge),
    )
    archs = target_requires_64_bit ? ['$(ARCHS_STANDARD_64_BIT)'] : []
  end
  platform = determine_platform(specs, target_definitions, build_type)
  file_accessors = create_file_accessors(specs, platform)
  PodTarget.new(sandbox, build_type, user_build_configurations, archs, platform, specs, target_definitions,
                file_accessors, scope_suffix, swift_version)
end
generate_pod_targets(resolver_specs_by_target, target_inspections) click to toggle source

Setup the pod targets for an aggregate target. Deduplicates resulting targets by grouping by platform and subspec by their root to create a {PodTarget} for each spec.

@param [Hash{TargetDefinition => Array<ResolvedSpecification>}] resolver_specs_by_target

the resolved specifications grouped by target.

@param [Hash{TargetDefinition => TargetInspectionResult}] target_inspections

the user target inspections used to construct the aggregate and pod targets.

@return [Array<PodTarget>]

# File lib/cocoapods/installer/analyzer.rb, line 609
def generate_pod_targets(resolver_specs_by_target, target_inspections)
  if installation_options.deduplicate_targets?
    distinct_targets = resolver_specs_by_target.each_with_object({}) do |dependency, hash|
      target_definition, dependent_specs = *dependency
      dependent_specs.group_by(&:root).each do |root_spec, resolver_specs|
        all_specs = resolver_specs.map(&:spec)
        all_specs_by_type = all_specs.group_by(&:spec_type)
        library_specs = all_specs_by_type[:library] || []
        test_specs = all_specs_by_type[:test] || []
        app_specs = all_specs_by_type[:app] || []
        build_type = determine_build_type(root_spec, target_definition.build_type)
        pod_variant = PodVariant.new(library_specs, test_specs, app_specs, target_definition.platform, build_type)
        hash[root_spec] ||= {}
        (hash[root_spec][pod_variant] ||= []) << target_definition
        pod_variant_spec = hash[root_spec].keys.find { |k| k == pod_variant }
        pod_variant_spec.test_specs.concat(test_specs).uniq!
        pod_variant_spec.app_specs.concat(app_specs).uniq!
      end
    end

    # Remap pod variants to a new instance that includes the Swift version since we now have the full set
    # of target definitions.
    distinct_targets = Hash[distinct_targets.map do |root, target_definitions_by_variant|
      variants = Hash[target_definitions_by_variant.map do |variant, target_definitions|
        swift_version = determine_swift_version(variant.root_spec, target_definitions)
        [variant.scoped_with_swift_version(swift_version), target_definitions]
      end]
      [root, variants]
    end]

    pod_targets = distinct_targets.flat_map do |_root, target_definitions_by_variant|
      target_definitions_by_variant.each_value do |target_definitions|
        target_definitions.reject!(&:abstract?) unless target_definitions.all?(&:abstract?)
      end
      suffixes = PodVariantSet.new(target_definitions_by_variant.keys).scope_suffixes
      target_definitions_by_variant.map do |variant, target_definitions|
        all_specs = variant.specs + variant.test_specs + variant.app_specs
        generate_pod_target(target_definitions, variant.build_type, target_inspections, all_specs,
                            :scope_suffix => suffixes[variant], :swift_version => variant.swift_version)
      end
    end

    all_specs = resolver_specs_by_target.values.flatten.map(&:spec).uniq.group_by(&:name)
    compute_pod_target_dependencies(pod_targets, all_specs)
  else
    dedupe_cache = {}
    resolver_specs_by_target.flat_map do |target_definition, specs|
      grouped_specs = specs.group_by(&:root).values.uniq
      pod_targets = grouped_specs.flat_map do |pod_specs|
        build_type = determine_build_type(pod_specs.first.spec, target_definition.build_type)
        swift_version = determine_swift_version(pod_specs.first.spec, [target_definition])
        generate_pod_target([target_definition], build_type, target_inspections, pod_specs.map(&:spec),
                            :swift_version => swift_version).scoped(dedupe_cache)
      end

      compute_pod_target_dependencies(pod_targets, specs.map(&:spec).group_by(&:name))
    end
  end
end
generate_podfile_state() click to toggle source

Compares the {Podfile} with the {Lockfile} in order to detect which dependencies should be locked.

@return [SpecsState] the states of the Podfile specs.

@note As the target definitions share the same sandbox they should have

the same version of a Pod. For this reason this method returns
the name of the Pod (root name of the dependencies) and doesn't
group them by target definition.

@return [SpecState]

# File lib/cocoapods/installer/analyzer.rb, line 260
def generate_podfile_state
  if lockfile
    pods_state = nil
    UI.section 'Finding Podfile changes' do
      pods_by_state = lockfile.detect_changes_with_podfile(podfile)
      pods_state = SpecsState.new(pods_by_state)
      pods_state.print if config.verbose?
    end
    pods_state
  else
    state = SpecsState.new
    state.added.merge(podfile_dependencies.map(&:root_name))
    state
  end
end
generate_sandbox_state(specifications) click to toggle source

Computes the state of the sandbox respect to the resolved specifications.

@return [SpecsState] the representation of the state of the manifest

specifications.
# File lib/cocoapods/installer/analyzer.rb, line 1123
def generate_sandbox_state(specifications)
  sandbox_state = nil
  UI.section 'Comparing resolved specification to the sandbox manifest' do
    sandbox_analyzer = SandboxAnalyzer.new(sandbox, podfile, specifications, update_mode?)
    sandbox_state = sandbox_analyzer.analyze
    sandbox_state.print
  end
  sandbox_state
end
generate_specifications(resolver_specs_by_target) click to toggle source

Returns the list of all the resolved specifications.

@param [Hash{TargetDefinition => Array<Specification>}] resolver_specs_by_target

the resolved specifications grouped by target.

@return [Array<Specification>] the list of the specifications.

# File lib/cocoapods/installer/analyzer.rb, line 1113
def generate_specifications(resolver_specs_by_target)
  resolver_specs_by_target.values.flatten.map(&:spec).uniq
end
generate_targets(resolver_specs_by_target, target_inspections) click to toggle source

Creates the models that represent the targets generated by CocoaPods.

@param [Hash{TargetDefinition => Array<ResolvedSpecification>}] resolver_specs_by_target

mapping of targets to resolved specs (containing information about test usage)
aggregate targets

@param [Hash{TargetDefinition => TargetInspectionResult}] target_inspections

the user target inspections used to construct the aggregate and pod targets.

@return [(Array<AggregateTarget>, Array<PodTarget>)] the list of aggregate targets generated,

and the list of pod targets generated.
# File lib/cocoapods/installer/analyzer.rb, line 430
def generate_targets(resolver_specs_by_target, target_inspections)
  resolver_specs_by_target = resolver_specs_by_target.reject { |td, _| td.abstract? && !td.platform }
  pod_targets = generate_pod_targets(resolver_specs_by_target, target_inspections)
  pod_targets_by_target_definition = group_pod_targets_by_target_definition(pod_targets, resolver_specs_by_target)
  aggregate_targets = resolver_specs_by_target.keys.reject(&:abstract?).map do |target_definition|
    generate_aggregate_target(target_definition, target_inspections, pod_targets_by_target_definition)
  end
  aggregate_targets.each do |target|
    search_paths_aggregate_targets = aggregate_targets.select do |aggregate_target|
      target.target_definition.targets_to_inherit_search_paths.include?(aggregate_target.target_definition)
    end
    target.search_paths_aggregate_targets.concat(search_paths_aggregate_targets).freeze
  end

  aggregate_targets.each do |aggregate_target|
    is_app_extension = !(aggregate_target.user_targets.map(&:symbol_type) &
        [:app_extension, :watch_extension, :watch2_extension, :tv_extension, :messages_extension]).empty?
    is_app_extension ||= aggregate_target.user_targets.any? do |user_target|
      user_target.common_resolved_build_setting('APPLICATION_EXTENSION_API_ONLY', :resolve_against_xcconfig => true) == 'YES'
    end
    if is_app_extension
      aggregate_target.mark_application_extension_api_only
      aggregate_target.pod_targets.each(&:mark_application_extension_api_only)
    end

    build_library_for_distribution = aggregate_target.user_targets.any? do |user_target|
      user_target.common_resolved_build_setting('BUILD_LIBRARY_FOR_DISTRIBUTION', :resolve_against_xcconfig => true) == 'YES'
    end
    if build_library_for_distribution
      aggregate_target.mark_build_library_for_distribution
      aggregate_target.pod_targets.each(&:mark_build_library_for_distribution)
    end
  end

  if installation_options.integrate_targets?
    # Copy embedded target pods that cannot have their pods embedded as frameworks to
    # their host targets, and ensure we properly link library pods to their host targets
    embedded_targets = aggregate_targets.select(&:requires_host_target?)
    analyze_host_targets_in_podfile(aggregate_targets, embedded_targets)

    use_frameworks_embedded_targets, non_use_frameworks_embedded_targets = embedded_targets.partition(&:build_as_framework?)
    aggregate_targets = aggregate_targets.map do |aggregate_target|
      # For targets that require dynamic frameworks, we always have to copy their pods to their
      # host targets because those frameworks will all be loaded from the host target's bundle
      embedded_pod_targets = embedded_target_pod_targets_by_host(aggregate_target, use_frameworks_embedded_targets, false)

      # For targets that don't require dynamic frameworks, we only have to consider library-type
      # targets because their host targets will still need to link their pods
      embedded_pod_targets.merge!(embedded_target_pod_targets_by_host(aggregate_target, non_use_frameworks_embedded_targets, true))

      next aggregate_target if embedded_pod_targets.empty?
      aggregate_target.merge_embedded_pod_targets(embedded_pod_targets)
    end
  end
  [aggregate_targets, pod_targets]
end
generate_version_locking_dependencies(podfile_state) click to toggle source

Generates dependencies that require the specific version of the Pods that haven’t changed in the {Lockfile}.

These dependencies are passed to the {Resolver}, unless the installer is in update mode, to prevent it from upgrading the Pods that weren’t 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

generated by the lockfile that prevent the resolver to update
a Pod.
# File lib/cocoapods/installer/analyzer.rb, line 934
def generate_version_locking_dependencies(podfile_state)
  if update_mode == :all || !lockfile
    LockingDependencyAnalyzer.unlocked_dependency_graph
  else
    deleted_and_changed = podfile_state.changed + podfile_state.deleted
    deleted_and_changed += pods_to_update[:pods] if update_mode == :selected
    local_pod_names = podfile_dependencies.select(&:local?).map(&:root_name)
    pods_to_unlock = local_pod_names.to_set.delete_if do |pod_name|
      next unless sandbox_specification = sandbox.specification(pod_name)
      sandbox_specification.checksum == lockfile.checksum(pod_name)
    end
    LockingDependencyAnalyzer.generate_version_locking_dependencies(lockfile, deleted_and_changed, pods_to_unlock)
  end
end
group_pod_targets_by_target_definition(pod_targets, resolver_specs_by_target) click to toggle source

Returns a filtered list of pod targets that should or should not be part of the target definition. Pod targets used by tests only are filtered.

@return [Hash{TargetDefinition => Array<PodTarget>}]

# File lib/cocoapods/installer/analyzer.rb, line 533
def group_pod_targets_by_target_definition(pod_targets, resolver_specs_by_target)
  pod_targets_by_target_definition = Hash.new { |h, td| h[td] = [] }
  pod_targets.each do |pod_target|
    pod_target.target_definitions.each do |td|
      pod_targets_by_target_definition[td] << pod_target
    end
  end
  resolver_specs_by_target.each do |td, resolver_specs|
    specs_by_pod_name = resolver_specs.group_by { |s| s.root.name }
    specs_by_pod_name.reject! { |_, specs| specs.all?(&:used_by_non_library_targets_only?) }
    pod_targets_by_target_definition[td].keep_if { |pod_target| specs_by_pod_name.key?(pod_target.pod_name) }
  end

  pod_targets_by_target_definition
end
inspect_targets_to_integrate() click to toggle source

Precompute information for each target_definition in the Podfile

@note The platforms are computed and added to each target_definition

because it might be necessary to infer the platform from the
user targets.

@return [Hash{TargetDefinition => TargetInspectionResult}]

# File lib/cocoapods/installer/analyzer.rb, line 1186
def inspect_targets_to_integrate
  inspection_result = {}
  UI.section 'Inspecting targets to integrate' do
    inspectors = @podfile_dependency_cache.target_definition_list.map do |target_definition|
      next if target_definition.abstract?
      TargetInspector.new(target_definition, config.installation_root)
    end.compact
    inspectors.group_by(&:compute_project_path).each do |project_path, target_inspectors|
      project = Xcodeproj::Project.open(project_path)
      target_inspectors.each do |inspector|
        target_definition = inspector.target_definition
        results = inspector.compute_results(project)
        inspection_result[target_definition] = results
        UI.message('Using `ARCHS` setting to build architectures of ' \
          "target `#{target_definition.label}`: (`#{results.archs.join('`, `')}`)")
      end
    end
  end
  inspection_result
end
podfile_dependencies() click to toggle source
# File lib/cocoapods/installer/analyzer.rb, line 217
def podfile_dependencies
  @podfile_dependency_cache.podfile_dependencies
end
pods_to_fetch(podfile_state) click to toggle source
# File lib/cocoapods/installer/analyzer.rb, line 1028
def pods_to_fetch(podfile_state)
  @pods_to_fetch ||= begin
    pods_to_fetch = podfile_state.added + podfile_state.changed
    if update_mode == :selected
      pods_to_fetch += pods_to_update[:pods]
    elsif update_mode == :all
      pods_to_fetch += podfile_state.unchanged + podfile_state.deleted
    end
    pods_to_fetch += podfile_dependencies.
      select { |dep| Hash(dep.external_source).key?(:podspec) && sandbox.specification_path(dep.root_name).nil? }.
      map(&:root_name)
    pods_to_fetch
  end
end
resolve_dependencies(locked_dependencies) click to toggle source

Converts the Podfile in a list of specifications grouped by target.

@note As some dependencies might have external sources the resolver

is aware of the {Sandbox} and interacts with it to download the
podspecs of the external sources. This is necessary because the
resolver needs their specifications to analyze their
dependencies.

@note The specifications of the external sources which are added,

modified or removed need to deleted from the sandbox before the
resolution process. Otherwise the resolver might use an
incorrect specification instead of pre-downloading it.

@note In update mode the resolver is set to always update the specs

from external sources.

@return [Hash{TargetDefinition => Array<Spec>}] the specifications

grouped by target.
# File lib/cocoapods/installer/analyzer.rb, line 1071
def resolve_dependencies(locked_dependencies)
  duplicate_dependencies = podfile_dependencies.group_by(&:name).
    select { |_name, dependencies| dependencies.count > 1 }
  duplicate_dependencies.each do |name, dependencies|
    UI.warn "There are duplicate dependencies on `#{name}` in #{UI.path podfile.defined_in_file}:\n\n" \
     "- #{dependencies.map(&:to_s).join("\n- ")}"
  end

  resolver_specs_by_target = nil
  UI.section "Resolving dependencies of #{UI.path(podfile.defined_in_file) || 'Podfile'}" do
    resolver = Pod::Resolver.new(sandbox, podfile, locked_dependencies, sources, @specs_updated, :sources_manager => sources_manager)
    resolver_specs_by_target = resolver.resolve
    resolver_specs_by_target.values.flatten(1).map(&:spec).each(&:validate_cocoapods_version)
  end
  resolver_specs_by_target
end
store_existing_checkout_options() click to toggle source
# File lib/cocoapods/installer/analyzer.rb, line 1043
def store_existing_checkout_options
  return unless lockfile
  podfile_dependencies.select(&:external_source).each do |dep|
    if checkout_options = lockfile.checkout_options_for_pod_named(dep.root_name)
      sandbox.store_checkout_source(dep.root_name, checkout_options)
    end
  end
end
update_mode() click to toggle source

@return [Symbol] Whether and how the dependencies in the Podfile

should be updated.
# File lib/cocoapods/installer/analyzer.rb, line 207
def update_mode
  if !pods_to_update
    :none
  elsif pods_to_update == true
    :all
  elsif !pods_to_update[:pods].nil?
    :selected
  end
end
update_mode?() click to toggle source

@return [Boolean] Whether the version of the dependencies which did not

change in the Podfile should be locked.
# File lib/cocoapods/installer/analyzer.rb, line 200
def update_mode?
  pods_to_update != nil
end
validate_lockfile_version!() click to toggle source

@note The warning about the version of the Lockfile doesn’t use the

`UI.warn` method because it prints the output only at the end
of the installation. At that time CocoaPods could have crashed.
# File lib/cocoapods/installer/analyzer.rb, line 239
def validate_lockfile_version!
  if lockfile && lockfile.cocoapods_version > Version.new(VERSION)
    STDERR.puts '[!] The version of CocoaPods used to generate ' \
      "the lockfile (#{lockfile.cocoapods_version}) is "\
      "higher than the version of the current executable (#{VERSION}). " \
      'Incompatibility issues may arise.'.yellow
  end
end
validate_platforms(resolver_specs_by_target) click to toggle source

Warns for any specification that is incompatible with its target.

@param [Hash{TargetDefinition => Array<Specification>}] resolver_specs_by_target

the resolved specifications grouped by target.
# File lib/cocoapods/installer/analyzer.rb, line 1093
def validate_platforms(resolver_specs_by_target)
  resolver_specs_by_target.each do |target, specs|
    specs.map(&:spec).each do |spec|
      next unless target_platform = target.platform
      unless spec.available_platforms.any? { |p| target_platform.supports?(p) }
        UI.warn "The platform of the target `#{target.name}` "     \
          "(#{target.platform}) may not be compatible with `#{spec}` which has "  \
          "a minimum requirement of #{spec.available_platforms.join(' - ')}."
      end
    end
  end
end
validate_podfile!() click to toggle source
# File lib/cocoapods/installer/analyzer.rb, line 223
def validate_podfile!
  validator = Installer::PodfileValidator.new(podfile, @podfile_dependency_cache)
  validator.validate

  unless validator.valid?
    raise Informative, validator.message
  end
  validator.warnings.uniq.each { |w| UI.warn(w) }
end
verify_no_pods_with_different_sources!() click to toggle source
# File lib/cocoapods/installer/analyzer.rb, line 981
def verify_no_pods_with_different_sources!
  deps_with_different_sources = podfile_dependencies.group_by(&:root_name).
    select { |_root_name, dependencies| dependencies.map(&:external_source).uniq.count > 1 }
  deps_with_different_sources.each do |root_name, dependencies|
    raise Informative, 'There are multiple dependencies with different ' \
    "sources for `#{root_name}` in #{UI.path podfile.defined_in_file}:" \
    "\n\n- #{dependencies.map(&:to_s).join("\n- ")}"
  end
end
verify_platforms_specified!() click to toggle source

Checks whether the platform is specified if not integrating

@return [void]

# File lib/cocoapods/installer/analyzer.rb, line 1169
def verify_platforms_specified!
  return if installation_options.integrate_targets?
  @podfile_dependency_cache.target_definition_list.each do |target_definition|
    if !target_definition.empty? && target_definition.platform.nil?
      raise Informative, 'It is necessary to specify the platform in the Podfile if not integrating.'
    end
  end
end