Class: Pod::Installer

Inherits:
Object
  • Object
show all
Includes:
Config::Mixin
Defined in:
lib/cocoapods/installer.rb,
lib/cocoapods/installer/xcode.rb,
lib/cocoapods/installer/analyzer.rb,
lib/cocoapods/installer/podfile_validator.rb,
lib/cocoapods/installer/pod_source_preparer.rb,
lib/cocoapods/installer/sandbox_dir_cleaner.rb,
lib/cocoapods/installer/analyzer/pod_variant.rb,
lib/cocoapods/installer/analyzer/specs_state.rb,
lib/cocoapods/installer/installation_options.rb,
lib/cocoapods/installer/pod_source_installer.rb,
lib/cocoapods/installer/target_uuid_generator.rb,
lib/cocoapods/installer/xcode/target_validator.rb,
lib/cocoapods/installer/user_project_integrator.rb,
lib/cocoapods/installer/analyzer/analysis_result.rb,
lib/cocoapods/installer/analyzer/pod_variant_set.rb,
lib/cocoapods/installer/analyzer/sandbox_analyzer.rb,
lib/cocoapods/installer/analyzer/target_inspector.rb,
lib/cocoapods/installer/pre_install_hooks_context.rb,
lib/cocoapods/installer/base_install_hooks_context.rb,
lib/cocoapods/installer/post_install_hooks_context.rb,
lib/cocoapods/installer/project_cache/project_cache.rb,
lib/cocoapods/installer/post_integrate_hooks_context.rb,
lib/cocoapods/installer/xcode/pods_project_generator.rb,
lib/cocoapods/installer/project_cache/target_metadata.rb,
lib/cocoapods/installer/source_provider_hooks_context.rb,
lib/cocoapods/installer/project_cache/target_cache_key.rb,
lib/cocoapods/installer/sandbox_header_paths_installer.rb,
lib/cocoapods/installer/analyzer/podfile_dependency_cache.rb,
lib/cocoapods/installer/analyzer/target_inspection_result.rb,
lib/cocoapods/installer/xcode/multi_pods_project_generator.rb,
lib/cocoapods/installer/project_cache/project_cache_version.rb,
lib/cocoapods/installer/xcode/pods_project_generator_result.rb,
lib/cocoapods/installer/xcode/single_pods_project_generator.rb,
lib/cocoapods/installer/analyzer/locking_dependency_analyzer.rb,
lib/cocoapods/installer/project_cache/project_cache_analyzer.rb,
lib/cocoapods/installer/project_cache/project_metadata_cache.rb,
lib/cocoapods/installer/project_cache/project_installation_cache.rb,
lib/cocoapods/installer/user_project_integrator/target_integrator.rb,
lib/cocoapods/installer/project_cache/project_cache_analysis_result.rb,
lib/cocoapods/installer/xcode/pods_project_generator/target_installer.rb,
lib/cocoapods/installer/xcode/pods_project_generator/project_generator.rb,
lib/cocoapods/installer/xcode/pods_project_generator/app_host_installer.rb,
lib/cocoapods/installer/xcode/pods_project_generator/pods_project_writer.rb,
lib/cocoapods/installer/xcode/pods_project_generator/pod_target_installer.rb,
lib/cocoapods/installer/xcode/pods_project_generator/pod_target_integrator.rb,
lib/cocoapods/installer/xcode/pods_project_generator/target_installer_helper.rb,
lib/cocoapods/installer/xcode/pods_project_generator/file_references_installer.rb,
lib/cocoapods/installer/xcode/pods_project_generator/aggregate_target_installer.rb,
lib/cocoapods/installer/xcode/pods_project_generator/target_installation_result.rb,
lib/cocoapods/installer/xcode/pods_project_generator/pod_target_dependency_installer.rb,
lib/cocoapods/installer/user_project_integrator/target_integrator/xcconfig_integrator.rb,
lib/cocoapods/installer/xcode/pods_project_generator/aggregate_target_dependency_installer.rb

Overview

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.

Defined Under Namespace

Modules: ProjectCache Classes: Analyzer, BaseInstallHooksContext, InstallationOptions, PodSourceInstaller, PodSourcePreparer, PodfileValidator, PostInstallHooksContext, PostIntegrateHooksContext, PreInstallHooksContext, SandboxDirCleaner, SandboxHeaderPathsInstaller, SourceProviderHooksContext, TargetUUIDGenerator, UserProjectIntegrator, Xcode

Installation steps collapse

DEFAULT_PLUGINS =
{}

Constant Summary collapse

MASTER_SPECS_REPO_GIT_URL =
'https://github.com/CocoaPods/Specs.git'.freeze

Installation results collapse

Instance Attribute Summary collapse

Installation steps collapse

Hooks collapse

Private helpers collapse

Convenience Methods collapse

Instance Method Summary collapse

Methods included from Config::Mixin

#config

Constructor Details

#initialize(sandbox, podfile, lockfile = nil) ⇒ Installer

Initialize a new instance

Parameters:

  • sandbox (Sandbox)

    @see #sandbox

  • podfile (Podfile)

    @see #podfile

  • lockfile (Lockfile) (defaults to: nil)

    @see #lockfile


74
75
76
77
78
79
80
81
82
# File 'lib/cocoapods/installer.rb', line 74

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

Instance Attribute Details

#aggregate_targetsArray<AggregateTarget> (readonly)

Returns The model representations of an aggregation of pod targets generated for a target definition in the Podfile as result of the analyzer.

Returns:

  • (Array<AggregateTarget>)

    The model representations of an aggregation of pod targets generated for a target definition in the Podfile as result of the analyzer.


378
379
380
# File 'lib/cocoapods/installer.rb', line 378

def aggregate_targets
  @aggregate_targets
end

#analysis_resultAnalyzer::AnalysisResult (readonly)

Returns the result of the analysis performed during installation.

Returns:


359
360
361
# File 'lib/cocoapods/installer.rb', line 359

def analysis_result
  @analysis_result
end

#clean_installBoolean Also known as: clean_install?

when incremental installation is enabled.

Returns:

  • (Boolean)

    Whether installation should ignore the contents of the project cache


116
117
118
# File 'lib/cocoapods/installer.rb', line 116

def clean_install
  @clean_install
end

#deploymentBoolean Also known as: deployment?

Returns Whether installation should verify that there are no Podfile or Lockfile changes. Defaults to false.

Returns:

  • (Boolean)

    Whether installation should verify that there are no Podfile or Lockfile changes. Defaults to false.


110
111
112
# File 'lib/cocoapods/installer.rb', line 110

def deployment
  @deployment
end

#generated_aggregate_targetsArray<AggregateTarget> (readonly)

Returns The list of aggregate targets that were generated from the installation.

Returns:

  • (Array<AggregateTarget>)

    The list of aggregate targets that were generated from the installation.


395
396
397
# File 'lib/cocoapods/installer.rb', line 395

def generated_aggregate_targets
  @generated_aggregate_targets
end

#generated_pod_targetsArray<PodTarget> (readonly)

Returns The list of pod targets that were generated from the installation.

Returns:

  • (Array<PodTarget>)

    The list of pod targets that were generated from the installation.


391
392
393
# File 'lib/cocoapods/installer.rb', line 391

def generated_pod_targets
  @generated_pod_targets
end

#generated_projectsArray<Project> (readonly)

Returns The list of projects generated from the installation.

Returns:

  • (Array<Project>)

    The list of projects generated from the installation.


387
388
389
# File 'lib/cocoapods/installer.rb', line 387

def generated_projects
  @generated_projects
end

#has_dependenciesBoolean Also known as: has_dependencies?

Returns Whether it has dependencies. Defaults to true.

Returns:

  • (Boolean)

    Whether it has dependencies. Defaults to true.


93
94
95
# File 'lib/cocoapods/installer.rb', line 93

def has_dependencies
  @has_dependencies
end

#installation_cacheProjectInstallationCache (readonly, private)

Returns The installation cache stored in Pods/.project_cache/installation_cache.

Returns:

  • (ProjectInstallationCache)

    The installation cache stored in Pods/.project_cache/installation_cache


130
131
132
# File 'lib/cocoapods/installer.rb', line 130

def installation_cache
  @installation_cache
end

#installed_specsArray<Specification>

Returns The specifications that were installed.

Returns:

  • (Array<Specification>)

    The specifications that were installed.


399
400
401
# File 'lib/cocoapods/installer.rb', line 399

def installed_specs
  @installed_specs
end

#lockfileLockfile (readonly)

Returns The Lockfile that stores the information about the Pods previously installed on any machine.

Returns:

  • (Lockfile)

    The Lockfile that stores the information about the Pods previously installed on any machine.


66
67
68
# File 'lib/cocoapods/installer.rb', line 66

def lockfile
  @lockfile
end

#metadata_cacheProjectMetadataCache (readonly, private)

Returns The metadata cache stored in Pods/.project_cache/metadata_cache.

Returns:

  • (ProjectMetadataCache)

    The metadata cache stored in Pods/.project_cache/metadata_cache


134
135
136
# File 'lib/cocoapods/installer.rb', line 134

def 
  @metadata_cache
end

#pod_installersArray<PodSourceInstaller> (readonly, private)

Returns the pod installers created while installing pod targets.

Returns:


126
127
128
# File 'lib/cocoapods/installer.rb', line 126

def pod_installers
  @pod_installers
end

#pod_target_subprojectsArray<Pod::Project> (readonly)

Returns the subprojects nested under pods_project.

Returns:

  • (Array<Pod::Project>)

    the subprojects nested under pods_project.


372
373
374
# File 'lib/cocoapods/installer.rb', line 372

def pod_target_subprojects
  @pod_target_subprojects
end

#pod_targetsArray<PodTarget> (readonly)

Returns The model representations of pod targets generated as result of the analyzer.

Returns:

  • (Array<PodTarget>)

    The model representations of pod targets generated as result of the analyzer.


383
384
385
# File 'lib/cocoapods/installer.rb', line 383

def pod_targets
  @pod_targets
end

#podfilePodfile (readonly)

Returns The Podfile specification that contains the information of the Pods that should be installed.

Returns:

  • (Podfile)

    The Podfile specification that contains the information of the Pods that should be installed.


61
62
63
# File 'lib/cocoapods/installer.rb', line 61

def podfile
  @podfile
end

#pods_projectPod::Project (readonly)

Returns the Pods/Pods.xcodeproj project.

Returns:


368
369
370
# File 'lib/cocoapods/installer.rb', line 368

def pods_project
  @pods_project
end

#project_cache_versionProjectCacheVersion (readonly, private)

Returns The version of the project cache stored in Pods/.project_cache/version.

Returns:

  • (ProjectCacheVersion)

    The version of the project cache stored in Pods/.project_cache/version


138
139
140
# File 'lib/cocoapods/installer.rb', line 138

def project_cache_version
  @project_cache_version
end

#repo_updateBoolean Also known as: repo_update?

Returns Whether the spec repos should be updated.

Returns:

  • (Boolean)

    Whether the spec repos should be updated.


98
99
100
# File 'lib/cocoapods/installer.rb', line 98

def repo_update
  @repo_update
end

#sandboxSandbox (readonly)

Returns The sandbox where the Pods should be installed.

Returns:

  • (Sandbox)

    The sandbox where the Pods should be installed.


56
57
58
# File 'lib/cocoapods/installer.rb', line 56

def sandbox
  @sandbox
end

#target_installation_resultsArray<Hash{String, TargetInstallationResult}> (readonly)

Returns the installation results produced by the pods project generator.

Returns:

  • (Array<Hash{String, TargetInstallationResult}>)

    the installation results produced by the pods project generator


364
365
366
# File 'lib/cocoapods/installer.rb', line 364

def target_installation_results
  @target_installation_results
end

#updateHash, ...

Returns 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.

Returns:

  • (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.


89
90
91
# File 'lib/cocoapods/installer.rb', line 89

def update
  @update
end

#use_default_pluginsBoolean Also known as: use_default_plugins?

Returns Whether default plugins should be used during installation. Defaults to true.

Returns:

  • (Boolean)

    Whether default plugins should be used during installation. Defaults to true.


104
105
106
# File 'lib/cocoapods/installer.rb', line 104

def use_default_plugins
  @use_default_plugins
end

Class Method Details

.targets_from_sandbox(sandbox, podfile, lockfile) ⇒ Object

Raises:


978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
# File 'lib/cocoapods/installer.rb', line 978

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

Instance Method Details

#analyze(analyzer = create_analyzer) ⇒ void (private)

This method returns an undefined value.

Performs the analysis.

Parameters:

  • analyzer (Analyzer) (defaults to: create_analyzer)

    the analyzer to use for analysis


413
414
415
416
417
# File 'lib/cocoapods/installer.rb', line 413

def analyze(analyzer = create_analyzer)
  @analysis_result = analyzer.analyze
  @aggregate_targets = @analysis_result.targets
  @pod_targets = @analysis_result.pod_targets
end

#analyze_project_cacheObject


186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
# File 'lib/cocoapods/installer.rb', line 186

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_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

#any_plugin_post_install_hooks?Boolean (private)

Returns whether there are any plugin post-install hooks to run.

Returns:

  • (Boolean)

    whether there are any plugin post-install hooks to run


655
656
657
# File 'lib/cocoapods/installer.rb', line 655

def any_plugin_post_install_hooks?
  HooksManager.hooks_to_run(:post_install, plugins).any?
end

#any_plugin_post_integrate_hooks?Boolean (private)

Returns whether there are any plugin post-integrate hooks to run.

Returns:

  • (Boolean)

    whether there are any plugin post-integrate hooks to run


661
662
663
# File 'lib/cocoapods/installer.rb', line 661

def any_plugin_post_integrate_hooks?
  HooksManager.hooks_to_run(:post_integrate, plugins).any?
end

#clean_pod_sourcesObject (private)

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


568
569
570
571
572
# File 'lib/cocoapods/installer.rb', line 568

def clean_pod_sources
  return unless installation_options.clean?
  return if installed_specs.empty?
  pod_installers.each(&:clean!)
end

#clean_sandbox(pod_targets) ⇒ void (private)

This method returns an undefined value.

Returns In this step we clean all the header folders for pod targets that will be regenerated from scratch and cleanup any pods that have been removed.


447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
# File 'lib/cocoapods/installer.rb', line 447

def clean_sandbox(pod_targets)
  pod_targets.each do |pod_target|
    pod_target.build_headers.implode_path!(pod_target.headers_sandbox)
    sandbox.public_headers.implode_path!(pod_target.headers_sandbox)
  end

  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
        sandbox.clean_pod(pod_name)
      end
    end
  end
end

#create_analyzer(plugin_sources = nil) ⇒ Object (private)


419
420
421
# File 'lib/cocoapods/installer.rb', line 419

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) ⇒ Object (private)


306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
# File 'lib/cocoapods/installer.rb', line 306

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) ⇒ Object (private)


279
280
281
282
283
284
285
286
# File 'lib/cocoapods/installer.rb', line 279

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, )
  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_installer(pod_name) ⇒ Object (private)


522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
# File 'lib/cocoapods/installer.rb', line 522

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 += ", dependended 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_versionvoid (private)

This method returns an undefined value.

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.


681
682
683
684
685
686
687
688
689
690
691
692
# File 'lib/cocoapods/installer.rb', line 681

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

#development_pod_targets(targets = pod_targets) ⇒ Array<PodTarget>

Returns The targets of the development pods generated by the installation process. This can be used as a convenience method for external scripts.

Parameters:

  • targets (Array<PodTarget>) (defaults to: pod_targets)

Returns:

  • (Array<PodTarget>)

    The targets of the development pods generated by the installation process. This can be used as a convenience method for external scripts.


941
942
943
944
945
# File 'lib/cocoapods/installer.rb', line 941

def development_pod_targets(targets = pod_targets)
  targets.select do |pod_target|
    sandbox.local?(pod_target.pod_name)
  end
end

#download_dependenciesObject


251
252
253
254
255
256
257
# File 'lib/cocoapods/installer.rb', line 251

def download_dependencies
  UI.section 'Downloading dependencies' do
    install_pod_sources
    run_podfile_pre_install_hooks
    clean_pod_sources
  end
end

#ensure_plugins_are_installed!void (private)

This method returns an undefined value.

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


698
699
700
701
702
703
704
705
706
707
708
# File 'lib/cocoapods/installer.rb', line 698

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_lockfileLockfile (private)

Returns The lockfile to write to disk.

Returns:

  • (Lockfile)

    The lockfile to write to disk.


780
781
782
783
784
# File 'lib/cocoapods/installer.rb', line 780

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_projectObject (private)

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


290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
# File 'lib/cocoapods/installer.rb', line 290

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

  clean_sandbox(pod_targets_to_generate)

  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!void

This method returns an undefined value.

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).

158
159
160
161
162
163
164
165
166
167
168
169
170
# File 'lib/cocoapods/installer.rb', line 158

def install!
  prepare
  resolve_dependencies
  download_dependencies
  validate_targets
  if installation_options.skip_pods_project_generation?
    show_skip_pods_project_generation_message
  else
    integrate
  end
  write_lockfiles
  perform_post_install_actions
end

#install_pod_sourcesvoid (private)

This method returns an undefined value.

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


490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
# File 'lib/cocoapods/installer.rb', line 490

def install_pod_sources
  @installed_specs = []
  pods_to_install = sandbox_state.added | sandbox_state.changed
  title_options = { :verbose_prefix => '-> '.green }
  root_specs.sort_by(&:name).each do |spec|
    if pods_to_install.include?(spec.name)
      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 = "Installing #{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 = "Installing #{spec}"
      end
      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) ⇒ void (private)

This method returns an undefined value.

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.


559
560
561
562
563
# File 'lib/cocoapods/installer.rb', line 559

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_optionsInstallationOptions (private)

Returns the installation options to use during install.

Returns:


968
969
970
# File 'lib/cocoapods/installer.rb', line 968

def installation_options
  podfile.installation_options
end

#integrateObject


177
178
179
180
181
182
183
184
# File 'lib/cocoapods/installer.rb', line 177

def integrate
  generate_pods_project
  if installation_options.integrate_targets?
    integrate_user_project
  else
    UI.section 'Skipping User Project Integration'
  end
end

#integrate_user_projectvoid (private)

This method returns an undefined value.

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.


836
837
838
839
840
841
842
843
844
# File 'lib/cocoapods/installer.rb', line 836

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_sourcesObject (private)

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


585
586
587
588
589
590
591
# File 'lib/cocoapods/installer.rb', line 585

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_actionsvoid (private)

This method returns an undefined value.

Performs any post-installation actions


611
612
613
614
615
616
617
# File 'lib/cocoapods/installer.rb', line 611

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

#pluginsHash<String, Hash> (private)

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

Returns:

  • (Hash<String, Hash>)

    The plugins to be used


717
718
719
720
721
722
723
# File 'lib/cocoapods/installer.rb', line 717

def plugins
  if use_default_plugins?
    DEFAULT_PLUGINS.merge(podfile.plugins)
  else
    podfile.plugins
  end
end

#predictabilize_uuids(projects) ⇒ Object (private)


343
344
345
# File 'lib/cocoapods/installer.rb', line 343

def predictabilize_uuids(projects)
  UI.message('- Generating deterministic UUIDs') { Xcodeproj::Project.predictabilize_uuids(projects) }
end

#prepareObject


213
214
215
216
217
218
219
220
221
222
223
224
225
226
# File 'lib/cocoapods/installer.rb', line 213

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

#print_post_install_messageObject (private)


619
620
621
622
623
624
625
626
627
628
# File 'lib/cocoapods/installer.rb', line 619

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

#resolve_dependenciesAnalyzer

Returns The analyzer used to resolve dependencies.

Returns:

  • (Analyzer)

    The analyzer used to resolve dependencies


230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
# File 'lib/cocoapods/installer.rb', line 230

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

#root_specsArray<Specification> (private)

Returns All the root specifications of the installation.

Returns:

  • (Array<Specification>)

    All the root specifications of the installation.


956
957
958
# File 'lib/cocoapods/installer.rb', line 956

def root_specs
  analysis_result.specifications.map(&:root).uniq
end

#run_plugins_post_install_hooksObject (private)

Runs the registered callbacks for the plugins post install hooks.


632
633
634
635
636
637
638
639
640
641
642
# File 'lib/cocoapods/installer.rb', line 632

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, aggregate_targets)
    HooksManager.run(:post_install, context, plugins)
  end

  lock_pod_sources
end

#run_plugins_post_integrate_hooksObject (private)

Runs the registered callbacks for the plugins post integrate hooks.


646
647
648
649
650
651
# File 'lib/cocoapods/installer.rb', line 646

def run_plugins_post_integrate_hooks
  if any_plugin_post_integrate_hooks?
    context = PostIntegrateHooksContext.generate(sandbox, pods_project, aggregate_targets)
    HooksManager.run(:post_integrate, context, plugins)
  end
end

#run_plugins_pre_install_hooksvoid (private)

This method returns an undefined value.

Runs the registered callbacks for the plugins pre install hooks.


602
603
604
605
# File 'lib/cocoapods/installer.rb', line 602

def run_plugins_pre_install_hooks
  context = PreInstallHooksContext.generate(sandbox, podfile, lockfile)
  HooksManager.run(:pre_install, context, plugins)
end

#run_podfile_post_install_hookBoolean (private)

Runs the post install hook of the Podfile

Returns:

  • (Boolean)

    Whether the hook was run.

Raises:

  • Raises an informative if the hooks raises.


897
898
899
900
901
902
903
# File 'lib/cocoapods/installer.rb', line 897

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_hooksvoid (private)

Note:

Post install hooks run before saving of project, so that they can alter it before it is written to the disk.

This method returns an undefined value.

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


884
885
886
887
888
889
# File 'lib/cocoapods/installer.rb', line 884

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_hookBoolean (private)

Runs the post integrate hook of the Podfile.

Returns:

  • (Boolean)

    Whether the hook was run.

Raises:

  • Raises an informative if the hooks raises.


925
926
927
928
929
930
931
# File 'lib/cocoapods/installer.rb', line 925

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_hooksvoid (private)

Note:

Post integrate hooks run after saving of project, so that they can alter it after it is written to the disk.

This method returns an undefined value.

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


912
913
914
915
916
917
# File 'lib/cocoapods/installer.rb', line 912

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_hookBoolean (private)

Runs the pre install hook of the Podfile

Returns:

  • (Boolean)

    Whether the hook was run.

Raises:

  • Raises an informative if the hooks raises.


869
870
871
872
873
874
875
# File 'lib/cocoapods/installer.rb', line 869

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_hooksvoid (private)

This method returns an undefined value.

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


856
857
858
859
860
861
# File 'lib/cocoapods/installer.rb', line 856

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_source_provider_hooksArray<Pod::Source> (private)

Runs the registered callbacks for the source provider plugin hooks.

Returns:


669
670
671
672
673
# File 'lib/cocoapods/installer.rb', line 669

def run_source_provider_hooks
  context = SourceProviderHooksContext.generate
  HooksManager.run(:source_provider, context, plugins)
  context.sources
end

#sandbox_stateSpecsState (private)

Returns The state of the sandbox returned by the analyzer.

Returns:

  • (SpecsState)

    The state of the sandbox returned by the analyzer.


962
963
964
# File 'lib/cocoapods/installer.rb', line 962

def sandbox_state
  analysis_result.sandbox_state
end

#show_skip_pods_project_generation_messageObject


172
173
174
175
# File 'lib/cocoapods/installer.rb', line 172

def show_skip_pods_project_generation_message
  UI.section 'Skipping Pods Project Creation'
  UI.section 'Skipping User Project Integration'
end

#specs_for_pod(pod_name) ⇒ Hash{Platform => Array<Specification>} (private)

The specifications matching the specified pod name

Parameters:

  • pod_name (String)

    the name of the pod

Returns:

  • (Hash{Platform => Array<Specification>})

    the specifications grouped by platform


544
545
546
547
548
549
550
551
# File 'lib/cocoapods/installer.rb', line 544

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) ⇒ Object (private)


347
348
349
# File 'lib/cocoapods/installer.rb', line 347

def stabilize_target_uuids(projects)
  UI.message('- Stabilizing target UUIDs') { TargetUUIDGenerator.new(projects).generate! }
end

#stage_sandbox(sandbox, pod_targets) ⇒ void

This method returns an undefined value.

Stages the sandbox after analysis.

Parameters:

  • sandbox (Sandbox)

    The sandbox to stage.

  • pod_targets (Array<PodTarget>)

    The list of all pod targets.


269
270
271
# File 'lib/cocoapods/installer.rb', line 269

def stage_sandbox(sandbox, pod_targets)
  SandboxHeaderPathsInstaller.new(sandbox, pod_targets).install!
end

#unlock_pod_sourcesObject (private)

Unlocks the sources of the Pods.


576
577
578
579
580
581
# File 'lib/cocoapods/installer.rb', line 576

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) ⇒ Object (private)

Parameters:

  • cache_analysis_result (ProjectCacheAnalysisResult)

    The cache analysis result for the current installation.

  • target_installation_results (Hash{String => TargetInstallationResult})

    The installation results for pod targets installed.


812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
# File 'lib/cocoapods/installer.rb', line 812

def update_project_cache(cache_analysis_result, target_installation_results)
  return unless installation_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)

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

  cache_version = ProjectCache::ProjectCacheVersion.new(VersionMetadata.project_cache_version)
  cache_version.save_as(sandbox.project_version_cache_path)
end

#validate_build_configurationsObject (private)

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

Raises:

  • If an unknown user configuration is found.


428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
# File 'lib/cocoapods/installer.rb', line 428

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_targetsObject (private)


593
594
595
596
# File 'lib/cocoapods/installer.rb', line 593

def validate_targets
  validator = Xcode::TargetValidator.new(aggregate_targets, pod_targets, installation_options)
  validator.validate!
end

#verify_no_lockfile_changes!Object (private)

Raises:


474
475
476
477
478
479
480
481
482
483
# File 'lib/cocoapods/installer.rb', line 474

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!Object (private)

Raises:


465
466
467
468
469
470
# File 'lib/cocoapods/installer.rb', line 465

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_deprecationsvoid (private)

This method returns an undefined value.

Prints a warning for any pods that are deprecated


729
730
731
732
733
734
735
736
737
738
739
740
741
# File 'lib/cocoapods/installer.rb', line 729

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_phasesvoid (private)

This method returns an undefined value.

Prints a warning for any pods that included script phases


747
748
749
750
751
752
753
754
755
756
757
758
# File 'lib/cocoapods/installer.rb', line 747

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)
      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_repovoid (private)

This method returns an undefined value.

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.


767
768
769
770
771
772
773
774
775
776
# File 'lib/cocoapods/installer.rb', line 767

def warn_for_removing_git_master_specs_repo
  return unless installation_options.warn_for_unused_master_specs_repo?
  podfile_master_source = podfile.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 podfile_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_lockfilesvoid (private)

This method returns an undefined value.

Writes the Podfile and the lock files.


790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
# File 'lib/cocoapods/installer.rb', line 790

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