Class: Pod::Installer::Xcode::PodsProjectGenerator

Inherits:
Object
  • Object
show all
Defined in:
lib/cocoapods/installer/xcode/pods_project_generator.rb,
lib/cocoapods/installer/xcode/pods_project_generator_result.rb,
lib/cocoapods/installer/xcode/pods_project_generator/target_installer.rb,
lib/cocoapods/installer/xcode/pods_project_generator/app_host_installer.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

Overview

The PodsProjectGenerator handles generation of CocoaPods Xcode projects.

Defined Under Namespace

Modules: TargetInstallerHelper Classes: AggregateTargetInstaller, AppHostInstaller, FileReferencesInstaller, InstallationResults, PodTargetInstaller, PodTargetIntegrator, PodsProjectGeneratorResult, TargetInstallationResult, TargetInstaller

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(sandbox, aggregate_targets, pod_targets, build_configurations, installation_options, config, project_object_version, metadata_cache = nil) ⇒ PodsProjectGenerator

Initialize a new instance

Parameters:

  • sandbox (Sandbox)

    @see #sandbox

  • aggregate_targets (Array<AggregateTarget>)

    @see #aggregate_targets

  • pod_targets (Array<PodTarget>)

    @see #pod_targets

  • build_configurations (Hash{String => Symbol})

    @see #build_configurations

  • installation_options (InstallationOptions)

    @see #installation_options

  • config (Config)

    @see #config

  • project_object_version (Integer)

    @see #project_object_version

  • metadata_cache (ProjectMetadataCache) (defaults to: nil)

    @see #metadata_cache



65
66
67
68
69
70
71
72
73
74
75
# 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,  = 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 = 
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.

Returns:

  • (Array<AggregateTarget>)

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



28
29
30
# File 'lib/cocoapods/installer/xcode/pods_project_generator.rb', line 28

def aggregate_targets
  @aggregate_targets
end

#build_configurationsHash{String => Symbol} (readonly)

Returns The build configurations that need to be installed.

Returns:

  • (Hash{String => Symbol})

    The build configurations that need to be installed.



36
37
38
# File 'lib/cocoapods/installer/xcode/pods_project_generator.rb', line 36

def build_configurations
  @build_configurations
end

#configConfig (readonly)

Returns the global CocoaPods configuration.

Returns:

  • (Config)

    the global CocoaPods configuration.



44
45
46
# File 'lib/cocoapods/installer/xcode/pods_project_generator.rb', line 44

def config
  @config
end

#installation_optionsInstallationOptions (readonly)

Returns the installation options from the Podfile.

Returns:



40
41
42
# File 'lib/cocoapods/installer/xcode/pods_project_generator.rb', line 40

def installation_options
  @installation_options
end

#metadata_cacheProjectMetadataCache (readonly)

Returns the metadata cache used to reconstruct target dependencies.

Returns:

  • (ProjectMetadataCache)

    the metadata cache used to reconstruct target dependencies.



52
53
54
# File 'lib/cocoapods/installer/xcode/pods_project_generator.rb', line 52

def 
  @metadata_cache
end

#pod_targetsArray<PodTarget> (readonly)

Returns The model representations of pod targets.

Returns:

  • (Array<PodTarget>)

    The model representations of pod targets.



32
33
34
# File 'lib/cocoapods/installer/xcode/pods_project_generator.rb', line 32

def pod_targets
  @pod_targets
end

#project_object_versionInteger (readonly)

Returns the object version for the projects we will generate.

Returns:

  • (Integer)

    the object version for the projects we will generate.



48
49
50
# File 'lib/cocoapods/installer/xcode/pods_project_generator.rb', line 48

def project_object_version
  @project_object_version
end

#sandboxSandbox (readonly)

Returns The sandbox where the Pods should be installed.

Returns:

  • (Sandbox)

    The sandbox where the Pods should be installed.



22
23
24
# File 'lib/cocoapods/installer/xcode/pods_project_generator.rb', line 22

def sandbox
  @sandbox
end

Instance Method Details

#add_system_framework_dependencies(pod_target_installation_results) ⇒ Object (private)



162
163
164
165
166
167
168
169
170
171
172
173
174
175
# 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) ⇒ Object (private)

@! group Private Helpers



218
219
220
221
222
# 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(project, pod_targets, generator_result) ⇒ void

This method returns an undefined value.

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

Parameters:

  • project (PBXProject)

    The project to configure schemes for.

  • pod_targets (Array<PodTarget>)

    The pod targets within that project to configure their schemes.

  • generator_result (PodsProjectGeneratorResult)

    the result of the project generation



86
87
88
89
90
91
# 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

#configure_schemes_for_pod_target(project, pod_target, share_scheme, generator_result) ⇒ Object (private)

Parameters:

  • project (Project)

    the project of the pod target

  • pod_target (Pod::PodTarget)

    the pod target for which to configure schemes

  • share_scheme (Boolean)

    whether the created schemes should be shared

  • generator_result (PodsProjectGeneratorResult)

    the project generation result



236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
# 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) ⇒ Object (private)



127
128
129
130
131
132
133
134
135
136
# 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) ⇒ Object (private)



99
100
101
102
103
104
# 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) ⇒ Object (private)



106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
# 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) ⇒ void (private)

This method returns an undefined value.

Parameters:

  • pod_target_installation_results (Hash{String => InstallationResult})

    the installations to integrate



143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
# 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) ⇒ void (private)

This method returns an undefined value.

scheme to apply configuration to

action => build configuration to use for the action

Parameters:

  • scheme (Xcodeproj::XCSheme)
  • configuration (Hash{String => String})


301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
# 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) ⇒ Boolean (private)

Returns whether the scheme for the given development pod should be shared.

Parameters:

  • pod (String)

    The root name of the development pod.

Returns:

  • (Boolean)

    whether the scheme for the given development pod should be shared.



201
202
203
204
205
206
207
208
209
210
211
212
# 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) ⇒ void (private)

This method returns an undefined value.

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

Parameters:

  • target_installation_results (Array[Hash{String=>TargetInstallationResult}])

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



186
187
188
189
190
191
192
193
194
# 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, ).install!

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