class Pod::Installer

The Installer is responsible of taking a Podfile and transform it in the Pods libraries. It also integrates the user project so the Pods libraries can be used out of the box.

The Installer is capable of doing incremental updates to an existing Pod installation.

The Installer gets the information that it needs mainly from 3 files:

- Podfile: The specification written by the user that contains
  information about targets and Pods.
- Podfile.lock: Contains information about the pods that were previously
  installed and in concert with the Podfile provides information about
  which specific version of a Pod should be installed. This file is
  ignored in update mode.
- Manifest.lock: A file contained in the Pods folder that keeps track of
  the pods installed in the local machine. This files is used once the
  exact versions of the Pods has been computed to detect if that version
  is already installed. This file is not intended to be kept under source
  control and is a copy of the Podfile.lock.

The Installer is designed to work in environments where the Podfile folder is under source control and environments where it is not. The rest of the files, like the user project and the workspace are assumed to be under source control.

Constants

DEFAULT_PLUGINS
MASTER_SPECS_REPO_GIT_URL

Attributes

aggregate_targets[R]

@return [Array<AggregateTarget>] The model representations of an

aggregation of pod targets generated for a target definition
in the Podfile as result of the analyzer.
analysis_result[R]

@return [Analyzer::AnalysisResult] the result of the analysis performed during installation

clean_install[RW]

@return [Boolean] Whether installation should ignore the contents of the project cache when incremental installation is enabled.

clean_install?[RW]

@return [Boolean] Whether installation should ignore the contents of the project cache when incremental installation is enabled.

deployment[RW]

@return [Boolean] Whether installation should verify that there are no

Podfile or Lockfile changes. Defaults to false.
deployment?[RW]

@return [Boolean] Whether installation should verify that there are no

Podfile or Lockfile changes. Defaults to false.
generated_aggregate_targets[R]

@return [Array<AggregateTarget>] The list of aggregate targets that were generated from the installation.

generated_pod_targets[R]

@return [Array<PodTarget>] The list of pod targets that were generated from the installation.

generated_projects[R]

@return [Array<Project>] The list of projects generated from the installation.

has_dependencies[RW]

@return [Boolean] Whether it has dependencies. Defaults to true.

has_dependencies?[RW]

@return [Boolean] Whether it has dependencies. Defaults to true.

installation_cache[R]

@return [ProjectInstallationCache] The installation cache stored in Pods/.project_cache/installation_cache

installed_specs[RW]

@return [Array<Specification>] The specifications that were installed.

lockfile[R]

@return [Lockfile] The Lockfile that stores the information about the

Pods previously installed on any machine.
metadata_cache[R]

@return [ProjectMetadataCache] The metadata cache stored in Pods/.project_cache/metadata_cache

pod_installers[R]

@return [Array<PodSourceInstaller>] the pod installers created

while installing pod targets
pod_target_subprojects[R]

@return [Array<Pod::Project>] the subprojects nested under pods_project.

pod_targets[R]

@return [Array<PodTarget>] The model representations of pod targets

generated as result of the analyzer.
podfile[R]

@return [Podfile] The Podfile specification that contains the information

of the Pods that should be installed.
pods_project[R]

@return [Pod::Project] the ‘Pods/Pods.xcodeproj` project.

project_cache_version[R]

@return [ProjectCacheVersion] The version of the project cache stored in Pods/.project_cache/version

repo_update[RW]

@return [Boolean] Whether the spec repos should be updated.

repo_update?[RW]

@return [Boolean] Whether the spec repos should be updated.

sandbox[R]

@return [Sandbox] The sandbox where the Pods should be installed.

target_installation_results[R]

@return [Array<Hash{String, TargetInstallationResult}>] the installation results produced by the pods project

generator
update[RW]

@return [Hash, Boolean, nil] Pods that have been requested to be

updated or true if all Pods should be updated.
If all Pods should been updated the contents of the Lockfile are
not taken into account for deciding what Pods to install.
use_default_plugins[RW]

@return [Boolean] Whether default plugins should be used during

installation. Defaults to true.
use_default_plugins?[RW]

@return [Boolean] Whether default plugins should be used during

installation. Defaults to true.

Public Class Methods

new(sandbox, podfile, lockfile = nil) click to toggle source

Initialize a new instance

@param [Sandbox] sandbox @see sandbox @param [Podfile] podfile @see podfile @param [Lockfile] lockfile @see lockfile

# File lib/cocoapods/installer.rb, line 76
def initialize(sandbox, podfile, lockfile = nil)
  @sandbox  = sandbox || raise(ArgumentError, 'Missing required argument `sandbox`')
  @podfile  = podfile || raise(ArgumentError, 'Missing required argument `podfile`')
  @lockfile = lockfile

  @use_default_plugins = true
  @has_dependencies = true
  @pod_installers = []
end
targets_from_sandbox(sandbox, podfile, lockfile) click to toggle source

@!group Convenience Methods

# File lib/cocoapods/installer.rb, line 1093
def self.targets_from_sandbox(sandbox, podfile, lockfile)
  raise Informative, 'You must run `pod install` to be able to generate target information' unless lockfile

  new(sandbox, podfile, lockfile).instance_exec do
    plugin_sources = run_source_provider_hooks
    analyzer = create_analyzer(plugin_sources)
    analyze(analyzer)
    if analysis_result.podfile_needs_install?
      raise Pod::Informative, 'The Podfile has changed, you must run `pod install`'
    elsif analysis_result.sandbox_needs_install?
      raise Pod::Informative, 'The `Pods` directory is out-of-date, you must run `pod install`'
    end

    aggregate_targets
  end
end

Public Instance Methods

analyze_project_cache() click to toggle source
# File lib/cocoapods/installer.rb, line 191
def analyze_project_cache
  user_projects = aggregate_targets.map(&:user_project).compact.uniq
  object_version = user_projects.min_by { |p| p.object_version.to_i }.object_version.to_i unless user_projects.empty?

  if !installation_options.incremental_installation
    # Run entire installation.
    ProjectCache::ProjectCacheAnalysisResult.new(pod_targets, aggregate_targets, {},
                                                 analysis_result.all_user_build_configurations, object_version)
  else
    UI.message 'Analyzing Project Cache' do
      @installation_cache = ProjectCache::ProjectInstallationCache.from_file(sandbox, sandbox.project_installation_cache_path)
      @metadata_cache = ProjectCache::ProjectMetadataCache.from_file(sandbox, sandbox.project_metadata_cache_path)
      @project_cache_version = ProjectCache::ProjectCacheVersion.from_file(sandbox.project_version_cache_path)

      force_clean_install = clean_install || project_cache_version.version != Version.create(VersionMetadata.project_cache_version)
      cache_result = ProjectCache::ProjectCacheAnalyzer.new(sandbox, installation_cache, analysis_result.all_user_build_configurations,
                                                            object_version, plugins, pod_targets, aggregate_targets, installation_options.to_h, :clean_install => force_clean_install).analyze
      aggregate_targets_to_generate = cache_result.aggregate_targets_to_generate || []
      pod_targets_to_generate = cache_result.pod_targets_to_generate
      (aggregate_targets_to_generate + pod_targets_to_generate).each do |target|
        UI.message "- Regenerating #{target.label}"
      end
      cache_result
    end
  end
end
development_pod_targets(targets = pod_targets) click to toggle source

@param [Array<PodTarget>] targets

@return [Array<PodTarget>] The targets of the development pods generated by

the installation process. This can be used as a convenience method for external scripts.
# File lib/cocoapods/installer.rb, line 1056
def development_pod_targets(targets = pod_targets)
  targets.select do |pod_target|
    sandbox.local?(pod_target.pod_name)
  end
end
download_dependencies() click to toggle source
# File lib/cocoapods/installer.rb, line 256
def download_dependencies
  UI.section 'Downloading dependencies' do
    install_pod_sources
    run_podfile_pre_install_hooks
    clean_pod_sources
  end
end
install!() click to toggle source

Installs the Pods.

The installation process is mostly linear with a few minor complications to keep in mind:

  • The stored podspecs need to be cleaned before the resolution step otherwise the sandbox might return an old podspec and not download the new one from an external source.

  • The resolver might trigger the download of Pods from external sources necessary to retrieve their podspec (unless it is instructed not to do it).

@return [void]

# File lib/cocoapods/installer.rb, line 160
def install!
  prepare
  resolve_dependencies
  download_dependencies
  validate_targets
  clean_sandbox
  if installation_options.skip_pods_project_generation?
    show_skip_pods_project_generation_message
    run_podfile_post_install_hooks
  else
    integrate
  end
  write_lockfiles
  perform_post_install_actions
end
integrate() click to toggle source
# File lib/cocoapods/installer.rb, line 181
def integrate
  run_podfile_pre_integrate_hooks
  generate_pods_project
  if installation_options.integrate_targets?
    integrate_user_project
  else
    UI.section 'Skipping User Project Integration'
  end
end
prepare() click to toggle source
# File lib/cocoapods/installer.rb, line 218
def prepare
  # Raise if pwd is inside Pods
  if Dir.pwd.start_with?(sandbox.root.to_path)
    message = 'Command should be run from a directory outside Pods directory.'
    message << "\n\n\tCurrent directory is #{UI.path(Pathname.pwd)}\n"
    raise Informative, message
  end
  UI.message 'Preparing' do
    deintegrate_if_different_major_version
    sandbox.prepare
    ensure_plugins_are_installed!
    run_plugins_pre_install_hooks
  end
end
resolve_dependencies() click to toggle source

@return [Analyzer] The analyzer used to resolve dependencies

# File lib/cocoapods/installer.rb, line 235
def resolve_dependencies
  plugin_sources = run_source_provider_hooks
  analyzer = create_analyzer(plugin_sources)

  UI.section 'Updating local specs repositories' do
    analyzer.update_repositories
  end if repo_update?

  UI.section 'Analyzing dependencies' do
    analyze(analyzer)
    validate_build_configurations
  end

  UI.section 'Verifying no changes' do
    verify_no_podfile_changes!
    verify_no_lockfile_changes!
  end if deployment?

  analyzer
end
show_skip_pods_project_generation_message() click to toggle source
# File lib/cocoapods/installer.rb, line 176
def show_skip_pods_project_generation_message
  UI.section 'Skipping Pods Project Creation'
  UI.section 'Skipping User Project Integration'
end
stage_sandbox(sandbox, pod_targets) click to toggle source

Stages the sandbox after analysis.

@param [Sandbox] sandbox

The sandbox to stage.

@param [Array<PodTarget>] pod_targets

The list of all pod targets.

@return [void]

# File lib/cocoapods/installer.rb, line 274
def stage_sandbox(sandbox, pod_targets)
  SandboxHeaderPathsInstaller.new(sandbox, pod_targets).install!
end

Private Instance Methods

analyze(analyzer = create_analyzer) click to toggle source

Performs the analysis.

@param [Analyzer] analyzer the analyzer to use for analysis

@return [void]

# File lib/cocoapods/installer.rb, line 421
def analyze(analyzer = create_analyzer)
  @analysis_result = analyzer.analyze
  @aggregate_targets = @analysis_result.targets
  @pod_targets = @analysis_result.pod_targets
end
any_plugin_post_install_hooks?() click to toggle source

@return [Boolean] whether there are any plugin post-install hooks to run

# File lib/cocoapods/installer.rb, line 741
def any_plugin_post_install_hooks?
  HooksManager.hooks_to_run(:post_install, plugins).any?
end
any_plugin_post_integrate_hooks?() click to toggle source

@return [Boolean] whether there are any plugin post-integrate hooks to run

# File lib/cocoapods/installer.rb, line 747
def any_plugin_post_integrate_hooks?
  HooksManager.hooks_to_run(:post_integrate, plugins).any?
end
any_plugin_pre_integrate_hooks?() click to toggle source

@return [Boolean] whether there are any plugin pre-integrate hooks to run

# File lib/cocoapods/installer.rb, line 735
def any_plugin_pre_integrate_hooks?
  HooksManager.hooks_to_run(:pre_integrate, plugins).any?
end
clean_pod_sources() click to toggle source

Cleans the sources of the Pods if the config instructs to do so.

# File lib/cocoapods/installer.rb, line 639
def clean_pod_sources
  return unless installation_options.clean?
  return if installed_specs.empty?
  pod_installers.each(&:clean!)
end
clean_sandbox() click to toggle source

@return [void] Performs a general clean up of the sandbox related to the sandbox state that was

calculated. For example, pods that were marked for deletion are removed.
# File lib/cocoapods/installer.rb, line 455
def clean_sandbox
  unless sandbox_state.deleted.empty?
    title_options = { :verbose_prefix => '-> '.red }
    sandbox_state.deleted.each do |pod_name|
      UI.titled_section("Removing #{pod_name}".red, title_options) do
        root_name = Specification.root_name(pod_name)
        pod_dir = sandbox.local?(root_name) ? nil : sandbox.pod_dir(root_name)
        sandbox.clean_pod(pod_name, pod_dir)
      end
    end
  end

  # Check any changed pods that became local pods and used to be remote pods and
  # ensure the sandbox is cleaned up.
  unless sandbox_state.changed.empty?
    sandbox_state.changed.each do |pod_name|
      previous_spec_repo = sandbox.manifest.spec_repo(pod_name)
      should_clean = !previous_spec_repo.nil? && sandbox.local?(pod_name)
      sandbox.clean_pod(pod_name, sandbox.sources_root + Specification.root_name(pod_name)) if should_clean
    end
  end
end
create_analyzer(plugin_sources = nil) click to toggle source
# File lib/cocoapods/installer.rb, line 427
def create_analyzer(plugin_sources = nil)
  Analyzer.new(sandbox, podfile, lockfile, plugin_sources, has_dependencies?, update)
end
create_and_save_projects(pod_targets_to_generate, aggregate_targets_to_generate, build_configurations, project_object_version) click to toggle source
# File lib/cocoapods/installer.rb, line 314
def create_and_save_projects(pod_targets_to_generate, aggregate_targets_to_generate, build_configurations, project_object_version)
  UI.section 'Generating Pods project' do
    generator = create_generator(pod_targets_to_generate, aggregate_targets_to_generate,
                                 build_configurations, project_object_version,
                                 installation_options.generate_multiple_pod_projects)

    pod_project_generation_result = generator.generate!
    @target_installation_results = pod_project_generation_result.target_installation_results
    @pods_project = pod_project_generation_result.project
    # The `pod_target_subprojects` is used for backwards compatibility so that consumers can iterate over
    # all pod targets across projects without needing to open each one.
    @pod_target_subprojects = pod_project_generation_result.projects_by_pod_targets.keys
    @generated_projects = ([pods_project] + pod_target_subprojects || []).compact
    @generated_pod_targets = pod_targets_to_generate
    @generated_aggregate_targets = aggregate_targets_to_generate || []
    projects_by_pod_targets = pod_project_generation_result.projects_by_pod_targets

    predictabilize_uuids(generated_projects) if installation_options.deterministic_uuids?
    stabilize_target_uuids(generated_projects)

    projects_writer = Xcode::PodsProjectWriter.new(sandbox, generated_projects,
                                                   target_installation_results.pod_target_installation_results, installation_options)
    projects_writer.write! do
      run_podfile_post_install_hooks
    end

    pods_project_pod_targets = pod_targets_to_generate - projects_by_pod_targets.values.flatten
    all_projects_by_pod_targets = {}
    pods_project_by_targets = { pods_project => pods_project_pod_targets } if pods_project
    all_projects_by_pod_targets.merge!(pods_project_by_targets) if pods_project_by_targets
    all_projects_by_pod_targets.merge!(projects_by_pod_targets) if projects_by_pod_targets
    all_projects_by_pod_targets.each do |project, pod_targets|
      generator.configure_schemes(project, pod_targets, pod_project_generation_result)
    end
  end
end
create_generator(pod_targets_to_generate, aggregate_targets_to_generate, build_configurations, project_object_version, generate_multiple_pod_projects = false) click to toggle source

@!group Pods Project Generation

# File lib/cocoapods/installer.rb, line 284
def create_generator(pod_targets_to_generate, aggregate_targets_to_generate, build_configurations, project_object_version, generate_multiple_pod_projects = false)
  if generate_multiple_pod_projects
    Xcode::MultiPodsProjectGenerator.new(sandbox, aggregate_targets_to_generate, pod_targets_to_generate,
                                         build_configurations, installation_options, config, project_object_version, metadata_cache)
  else
    Xcode::SinglePodsProjectGenerator.new(sandbox, aggregate_targets_to_generate, pod_targets_to_generate, build_configurations, installation_options, config, project_object_version)
  end
end
create_pod_downloader(pod_name) click to toggle source
# File lib/cocoapods/installer.rb, line 584
def create_pod_downloader(pod_name)
  specs_by_platform = specs_for_pod(pod_name)

  if specs_by_platform.empty?
    requiring_targets = pod_targets.select { |pt| pt.recursive_dependent_targets.any? { |dt| dt.pod_name == pod_name } }
    message = "Could not download '#{pod_name}' pod"
    message += ", depended upon by #{requiring_targets.to_sentence}" unless requiring_targets.empty?
    message += '. There is either no platform to build for, or no target to build.'
    raise StandardError, message
  end

  PodSourceDownloader.new(sandbox, podfile, specs_by_platform, :can_cache => installation_options.clean?)
end
create_pod_installer(pod_name) click to toggle source
# File lib/cocoapods/installer.rb, line 568
def create_pod_installer(pod_name)
  specs_by_platform = specs_for_pod(pod_name)

  if specs_by_platform.empty?
    requiring_targets = pod_targets.select { |pt| pt.recursive_dependent_targets.any? { |dt| dt.pod_name == pod_name } }
    message = "Could not install '#{pod_name}' pod"
    message += ", depended upon by #{requiring_targets.to_sentence}" unless requiring_targets.empty?
    message += '. There is either no platform to build for, or no target to build.'
    raise StandardError, message
  end

  pod_installer = PodSourceInstaller.new(sandbox, podfile, specs_by_platform, :can_cache => installation_options.clean?)
  pod_installers << pod_installer
  pod_installer
end
deintegrate_if_different_major_version() click to toggle source

Run the deintegrator against all projects in the installation root if the current CocoaPods major version part is different than the one in the lockfile.

@return [void]

# File lib/cocoapods/installer.rb, line 767
def deintegrate_if_different_major_version
  return unless lockfile
  return if lockfile.cocoapods_version.major == Version.create(VERSION).major
  UI.section('Re-creating CocoaPods due to major version update.') do
    projects = Pathname.glob(config.installation_root + '*.xcodeproj').map { |path| Xcodeproj::Project.open(path) }
    deintegrator = Deintegrator.new
    projects.each do |project|
      config.with_changes(:silent => true) { deintegrator.deintegrate_project(project) }
      project.save if project.dirty?
    end
  end
end
download_source_of_pod(pod_name) click to toggle source

Download the pod unless it is local or has been predownloaded from an external source.

@return [void]

# File lib/cocoapods/installer.rb, line 630
def download_source_of_pod(pod_name)
  return if sandbox.local?(pod_name) || sandbox.predownloaded?(pod_name)

  pod_downloader = create_pod_downloader(pod_name)
  pod_downloader.download!
end
ensure_plugins_are_installed!() click to toggle source

Ensures that all plugins specified in the {#podfile} are loaded.

@return [void]

# File lib/cocoapods/installer.rb, line 784
def ensure_plugins_are_installed!
  require 'claide/command/plugin_manager'

  loaded_plugins = Command::PluginManager.specifications.map(&:name)

  podfile.plugins.keys.each do |plugin|
    unless loaded_plugins.include? plugin
      raise Informative, "Your Podfile requires that the plugin `#{plugin}` be installed. Please install it and try installation again."
    end
  end
end
generate_lockfile() click to toggle source

@return [Lockfile] The lockfile to write to disk.

# File lib/cocoapods/installer.rb, line 868
def generate_lockfile
  external_source_pods = analysis_result.podfile_dependency_cache.podfile_dependencies.select(&:external_source).map(&:root_name).uniq
  checkout_options = sandbox.checkout_sources.select { |root_name, _| external_source_pods.include? root_name }
  Lockfile.generate(podfile, analysis_result.specifications, checkout_options, analysis_result.specs_by_source)
end
generate_pods_project() click to toggle source

Generates the Xcode project(s) that go inside the ‘Pods/` directory.

# File lib/cocoapods/installer.rb, line 295
def generate_pods_project
  stage_sandbox(sandbox, pod_targets)

  cache_analysis_result = analyze_project_cache
  pod_targets_to_generate = cache_analysis_result.pod_targets_to_generate
  aggregate_targets_to_generate = cache_analysis_result.aggregate_targets_to_generate

  pod_targets_to_generate.each do |pod_target|
    pod_target.build_headers.implode_path!(pod_target.headers_sandbox)
    sandbox.public_headers.implode_path!(pod_target.headers_sandbox)
  end

  create_and_save_projects(pod_targets_to_generate, aggregate_targets_to_generate,
                           cache_analysis_result.build_configurations, cache_analysis_result.project_object_version)
  SandboxDirCleaner.new(sandbox, pod_targets, aggregate_targets).clean!

  update_project_cache(cache_analysis_result, target_installation_results)
end
install_pod_sources() click to toggle source

Downloads, installs the documentation and cleans the sources of the Pods which need to be installed.

@return [void]

# File lib/cocoapods/installer.rb, line 505
def install_pod_sources
  @downloaded_specs = []
  @installed_specs = []
  pods_to_install = sandbox_state.added | sandbox_state.changed
  title_options = { :verbose_prefix => '-> '.green }

  sorted_root_specs = root_specs.sort_by(&:name)

  # Download pods in parallel before installing if the option is set
  if installation_options.parallel_pod_downloads
    require 'concurrent/executor/fixed_thread_pool'
    thread_pool_size = installation_options.parallel_pod_download_thread_pool_size
    thread_pool = Concurrent::FixedThreadPool.new(thread_pool_size, :idletime => 300)

    sorted_root_specs.each do |spec|
      if pods_to_install.include?(spec.name)
        title = section_title(spec, 'Downloading')
        UI.titled_section(title.green, title_options) do
          thread_pool.post do
            download_source_of_pod(spec.name)
          end
        end
      end
    end

    thread_pool.shutdown
    thread_pool.wait_for_termination
  end

  # Install pods, which includes downloading only if parallel_pod_downloads is set to false
  sorted_root_specs.each do |spec|
    if pods_to_install.include?(spec.name)
      title = section_title(spec, 'Installing')
      UI.titled_section(title.green, title_options) do
        install_source_of_pod(spec.name)
      end
    else
      UI.section("Using #{spec}", title_options[:verbose_prefix]) do
        create_pod_installer(spec.name)
      end
    end
  end
end
install_source_of_pod(pod_name) click to toggle source

Install the Pods. If the resolver indicated that a Pod should be installed and it exits, it is removed and then reinstalled. In any case if the Pod doesn’t exits it is installed.

@return [void]

# File lib/cocoapods/installer.rb, line 619
def install_source_of_pod(pod_name)
  pod_installer = create_pod_installer(pod_name)
  pod_installer.install!
  @installed_specs.concat(pod_installer.specs_by_platform.values.flatten.uniq)
end
installation_options() click to toggle source

@return [InstallationOptions] the installation options to use during install

# File lib/cocoapods/installer.rb, line 1083
def installation_options
  podfile.installation_options
end
integrate_user_project() click to toggle source

Integrates the user projects adding the dependencies on the CocoaPods libraries, setting them up to use the xcconfigs and performing other actions. This step is also responsible of creating the workspace if needed.

@return [void]

# File lib/cocoapods/installer.rb, line 924
def integrate_user_project
  UI.section "Integrating client #{'project'.pluralize(aggregate_targets.map(&:user_project_path).uniq.count)}" do
    installation_root = config.installation_root
    integrator = UserProjectIntegrator.new(podfile, sandbox, installation_root, aggregate_targets, generated_aggregate_targets,
                                           :use_input_output_paths => !installation_options.disable_input_output_paths?)
    integrator.integrate!
    run_podfile_post_integrate_hooks
  end
end
lock_pod_sources() click to toggle source

Locks the sources of the Pods if the config instructs to do so.

# File lib/cocoapods/installer.rb, line 656
def lock_pod_sources
  return unless installation_options.lock_pod_sources?
  pod_installers.each do |installer|
    pod_target = pod_targets.find { |target| target.pod_name == installer.name }
    installer.lock_files!(pod_target.file_accessors)
  end
end
perform_post_install_actions() click to toggle source

Performs any post-installation actions

@return [void]

# File lib/cocoapods/installer.rb, line 682
def perform_post_install_actions
  run_plugins_post_install_hooks
  warn_for_deprecations
  warn_for_installed_script_phases
  warn_for_removing_git_master_specs_repo
  print_post_install_message
end
plugins() click to toggle source

Returns the plugins that should be run, as indicated by the default plugins and the podfile’s plugins

@return [Hash<String, Hash>] The plugins to be used

# File lib/cocoapods/installer.rb, line 803
def plugins
  if use_default_plugins?
    DEFAULT_PLUGINS.merge(podfile.plugins)
  else
    podfile.plugins
  end
end
predictabilize_uuids(projects) click to toggle source
# File lib/cocoapods/installer.rb, line 351
def predictabilize_uuids(projects)
  UI.message('- Generating deterministic UUIDs') { Xcodeproj::Project.predictabilize_uuids(projects) }
end
print_post_install_message() click to toggle source
# File lib/cocoapods/installer.rb, line 690
def print_post_install_message
  podfile_dependencies = analysis_result.podfile_dependency_cache.podfile_dependencies.size
  pods_installed = root_specs.size
  title_options = { :verbose_prefix => '-> '.green }
  UI.titled_section('Pod installation complete! ' \
                    "There #{podfile_dependencies == 1 ? 'is' : 'are'} #{podfile_dependencies} " \
                    "#{'dependency'.pluralize(podfile_dependencies)} from the Podfile " \
                    "and #{pods_installed} total #{'pod'.pluralize(pods_installed)} installed.".green,
                    title_options)
end
root_specs() click to toggle source

@return [Array<Specification>] All the root specifications of the

installation.
# File lib/cocoapods/installer.rb, line 1071
def root_specs
  analysis_result.specifications.map(&:root).uniq
end
run_plugins_post_install_hooks() click to toggle source

Runs the registered callbacks for the plugins post install hooks.

# File lib/cocoapods/installer.rb, line 712
def run_plugins_post_install_hooks
  # This short-circuits because unlocking pod sources is expensive
  if any_plugin_post_install_hooks?
    unlock_pod_sources

    context = PostInstallHooksContext.generate(sandbox, pods_project, pod_target_subprojects, aggregate_targets)
    HooksManager.run(:post_install, context, plugins)
  end

  lock_pod_sources
end
run_plugins_post_integrate_hooks() click to toggle source

Runs the registered callbacks for the plugins post integrate hooks.

# File lib/cocoapods/installer.rb, line 726
def run_plugins_post_integrate_hooks
  if any_plugin_post_integrate_hooks?
    context = PostIntegrateHooksContext.generate(sandbox, pods_project, pod_target_subprojects, aggregate_targets)
    HooksManager.run(:post_integrate, context, plugins)
  end
end
run_plugins_pre_install_hooks() click to toggle source

Runs the registered callbacks for the plugins pre install hooks.

@return [void]

# File lib/cocoapods/installer.rb, line 673
def run_plugins_pre_install_hooks
  context = PreInstallHooksContext.generate(sandbox, podfile, lockfile)
  HooksManager.run(:pre_install, context, plugins)
end
run_plugins_pre_integrate_hooks() click to toggle source

Runs the registered callbacks for the plugins pre integrate hooks.

# File lib/cocoapods/installer.rb, line 703
def run_plugins_pre_integrate_hooks
  if any_plugin_pre_integrate_hooks?
    context = PreIntegrateHooksContext.generate(sandbox, pods_project, pod_target_subprojects, aggregate_targets)
    HooksManager.run(:pre_integrate, context, plugins)
  end
end
run_podfile_post_install_hook() click to toggle source

Runs the post install hook of the Podfile

@raise Raises an informative if the hooks raises.

@return [Boolean] Whether the hook was run.

# File lib/cocoapods/installer.rb, line 1012
def run_podfile_post_install_hook
  podfile.post_install!(self)
rescue => e
  raise Informative, 'An error occurred while processing the post-install ' \
    'hook of the Podfile.' \
    "\n\n#{e.message}\n\n#{e.backtrace * "\n"}"
end
run_podfile_post_install_hooks() click to toggle source

Runs the post install hooks of the installed specs and of the Podfile.

@note Post install hooks run before saving of project, so that they

can alter it before it is written to the disk.

@return [void]

# File lib/cocoapods/installer.rb, line 999
def run_podfile_post_install_hooks
  UI.message '- Running post install hooks' do
    executed = run_podfile_post_install_hook
    UI.message '- Podfile' if executed
  end
end
run_podfile_post_integrate_hook() click to toggle source

Runs the post integrate hook of the Podfile.

@raise Raises an informative if the hooks raises.

@return [Boolean] Whether the hook was run.

# File lib/cocoapods/installer.rb, line 1040
def run_podfile_post_integrate_hook
  podfile.post_integrate!(self)
rescue => e
  raise Informative, 'An error occurred while processing the post-integrate ' \
    'hook of the Podfile.' \
    "\n\n#{e.message}\n\n#{e.backtrace * "\n"}"
end
run_podfile_post_integrate_hooks() click to toggle source

Runs the post integrate hooks of the installed specs and of the Podfile.

@note Post integrate hooks run after saving of project, so that they

can alter it after it is written to the disk.

@return [void]

# File lib/cocoapods/installer.rb, line 1027
def run_podfile_post_integrate_hooks
  UI.message '- Running post integrate hooks' do
    executed = run_podfile_post_integrate_hook
    UI.message '- Podfile' if executed
  end
end
run_podfile_pre_install_hook() click to toggle source

Runs the pre install hook of the Podfile

@raise Raises an informative if the hooks raises.

@return [Boolean] Whether the hook was run.

# File lib/cocoapods/installer.rb, line 957
def run_podfile_pre_install_hook
  podfile.pre_install!(self)
rescue => e
  raise Informative, 'An error occurred while processing the pre-install ' \
    'hook of the Podfile.' \
    "\n\n#{e.message}\n\n#{e.backtrace * "\n"}"
end
run_podfile_pre_install_hooks() click to toggle source

Runs the pre install hooks of the installed specs and of the Podfile.

@return [void]

# File lib/cocoapods/installer.rb, line 944
def run_podfile_pre_install_hooks
  UI.message '- Running pre install hooks' do
    executed = run_podfile_pre_install_hook
    UI.message '- Podfile' if executed
  end
end
run_podfile_pre_integrate_hook() click to toggle source

Runs the pre integrate hook of the Podfile.

@raise Raises an informative if the hooks raises.

@return [Boolean] Whether the hook was run.

# File lib/cocoapods/installer.rb, line 984
def run_podfile_pre_integrate_hook
  podfile.pre_integrate!(self)
rescue => e
  raise Informative, 'An error occurred while processing the pre-integrate ' \
    'hook of the Podfile.' \
    "\n\n#{e.message}\n\n#{e.backtrace * "\n"}"
end
run_podfile_pre_integrate_hooks() click to toggle source

Runs the pre integrate hooks of the installed specs and of the Podfile.

@note Pre integrate hooks run before generation of the Pods project.

@return [void]

# File lib/cocoapods/installer.rb, line 971
def run_podfile_pre_integrate_hooks
  UI.message '- Running pre integrate hooks' do
    executed = run_podfile_pre_integrate_hook
    UI.message '- Podfile' if executed
  end
end
run_source_provider_hooks() click to toggle source

Runs the registered callbacks for the source provider plugin hooks.

@return [Array<Pod::Source>] the plugin sources

# File lib/cocoapods/installer.rb, line 755
def run_source_provider_hooks
  context = SourceProviderHooksContext.generate
  HooksManager.run(:source_provider, context, plugins)
  context.sources
end
sandbox_state() click to toggle source

@return [SpecsState] The state of the sandbox returned by the analyzer.

# File lib/cocoapods/installer.rb, line 1077
def sandbox_state
  analysis_result.sandbox_state
end
section_title(spec, current_action) click to toggle source
# File lib/cocoapods/installer.rb, line 549
def section_title(spec, current_action)
  if sandbox_state.changed.include?(spec.name) && sandbox.manifest
    current_version = spec.version
    previous_version = sandbox.manifest.version(spec.name)
    has_changed_version = current_version != previous_version
    current_repo = analysis_result.specs_by_source.detect { |key, values| break key if values.map(&:name).include?(spec.name) }
    current_repo &&= (Pod::TrunkSource::TRUNK_REPO_NAME if current_repo.name == Pod::TrunkSource::TRUNK_REPO_NAME) || current_repo.url || current_repo.name
    previous_spec_repo = sandbox.manifest.spec_repo(spec.name)
    has_changed_repo = !previous_spec_repo.nil? && current_repo && !current_repo.casecmp(previous_spec_repo).zero?
    title = "#{current_action} #{spec.name} #{spec.version}"
    title << " (was #{previous_version} and source changed to `#{current_repo}` from `#{previous_spec_repo}`)" if has_changed_version && has_changed_repo
    title << " (was #{previous_version})" if has_changed_version && !has_changed_repo
    title << " (source changed to `#{current_repo}` from `#{previous_spec_repo}`)" if !has_changed_version && has_changed_repo
  else
    title = "#{current_action} #{spec}"
  end
  title
end
specs_for_pod(pod_name) click to toggle source

The specifications matching the specified pod name

@param [String] pod_name the name of the pod

@return [Hash{Platform => Array<Specification>}] the specifications grouped by platform

# File lib/cocoapods/installer.rb, line 604
def specs_for_pod(pod_name)
  pod_targets.each_with_object({}) do |pod_target, hash|
    if pod_target.root_spec.name == pod_name
      hash[pod_target.platform] ||= []
      hash[pod_target.platform].concat(pod_target.specs)
    end
  end
end
stabilize_target_uuids(projects) click to toggle source
# File lib/cocoapods/installer.rb, line 355
def stabilize_target_uuids(projects)
  UI.message('- Stabilizing target UUIDs') { TargetUUIDGenerator.new(projects).generate! }
end
unlock_pod_sources() click to toggle source

Unlocks the sources of the Pods.

# File lib/cocoapods/installer.rb, line 647
def unlock_pod_sources
  pod_installers.each do |installer|
    pod_target = pod_targets.find { |target| target.pod_name == installer.name }
    installer.unlock_files!(pod_target.file_accessors)
  end
end
update_project_cache(cache_analysis_result, target_installation_results) click to toggle source

@param [ProjectCacheAnalysisResult] cache_analysis_result

The cache analysis result for the current installation.

@param [Hash{String => TargetInstallationResult}] target_installation_results

The installation results for pod targets installed.
# File lib/cocoapods/installer.rb, line 900
def update_project_cache(cache_analysis_result, target_installation_results)
  return unless installation_cache || metadata_cache
  installation_cache.update_cache_key_by_target_label!(cache_analysis_result.cache_key_by_target_label)
  installation_cache.update_project_object_version!(cache_analysis_result.project_object_version)
  installation_cache.update_build_configurations!(cache_analysis_result.build_configurations)
  installation_cache.update_podfile_plugins!(plugins)
  installation_cache.update_installation_options!(installation_options.to_h)
  installation_cache.save_as(sandbox.project_installation_cache_path)

  metadata_cache.update_metadata!(target_installation_results.pod_target_installation_results || {},
                                  target_installation_results.aggregate_target_installation_results || {})
  metadata_cache.save_as(sandbox.project_metadata_cache_path)

  cache_version = ProjectCache::ProjectCacheVersion.new(VersionMetadata.project_cache_version)
  cache_version.save_as(sandbox.project_version_cache_path)
end
validate_build_configurations() click to toggle source

Ensures that the white-listed build configurations are known to prevent silent typos.

@raise If an unknown user configuration is found.

# File lib/cocoapods/installer.rb, line 436
def validate_build_configurations
  whitelisted_configs = pod_targets.
    flat_map(&:target_definitions).
    flat_map(&:all_whitelisted_configurations).
    map(&:downcase).
    uniq
  all_user_configurations = analysis_result.all_user_build_configurations.keys.map(&:downcase)

  remainder = whitelisted_configs - all_user_configurations
  unless remainder.empty?
    raise Informative,
          "Unknown #{'configuration'.pluralize(remainder.size)} whitelisted: #{remainder.sort.to_sentence}. " \
          "CocoaPods found #{all_user_configurations.sort.to_sentence}, did you mean one of these?"
  end
end
validate_targets() click to toggle source
# File lib/cocoapods/installer.rb, line 664
def validate_targets
  validator = Xcode::TargetValidator.new(aggregate_targets, pod_targets, installation_options)
  validator.validate!
end
verify_no_lockfile_changes!() click to toggle source

@raise [Informative] If there are any Lockfile changes

# File lib/cocoapods/installer.rb, line 489
def verify_no_lockfile_changes!
  new_lockfile = generate_lockfile
  return if new_lockfile == lockfile

  return unless diff = Xcodeproj::Differ.hash_diff(lockfile.to_hash, new_lockfile.to_hash, :key_1 => 'Old Lockfile', :key_2 => 'New Lockfile')
  pretty_diff = YAMLHelper.convert_hash(diff, Lockfile::HASH_KEY_ORDER, "\n\n")
  pretty_diff.gsub!(':diff:', 'diff:'.yellow)

  raise Informative, "There were changes to the lockfile in deployment mode:\n#{pretty_diff}"
end
verify_no_podfile_changes!() click to toggle source

@raise [Informative] If there are any Podfile changes

# File lib/cocoapods/installer.rb, line 480
def verify_no_podfile_changes!
  return unless analysis_result.podfile_needs_install?

  changed_state = analysis_result.podfile_state.to_s(:states => %i(added deleted changed))
  raise Informative, "There were changes to the podfile in deployment mode:\n#{changed_state}"
end
warn_for_deprecations() click to toggle source

Prints a warning for any pods that are deprecated

@return [void]

# File lib/cocoapods/installer.rb, line 815
def warn_for_deprecations
  deprecated_pods = root_specs.select do |spec|
    spec.deprecated || spec.deprecated_in_favor_of
  end
  deprecated_pods.each do |spec|
    if spec.deprecated_in_favor_of
      UI.warn "#{spec.name} has been deprecated in " \
        "favor of #{spec.deprecated_in_favor_of}"
    else
      UI.warn "#{spec.name} has been deprecated"
    end
  end
end
warn_for_installed_script_phases() click to toggle source

Prints a warning for any pods that included script phases

@return [void]

# File lib/cocoapods/installer.rb, line 833
def warn_for_installed_script_phases
  pods_to_install = sandbox_state.added | sandbox_state.changed
  pod_targets.group_by(&:pod_name).each do |name, pod_targets|
    if pods_to_install.include?(name) && !sandbox.local?(name)
      script_phase_count = pod_targets.inject(0) { |sum, target| sum + target.script_phases.count }
      unless script_phase_count.zero?
        UI.warn "#{name} has added #{script_phase_count} #{'script phase'.pluralize(script_phase_count)}. " \
          'Please inspect before executing a build. See `https://guides.cocoapods.org/syntax/podspec.html#script_phases` for more information.'
      end
    end
  end
end
warn_for_removing_git_master_specs_repo() click to toggle source

Prints a warning if the project is not explicitly using the git based master specs repo.

Helps users to delete the git based master specs repo from the repos directory which reduces ‘–repo-update` speed and hopefully reduces Github workload.

@return [void]

# File lib/cocoapods/installer.rb, line 853
def warn_for_removing_git_master_specs_repo
  return unless installation_options.warn_for_unused_master_specs_repo?
  plugin_sources = run_source_provider_hooks
  all_sources = podfile.sources + plugin_sources.map(&:url)
  master_source = all_sources.find { |source| source == MASTER_SPECS_REPO_GIT_URL }
  master_repo = config.sources_manager.all.find { |s| s.url == MASTER_SPECS_REPO_GIT_URL }
  if master_source.nil? && !master_repo.nil?
    UI.warn 'Your project does not explicitly specify the CocoaPods master specs repo. Since CDN is now used as the' \
    ' default, you may safely remove it from your repos directory via `pod repo remove master`. To suppress this warning' \
    ' please add `warn_for_unused_master_specs_repo => false` to your Podfile.'
  end
end
write_lockfiles() click to toggle source

Writes the Podfile and the lock files.

@return [void]

# File lib/cocoapods/installer.rb, line 878
def write_lockfiles
  @lockfile = generate_lockfile

  UI.message "- Writing Lockfile in #{UI.path config.lockfile_path}" do
    # No need to invoke Sandbox#update_changed_file here since this logic already handles checking if the
    # contents of the file are the same.
    @lockfile.write_to_disk(config.lockfile_path)
  end

  UI.message "- Writing Manifest in #{UI.path sandbox.manifest_path}" do
    # No need to invoke Sandbox#update_changed_file here since this logic already handles checking if the
    # contents of the file are the same.
    @lockfile.write_to_disk(sandbox.manifest_path)
  end
end