class Pod::Installer::Xcode::PodsProjectGenerator

The {PodsProjectGenerator} handles generation of CocoaPods Xcode projects.

Constants

InstallationResults

@!attribute [Hash{String => TargetInstallationResult}] pod_target_installation_results @!attribute [Hash{String => TargetInstallationResult}] aggregate_target_installation_results

Attributes

aggregate_targets[R]

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

aggregation of pod targets generated for a target definition
in the Podfile.
build_configurations[R]

@return [Hash{String => Symbol}] The build configurations that need to be installed.

config[R]

@return [Config] the global CocoaPods configuration.

installation_options[R]

@return [InstallationOptions] the installation options from the Podfile.

metadata_cache[R]

@return [ProjectMetadataCache] the metadata cache used to reconstruct target dependencies.

pod_targets[R]

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

project_object_version[R]

@return [Integer] the object version for the projects we will generate.

sandbox[R]

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

Public Class Methods

new(sandbox, aggregate_targets, pod_targets, build_configurations, installation_options, config, project_object_version, metadata_cache = nil) click to toggle source

Initialize a new instance

@param [Sandbox] sandbox @see sandbox @param [Array<AggregateTarget>] aggregate_targets @see aggregate_targets @param [Array<PodTarget>] pod_targets @see pod_targets @param [Hash{String => Symbol}] build_configurations @see build_configurations @param [InstallationOptions] installation_options @see installation_options @param [Config] config @see config @param [Integer] project_object_version @see project_object_version @param [ProjectMetadataCache] metadata_cache @see metadata_cache

# File lib/cocoapods/installer/xcode/pods_project_generator.rb, line 65
def initialize(sandbox, aggregate_targets, pod_targets, build_configurations, installation_options, config,
               project_object_version, metadata_cache = nil)
  @sandbox = sandbox
  @aggregate_targets = aggregate_targets
  @pod_targets = pod_targets
  @build_configurations = build_configurations
  @installation_options = installation_options
  @config = config
  @project_object_version = project_object_version
  @metadata_cache = metadata_cache
end

Public Instance Methods

configure_schemes(project, pod_targets, generator_result) click to toggle source

Configure schemes for the specified project and pod targets. Schemes for development pods will be shared if requested by the integration.

@param [PBXProject] project The project to configure schemes for. @param [Array<PodTarget>] pod_targets The pod targets within that project to configure their schemes. @param [PodsProjectGeneratorResult] generator_result the result of the project generation

@return [void]

# File lib/cocoapods/installer/xcode/pods_project_generator.rb, line 86
def configure_schemes(project, pod_targets, generator_result)
  pod_targets.each do |pod_target|
    share_scheme = pod_target.should_build? && share_scheme_for_development_pod?(pod_target.pod_name) && sandbox.local?(pod_target.pod_name)
    configure_schemes_for_pod_target(project, pod_target, share_scheme, generator_result)
  end
end

Private Instance Methods

add_system_framework_dependencies(pod_target_installation_results) click to toggle source
# File lib/cocoapods/installer/xcode/pods_project_generator.rb, line 162
def add_system_framework_dependencies(pod_target_installation_results)
  sorted_installation_results = pod_target_installation_results.sort_by do |pod_target_installation_result|
    pod_target_installation_result.target.name
  end
  sorted_installation_results.each do |target_installation_result|
    pod_target = target_installation_result.target
    next unless pod_target.should_build?
    next if pod_target.build_as_static?
    pod_target.file_accessors.each do |file_accessor|
      native_target = target_installation_result.native_target_for_spec(file_accessor.spec)
      add_system_frameworks_to_native_target(native_target, file_accessor)
    end
  end
end
add_system_frameworks_to_native_target(native_target, file_accessor) click to toggle source

@! group Private Helpers

# File lib/cocoapods/installer/xcode/pods_project_generator.rb, line 218
def add_system_frameworks_to_native_target(native_target, file_accessor)
  file_accessor.spec_consumer.frameworks.each do |framework|
    native_target.add_system_framework(framework)
  end
end
configure_schemes_for_pod_target(project, pod_target, share_scheme, generator_result) click to toggle source

@param [Project] project

the project of the pod target

@param [Pod::PodTarget] pod_target

the pod target for which to configure schemes

@param [Boolean] share_scheme

whether the created schemes should be shared

@param [PodsProjectGeneratorResult] generator_result

the project generation result
# File lib/cocoapods/installer/xcode/pods_project_generator.rb, line 236
def configure_schemes_for_pod_target(project, pod_target, share_scheme, generator_result)
  # Ignore subspecs because they do not provide a scheme configuration due to the fact that they are always
  # merged with the root spec scheme.
  specs = [pod_target.root_spec] + pod_target.test_specs + pod_target.app_specs
  hosted_test_specs_by_host = Hash.new do |hash, key|
    hash[key] = []
  end
  pod_target.test_app_hosts_by_spec.each do |spec, (host_spec, host_target)|
    if host_target == pod_target
      hosted_test_specs_by_host[host_spec] << spec
    end
  end
  is_custom_host = !hosted_test_specs_by_host.empty?
  specs.each do |spec|
    scheme_name = pod_target.spec_label(spec)
    scheme_configuration = pod_target.scheme_for_spec(spec)
    if !scheme_configuration.empty? || is_custom_host
      scheme_path = Xcodeproj::XCScheme.user_data_dir(project.path) + "#{scheme_name}.xcscheme"
      scheme = Xcodeproj::XCScheme.new(scheme_path)
      command_line_arguments = scheme.launch_action.command_line_arguments
      scheme_configuration.fetch(:launch_arguments, []).each do |launch_arg|
        command_line_arguments.assign_argument(:argument => launch_arg, :enabled => true)
      end
      scheme.launch_action.command_line_arguments = command_line_arguments
      environment_variables = scheme.launch_action.environment_variables
      scheme_configuration.fetch(:environment_variables, {}).each do |k, v|
        environment_variables.assign_variable(:key => k, :value => v)
      end
      scheme.launch_action.environment_variables = environment_variables
      if scheme_configuration.key?(:code_coverage)
        scheme.test_action.code_coverage_enabled = scheme_configuration[:code_coverage]
      end
      if scheme_configuration.key?(:parallelizable)
        scheme.test_action.testables.each { |testable| testable.parallelizable = scheme_configuration[:parallelizable] }
      end
      set_scheme_build_configurations(scheme, scheme_configuration.fetch(:build_configurations, {}))

      hosted_test_specs_by_host[spec].each do |hosted_spec|
        # We are an app spec which hosts this test spec.
        # Include the test specs's test bundle within our scheme's test action
        native_target = generator_result.native_target_for_spec(hosted_spec)
        testable = Xcodeproj::XCScheme::TestAction::TestableReference.new(native_target)
        scheme.test_action.add_testable(testable)
      end

      if spec.test_specification?
        # Default to using the test bundle to expand variables
        native_target_for_expansion = generator_result.native_target_for_spec(spec)
        macro_expansion = Xcodeproj::XCScheme::MacroExpansion.new(native_target_for_expansion)
        scheme.launch_action.add_macro_expansion(macro_expansion)
      end
      scheme.save!
    end
    Xcodeproj::XCScheme.share_scheme(project.path, scheme_name) if share_scheme
  end
end
install_aggregate_targets(project, aggregate_targets) click to toggle source
# File lib/cocoapods/installer/xcode/pods_project_generator.rb, line 127
def install_aggregate_targets(project, aggregate_targets)
  UI.message '- Installing Aggregate Targets' do
    aggregate_target_installation_results = Hash[aggregate_targets.sort_by(&:name).map do |target|
      target_installer = AggregateTargetInstaller.new(sandbox, project, target)
      [target.name, target_installer.install!]
    end]

    aggregate_target_installation_results
  end
end
install_file_references(project, pod_targets) click to toggle source
# File lib/cocoapods/installer/xcode/pods_project_generator.rb, line 99
def install_file_references(project, pod_targets)
  UI.message "- Installing files into #{project.project_name} project" do
    installer = FileReferencesInstaller.new(sandbox, pod_targets, project, installation_options.preserve_pod_file_structure)
    installer.install!
  end
end
install_pod_targets(project, pod_targets) click to toggle source
# File lib/cocoapods/installer/xcode/pods_project_generator.rb, line 106
def install_pod_targets(project, pod_targets)
  umbrella_headers_by_dir = pod_targets.map do |pod_target|
    next unless pod_target.should_build? && pod_target.defines_module?
    pod_target.umbrella_header_path
  end.compact.group_by(&:dirname)

  pod_target_installation_results = Hash[pod_targets.sort_by(&:name).map do |pod_target|
    umbrella_headers_in_header_dir = umbrella_headers_by_dir[pod_target.module_map_path.dirname]
    target_installer = PodTargetInstaller.new(sandbox, project, pod_target, umbrella_headers_in_header_dir)
    [pod_target.name, target_installer.install!]
  end]

  # Hook up system framework dependencies for the pod targets that were just installed.
  pod_target_installation_result_values = pod_target_installation_results.values.compact
  unless pod_target_installation_result_values.empty?
    add_system_framework_dependencies(pod_target_installation_result_values)
  end

  pod_target_installation_results
end
integrate_targets(pod_target_installation_results) click to toggle source

@param [Hash{String => InstallationResult}] pod_target_installation_results

the installations to integrate

@return [void]

# File lib/cocoapods/installer/xcode/pods_project_generator.rb, line 143
def integrate_targets(pod_target_installation_results)
  pod_installations_to_integrate = pod_target_installation_results.values.select do |pod_target_installation_result|
    pod_target = pod_target_installation_result.target
    !pod_target_installation_result.test_native_targets.empty? ||
      !pod_target_installation_result.app_native_targets.empty? ||
      pod_target.contains_script_phases? ||
      pod_target.framework_paths.values.flatten.any? { |paths| !paths.dsym_path.nil? } ||
      pod_target.xcframeworks.values.any? { |xcframeworks| !xcframeworks.empty? }
  end
  return if pod_installations_to_integrate.empty?

  UI.message '- Integrating targets' do
    use_input_output_paths = !installation_options.disable_input_output_paths
    pod_installations_to_integrate.each do |pod_target_installation_result|
      PodTargetIntegrator.new(pod_target_installation_result, :use_input_output_paths => use_input_output_paths).integrate!
    end
  end
end
set_scheme_build_configurations(scheme, configuration) click to toggle source

@param [Xcodeproj::XCSheme] scheme scheme to apply configuration to

@param [Hash{String => String}] configuration action => build configuration to use for the action

@return [void]

# File lib/cocoapods/installer/xcode/pods_project_generator.rb, line 301
def set_scheme_build_configurations(scheme, configuration)
  configuration.each do |k, v|
    unless @build_configurations.include?(v)
      raise Informative, "Unable to set `#{v}` as a build configuration as " \
      "it doesn't match with any of your projects build configurations."
    end

    case k
    when 'Run'
      scheme.launch_action.build_configuration = v
    when 'Test'
      scheme.test_action.build_configuration = v
    when 'Analyze'
      scheme.analyze_action.build_configuration = v
    when 'Archive'
      scheme.archive_action.build_configuration = v
    else
      raise Informative, "#{k} is not a valid scheme action " \
      "only one of ['run', 'test', 'analyze', 'archive'] is available"
    end
  end
end
share_scheme_for_development_pod?(pod) click to toggle source

@param [String] pod The root name of the development pod.

@return [Boolean] whether the scheme for the given development pod should be

shared.
# File lib/cocoapods/installer/xcode/pods_project_generator.rb, line 201
def share_scheme_for_development_pod?(pod)
  case dev_pods_to_share = installation_options.share_schemes_for_development_pods
  when TrueClass, FalseClass, NilClass
    dev_pods_to_share
  when Array
    dev_pods_to_share.any? { |dev_pod| dev_pod === pod } # rubocop:disable Style/CaseEquality
  else
    raise Informative, 'Unable to handle share_schemes_for_development_pods ' \
      "being set to #{dev_pods_to_share.inspect} -- please set it to true, " \
      'false, or an array of pods to share schemes for.'
  end
end
wire_target_dependencies(target_installation_results) click to toggle source

Adds a target dependency for each pod spec to each aggregate target and links the pod targets among each other.

@param [Array] target_installation_results

the installation results that were produced when all targets were installed. This includes
pod target installation results and aggregate target installation results.

@return [void]

# File lib/cocoapods/installer/xcode/pods_project_generator.rb, line 186
def wire_target_dependencies(target_installation_results)
  pod_target_installation_results_hash = target_installation_results.pod_target_installation_results
  aggregate_target_installation_results_hash = target_installation_results.aggregate_target_installation_results

  AggregateTargetDependencyInstaller.new(sandbox, aggregate_target_installation_results_hash,
                                         pod_target_installation_results_hash, metadata_cache).install!

  PodTargetDependencyInstaller.new(sandbox, pod_target_installation_results_hash, metadata_cache).install!
end