cocoapods-tt 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (124) hide show
  1. checksums.yaml +7 -0
  2. data/lib/cocoapods-tt/command/native/install.rb +56 -0
  3. data/lib/cocoapods-tt/command/native/update.rb +157 -0
  4. data/lib/cocoapods-tt/command/tt/make.rb +92 -0
  5. data/lib/cocoapods-tt/command/tt.rb +115 -0
  6. data/lib/cocoapods-tt/command.rb +1 -0
  7. data/lib/cocoapods-tt/gem_version.rb +3 -0
  8. data/lib/cocoapods-tt/native/command.rb +185 -0
  9. data/lib/cocoapods-tt/native/config.rb +366 -0
  10. data/lib/cocoapods-tt/native/core_overrides.rb +1 -0
  11. data/lib/cocoapods-tt/native/downloader/cache.rb +322 -0
  12. data/lib/cocoapods-tt/native/downloader/request.rb +86 -0
  13. data/lib/cocoapods-tt/native/downloader/response.rb +16 -0
  14. data/lib/cocoapods-tt/native/downloader.rb +192 -0
  15. data/lib/cocoapods-tt/native/executable.rb +247 -0
  16. data/lib/cocoapods-tt/native/external_sources/abstract_external_source.rb +205 -0
  17. data/lib/cocoapods-tt/native/external_sources/downloader_source.rb +30 -0
  18. data/lib/cocoapods-tt/native/external_sources/path_source.rb +55 -0
  19. data/lib/cocoapods-tt/native/external_sources/podspec_source.rb +54 -0
  20. data/lib/cocoapods-tt/native/external_sources.rb +57 -0
  21. data/lib/cocoapods-tt/native/gem_version.rb +5 -0
  22. data/lib/cocoapods-tt/native/generator/acknowledgements/markdown.rb +44 -0
  23. data/lib/cocoapods-tt/native/generator/acknowledgements/plist.rb +94 -0
  24. data/lib/cocoapods-tt/native/generator/acknowledgements.rb +107 -0
  25. data/lib/cocoapods-tt/native/generator/app_target_helper.rb +363 -0
  26. data/lib/cocoapods-tt/native/generator/bridge_support.rb +22 -0
  27. data/lib/cocoapods-tt/native/generator/constant.rb +19 -0
  28. data/lib/cocoapods-tt/native/generator/copy_dsyms_script.rb +56 -0
  29. data/lib/cocoapods-tt/native/generator/copy_resources_script.rb +223 -0
  30. data/lib/cocoapods-tt/native/generator/copy_xcframework_script.rb +227 -0
  31. data/lib/cocoapods-tt/native/generator/dummy_source.rb +31 -0
  32. data/lib/cocoapods-tt/native/generator/embed_frameworks_script.rb +196 -0
  33. data/lib/cocoapods-tt/native/generator/file_list.rb +39 -0
  34. data/lib/cocoapods-tt/native/generator/header.rb +103 -0
  35. data/lib/cocoapods-tt/native/generator/info_plist_file.rb +128 -0
  36. data/lib/cocoapods-tt/native/generator/module_map.rb +99 -0
  37. data/lib/cocoapods-tt/native/generator/prefix_header.rb +60 -0
  38. data/lib/cocoapods-tt/native/generator/script_phase_constants.rb +100 -0
  39. data/lib/cocoapods-tt/native/generator/umbrella_header.rb +46 -0
  40. data/lib/cocoapods-tt/native/hooks_manager.rb +132 -0
  41. data/lib/cocoapods-tt/native/installer/analyzer/analysis_result.rb +87 -0
  42. data/lib/cocoapods-tt/native/installer/analyzer/locking_dependency_analyzer.rb +103 -0
  43. data/lib/cocoapods-tt/native/installer/analyzer/pod_variant.rb +87 -0
  44. data/lib/cocoapods-tt/native/installer/analyzer/pod_variant_set.rb +175 -0
  45. data/lib/cocoapods-tt/native/installer/analyzer/podfile_dependency_cache.rb +55 -0
  46. data/lib/cocoapods-tt/native/installer/analyzer/sandbox_analyzer.rb +268 -0
  47. data/lib/cocoapods-tt/native/installer/analyzer/specs_state.rb +108 -0
  48. data/lib/cocoapods-tt/native/installer/analyzer/target_inspection_result.rb +58 -0
  49. data/lib/cocoapods-tt/native/installer/analyzer/target_inspector.rb +258 -0
  50. data/lib/cocoapods-tt/native/installer/analyzer.rb +1204 -0
  51. data/lib/cocoapods-tt/native/installer/base_install_hooks_context.rb +135 -0
  52. data/lib/cocoapods-tt/native/installer/installation_options.rb +195 -0
  53. data/lib/cocoapods-tt/native/installer/pod_source_installer.rb +224 -0
  54. data/lib/cocoapods-tt/native/installer/pod_source_preparer.rb +77 -0
  55. data/lib/cocoapods-tt/native/installer/podfile_validator.rb +168 -0
  56. data/lib/cocoapods-tt/native/installer/post_install_hooks_context.rb +9 -0
  57. data/lib/cocoapods-tt/native/installer/post_integrate_hooks_context.rb +9 -0
  58. data/lib/cocoapods-tt/native/installer/pre_install_hooks_context.rb +51 -0
  59. data/lib/cocoapods-tt/native/installer/pre_integrate_hooks_context.rb +9 -0
  60. data/lib/cocoapods-tt/native/installer/project_cache/project_cache.rb +11 -0
  61. data/lib/cocoapods-tt/native/installer/project_cache/project_cache_analysis_result.rb +53 -0
  62. data/lib/cocoapods-tt/native/installer/project_cache/project_cache_analyzer.rb +200 -0
  63. data/lib/cocoapods-tt/native/installer/project_cache/project_cache_version.rb +43 -0
  64. data/lib/cocoapods-tt/native/installer/project_cache/project_installation_cache.rb +103 -0
  65. data/lib/cocoapods-tt/native/installer/project_cache/project_metadata_cache.rb +73 -0
  66. data/lib/cocoapods-tt/native/installer/project_cache/target_cache_key.rb +176 -0
  67. data/lib/cocoapods-tt/native/installer/project_cache/target_metadata.rb +74 -0
  68. data/lib/cocoapods-tt/native/installer/sandbox_dir_cleaner.rb +105 -0
  69. data/lib/cocoapods-tt/native/installer/sandbox_header_paths_installer.rb +45 -0
  70. data/lib/cocoapods-tt/native/installer/source_provider_hooks_context.rb +34 -0
  71. data/lib/cocoapods-tt/native/installer/target_uuid_generator.rb +34 -0
  72. data/lib/cocoapods-tt/native/installer/user_project_integrator/target_integrator/xcconfig_integrator.rb +179 -0
  73. data/lib/cocoapods-tt/native/installer/user_project_integrator/target_integrator.rb +815 -0
  74. data/lib/cocoapods-tt/native/installer/user_project_integrator.rb +280 -0
  75. data/lib/cocoapods-tt/native/installer/xcode/multi_pods_project_generator.rb +82 -0
  76. data/lib/cocoapods-tt/native/installer/xcode/pods_project_generator/aggregate_target_dependency_installer.rb +66 -0
  77. data/lib/cocoapods-tt/native/installer/xcode/pods_project_generator/aggregate_target_installer.rb +192 -0
  78. data/lib/cocoapods-tt/native/installer/xcode/pods_project_generator/app_host_installer.rb +154 -0
  79. data/lib/cocoapods-tt/native/installer/xcode/pods_project_generator/file_references_installer.rb +329 -0
  80. data/lib/cocoapods-tt/native/installer/xcode/pods_project_generator/pod_target_dependency_installer.rb +195 -0
  81. data/lib/cocoapods-tt/native/installer/xcode/pods_project_generator/pod_target_installer.rb +1239 -0
  82. data/lib/cocoapods-tt/native/installer/xcode/pods_project_generator/pod_target_integrator.rb +312 -0
  83. data/lib/cocoapods-tt/native/installer/xcode/pods_project_generator/pods_project_writer.rb +90 -0
  84. data/lib/cocoapods-tt/native/installer/xcode/pods_project_generator/project_generator.rb +120 -0
  85. data/lib/cocoapods-tt/native/installer/xcode/pods_project_generator/target_installation_result.rb +140 -0
  86. data/lib/cocoapods-tt/native/installer/xcode/pods_project_generator/target_installer.rb +257 -0
  87. data/lib/cocoapods-tt/native/installer/xcode/pods_project_generator/target_installer_helper.rb +110 -0
  88. data/lib/cocoapods-tt/native/installer/xcode/pods_project_generator.rb +291 -0
  89. data/lib/cocoapods-tt/native/installer/xcode/pods_project_generator_result.rb +54 -0
  90. data/lib/cocoapods-tt/native/installer/xcode/single_pods_project_generator.rb +38 -0
  91. data/lib/cocoapods-tt/native/installer/xcode/target_validator.rb +170 -0
  92. data/lib/cocoapods-tt/native/installer/xcode.rb +11 -0
  93. data/lib/cocoapods-tt/native/installer.rb +1044 -0
  94. data/lib/cocoapods-tt/native/native_target_extension.rb +60 -0
  95. data/lib/cocoapods-tt/native/open-uri.rb +33 -0
  96. data/lib/cocoapods-tt/native/podfile.rb +13 -0
  97. data/lib/cocoapods-tt/native/project.rb +544 -0
  98. data/lib/cocoapods-tt/native/resolver/lazy_specification.rb +88 -0
  99. data/lib/cocoapods-tt/native/resolver/resolver_specification.rb +41 -0
  100. data/lib/cocoapods-tt/native/resolver.rb +600 -0
  101. data/lib/cocoapods-tt/native/sandbox/file_accessor.rb +532 -0
  102. data/lib/cocoapods-tt/native/sandbox/headers_store.rb +163 -0
  103. data/lib/cocoapods-tt/native/sandbox/path_list.rb +242 -0
  104. data/lib/cocoapods-tt/native/sandbox/pod_dir_cleaner.rb +71 -0
  105. data/lib/cocoapods-tt/native/sandbox/podspec_finder.rb +23 -0
  106. data/lib/cocoapods-tt/native/sandbox.rb +470 -0
  107. data/lib/cocoapods-tt/native/sources_manager.rb +221 -0
  108. data/lib/cocoapods-tt/native/target/aggregate_target.rb +558 -0
  109. data/lib/cocoapods-tt/native/target/build_settings.rb +1385 -0
  110. data/lib/cocoapods-tt/native/target/pod_target.rb +1168 -0
  111. data/lib/cocoapods-tt/native/target.rb +378 -0
  112. data/lib/cocoapods-tt/native/user_interface/error_report.rb +204 -0
  113. data/lib/cocoapods-tt/native/user_interface/inspector_reporter.rb +102 -0
  114. data/lib/cocoapods-tt/native/user_interface.rb +463 -0
  115. data/lib/cocoapods-tt/native/validator.rb +1170 -0
  116. data/lib/cocoapods-tt/native/version_metadata.rb +26 -0
  117. data/lib/cocoapods-tt/native/xcode/framework_paths.rb +54 -0
  118. data/lib/cocoapods-tt/native/xcode/linkage_analyzer.rb +22 -0
  119. data/lib/cocoapods-tt/native/xcode/xcframework/xcframework_slice.rb +138 -0
  120. data/lib/cocoapods-tt/native/xcode/xcframework.rb +99 -0
  121. data/lib/cocoapods-tt/native/xcode.rb +7 -0
  122. data/lib/cocoapods-tt.rb +1 -0
  123. data/lib/cocoapods_plugin.rb +17 -0
  124. metadata +193 -0
@@ -0,0 +1,1168 @@
1
+ require 'cocoapods/xcode/framework_paths'
2
+ require 'cocoapods/xcode/xcframework'
3
+
4
+ module Pod
5
+ # Stores the information relative to the target used to compile a single Pod.
6
+ # A pod can have one or more activated spec, subspecs and test specs.
7
+ #
8
+ class PodTarget < Target
9
+ # @return [Array<Specification>] the spec, subspecs and test specs of the target.
10
+ #
11
+ attr_reader :specs
12
+
13
+ # @return [Array<Specification>] All of the test specs within this target.
14
+ # Subset of #specs.
15
+ #
16
+ attr_reader :test_specs
17
+
18
+ # @return [Array<Specification>] All of the specs within this target that are library specs.
19
+ # Subset of #specs.
20
+ #
21
+ attr_reader :library_specs
22
+
23
+ # @return [Array<Specification>] All of the specs within this target that are app specs.
24
+ # Subset of #specs.
25
+ #
26
+ attr_reader :app_specs
27
+
28
+ # @return [Array<TargetDefinition>] the target definitions of the Podfile
29
+ # that generated this target.
30
+ #
31
+ attr_reader :target_definitions
32
+
33
+ # @return [Array<Sandbox::FileAccessor>] the file accessors for the
34
+ # specifications of this target.
35
+ #
36
+ attr_reader :file_accessors
37
+
38
+ # @return [String] the suffix used for this target when deduplicated. May be `nil`.
39
+ #
40
+ # @note This affects the value returned by #configuration_build_dir
41
+ # and accessors relying on this as #build_product_path.
42
+ #
43
+ attr_reader :scope_suffix
44
+
45
+ # @return [HeadersStore] the header directory for the target.
46
+ #
47
+ attr_reader :build_headers
48
+
49
+ # @return [Array<PodTarget>] the targets that this target has a dependency
50
+ # upon.
51
+ #
52
+ attr_reader :dependent_targets
53
+ attr_reader :dependent_targets_by_config
54
+
55
+ # @deprecated
56
+ def dependent_targets=(dependent_targets)
57
+ @dependent_targets = dependent_targets
58
+ @dependent_targets_by_config = { :debug => dependent_targets, :release => dependent_targets }
59
+ end
60
+
61
+ def dependent_targets_by_config=(dependent_targets_by_config)
62
+ @dependent_targets_by_config = dependent_targets_by_config
63
+ @dependent_targets = dependent_targets_by_config.each_value.reduce([], &:|)
64
+ end
65
+
66
+ # @return [Hash{String=>Array<PodTarget>}] all target dependencies by test spec name.
67
+ #
68
+ attr_reader :test_dependent_targets_by_spec_name
69
+ attr_reader :test_dependent_targets_by_spec_name_by_config
70
+
71
+ # @deprecated
72
+ def test_dependent_targets_by_spec_name=(test_dependent_targets_by_spec_name)
73
+ @test_dependent_targets_by_spec_name = test_dependent_targets_by_spec_name
74
+ @test_dependent_targets_by_spec_name_by_config = Hash[test_dependent_targets_by_spec_name.map do |k, v|
75
+ [k, { :debug => v, :release => v }]
76
+ end]
77
+ end
78
+
79
+ def test_dependent_targets_by_spec_name_by_config=(test_dependent_targets_by_spec_name_by_config)
80
+ @test_dependent_targets_by_spec_name_by_config = test_dependent_targets_by_spec_name_by_config
81
+ @test_dependent_targets_by_spec_name = Hash[test_dependent_targets_by_spec_name_by_config.map do |k, v|
82
+ [k, v.each_value.reduce(Set.new, &:|).to_a]
83
+ end]
84
+ end
85
+
86
+ # @return [Hash{String=>Array<PodTarget>}] all target dependencies by app spec name.
87
+ #
88
+ attr_reader :app_dependent_targets_by_spec_name
89
+ attr_reader :app_dependent_targets_by_spec_name_by_config
90
+
91
+ # @deprecated
92
+ def app_dependent_targets_by_spec_name=(app_dependent_targets_by_spec_name)
93
+ @app_dependent_targets_by_spec_name = app_dependent_targets_by_spec_name
94
+ @app_dependent_targets_by_spec_name_by_config = Hash[app_dependent_targets_by_spec_name.map do |k, v|
95
+ [k, { :debug => v, :release => v }]
96
+ end]
97
+ end
98
+
99
+ def app_dependent_targets_by_spec_name_by_config=(app_dependent_targets_by_spec_name_by_config)
100
+ @app_dependent_targets_by_spec_name_by_config = app_dependent_targets_by_spec_name_by_config
101
+ @app_dependent_targets_by_spec_name = Hash[app_dependent_targets_by_spec_name_by_config.map do |k, v|
102
+ [k, v.each_value.reduce(Set.new, &:|).to_a]
103
+ end]
104
+ end
105
+
106
+ # @return [Hash{Specification => (Specification,PodTarget)}] tuples of app specs and pod targets by test spec.
107
+ #
108
+ attr_accessor :test_app_hosts_by_spec
109
+
110
+ # @return [Hash{String => BuildSettings}] the test spec build settings for this target.
111
+ #
112
+ attr_reader :test_spec_build_settings
113
+ attr_reader :test_spec_build_settings_by_config
114
+
115
+ # @return [Hash{String => BuildSettings}] the app spec build settings for this target.
116
+ #
117
+ attr_reader :app_spec_build_settings
118
+ attr_reader :app_spec_build_settings_by_config
119
+
120
+ # @return [String] the Swift version for this target.
121
+ #
122
+ attr_reader :swift_version
123
+
124
+ # Initialize a new instance
125
+ #
126
+ # @param [Sandbox] sandbox @see Target#sandbox
127
+ # @param [BuildType] build_type @see Target#build_type
128
+ # @param [Hash{String=>Symbol}] user_build_configurations @see Target#user_build_configurations
129
+ # @param [Array<String>] archs @see Target#archs
130
+ # @param [Platform] platform @see Target#platform
131
+ # @param [Array<Specification>] specs @see #specs
132
+ # @param [Array<TargetDefinition>] target_definitions @see #target_definitions
133
+ # @param [Array<Sandbox::FileAccessor>] file_accessors @see #file_accessors
134
+ # @param [String] scope_suffix @see #scope_suffix
135
+ # @param [String] swift_version @see #swift_version
136
+ #
137
+ def initialize(sandbox, build_type, user_build_configurations, archs, platform, specs, target_definitions,
138
+ file_accessors = [], scope_suffix = nil, swift_version = nil)
139
+ super(sandbox, build_type, user_build_configurations, archs, platform)
140
+ raise "Can't initialize a PodTarget without specs!" if specs.nil? || specs.empty?
141
+ raise "Can't initialize a PodTarget without TargetDefinition!" if target_definitions.nil? || target_definitions.empty?
142
+ raise "Can't initialize a PodTarget with an empty string scope suffix!" if scope_suffix == ''
143
+ @specs = specs.dup.freeze
144
+ @target_definitions = target_definitions
145
+ @file_accessors = file_accessors
146
+ @scope_suffix = scope_suffix
147
+ @swift_version = swift_version
148
+ all_specs_by_type = @specs.group_by(&:spec_type)
149
+ @library_specs = all_specs_by_type[:library] || []
150
+ @test_specs = all_specs_by_type[:test] || []
151
+ @app_specs = all_specs_by_type[:app] || []
152
+ @build_headers = Sandbox::HeadersStore.new(sandbox, 'Private', :private)
153
+ self.dependent_targets = []
154
+ self.test_dependent_targets_by_spec_name = Hash[test_specs.map { |ts| [ts.name, []] }]
155
+ self.app_dependent_targets_by_spec_name = Hash[app_specs.map { |as| [as.name, []] }]
156
+ @test_app_hosts_by_spec = {}
157
+ @build_config_cache = {}
158
+ @test_spec_build_settings_by_config = create_test_build_settings_by_config
159
+ @app_spec_build_settings_by_config = create_app_build_settings_by_config
160
+ end
161
+
162
+ # Scopes the current target based on the existing pod targets within the cache.
163
+ #
164
+ # @param [Hash{Array => PodTarget}] cache
165
+ # the cached target for a previously scoped target.
166
+ #
167
+ # @return [Array<PodTarget>] a scoped copy for each target definition.
168
+ #
169
+ def scoped(cache = {})
170
+ target_definitions.map do |target_definition|
171
+ cache_key = [specs, target_definition]
172
+ cache[cache_key] ||= begin
173
+ target = PodTarget.new(sandbox, build_type, user_build_configurations, archs, platform, specs,
174
+ [target_definition], file_accessors, target_definition.label, swift_version)
175
+ scope_dependent_targets = ->(dependent_targets) do
176
+ dependent_targets.flat_map do |pod_target|
177
+ pod_target.scoped(cache).select { |pt| pt.target_definitions == [target_definition] }
178
+ end
179
+ end
180
+
181
+ target.dependent_targets_by_config = Hash[dependent_targets_by_config.map { |k, v| [k, scope_dependent_targets[v]] }]
182
+ target.test_dependent_targets_by_spec_name_by_config = Hash[test_dependent_targets_by_spec_name_by_config.map do |spec_name, test_pod_targets_by_config|
183
+ [spec_name, Hash[test_pod_targets_by_config.map { |k, v| [k, scope_dependent_targets[v]] }]]
184
+ end]
185
+ target.app_dependent_targets_by_spec_name_by_config = Hash[app_dependent_targets_by_spec_name_by_config.map do |spec_name, app_pod_targets_by_config|
186
+ [spec_name, Hash[app_pod_targets_by_config.map { |k, v| [k, scope_dependent_targets[v]] }]]
187
+ end]
188
+ target.test_app_hosts_by_spec = Hash[test_app_hosts_by_spec.map do |spec, (app_host_spec, app_pod_target)|
189
+ [spec, [app_host_spec, app_pod_target.scoped(cache).find { |pt| pt.target_definitions == [target_definition] }]]
190
+ end]
191
+ target
192
+ end
193
+ end
194
+ end
195
+
196
+ # @return [String] the label for the target.
197
+ #
198
+ def label
199
+ if scope_suffix.nil? || scope_suffix[0] == '.'
200
+ "#{root_spec.name}#{scope_suffix}"
201
+ else
202
+ "#{root_spec.name}-#{scope_suffix}"
203
+ end
204
+ end
205
+
206
+ # @return [Array<Pathname>] The list of all files tracked.
207
+ #
208
+ def all_files
209
+ Sandbox::FileAccessor.all_files(file_accessors)
210
+ end
211
+
212
+ # @return [Pathname] the pathname for headers in the sandbox.
213
+ #
214
+ def headers_sandbox
215
+ Pathname.new(pod_name)
216
+ end
217
+
218
+ # @return [Hash{FileAccessor => Hash}] Hash of file accessors by header mappings.
219
+ #
220
+ def header_mappings_by_file_accessor
221
+ valid_accessors = file_accessors.reject { |fa| fa.spec.non_library_specification? }
222
+ Hash[valid_accessors.map do |file_accessor|
223
+ # Private headers will always end up in Pods/Headers/Private/PodA/*.h
224
+ # This will allow for `""` imports to work.
225
+ [file_accessor, header_mappings(file_accessor, file_accessor.headers)]
226
+ end]
227
+ end
228
+
229
+ # @return [Hash{FileAccessor => Hash}] Hash of file accessors by public header mappings.
230
+ #
231
+ def public_header_mappings_by_file_accessor
232
+ valid_accessors = file_accessors.reject { |fa| fa.spec.non_library_specification? }
233
+ Hash[valid_accessors.map do |file_accessor|
234
+ # Public headers on the other hand will be added in Pods/Headers/Public/PodA/PodA/*.h
235
+ # The extra folder is intentional in order for `<>` imports to work.
236
+ [file_accessor, header_mappings(file_accessor, file_accessor.public_headers)]
237
+ end]
238
+ end
239
+
240
+ # @return [Array<Version>] the Swift versions supported. Might be empty if the author has not
241
+ # specified any versions, most likely due to legacy reasons.
242
+ #
243
+ def spec_swift_versions
244
+ root_spec.swift_versions
245
+ end
246
+
247
+ # @return [Podfile] The podfile which declares the dependency.
248
+ #
249
+ def podfile
250
+ target_definitions.first.podfile
251
+ end
252
+
253
+ # @return [String] the project name derived from the target definitions that integrate this pod. If none is
254
+ # specified then the name of the pod is used by default.
255
+ #
256
+ # @note The name is guaranteed to be the same across all target definitions and is validated by the target
257
+ # validator during installation.
258
+ #
259
+ def project_name
260
+ target_definitions.map { |td| td.project_name_for_pod(pod_name) }.compact.first || pod_name
261
+ end
262
+
263
+ # @return [String] The name to use for the source code module constructed
264
+ # for this target, and which will be used to import the module in
265
+ # implementation source files.
266
+ #
267
+ def product_module_name
268
+ root_spec.module_name
269
+ end
270
+
271
+ # @param [Specification] spec the specification
272
+ #
273
+ # @return [String] the product basename of the specification's target
274
+ def product_basename_for_spec(spec)
275
+ user_specified = build_settings_by_config_for_spec(spec).
276
+ each_value.
277
+ map { |settings| settings.merged_pod_target_xcconfigs['PRODUCT_NAME'] }.
278
+ compact.
279
+ uniq
280
+
281
+ if user_specified.size == 1
282
+ user_specified.first
283
+ else
284
+ spec_label(spec)
285
+ end
286
+ end
287
+
288
+ # @return [Bool] Whether or not this target should be built.
289
+ #
290
+ # A target should not be built if it has no source files.
291
+ #
292
+ def should_build?
293
+ return @should_build if defined? @should_build
294
+ accessors = file_accessors.select { |fa| fa.spec.library_specification? }
295
+ source_files = accessors.flat_map(&:source_files)
296
+ source_files -= accessors.flat_map(&:headers)
297
+ @should_build = !source_files.empty?
298
+ end
299
+
300
+ # @return [Array<Specification::Consumer>] the specification consumers for
301
+ # the target.
302
+ #
303
+ def spec_consumers
304
+ specs.map { |spec| spec.consumer(platform) }
305
+ end
306
+
307
+ # @return [Array<Specification::Consumer>] the test specification consumers for
308
+ # the target.
309
+ #
310
+ def test_spec_consumers
311
+ test_specs.map { |test_spec| test_spec.consumer(platform) }
312
+ end
313
+
314
+ # @return [Array<Specification::Consumer>] the app specification consumers for
315
+ # the target.
316
+ #
317
+ def app_spec_consumers
318
+ app_specs.map { |app_spec| app_spec.consumer(platform) }
319
+ end
320
+
321
+ # Checks whether the target itself plus its specs uses Swift code.
322
+ # This check excludes source files from non library specs.
323
+ # Note that if a target does not need to be built (no source code),
324
+ # we fallback to check whether it indicates a swift version.
325
+ #
326
+ # @return [Boolean] Whether the target uses Swift code.
327
+ #
328
+ def uses_swift?
329
+ return @uses_swift if defined? @uses_swift
330
+ @uses_swift = (!should_build? && !spec_swift_versions.empty?) ||
331
+ file_accessors.select { |a| a.spec.library_specification? }.any? do |file_accessor|
332
+ uses_swift_for_spec?(file_accessor.spec)
333
+ end
334
+ end
335
+
336
+ # Checks whether a specification uses Swift or not.
337
+ #
338
+ # @param [Specification] spec
339
+ # The spec to query against.
340
+ #
341
+ # @return [Boolean] Whether the target uses Swift code within the requested non library spec.
342
+ #
343
+ def uses_swift_for_spec?(spec)
344
+ @uses_swift_for_spec_cache ||= {}
345
+ return @uses_swift_for_spec_cache[spec.name] if @uses_swift_for_spec_cache.key?(spec.name)
346
+ @uses_swift_for_spec_cache[spec.name] = begin
347
+ file_accessor = file_accessors.find { |fa| fa.spec == spec }
348
+ raise "[Bug] Unable to find file accessor for spec `#{spec.inspect}` in pod target `#{label}`" unless file_accessor
349
+ file_accessor.source_files.any? { |sf| sf.extname == '.swift' }
350
+ end
351
+ end
352
+
353
+ # @return [Boolean] Whether the target defines a "module"
354
+ # (and thus will need a module map and umbrella header).
355
+ #
356
+ # @note Static library targets can temporarily opt in to this behavior by setting
357
+ # `DEFINES_MODULE = YES` in their specification's `pod_target_xcconfig`.
358
+ #
359
+ def defines_module?
360
+ return @defines_module if defined?(@defines_module)
361
+ return @defines_module = true if uses_swift? || build_as_framework?
362
+
363
+ explicit_target_definitions = target_definitions.select { |td| td.dependencies.any? { |d| d.root_name == pod_name } }
364
+ tds_by_answer = explicit_target_definitions.group_by { |td| td.build_pod_as_module?(pod_name) }
365
+
366
+ if tds_by_answer.size > 1
367
+ UI.warn "Unable to determine whether to build `#{label}` as a module due to a conflict " \
368
+ "between the following target definitions:\n\t- #{tds_by_answer.map do |a, td|
369
+ "`#{td.to_sentence}` #{a ? "requires `#{label}` as a module" : "does not require `#{label}` as a module"}"
370
+ end.join("\n\t- ")}\n\n" \
371
+ "Defaulting to skip building `#{label}` as a module."
372
+ elsif tds_by_answer.keys.first == true || target_definitions.all? { |td| td.build_pod_as_module?(pod_name) }
373
+ return @defines_module = true
374
+ end
375
+
376
+ @defines_module = library_specs.any? { |s| s.consumer(platform).pod_target_xcconfig['DEFINES_MODULE'] == 'YES' }
377
+ end
378
+
379
+ # @return [Array<Hash{Symbol=>String}>] An array of hashes where each hash represents a single script phase.
380
+ #
381
+ def script_phases
382
+ spec_consumers.flat_map(&:script_phases)
383
+ end
384
+
385
+ # @return [Boolean] Whether the target contains any script phases.
386
+ #
387
+ def contains_script_phases?
388
+ !script_phases.empty?
389
+ end
390
+
391
+ # @return [Boolean] Whether the target has any tests specifications.
392
+ #
393
+ def contains_test_specifications?
394
+ !test_specs.empty?
395
+ end
396
+
397
+ # @return [Boolean] Whether the target has any app specifications.
398
+ #
399
+ def contains_app_specifications?
400
+ !app_specs.empty?
401
+ end
402
+
403
+ # @return [Hash{String=>Array<Xcode::FrameworkPaths>}] The vendored and non vendored framework paths this target
404
+ # depends upon keyed by spec name. For the root spec and subspecs the framework path of the target itself
405
+ # is included.
406
+ #
407
+ def framework_paths
408
+ @framework_paths ||= begin
409
+ file_accessors.each_with_object({}) do |file_accessor, hash|
410
+ frameworks = file_accessor.vendored_dynamic_artifacts.map do |framework_path|
411
+ relative_path_to_sandbox = framework_path.relative_path_from(sandbox.root)
412
+ framework_source = "${PODS_ROOT}/#{relative_path_to_sandbox}"
413
+ # Until this can be configured, assume the dSYM file uses the file name as the framework.
414
+ # See https://github.com/CocoaPods/CocoaPods/issues/1698
415
+ dsym_name = "#{framework_path.basename}.dSYM"
416
+ dsym_path = Pathname.new("#{framework_path.dirname}/#{dsym_name}")
417
+ dsym_source = if dsym_path.exist?
418
+ "${PODS_ROOT}/#{relative_path_to_sandbox}.dSYM"
419
+ end
420
+ dirname = framework_path.dirname
421
+ bcsymbolmap_paths = if dirname.exist?
422
+ Dir.chdir(dirname) do
423
+ Dir.glob('*.bcsymbolmap').map do |bcsymbolmap_file_name|
424
+ bcsymbolmap_path = dirname + bcsymbolmap_file_name
425
+ "${PODS_ROOT}/#{bcsymbolmap_path.relative_path_from(sandbox.root)}"
426
+ end
427
+ end
428
+ end
429
+ Xcode::FrameworkPaths.new(framework_source, dsym_source, bcsymbolmap_paths)
430
+ end
431
+ if file_accessor.spec.library_specification? && should_build? && build_as_dynamic_framework?
432
+ frameworks << Xcode::FrameworkPaths.new(build_product_path('${BUILT_PRODUCTS_DIR}'))
433
+ end
434
+ hash[file_accessor.spec.name] = frameworks
435
+ end
436
+ end
437
+ end
438
+
439
+ # @return [Hash{String=>Array<Xcode::XCFramework>}] The vendored xcframeworks this target
440
+ # depends upon keyed by spec name.
441
+ #
442
+ def xcframeworks
443
+ @xcframeworks ||= begin
444
+ file_accessors.each_with_object({}) do |file_accessor, hash|
445
+ frameworks = file_accessor.vendored_xcframeworks.map do |framework_path|
446
+ Xcode::XCFramework.new(file_accessor.spec.name, framework_path)
447
+ end
448
+ hash[file_accessor.spec.name] = frameworks
449
+ end
450
+ end
451
+ end
452
+
453
+ # @return [Hash{String=>Array<String>}] The resource and resource bundle paths this target depends upon keyed by
454
+ # spec name. Resource (not resource bundles) paths can vary depending on the type of spec:
455
+ # - App specs _always_ get their resource paths added to "Copy Bundle Resources" phase from
456
+ # [PodTargetInstaller] therefore their resource paths are never included here.
457
+ # - Test specs may have their resource paths added to "Copy Bundle Resources" if the target itself is
458
+ # built as a framework, which is again checked and handled by PodTargetInstaller. If that is true then
459
+ # the resource paths are not included, otherwise they are included and handled via the CocoaPods copy
460
+ # resources script phase.
461
+ # - Library specs _do not_ have per-configuration CocoaPods copy resources script phase and their resource
462
+ # paths will be added to "Copy Bundle Resources" phase if the target is built as a framework because
463
+ # it supports it. We always include the resource paths for library specs because they are also
464
+ # integrated to the user target.
465
+ #
466
+ def resource_paths
467
+ @resource_paths ||= begin
468
+ file_accessors.each_with_object({}) do |file_accessor, hash|
469
+ resource_paths = if file_accessor.spec.app_specification? || (file_accessor.spec.test_specification? && build_as_framework?)
470
+ []
471
+ else
472
+ file_accessor.resources.map do |res|
473
+ "${PODS_ROOT}/#{res.relative_path_from(sandbox.project_path.dirname)}"
474
+ end
475
+ end
476
+ prefix = Pod::Target::BuildSettings::CONFIGURATION_BUILD_DIR_VARIABLE
477
+ prefix = configuration_build_dir unless file_accessor.spec.test_specification?
478
+ resource_bundle_paths = file_accessor.resource_bundles.keys.map { |name| "#{prefix}/#{name.shellescape}.bundle" }
479
+ hash[file_accessor.spec.name] = (resource_paths + resource_bundle_paths).map(&:to_s)
480
+ end
481
+ end
482
+ end
483
+
484
+ # @param [Specification] spec The non library spec to calculate the deployment target for.
485
+ #
486
+ # @return [String] The deployment target to use for the non library spec. If the non library spec explicitly
487
+ # specifies one then this is the one used otherwise the one that was determined by the analyzer is used.
488
+ #
489
+ def deployment_target_for_non_library_spec(spec)
490
+ raise ArgumentError, 'Must be a non library spec.' unless spec.non_library_specification?
491
+ spec.deployment_target(platform.name.to_s) || platform.deployment_target.to_s
492
+ end
493
+
494
+ # Returns the corresponding native product type to use given the test type.
495
+ # This is primarily used when creating the native targets in order to produce the correct test bundle target
496
+ # based on the type of tests included.
497
+ #
498
+ # @param [Symbol] test_type
499
+ # The test type to map to provided by the test specification DSL.
500
+ #
501
+ # @return [Symbol] The native product type to use.
502
+ #
503
+ def product_type_for_test_type(test_type)
504
+ case test_type
505
+ when :unit
506
+ :unit_test_bundle
507
+ when :ui
508
+ :ui_test_bundle
509
+ else
510
+ raise ArgumentError, "Unknown test type `#{test_type}`."
511
+ end
512
+ end
513
+
514
+ # Returns the label to use for the given test type.
515
+ # This is used to generate native target names for test specs.
516
+ #
517
+ # @param [Symbol] test_type
518
+ # The test type to map to provided by the test specification DSL.
519
+ #
520
+ # @return [String] The native product type to use.
521
+ #
522
+ def label_for_test_type(test_type)
523
+ case test_type
524
+ when :unit
525
+ 'Unit'
526
+ when :ui
527
+ 'UI'
528
+ else
529
+ raise ArgumentError, "Unknown test type `#{test_type}`."
530
+ end
531
+ end
532
+
533
+ # @return [Specification] The root specification for the target.
534
+ #
535
+ def root_spec
536
+ @root_spec ||= specs.first.root
537
+ end
538
+
539
+ # @return [String] The name of the Pod that this target refers to.
540
+ #
541
+ def pod_name
542
+ root_spec.name
543
+ end
544
+
545
+ # @return [Pathname] the absolute path of the LLVM module map file that
546
+ # defines the module structure for the compiler.
547
+ #
548
+ def module_map_path
549
+ basename = "#{label}.modulemap"
550
+ if build_as_framework?
551
+ super
552
+ elsif file_accessors.any?(&:module_map)
553
+ build_headers.root + product_module_name + basename
554
+ else
555
+ sandbox.public_headers.root + product_module_name + basename
556
+ end
557
+ end
558
+
559
+ # @return [Pathname] the absolute path of the prefix header file.
560
+ #
561
+ def prefix_header_path
562
+ support_files_dir + "#{label}-prefix.pch"
563
+ end
564
+
565
+ # @return [Hash] the additional entries to add to the generated Info.plist
566
+ #
567
+ def info_plist_entries
568
+ root_spec.info_plist
569
+ end
570
+
571
+ # @param [String] bundle_name
572
+ # The name of the bundle product, which is given by the +spec+.
573
+ #
574
+ # @return [String] The derived name of the resource bundle target.
575
+ #
576
+ def resources_bundle_target_label(bundle_name)
577
+ "#{label}-#{bundle_name}"
578
+ end
579
+
580
+ # @param [Specification] subspec
581
+ # The subspec to use for producing the label.
582
+ #
583
+ # @return [String] The derived name of the target.
584
+ #
585
+ def subspec_label(subspec)
586
+ raise ArgumentError, 'Must not be a root spec' if subspec.root?
587
+ subspec.name.split('/')[1..-1].join('-').to_s
588
+ end
589
+
590
+ # @param [Specification] test_spec
591
+ # The test spec to use for producing the test label.
592
+ #
593
+ # @return [String] The derived name of the test target.
594
+ #
595
+ def test_target_label(test_spec)
596
+ "#{label}-#{label_for_test_type(test_spec.test_type)}-#{subspec_label(test_spec)}"
597
+ end
598
+
599
+ # @param [Specification] app_spec
600
+ # The app spec to use for producing the app label.
601
+ #
602
+ # @return [String] The derived name of the app target.
603
+ #
604
+ def app_target_label(app_spec)
605
+ "#{label}-#{subspec_label(app_spec)}"
606
+ end
607
+
608
+ # @param [Specification] test_spec
609
+ # the test spec to use for producing the app host target label.
610
+ #
611
+ # @return [(String,String)] a tuple, where the first item is the PodTarget#label of the pod target that defines the
612
+ # app host, and the second item is the target name of the app host
613
+ #
614
+ def app_host_target_label(test_spec)
615
+ app_spec, app_target = test_app_hosts_by_spec[test_spec]
616
+
617
+ if app_spec
618
+ [app_target.name, app_target.app_target_label(app_spec)]
619
+ elsif test_spec.consumer(platform).requires_app_host?
620
+ [name, "AppHost-#{label}-#{label_for_test_type(test_spec.test_type)}-Tests"]
621
+ end
622
+ end
623
+
624
+ # @param [Specification] spec
625
+ # the spec to return app host dependencies for
626
+ #
627
+ # @param [String] configuration
628
+ # the configuration to retrieve the app host dependent targets for.
629
+ #
630
+ # @return [Array<PodTarget>] the app host dependent targets for the given spec.
631
+ #
632
+ def app_host_dependent_targets_for_spec(spec, configuration: nil)
633
+ return [] unless spec.test_specification? && spec.consumer(platform).test_type == :unit
634
+ app_host_info = test_app_hosts_by_spec[spec]
635
+ if app_host_info.nil?
636
+ []
637
+ else
638
+ app_spec, app_target = *app_host_info
639
+ app_target.dependent_targets_for_app_spec(app_spec, :configuration => configuration)
640
+ end
641
+ end
642
+
643
+ def spec_label(spec)
644
+ case spec.spec_type
645
+ when :library then label
646
+ when :test then test_target_label(spec)
647
+ when :app then app_target_label(spec)
648
+ else raise ArgumentError, "Unhandled spec type #{spec.spec_type.inspect} for #{spec.inspect}"
649
+ end
650
+ end
651
+ # for backwards compatibility
652
+ alias non_library_spec_label spec_label
653
+
654
+ # @param [Specification] spec
655
+ # The spec to return scheme configuration for.
656
+ #
657
+ # @return [Hash] The scheme configuration used or empty if none is specified.
658
+ #
659
+ def scheme_for_spec(spec)
660
+ return {} if (spec.library_specification? && !spec.root?) || spec.available_platforms.none? do |p|
661
+ p.name == platform.name
662
+ end
663
+ spec.consumer(platform).scheme
664
+ end
665
+
666
+ # @param [Specification] spec
667
+ # The spec this copy resources script path is for.
668
+ #
669
+ # @return [Pathname] The absolute path of the copy resources script for the given spec.
670
+ #
671
+ def copy_resources_script_path_for_spec(spec)
672
+ support_files_dir + "#{spec_label(spec)}-resources.sh"
673
+ end
674
+
675
+ # @param [Specification] spec
676
+ # The spec this copy resources script path is for.
677
+ #
678
+ # @return [Pathname] The absolute path of the copy resources script input file list for the given spec.
679
+ #
680
+ def copy_resources_script_input_files_path_for_spec(spec)
681
+ support_files_dir + "#{spec_label(spec)}-resources-input-files.xcfilelist"
682
+ end
683
+
684
+ # @param [Specification] spec
685
+ # The spec this copy resources script path is for.
686
+ #
687
+ # @return [Pathname] The absolute path of the copy resources script output file list for the given spec.
688
+ #
689
+ def copy_resources_script_output_files_path_for_spec(spec)
690
+ support_files_dir + "#{spec_label(spec)}-resources-output-files.xcfilelist"
691
+ end
692
+
693
+ # @param [Specification] spec
694
+ # The spec this embed frameworks script path is for.
695
+ #
696
+ # @return [Pathname] The absolute path of the embed frameworks script for the given spec.
697
+ #
698
+ def embed_frameworks_script_path_for_spec(spec)
699
+ support_files_dir + "#{spec_label(spec)}-frameworks.sh"
700
+ end
701
+
702
+ # @param [Specification] spec
703
+ # The spec this embed frameworks script path is for.
704
+ #
705
+ # @return [Pathname] The absolute path of the embed frameworks script input file list for the given spec.
706
+ #
707
+ def embed_frameworks_script_input_files_path_for_spec(spec)
708
+ support_files_dir + "#{spec_label(spec)}-frameworks-input-files.xcfilelist"
709
+ end
710
+
711
+ # @param [Specification] spec
712
+ # The spec this embed frameworks script path is for.
713
+ #
714
+ # @return [Pathname] The absolute path of the embed frameworks script output file list for the given spec.
715
+ #
716
+ def embed_frameworks_script_output_files_path_for_spec(spec)
717
+ support_files_dir + "#{spec_label(spec)}-frameworks-output-files.xcfilelist"
718
+ end
719
+
720
+ # @return [Pathname] The absolute path of the copy xcframeworks script.
721
+ #
722
+ def copy_xcframeworks_script_path
723
+ support_files_dir + "#{label}-xcframeworks.sh"
724
+ end
725
+
726
+ # @return [String] The path of the copy xcframeworks input files file list
727
+ #
728
+ def copy_xcframeworks_script_input_files_path
729
+ support_files_dir + "#{label}-xcframeworks-input-files.xcfilelist"
730
+ end
731
+
732
+ # @return [String] The path of the copy xcframeworks output files file list
733
+ #
734
+ def copy_xcframeworks_script_output_files_path
735
+ support_files_dir + "#{label}-xcframeworks-output-files.xcfilelist"
736
+ end
737
+
738
+ # @param [Specification] spec
739
+ # The spec this script path is for.
740
+ #
741
+ # @return [Pathname] The absolute path of the prepare artifacts script for the given spec.
742
+ #
743
+ # @deprecated
744
+ #
745
+ # @todo Remove in 2.0
746
+ #
747
+ def prepare_artifacts_script_path_for_spec(spec)
748
+ support_files_dir + "#{spec_label(spec)}-artifacts.sh"
749
+ end
750
+
751
+ # @param [Specification] spec
752
+ # The spec this script path is for.
753
+ #
754
+ # @return [Pathname] The absolute path of the prepare artifacts script input file list for the given spec.
755
+ #
756
+ # @deprecated
757
+ #
758
+ # @todo Remove in 2.0
759
+ #
760
+ def prepare_artifacts_script_input_files_path_for_spec(spec)
761
+ support_files_dir + "#{spec_label(spec)}-artifacts-input-files.xcfilelist"
762
+ end
763
+
764
+ # @param [Specification] spec
765
+ # The spec this script path is for.
766
+ #
767
+ # @return [Pathname] The absolute path of the prepare artifacts script output file list for the given spec.
768
+ #
769
+ # @deprecated
770
+ #
771
+ # @todo Remove in 2.0
772
+ #
773
+ def prepare_artifacts_script_output_files_path_for_spec(spec)
774
+ support_files_dir + "#{spec_label(spec)}-artifacts-output-files.xcfilelist"
775
+ end
776
+
777
+ # @return [Pathname] The absolute path of the copy dSYMs script.
778
+ #
779
+ def copy_dsyms_script_path
780
+ support_files_dir + "#{label}-copy-dsyms.sh"
781
+ end
782
+
783
+ # @return [Pathname] The absolute path of the copy dSYM script phase input file list.
784
+ #
785
+ def copy_dsyms_script_input_files_path
786
+ support_files_dir + "#{label}-copy-dsyms-input-files.xcfilelist"
787
+ end
788
+
789
+ # @return [Pathname] The absolute path of the copy dSYM script phase output file list.
790
+ #
791
+ def copy_dsyms_script_output_files_path
792
+ support_files_dir + "#{label}-copy-dsyms-output-files.xcfilelist"
793
+ end
794
+
795
+ # @param [Specification] spec
796
+ # The spec this Info.plist path is for.
797
+ #
798
+ # @return [Pathname] The absolute path of the Info.plist for the given spec.
799
+ #
800
+ def info_plist_path_for_spec(spec)
801
+ support_files_dir + "#{spec_label(spec)}-Info.plist"
802
+ end
803
+
804
+ # @param [Specification] spec
805
+ # The spec this prefix header path is for.
806
+ #
807
+ # @return [Pathname] the absolute path of the prefix header file for the given spec.
808
+ #
809
+ def prefix_header_path_for_spec(spec)
810
+ support_files_dir + "#{spec_label(spec)}-prefix.pch"
811
+ end
812
+
813
+ # @return [Array<String>] The names of the Pods on which this target
814
+ # depends.
815
+ #
816
+ def dependencies
817
+ spec_consumers.flat_map do |consumer|
818
+ consumer.dependencies.map { |dep| Specification.root_name(dep.name) }
819
+ end.uniq
820
+ end
821
+
822
+ # Returns all dependent targets of this target. If a configuration is passed then the list can be scoped to a given
823
+ # configuration.
824
+ #
825
+ # @param [String] configuration
826
+ # The configuration to return the dependent targets for or `nil` if all configurations should be included.
827
+ #
828
+ # @return [Array<PodTarget>] the recursive targets that this target has a dependency upon.
829
+ #
830
+ def recursive_dependent_targets(configuration: nil)
831
+ @recursive_dependent_targets ||= begin
832
+ hash = Hash[config_variants.map do |config|
833
+ [config, _add_recursive_dependent_targets(Set.new, :configuration => config).delete(self).to_a.freeze]
834
+ end]
835
+ hash[nil] = hash.each_value.reduce(Set.new, &:|).to_a
836
+ hash
837
+ end
838
+ @recursive_dependent_targets.fetch(configuration) { raise ArgumentError, "No configuration #{configuration} for #{self}, known configurations are #{@recursive_dependent_targets.keys}" }
839
+ end
840
+
841
+ def _add_recursive_dependent_targets(set, configuration: nil)
842
+ if defined?(@recursive_dependent_targets)
843
+ return set.merge(@recursive_dependent_targets[configuration])
844
+ end
845
+ dependent_targets = configuration ? dependent_targets_by_config[configuration] : self.dependent_targets
846
+ dependent_targets.each do |target|
847
+ target._add_recursive_dependent_targets(set, :configuration => configuration) if set.add?(target)
848
+ end
849
+
850
+ set
851
+ end
852
+ protected :_add_recursive_dependent_targets
853
+
854
+ # @param [Specification] test_spec
855
+ # the test spec to scope dependencies for
856
+ #
857
+ # @param [String] configuration
858
+ # the configuration to retrieve the test dependent targets for.
859
+ #
860
+ # @return [Array<PodTarget>] the recursive targets that this target has a
861
+ # test dependency upon.
862
+ #
863
+ def recursive_test_dependent_targets(test_spec, configuration: nil)
864
+ @recursive_test_dependent_targets ||= {}
865
+ @recursive_test_dependent_targets[test_spec] ||= begin
866
+ hash = Hash[config_variants.map do |config|
867
+ [config, _add_recursive_test_dependent_targets(test_spec, Set.new, :configuration => config).to_a.freeze]
868
+ end]
869
+ hash[nil] = hash.each_value.reduce(Set.new, &:|).to_a.freeze
870
+ hash
871
+ end
872
+ @recursive_test_dependent_targets[test_spec][configuration]
873
+ end
874
+
875
+ def _add_recursive_test_dependent_targets(test_spec, set, configuration: nil)
876
+ raise ArgumentError, 'Must give a test spec' unless test_spec
877
+ dependent_targets = configuration ? test_dependent_targets_by_spec_name_by_config[test_spec.name][configuration] : test_dependent_targets_by_spec_name[test_spec.name]
878
+ raise ArgumentError, "Unable to find deps for #{test_spec} for config #{configuration.inspect} (out of #{test_dependent_targets_by_spec_name_by_config.inspect})" unless dependent_targets
879
+
880
+ dependent_targets.each do |target|
881
+ target._add_recursive_dependent_targets(set, :configuration => configuration) if set.add?(target)
882
+ end
883
+
884
+ set
885
+ end
886
+ private :_add_recursive_test_dependent_targets
887
+
888
+ # @param [Specification] test_spec
889
+ # the test spec to scope dependencies for
890
+ #
891
+ # @param [String] configuration
892
+ # the configuration to retrieve the test dependent targets for.
893
+ #
894
+ # @return [Array<PodTarget>] the canonical list of dependent targets this target has a dependency upon.
895
+ # This list includes the target itself as well as its recursive dependent and test dependent targets.
896
+ #
897
+ def dependent_targets_for_test_spec(test_spec, configuration: nil)
898
+ [self, *recursive_dependent_targets(:configuration => configuration), *recursive_test_dependent_targets(test_spec, :configuration => configuration)].uniq
899
+ end
900
+
901
+ # @param [Specification] app_spec
902
+ # the app spec to scope dependencies for
903
+ #
904
+ # @param [String] configuration
905
+ # the configuration to retrieve the app dependent targets for.
906
+ #
907
+ # @return [Array<PodTarget>] the recursive targets that this target has a
908
+ # app dependency upon.
909
+ #
910
+ def recursive_app_dependent_targets(app_spec, configuration: nil)
911
+ @recursive_app_dependent_targets ||= {}
912
+ @recursive_app_dependent_targets[app_spec] ||= begin
913
+ hash = Hash[config_variants.map do |config|
914
+ [config, _add_recursive_app_dependent_targets(app_spec, Set.new, :configuration => config).to_a.freeze]
915
+ end]
916
+ hash[nil] = hash.each_value.reduce(Set.new, &:|).to_a.freeze
917
+ hash
918
+ end
919
+ @recursive_app_dependent_targets[app_spec][configuration]
920
+ end
921
+
922
+ def _add_recursive_app_dependent_targets(app_spec, set, configuration: nil)
923
+ raise ArgumentError, 'Must give a app spec' unless app_spec
924
+ dependent_targets = configuration ? app_dependent_targets_by_spec_name_by_config[app_spec.name][configuration] : app_dependent_targets_by_spec_name[app_spec.name]
925
+ raise ArgumentError, "Unable to find deps for #{app_spec} for config #{configuration.inspect} #{app_dependent_targets_by_spec_name_by_config.inspect}" unless dependent_targets
926
+
927
+ dependent_targets.each do |target|
928
+ target._add_recursive_dependent_targets(set, :configuration => configuration) if set.add?(target)
929
+ end
930
+
931
+ set
932
+ end
933
+ private :_add_recursive_app_dependent_targets
934
+
935
+ # @param [Specification] app_spec
936
+ # the app spec to scope dependencies for
937
+ #
938
+ # @param [String] configuration
939
+ # the configuration to retrieve the app dependent targets for.
940
+ #
941
+ # @return [Array<PodTarget>] the canonical list of dependent targets this target has a dependency upon.
942
+ # This list includes the target itself as well as its recursive dependent and app dependent targets.
943
+ #
944
+ def dependent_targets_for_app_spec(app_spec, configuration: nil)
945
+ [self, *recursive_dependent_targets(:configuration => configuration), *recursive_app_dependent_targets(app_spec, :configuration => configuration)].uniq
946
+ end
947
+
948
+ # Checks if warnings should be inhibited for this pod.
949
+ #
950
+ # @return [Bool]
951
+ #
952
+ def inhibit_warnings?
953
+ return @inhibit_warnings if defined? @inhibit_warnings
954
+ whitelists = target_definitions.map do |target_definition|
955
+ target_definition.inhibits_warnings_for_pod?(root_spec.name)
956
+ end.uniq
957
+
958
+ if whitelists.empty?
959
+ @inhibit_warnings = false
960
+ false
961
+ elsif whitelists.count == 1
962
+ @inhibit_warnings = whitelists.first
963
+ whitelists.first
964
+ else
965
+ UI.warn "The pod `#{pod_name}` is linked to different targets " \
966
+ "(#{target_definitions.map { |td| "`#{td.name}`" }.to_sentence}), which contain different " \
967
+ 'settings to inhibit warnings. CocoaPods does not currently ' \
968
+ 'support different settings and will fall back to your preference ' \
969
+ 'set in the root target definition.'
970
+ @inhibit_warnings = podfile.root_target_definitions.first.inhibits_warnings_for_pod?(root_spec.name)
971
+ end
972
+ end
973
+
974
+ # @param [String] dir
975
+ # The directory (which might be a variable) relative to which
976
+ # the returned path should be. This must be used if the
977
+ # $CONFIGURATION_BUILD_DIR is modified.
978
+ #
979
+ # @return [String] The absolute path to the configuration build dir
980
+ #
981
+ def configuration_build_dir(dir = BuildSettings::CONFIGURATION_BUILD_DIR_VARIABLE)
982
+ "#{dir}/#{label}"
983
+ end
984
+
985
+ # @param [String] dir
986
+ # @see #configuration_build_dir
987
+ #
988
+ # @return [String] The absolute path to the build product
989
+ #
990
+ def build_product_path(dir = BuildSettings::CONFIGURATION_BUILD_DIR_VARIABLE)
991
+ "#{configuration_build_dir(dir)}/#{product_name}"
992
+ end
993
+
994
+ # @return [String] The source path of the root for this target relative to `$(PODS_ROOT)`
995
+ #
996
+ def pod_target_srcroot
997
+ "${PODS_ROOT}/#{sandbox.pod_dir(pod_name).relative_path_from(sandbox.root)}"
998
+ end
999
+
1000
+ # @return [String] The version associated with this target
1001
+ #
1002
+ def version
1003
+ version = root_spec.version
1004
+ [version.major, version.minor, version.patch].join('.')
1005
+ end
1006
+
1007
+ # @param [Boolean] include_dependent_targets_for_test_spec
1008
+ # whether to include header search paths for test dependent targets
1009
+ #
1010
+ # @param [Boolean] include_dependent_targets_for_app_spec
1011
+ # whether to include header search paths for app dependent targets
1012
+ #
1013
+ # @param [Boolean] include_private_headers
1014
+ # whether to include header search paths for private headers of this
1015
+ # target
1016
+ #
1017
+ # @param [String] configuration
1018
+ # the configuration to return header search paths for or `nil` for all configurations.
1019
+ #
1020
+ # @return [Array<String>] The set of header search paths this target uses.
1021
+ #
1022
+ def header_search_paths(include_dependent_targets_for_test_spec: nil, include_dependent_targets_for_app_spec: nil,
1023
+ include_private_headers: true, configuration: nil)
1024
+ header_search_paths = []
1025
+ header_search_paths.concat(build_headers.search_paths(platform, nil, false)) if include_private_headers
1026
+ header_search_paths.concat(sandbox.public_headers.search_paths(platform, pod_name, uses_modular_headers?))
1027
+ dependent_targets = recursive_dependent_targets(:configuration => configuration)
1028
+ if include_dependent_targets_for_test_spec
1029
+ dependent_targets += recursive_test_dependent_targets(include_dependent_targets_for_test_spec, :configuration => configuration)
1030
+ end
1031
+ if include_dependent_targets_for_app_spec
1032
+ dependent_targets += recursive_app_dependent_targets(include_dependent_targets_for_app_spec, :configuration => configuration)
1033
+ end
1034
+ dependent_targets.uniq.each do |dependent_target|
1035
+ header_search_paths.concat(sandbox.public_headers.search_paths(platform, dependent_target.pod_name, defines_module? && dependent_target.uses_modular_headers?(false)))
1036
+ end
1037
+ header_search_paths.uniq
1038
+ end
1039
+
1040
+ # @param [Specification] spec the specification to return build settings for.
1041
+ #
1042
+ # @param [String] configuration the configuration to scope the build settings.
1043
+ #
1044
+ # @return [BuildSettings::PodTargetSettings] The build settings for the given spec
1045
+ #
1046
+ def build_settings_for_spec(spec, configuration: nil)
1047
+ raise ArgumentError, 'Must give configuration' unless configuration
1048
+ configuration = user_build_configurations[configuration] if user_build_configurations.key?(configuration)
1049
+ build_settings_by_config_for_spec(spec)[configuration] || raise(ArgumentError, "No build settings for #{spec} (configuration #{configuration.inspect}) (known configurations #{config_variants})")
1050
+ end
1051
+
1052
+ def build_settings_by_config_for_spec(spec)
1053
+ case spec.spec_type
1054
+ when :test then test_spec_build_settings_by_config[spec.name]
1055
+ when :app then app_spec_build_settings_by_config[spec.name]
1056
+ else build_settings
1057
+ end || raise(ArgumentError, "No build settings for #{spec}")
1058
+ end
1059
+
1060
+ def user_config_names_by_config_type
1061
+ user_build_configurations.each_with_object({}) do |(user, type), hash|
1062
+ hash[type] ||= []
1063
+ hash[type] << user
1064
+ end.each_value(&:freeze).freeze
1065
+ end
1066
+
1067
+ protected
1068
+
1069
+ # Returns whether the pod target should use modular headers.
1070
+ #
1071
+ # @param [Boolean] only_if_defines_modules
1072
+ # whether the use of modular headers should require the target to define a module
1073
+ #
1074
+ # @note This must return false when a pod has a `header_mappings_dir` or `header_dir`,
1075
+ # as that allows the spec to customize the header structure, and
1076
+ # therefore it might not be expecting the module name to be prepended
1077
+ # to imports at all.
1078
+ #
1079
+ def uses_modular_headers?(only_if_defines_modules = true)
1080
+ return false if only_if_defines_modules && !defines_module?
1081
+ return @uses_modular_headers if defined? @uses_modular_headers
1082
+ @uses_modular_headers = spec_consumers.none?(&:header_mappings_dir) && spec_consumers.none?(&:header_dir)
1083
+ end
1084
+
1085
+ private
1086
+
1087
+ def config_variants
1088
+ if user_build_configurations.empty?
1089
+ %i(debug release)
1090
+ else
1091
+ user_build_configurations.values.uniq
1092
+ end
1093
+ end
1094
+
1095
+ def create_build_settings
1096
+ Hash[config_variants.map do |config|
1097
+ [config, BuildSettings::PodTargetSettings.new(self, nil, :configuration => config)]
1098
+ end]
1099
+ end
1100
+
1101
+ def create_test_build_settings_by_config
1102
+ Hash[test_specs.map do |test_spec|
1103
+ [test_spec.name, Hash[config_variants.map do |config|
1104
+ [config, BuildSettings::PodTargetSettings.new(self, test_spec, :configuration => config)]
1105
+ end]]
1106
+ end]
1107
+ end
1108
+
1109
+ def create_app_build_settings_by_config
1110
+ Hash[app_specs.map do |app_spec|
1111
+ [app_spec.name, Hash[config_variants.map do |config|
1112
+ [config, BuildSettings::PodTargetSettings.new(self, app_spec, :configuration => config)]
1113
+ end]]
1114
+ end]
1115
+ end
1116
+
1117
+ # Computes the destination sub-directory in the sandbox
1118
+ #
1119
+ # @param [Sandbox::FileAccessor] file_accessor
1120
+ # The consumer file accessor for which the headers need to be
1121
+ # linked.
1122
+ #
1123
+ # @param [Array<Pathname>] headers
1124
+ # The absolute paths of the headers which need to be mapped.
1125
+ #
1126
+ # @return [Hash{Pathname => Array<Pathname>}] A hash containing the
1127
+ # headers folders as the keys and the absolute paths of the
1128
+ # header files as the values.
1129
+ #
1130
+ def header_mappings(file_accessor, headers)
1131
+ consumer = file_accessor.spec_consumer
1132
+ header_mappings_dir = consumer.header_mappings_dir
1133
+ dir = headers_sandbox
1134
+ dir += consumer.header_dir if consumer.header_dir
1135
+
1136
+ mappings = {}
1137
+ headers.each do |header|
1138
+ next if header.to_s.include?('.framework/')
1139
+
1140
+ sub_dir = dir
1141
+ if header_mappings_dir
1142
+ relative_path = header.relative_path_from(file_accessor.path_list.root + header_mappings_dir)
1143
+ sub_dir += relative_path.dirname
1144
+ end
1145
+ mappings[sub_dir] ||= []
1146
+ mappings[sub_dir] << header
1147
+ end
1148
+ mappings
1149
+ end
1150
+
1151
+ # @!group Deprecated APIs
1152
+ # ----------------------------------------------------------------------- #
1153
+
1154
+ public
1155
+
1156
+ # @deprecated Use `test_app_hosts_by_spec` instead.
1157
+ #
1158
+ # @todo Remove in 2.0
1159
+ #
1160
+ # @return [Hash{String => (Specification,PodTarget)}] tuples of app specs and pod targets by test spec name.
1161
+ #
1162
+ def test_app_hosts_by_spec_name
1163
+ Hash[test_app_hosts_by_spec.map do |spec, value|
1164
+ [spec.name, value]
1165
+ end]
1166
+ end
1167
+ end
1168
+ end