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
@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.
@return [Analyzer::AnalysisResult] the result of the analysis performed during installation
@return [Boolean] Whether installation should ignore the contents of the project cache when incremental installation is enabled.
@return [Boolean] Whether installation should ignore the contents of the project cache when incremental installation is enabled.
@return [Boolean] Whether installation should verify that there are no
Podfile or Lockfile changes. Defaults to false.
@return [Boolean] Whether installation should verify that there are no
Podfile or Lockfile changes. Defaults to false.
@return [Array<AggregateTarget>] The list of aggregate targets that were generated from the installation.
@return [Array<PodTarget>] The list of pod targets that were generated from the installation.
@return [Array<Project>] The list of projects generated from the installation.
@return [Boolean] Whether it has dependencies. Defaults to true.
@return [Boolean] Whether it has dependencies. Defaults to true.
@return [ProjectInstallationCache] The installation cache stored in Pods/.project_cache/installation_cache
@return [Array<Specification>] The specifications that were installed.
@return [Lockfile] The Lockfile that stores the information about the
Pods previously installed on any machine.
@return [ProjectMetadataCache] The metadata cache stored in Pods/.project_cache/metadata_cache
@return [Array<PodSourceInstaller>] the pod installers created
while installing pod targets
@return [Array<Pod::Project>] the subprojects nested under pods_project.
@return [Array<PodTarget>] The model representations of pod targets
generated as result of the analyzer.
@return [Podfile] The Podfile
specification that contains the information
of the Pods that should be installed.
@return [Pod::Project] the ‘Pods/Pods.xcodeproj` project.
@return [ProjectCacheVersion] The version of the project cache stored in Pods/.project_cache/version
@return [Boolean] Whether the spec repos should be updated.
@return [Boolean] Whether the spec repos should be updated.
@return [Sandbox] The sandbox where the Pods should be installed.
@return [Array<Hash{String, TargetInstallationResult}>] the installation results produced by the pods project
generator
@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.
@return [Boolean] Whether default plugins should be used during
installation. Defaults to true.
@return [Boolean] Whether default plugins should be used during
installation. Defaults to true.
Public Class Methods
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
@!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
# 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
@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
# 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
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
# 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
# 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
@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
# 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
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
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
@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
@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
@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
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
@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
# File lib/cocoapods/installer.rb, line 427 def create_analyzer(plugin_sources = nil) Analyzer.new(sandbox, podfile, lockfile, plugin_sources, has_dependencies?, update) end
# 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
@!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
# 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
# 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
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 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
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
@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
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
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 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
@return [InstallationOptions] the installation options to use during install
# File lib/cocoapods/installer.rb, line 1083 def installation_options podfile.installation_options end
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
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
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
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
# File lib/cocoapods/installer.rb, line 351 def predictabilize_uuids(projects) UI.message('- Generating deterministic UUIDs') { Xcodeproj::Project.predictabilize_uuids(projects) } end
# 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
@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
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
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
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
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
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
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
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
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
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
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
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
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
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
@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
# 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
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
# File lib/cocoapods/installer.rb, line 355 def stabilize_target_uuids(projects) UI.message('- Stabilizing target UUIDs') { TargetUUIDGenerator.new(projects).generate! } end
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
@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
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
# File lib/cocoapods/installer.rb, line 664 def validate_targets validator = Xcode::TargetValidator.new(aggregate_targets, pod_targets, installation_options) validator.validate! end
@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
@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
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
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
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
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