cocoapods 1.5.2 → 1.6.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (81) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +365 -1
  3. data/bin/pod +1 -1
  4. data/lib/cocoapods/command/cache/clean.rb +1 -1
  5. data/lib/cocoapods/command/init.rb +4 -2
  6. data/lib/cocoapods/command/install.rb +7 -0
  7. data/lib/cocoapods/command/lib/lint.rb +8 -1
  8. data/lib/cocoapods/command/outdated.rb +4 -9
  9. data/lib/cocoapods/command/repo/add.rb +1 -1
  10. data/lib/cocoapods/command/repo/list.rb +1 -1
  11. data/lib/cocoapods/command/repo/push.rb +17 -12
  12. data/lib/cocoapods/command/repo/remove.rb +1 -1
  13. data/lib/cocoapods/command/repo/update.rb +1 -1
  14. data/lib/cocoapods/command/setup.rb +1 -1
  15. data/lib/cocoapods/command/spec/create.rb +39 -39
  16. data/lib/cocoapods/command/spec/lint.rb +8 -1
  17. data/lib/cocoapods/command.rb +3 -1
  18. data/lib/cocoapods/config.rb +13 -2
  19. data/lib/cocoapods/downloader/cache.rb +1 -1
  20. data/lib/cocoapods/executable.rb +3 -3
  21. data/lib/cocoapods/external_sources/abstract_external_source.rb +23 -13
  22. data/lib/cocoapods/external_sources.rb +7 -4
  23. data/lib/cocoapods/gem_version.rb +1 -1
  24. data/lib/cocoapods/generator/acknowledgements/markdown.rb +6 -0
  25. data/lib/cocoapods/generator/acknowledgements/plist.rb +13 -2
  26. data/lib/cocoapods/generator/app_target_helper.rb +141 -17
  27. data/lib/cocoapods/generator/copy_resources_script.rb +14 -3
  28. data/lib/cocoapods/generator/dummy_source.rb +14 -5
  29. data/lib/cocoapods/generator/embed_frameworks_script.rb +37 -20
  30. data/lib/cocoapods/generator/header.rb +1 -1
  31. data/lib/cocoapods/generator/info_plist_file.rb +12 -4
  32. data/lib/cocoapods/generator/prefix_header.rb +2 -2
  33. data/lib/cocoapods/hooks_manager.rb +28 -17
  34. data/lib/cocoapods/installer/analyzer/analysis_result.rb +52 -22
  35. data/lib/cocoapods/installer/analyzer/locking_dependency_analyzer.rb +14 -6
  36. data/lib/cocoapods/installer/analyzer/pod_variant.rb +4 -5
  37. data/lib/cocoapods/installer/analyzer/sandbox_analyzer.rb +3 -14
  38. data/lib/cocoapods/installer/analyzer/specs_state.rb +28 -4
  39. data/lib/cocoapods/installer/analyzer/target_inspection_result.rb +27 -14
  40. data/lib/cocoapods/installer/analyzer/target_inspector.rb +17 -11
  41. data/lib/cocoapods/installer/analyzer.rb +391 -284
  42. data/lib/cocoapods/installer/installation_options.rb +2 -0
  43. data/lib/cocoapods/installer/pod_source_installer.rb +31 -43
  44. data/lib/cocoapods/installer/post_install_hooks_context.rb +72 -47
  45. data/lib/cocoapods/installer/pre_install_hooks_context.rb +22 -13
  46. data/lib/cocoapods/installer/source_provider_hooks_context.rb +3 -1
  47. data/lib/cocoapods/installer/user_project_integrator/target_integrator/xcconfig_integrator.rb +44 -11
  48. data/lib/cocoapods/installer/user_project_integrator/target_integrator.rb +69 -29
  49. data/lib/cocoapods/installer/user_project_integrator.rb +6 -4
  50. data/lib/cocoapods/installer/xcode/pods_project_generator/aggregate_target_installer.rb +25 -16
  51. data/lib/cocoapods/installer/xcode/pods_project_generator/app_host_installer.rb +104 -0
  52. data/lib/cocoapods/installer/xcode/pods_project_generator/file_references_installer.rb +23 -50
  53. data/lib/cocoapods/installer/xcode/pods_project_generator/pod_target_installer.rb +296 -177
  54. data/lib/cocoapods/installer/xcode/pods_project_generator/pod_target_integrator.rb +51 -33
  55. data/lib/cocoapods/installer/xcode/pods_project_generator/target_installation_result.rb +93 -0
  56. data/lib/cocoapods/installer/xcode/pods_project_generator/target_installer.rb +62 -69
  57. data/lib/cocoapods/installer/xcode/pods_project_generator/target_installer_helper.rb +72 -0
  58. data/lib/cocoapods/installer/xcode/pods_project_generator.rb +130 -122
  59. data/lib/cocoapods/installer/xcode/target_validator.rb +15 -9
  60. data/lib/cocoapods/installer.rb +140 -63
  61. data/lib/cocoapods/project.rb +16 -14
  62. data/lib/cocoapods/resolver/resolver_specification.rb +41 -0
  63. data/lib/cocoapods/resolver.rb +79 -98
  64. data/lib/cocoapods/sandbox/file_accessor.rb +11 -6
  65. data/lib/cocoapods/sandbox/headers_store.rb +9 -8
  66. data/lib/cocoapods/sandbox/path_list.rb +5 -8
  67. data/lib/cocoapods/sandbox.rb +31 -43
  68. data/lib/cocoapods/sources_manager.rb +1 -1
  69. data/lib/cocoapods/target/aggregate_target.rb +143 -85
  70. data/lib/cocoapods/target/build_settings.rb +1124 -0
  71. data/lib/cocoapods/target/framework_paths.rb +36 -0
  72. data/lib/cocoapods/target/pod_target.rb +198 -295
  73. data/lib/cocoapods/target.rb +92 -37
  74. data/lib/cocoapods/user_interface.rb +5 -0
  75. data/lib/cocoapods/validator.rb +149 -44
  76. data/lib/cocoapods.rb +0 -1
  77. metadata +31 -23
  78. data/lib/cocoapods/generator/xcconfig/aggregate_xcconfig.rb +0 -260
  79. data/lib/cocoapods/generator/xcconfig/pod_xcconfig.rb +0 -87
  80. data/lib/cocoapods/generator/xcconfig/xcconfig_helper.rb +0 -558
  81. data/lib/cocoapods/generator/xcconfig.rb +0 -13
@@ -6,75 +6,108 @@ module Pod
6
6
  # relative support files.
7
7
  #
8
8
  class PodTargetInstaller < TargetInstaller
9
+ require 'cocoapods/installer/xcode/pods_project_generator/app_host_installer'
10
+
11
+ # @return [Array<Pathname>] Array of umbrella header paths in the headers directory
12
+ #
13
+ attr_reader :umbrella_header_paths
14
+
15
+ # Initialize a new instance
16
+ #
17
+ # @param [Sandbox] sandbox @see TargetInstaller#sandbox
18
+ # @param [Pod::Project] project @see TargetInstaller#project
19
+ # @param [Target] target @see TargetInstaller#target
20
+ # @param [Array<Pathname>] umbrella_header_paths @see #umbrella_header_paths
21
+ #
22
+ def initialize(sandbox, project, target, umbrella_header_paths = nil)
23
+ super(sandbox, project, target)
24
+ @umbrella_header_paths = umbrella_header_paths
25
+ end
26
+
9
27
  # Creates the target in the Pods project and the relative support files.
10
28
  #
11
- # @return [void]
29
+ # @return [TargetInstallationResult] the result of the installation of this target.
12
30
  #
13
31
  def install!
14
- unless target.should_build?
15
- add_resources_bundle_targets
16
- return
17
- end
18
-
19
32
  UI.message "- Installing target `#{target.name}` #{target.platform}" do
20
- add_target
21
33
  create_support_files_dir
22
- if target.contains_test_specifications?
23
- add_test_targets
24
- add_test_app_host_targets
34
+ test_file_accessors, file_accessors = target.file_accessors.partition { |fa| fa.spec.test_specification? }
35
+
36
+ unless target.should_build?
37
+ # For targets that should not be built (e.g. pre-built vendored frameworks etc), we add a placeholder
38
+ # PBXAggregateTarget that will be used to wire up dependencies later.
39
+ native_target = add_placeholder_target
40
+ resource_bundle_targets = add_resources_bundle_targets(file_accessors).values.flatten
41
+ create_xcconfig_file(native_target, resource_bundle_targets)
42
+ return TargetInstallationResult.new(target, native_target, resource_bundle_targets)
25
43
  end
26
- add_resources_bundle_targets
27
- add_files_to_build_phases
28
- create_xcconfig_file
29
- create_test_xcconfig_files if target.contains_test_specifications?
44
+
45
+ native_target = add_target
46
+ resource_bundle_targets = add_resources_bundle_targets(file_accessors).values.flatten
47
+
48
+ test_native_targets = add_test_targets
49
+ test_app_host_targets = add_test_app_host_targets(test_native_targets)
50
+ test_resource_bundle_targets = add_resources_bundle_targets(test_file_accessors)
51
+
52
+ add_files_to_build_phases(native_target, test_native_targets)
53
+ validate_targets_contain_sources(test_native_targets + [native_target])
54
+
55
+ create_xcconfig_file(native_target, resource_bundle_targets)
56
+ create_test_xcconfig_files(test_native_targets, test_resource_bundle_targets)
30
57
 
31
58
  if target.defines_module?
32
- create_module_map do |generator|
59
+ create_module_map(native_target) do |generator|
33
60
  generator.headers.concat module_map_additional_headers
34
61
  end
35
- create_umbrella_header do |generator|
36
- file_accessors = target.file_accessors
37
- file_accessors = file_accessors.reject { |f| f.spec.test_specification? } if target.contains_test_specifications?
38
- generator.imports += if header_mappings_dir
39
- file_accessors.flat_map(&:public_headers).map do |pathname|
40
- pathname.relative_path_from(header_mappings_dir)
41
- end
42
- else
43
- file_accessors.flat_map(&:public_headers).map(&:basename)
62
+ create_umbrella_header(native_target) do |generator|
63
+ generator.imports += file_accessors.flat_map do |file_accessor|
64
+ header_dir = if !target.requires_frameworks? && dir = file_accessor.spec_consumer.header_dir
65
+ Pathname.new(dir)
66
+ end
67
+
68
+ file_accessor.public_headers.map do |public_header|
69
+ public_header = if header_mappings_dir
70
+ public_header.relative_path_from(header_mappings_dir)
71
+ else
72
+ public_header.basename
44
73
  end
74
+ if header_dir
75
+ public_header = header_dir.join(public_header)
76
+ end
77
+ public_header
78
+ end
79
+ end
45
80
  end
46
81
  end
47
82
 
48
83
  if target.requires_frameworks?
49
- unless target.static_framework?
84
+ unless skip_info_plist?(native_target)
50
85
  create_info_plist_file(target.info_plist_path, native_target, target.version, target.platform)
51
86
  end
52
- create_build_phase_to_symlink_header_folders
87
+ create_build_phase_to_symlink_header_folders(native_target)
53
88
  elsif target.uses_swift?
54
- add_swift_static_library_compatibility_header_phase
89
+ add_swift_static_library_compatibility_header_phase(native_target)
55
90
  end
56
91
 
57
92
  unless skip_pch?(target.non_test_specs)
58
93
  path = target.prefix_header_path
59
- file_accessors = target.file_accessors.reject { |f| f.spec.test_specification? }
60
- create_prefix_header(path, file_accessors, target.platform, [native_target])
94
+ create_prefix_header(path, file_accessors, target.platform, native_target)
61
95
  end
62
96
  unless skip_pch?(target.test_specs)
63
- target.supported_test_types.each do |test_type|
64
- path = target.prefix_header_path_for_test_type(test_type)
65
- file_accessors = target.file_accessors.select { |f| f.spec.test_specification? }
66
- create_prefix_header(path, file_accessors, target.platform, target.test_native_targets)
97
+ target.test_specs.each do |test_spec|
98
+ path = target.prefix_header_path_for_test_spec(test_spec)
99
+ test_spec_consumer = test_spec.consumer(target.platform)
100
+ test_native_target = test_native_target_from_spec_consumer(test_spec_consumer, test_native_targets)
101
+ create_prefix_header(path, test_file_accessors, target.platform, test_native_target)
67
102
  end
68
103
  end
69
- create_dummy_source
104
+ create_dummy_source(native_target)
105
+ clean_support_files_temp_dir
106
+ TargetInstallationResult.new(target, native_target, resource_bundle_targets, test_native_targets,
107
+ test_resource_bundle_targets, test_app_host_targets)
70
108
  end
71
109
  end
72
110
 
73
- # @return [Hash<Pathname,Pathname>] A hash of all umbrella headers, grouped by the directory
74
- # the are stored in
75
- #
76
- attr_accessor :umbrella_headers_by_dir
77
-
78
111
  private
79
112
 
80
113
  # @param [Array<Specification>] specs
@@ -86,6 +119,17 @@ module Pod
86
119
  specs.any? { |spec| spec.prefix_header_file.is_a?(FalseClass) }
87
120
  end
88
121
 
122
+ # True if info.plist generation should be skipped
123
+ #
124
+ # @param [PXNativeTarget] native_target
125
+ #
126
+ # @return [Boolean] Whether the target should build an Info.plist file
127
+ #
128
+ def skip_info_plist?(native_target)
129
+ existing_setting = native_target.resolved_build_setting('INFOPLIST_FILE', true).values.compact
130
+ !existing_setting.empty?
131
+ end
132
+
89
133
  # Remove the default headers folder path settings for static library pod
90
134
  # targets.
91
135
  #
@@ -158,8 +202,6 @@ module Pod
158
202
 
159
203
  #-----------------------------------------------------------------------#
160
204
 
161
- SOURCE_FILE_EXTENSIONS = Sandbox::FileAccessor::SOURCE_FILE_EXTENSIONS
162
-
163
205
  # Adds the build files of the pods to the target and adds a reference to
164
206
  # the frameworks of the Pods.
165
207
  #
@@ -173,20 +215,26 @@ module Pod
173
215
  #
174
216
  # @return [void]
175
217
  #
176
- def add_files_to_build_phases
218
+ def add_files_to_build_phases(native_target, test_native_targets)
177
219
  target.file_accessors.each do |file_accessor|
178
220
  consumer = file_accessor.spec_consumer
179
221
 
180
- native_target = target.native_target_for_spec(consumer.spec)
222
+ native_target = if !consumer.spec.test_specification?
223
+ native_target
224
+ else
225
+ test_native_target_from_spec_consumer(consumer, test_native_targets)
226
+ end
227
+
181
228
  headers = file_accessor.headers
182
229
  public_headers = file_accessor.public_headers.map(&:realpath)
183
230
  private_headers = file_accessor.private_headers.map(&:realpath)
184
- other_source_files = file_accessor.source_files.reject { |sf| SOURCE_FILE_EXTENSIONS.include?(sf.extname) }
231
+ other_source_files = file_accessor.other_source_files
185
232
 
186
233
  {
187
234
  true => file_accessor.arc_source_files,
188
235
  false => file_accessor.non_arc_source_files,
189
236
  }.each do |arc, files|
237
+ next if files.empty?
190
238
  files = files - headers - other_source_files
191
239
  flags = compiler_flags_for_consumer(consumer, arc)
192
240
  regular_file_refs = project_file_references_array(files, 'source')
@@ -210,62 +258,27 @@ module Pod
210
258
  end
211
259
  end
212
260
 
213
- # Adds the test app host targets for the library to the Pods project with the
214
- # appropriate build configurations.
215
- #
216
- # @return [void]
217
- #
218
- def add_test_app_host_targets
219
- target.test_specs.each do |test_spec|
220
- next unless test_spec.consumer(target.platform).requires_app_host?
221
- name = target.app_host_label(test_spec.test_type)
222
- platform_name = target.platform.name
223
- app_host_target = project.targets.find { |t| t.name == name }
224
- if app_host_target.nil?
225
- app_host_target = Pod::Generator::AppTargetHelper.add_app_target(project, platform_name, deployment_target, name)
226
- app_host_target.build_configurations.each do |configuration|
227
- configuration.build_settings.merge!(custom_build_settings)
228
- configuration.build_settings['PRODUCT_NAME'] = name
229
- configuration.build_settings['PRODUCT_BUNDLE_IDENTIFIER'] = 'org.cocoapods.${PRODUCT_NAME:rfc1034identifier}'
230
- configuration.build_settings['CODE_SIGN_IDENTITY'] = '' if target.platform == :osx
231
- end
232
- Pod::Generator::AppTargetHelper.add_app_host_main_file(project, app_host_target, platform_name, name)
233
- app_host_info_plist_path = project.path.dirname.+("#{name}/Info.plist")
234
- create_info_plist_file(app_host_info_plist_path, app_host_target, '1.0.0', target.platform, :appl)
235
- end
236
- # Wire all test native targets with the app host.
237
- native_test_target = target.native_target_for_spec(test_spec)
238
- native_test_target.build_configurations.each do |configuration|
239
- test_host = "$(BUILT_PRODUCTS_DIR)/#{name}.app/"
240
- test_host << 'Contents/MacOS/' if target.platform == :osx
241
- test_host << name.to_s
242
- configuration.build_settings['TEST_HOST'] = test_host
243
- end
244
- target_attributes = project.root_object.attributes['TargetAttributes'] || {}
245
- target_attributes[native_test_target.uuid.to_s] = { 'TestTargetID' => app_host_target.uuid.to_s }
246
- project.root_object.attributes['TargetAttributes'] = target_attributes
247
- end
248
- end
249
-
250
261
  # Adds the test targets for the library to the Pods project with the
251
262
  # appropriate build configurations.
252
263
  #
253
- # @return [void]
264
+ # @return [Array<PBXNativeTarget>] the test native targets created.
254
265
  #
255
266
  def add_test_targets
256
- target.supported_test_types.each do |test_type|
267
+ target.test_specs.map do |test_spec|
268
+ spec_consumer = test_spec.consumer(target.platform)
269
+ test_type = spec_consumer.test_type
257
270
  product_type = target.product_type_for_test_type(test_type)
258
- name = target.test_target_label(test_type)
271
+ name = target.test_target_label(test_spec)
259
272
  platform_name = target.platform.name
260
- language = target.all_dependent_targets.any?(&:uses_swift?) ? :swift : :objc
261
- native_test_target = project.new_target(product_type, name, platform_name, deployment_target, nil, language)
262
- native_test_target.product_reference.name = name
273
+ language = target.uses_swift_for_test_spec?(test_spec) ? :swift : :objc
274
+ test_native_target = project.new_target(product_type, name, platform_name, deployment_target, nil, language)
275
+ test_native_target.product_reference.name = name
263
276
 
264
277
  target.user_build_configurations.each do |bc_name, type|
265
- native_test_target.add_build_configuration(bc_name, type)
278
+ test_native_target.add_build_configuration(bc_name, type)
266
279
  end
267
280
 
268
- native_test_target.build_configurations.each do |configuration|
281
+ test_native_target.build_configurations.each do |configuration|
269
282
  configuration.build_settings.merge!(custom_build_settings)
270
283
  # target_installer will automatically add an empty `OTHER_LDFLAGS`. For test
271
284
  # targets those are set via a test xcconfig file instead.
@@ -274,6 +287,9 @@ module Pod
274
287
  # requires frameworks. For tests we always use the test target name as the product name
275
288
  # irrelevant to whether we use frameworks or not.
276
289
  configuration.build_settings['PRODUCT_NAME'] = name
290
+ # target_installer sets 'MACH_O_TYPE' for static frameworks ensure this does not propagate
291
+ # to test target.
292
+ configuration.build_settings.delete('MACH_O_TYPE')
277
293
  # Use xcode default product module name, which is $(PRODUCT_NAME:c99extidentifier)
278
294
  # this gives us always valid name that is distinct from the parent spec module name
279
295
  # which allow tests to use either import or @testable import to access the parent framework
@@ -288,15 +304,46 @@ module Pod
288
304
  end
289
305
 
290
306
  # Test native targets also need frameworks and resources to be copied over to their xctest bundle.
291
- create_test_target_embed_frameworks_script(test_type)
292
- create_test_target_copy_resources_script(test_type)
307
+ create_test_target_embed_frameworks_script(test_spec)
308
+ create_test_target_copy_resources_script(test_spec)
293
309
 
294
- # Generate vanila Info.plist for test target similar to the one xcode gererates for new test target.
310
+ # Generate vanilla Info.plist for test target similar to the one Xcode generates for new test target.
295
311
  # This creates valid test bundle accessible at the runtime, allowing tests to load bundle resources
296
312
  # defined in podspec.
297
- create_info_plist_file(target.info_plist_path_for_test_type(test_type), native_test_target, '1.0', target.platform, :bndl)
313
+ create_info_plist_file(target.info_plist_path_for_test_spec(test_spec), test_native_target, '1.0', target.platform, :bndl)
314
+
315
+ test_native_target
316
+ end
317
+ end
298
318
 
299
- target.test_native_targets << native_test_target
319
+ # Adds the test app host targets for the library to the Pods project with the
320
+ # appropriate build configurations.
321
+ #
322
+ # @param [Array<PBXNativeTarget>] test_native_targets
323
+ # the test native targets that have been created to use as a lookup when linking the app host to.
324
+ #
325
+ # @return [Array<PBXNativeTarget>] the app host targets created.
326
+ #
327
+ def add_test_app_host_targets(test_native_targets)
328
+ target.test_spec_consumers.select(&:requires_app_host?).group_by(&:test_type).map do |test_type, test_spec_consumers|
329
+ platform = target.platform
330
+ name = "AppHost-#{target.label}-#{test_type.capitalize}-Tests"
331
+ app_host_target = AppHostInstaller.new(sandbox, project, platform, name, target.pod_name).install!
332
+ # Wire test native targets to the generated app host.
333
+ test_spec_consumers.each do |test_spec_consumer|
334
+ test_native_target = test_native_target_from_spec_consumer(test_spec_consumer, test_native_targets)
335
+ test_native_target.build_configurations.each do |configuration|
336
+ test_host = "$(BUILT_PRODUCTS_DIR)/#{app_host_target.name}.app/"
337
+ test_host << 'Contents/MacOS/' if platform == :osx
338
+ test_host << app_host_target.name.to_s
339
+ configuration.build_settings['TEST_HOST'] = test_host
340
+ end
341
+ target_attributes = project.root_object.attributes['TargetAttributes'] || {}
342
+ target_attributes[test_native_target.uuid.to_s] = { 'TestTargetID' => app_host_target.uuid.to_s }
343
+ project.root_object.attributes['TargetAttributes'] = target_attributes
344
+ test_native_target.add_dependency(app_host_target)
345
+ end
346
+ app_host_target
300
347
  end
301
348
  end
302
349
 
@@ -305,58 +352,53 @@ module Pod
305
352
  # @note The source files are grouped by Pod and in turn by subspec
306
353
  # (recursively) in the resources group.
307
354
  #
308
- # @return [void]
355
+ # @param [Array<Sandbox::FileAccessor>] file_accessors
356
+ # the file accessors list to generate resource bundles for.
309
357
  #
310
- def add_resources_bundle_targets
311
- target.file_accessors.each do |file_accessor|
312
- file_accessor.resource_bundles.each do |bundle_name, paths|
358
+ # @return [Array<PBXNativeTarget] the resource bundle native targets created.
359
+ #
360
+ def add_resources_bundle_targets(file_accessors)
361
+ file_accessors.each_with_object({}) do |file_accessor, hash|
362
+ hash[file_accessor.spec.name] = file_accessor.resource_bundles.map do |bundle_name, paths|
313
363
  label = target.resources_bundle_target_label(bundle_name)
314
- bundle_target = project.new_resources_bundle(label, file_accessor.spec_consumer.platform_name)
315
- bundle_target.product_reference.tap do |bundle_product|
364
+ resource_bundle_target = project.new_resources_bundle(label, file_accessor.spec_consumer.platform_name)
365
+ resource_bundle_target.product_reference.tap do |bundle_product|
316
366
  bundle_file_name = "#{bundle_name}.bundle"
317
367
  bundle_product.name = bundle_file_name
318
368
  end
319
369
 
370
+ contains_compile_phase_refs = false
320
371
  filter_resource_file_references(paths) do |resource_phase_refs, compile_phase_refs|
321
372
  # Resource bundles are only meant to have resources, so install everything
322
373
  # into the resources phase. See note in filter_resource_file_references.
323
- bundle_target.add_resources(resource_phase_refs + compile_phase_refs)
374
+ resource_bundle_target.add_resources(resource_phase_refs + compile_phase_refs)
375
+ contains_compile_phase_refs = !compile_phase_refs.empty?
324
376
  end
325
377
 
326
- native_target = target.native_target_for_spec(file_accessor.spec_consumer.spec)
327
378
  target.user_build_configurations.each do |bc_name, type|
328
- bundle_target.add_build_configuration(bc_name, type)
329
- end
330
- bundle_target.deployment_target = deployment_target
331
-
332
- test_specification = file_accessor.spec.test_specification?
333
-
334
- if test_specification
335
- target.test_resource_bundle_targets << bundle_target
336
- else
337
- target.resource_bundle_targets << bundle_target
338
- end
339
-
340
- if target.should_build?
341
- native_target.add_dependency(bundle_target)
342
- if target.requires_frameworks?
343
- native_target.add_resources([bundle_target.product_reference])
344
- end
379
+ resource_bundle_target.add_build_configuration(bc_name, type)
345
380
  end
381
+ resource_bundle_target.deployment_target = deployment_target
346
382
 
347
383
  # Create Info.plist file for bundle
348
384
  path = target.info_plist_path
349
385
  path.dirname.mkdir unless path.dirname.exist?
350
386
  info_plist_path = path.dirname + "ResourceBundle-#{bundle_name}-#{path.basename}"
351
- create_info_plist_file(info_plist_path, bundle_target, target.version, target.platform, :bndl)
387
+ create_info_plist_file(info_plist_path, resource_bundle_target, target.version, target.platform, :bndl)
352
388
 
353
- bundle_target.build_configurations.each do |c|
354
- c.build_settings['PRODUCT_NAME'] = bundle_name
389
+ resource_bundle_target.build_configurations.each do |configuration|
390
+ configuration.build_settings['PRODUCT_NAME'] = bundle_name
355
391
  # Do not set the CONFIGURATION_BUILD_DIR for resource bundles that are only meant for test targets.
356
392
  # This is because the test target itself also does not set this configuration build dir and it expects
357
393
  # all bundles to be copied from the default path.
358
- unless test_specification
359
- c.build_settings['CONFIGURATION_BUILD_DIR'] = target.configuration_build_dir('$(BUILD_DIR)/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)')
394
+ unless file_accessor.spec.test_specification?
395
+ configuration.build_settings['CONFIGURATION_BUILD_DIR'] = target.configuration_build_dir('$(BUILD_DIR)/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)')
396
+ end
397
+
398
+ # Set the `SWIFT_VERSION` build setting for resource bundles that could have resources that get
399
+ # compiled such as an `xcdatamodeld` file which has 'Swift' as its code generation language.
400
+ if contains_compile_phase_refs && target.uses_swift?
401
+ configuration.build_settings['SWIFT_VERSION'] = target.swift_version
360
402
  end
361
403
 
362
404
  # Set the correct device family for this bundle, based on the platform
@@ -367,21 +409,28 @@ module Pod
367
409
  }
368
410
 
369
411
  if (family = device_family_by_platform[target.platform.name])
370
- c.build_settings['TARGETED_DEVICE_FAMILY'] = family
412
+ configuration.build_settings['TARGETED_DEVICE_FAMILY'] = family
371
413
  end
372
414
  end
415
+
416
+ resource_bundle_target
373
417
  end
374
418
  end
375
419
  end
376
420
 
377
421
  # Generates the contents of the xcconfig file and saves it to disk.
378
422
  #
423
+ # @param [PBXNativeTarget] native_target
424
+ # the native target to link the xcconfig file into.
425
+ #
426
+ # @param [Array<PBXNativeTarget>] resource_bundle_targets
427
+ # the additional resource bundle targets to link the xcconfig file into.
428
+ #
379
429
  # @return [void]
380
430
  #
381
- def create_xcconfig_file
431
+ def create_xcconfig_file(native_target, resource_bundle_targets)
382
432
  path = target.xcconfig_path
383
- xcconfig_gen = Generator::XCConfig::PodXCConfig.new(target)
384
- update_changed_file(xcconfig_gen, path)
433
+ update_changed_file(target.build_settings, path)
385
434
  xcconfig_file_ref = add_file_to_support_group(path)
386
435
 
387
436
  native_target.build_configurations.each do |c|
@@ -389,46 +438,56 @@ module Pod
389
438
  end
390
439
 
391
440
  # also apply the private config to resource bundle targets.
392
- apply_xcconfig_file_ref_to_resource_bundle_targets(target.resource_bundle_targets, xcconfig_file_ref)
441
+ apply_xcconfig_file_ref_to_resource_bundle_targets(resource_bundle_targets, xcconfig_file_ref)
393
442
  end
394
443
 
395
444
  # Generates the contents of the xcconfig file used for each test target type and saves it to disk.
396
445
  #
446
+ # @param [Array<PBXNativeTarget>] test_native_targets
447
+ # the test native target to link the xcconfig file into.
448
+ #
449
+ # @param [Hash{String=>Array<PBXNativeTarget>}] test_resource_bundle_targets
450
+ # the additional test resource bundle targets to link the xcconfig file into.
451
+ #
397
452
  # @return [void]
398
453
  #
399
- def create_test_xcconfig_files
400
- target.supported_test_types.each do |test_type|
401
- path = target.xcconfig_path(test_type.to_s)
402
- xcconfig_gen = Generator::XCConfig::PodXCConfig.new(target, true)
403
- update_changed_file(xcconfig_gen, path)
404
- xcconfig_file_ref = add_file_to_support_group(path)
405
-
406
- target.test_native_targets.each do |test_target|
407
- test_target.build_configurations.each do |test_target_bc|
408
- test_target_swift_debug_hack(test_target_bc)
409
- test_target_bc.base_configuration_reference = xcconfig_file_ref
410
- end
454
+ def create_test_xcconfig_files(test_native_targets, test_resource_bundle_targets)
455
+ target.test_specs.each do |test_spec|
456
+ spec_consumer = test_spec.consumer(target.platform)
457
+ test_type = spec_consumer.test_type
458
+ path = target.xcconfig_path("#{test_type.capitalize}-#{test_spec.name.split('/')[1..-1].join('-')}")
459
+ update_changed_file(Target::BuildSettings::PodTargetSettings.new(target, test_spec), path)
460
+ test_xcconfig_file_ref = add_file_to_support_group(path)
461
+
462
+ test_native_target = test_native_target_from_spec_consumer(spec_consumer, test_native_targets)
463
+ test_native_target.build_configurations.each do |test_native_target_bc|
464
+ test_target_swift_debug_hack(test_spec, test_native_target_bc)
465
+ test_native_target_bc.base_configuration_reference = test_xcconfig_file_ref
411
466
  end
412
467
 
413
- # also apply the private config to resource bundle test targets.
414
- apply_xcconfig_file_ref_to_resource_bundle_targets(target.test_resource_bundle_targets, xcconfig_file_ref)
468
+ # also apply the private config to resource bundle test targets related to this test spec.
469
+ scoped_test_resource_bundle_targets = test_resource_bundle_targets[test_spec.name]
470
+ unless scoped_test_resource_bundle_targets.empty?
471
+ apply_xcconfig_file_ref_to_resource_bundle_targets(scoped_test_resource_bundle_targets, test_xcconfig_file_ref)
472
+ end
415
473
  end
416
474
  end
417
475
 
418
476
  # Creates a script that copies the resources to the bundle of the test target.
419
477
  #
420
- # @param [Symbol] test_type
421
- # The test type to create the script for.
478
+ # @param [Specification] test_spec
479
+ # The test spec to create the copy resources script for.
422
480
  #
423
481
  # @return [void]
424
482
  #
425
- def create_test_target_copy_resources_script(test_type)
426
- path = target.copy_resources_script_path_for_test_type(test_type)
427
- pod_targets = target.all_dependent_targets
483
+ def create_test_target_copy_resources_script(test_spec)
484
+ path = target.copy_resources_script_path_for_test_spec(test_spec)
485
+ pod_targets = target.dependent_targets_for_test_spec(test_spec)
428
486
  resource_paths_by_config = target.user_build_configurations.keys.each_with_object({}) do |config, resources_by_config|
429
487
  resources_by_config[config] = pod_targets.flat_map do |pod_target|
430
- include_test_spec_paths = pod_target == target
431
- pod_target.resource_paths(include_test_spec_paths)
488
+ spec_paths_to_include = pod_target.non_test_specs.map(&:name)
489
+ spec_paths_to_include << test_spec.name if pod_target == target
490
+ pod_target.resource_paths.values_at(*spec_paths_to_include).flatten.compact
432
491
  end
433
492
  end
434
493
  generator = Generator::CopyResourcesScript.new(resource_paths_by_config, target.platform)
@@ -438,18 +497,19 @@ module Pod
438
497
 
439
498
  # Creates a script that embeds the frameworks to the bundle of the test target.
440
499
  #
441
- # @param [Symbol] test_type
442
- # The test type to create the script for.
500
+ # @param [Specification] test_spec
501
+ # The test spec to create the embed frameworks script for.
443
502
  #
444
503
  # @return [void]
445
504
  #
446
- def create_test_target_embed_frameworks_script(test_type)
447
- path = target.embed_frameworks_script_path_for_test_type(test_type)
448
- pod_targets = target.all_dependent_targets
505
+ def create_test_target_embed_frameworks_script(test_spec)
506
+ path = target.embed_frameworks_script_path_for_test_spec(test_spec)
507
+ pod_targets = target.dependent_targets_for_test_spec(test_spec)
449
508
  framework_paths_by_config = target.user_build_configurations.keys.each_with_object({}) do |config, paths_by_config|
450
509
  paths_by_config[config] = pod_targets.flat_map do |pod_target|
451
- include_test_spec_paths = pod_target == target
452
- pod_target.framework_paths(include_test_spec_paths)
510
+ spec_paths_to_include = pod_target.non_test_specs.map(&:name)
511
+ spec_paths_to_include << test_spec.name if pod_target == target
512
+ pod_target.framework_paths.values_at(*spec_paths_to_include).flatten.compact.uniq
453
513
  end
454
514
  end
455
515
  generator = Generator::EmbedFrameworksScript.new(framework_paths_by_config)
@@ -462,9 +522,9 @@ module Pod
462
522
  #
463
523
  # @return [void]
464
524
  #
465
- def test_target_swift_debug_hack(test_target_bc)
525
+ def test_target_swift_debug_hack(test_spec, test_target_bc)
466
526
  return unless test_target_bc.debug?
467
- return unless target.all_dependent_targets.any?(&:uses_swift?)
527
+ return unless target.dependent_targets_for_test_spec(test_spec).any?(&:uses_swift?)
468
528
  ldflags = test_target_bc.build_settings['OTHER_LDFLAGS'] ||= '$(inherited)'
469
529
  ldflags << ' -lswiftSwiftOnoneSupport'
470
530
  end
@@ -476,9 +536,12 @@ module Pod
476
536
  # header_mappings_dir interferes with xcodebuild's expectations
477
537
  # about the existence of private or public headers.
478
538
  #
539
+ # @param [PBXNativeTarget] native_target
540
+ # the native target to add the script phase into.
541
+ #
479
542
  # @return [void]
480
543
  #
481
- def create_build_phase_to_symlink_header_folders
544
+ def create_build_phase_to_symlink_header_folders(native_target)
482
545
  return unless target.platform.name == :osx && header_mappings_dir
483
546
 
484
547
  build_phase = native_target.new_shell_script_build_phase('Create Symlinks to Header Folders')
@@ -502,21 +565,19 @@ module Pod
502
565
  # @param [Platform] platform
503
566
  # the platform to use for this prefix header.
504
567
  #
505
- # @param [Array<PBXNativetarget>] native_targets
506
- # the native targets on which the prefix header should be configured for.
568
+ # @param [PBXNativeTarget] native_target
569
+ # the native target on which the prefix header should be configured for.
507
570
  #
508
571
  # @return [void]
509
572
  #
510
- def create_prefix_header(path, file_accessors, platform, native_targets)
573
+ def create_prefix_header(path, file_accessors, platform, native_target)
511
574
  generator = Generator::PrefixHeader.new(file_accessors, platform)
512
575
  update_changed_file(generator, path)
513
576
  add_file_to_support_group(path)
514
577
 
515
- native_targets.each do |native_target|
516
- native_target.build_configurations.each do |c|
517
- relative_path = path.relative_path_from(project.path.dirname)
518
- c.build_settings['GCC_PREFIX_HEADER'] = relative_path.to_s
519
- end
578
+ relative_path = path.relative_path_from(project.path.dirname)
579
+ native_target.build_configurations.each do |c|
580
+ c.build_settings['GCC_PREFIX_HEADER'] = relative_path.to_s
520
581
  end
521
582
  end
522
583
 
@@ -587,10 +648,10 @@ module Pod
587
648
  end
588
649
  end
589
650
 
590
- def create_module_map
591
- return super unless custom_module_map
651
+ def create_module_map(native_target)
652
+ return super(native_target) unless custom_module_map
592
653
 
593
- path = target.module_map_path
654
+ path = target.module_map_path_to_write
594
655
  UI.message "- Copying module map file to #{UI.path(path)}" do
595
656
  contents = custom_module_map.read
596
657
  unless target.requires_frameworks?
@@ -600,17 +661,24 @@ module Pod
600
661
  update_changed_file(generator, path)
601
662
  add_file_to_support_group(path)
602
663
 
664
+ linked_path = target.module_map_path
665
+ if path != linked_path
666
+ linked_path.dirname.mkpath
667
+ source = path.relative_path_from(linked_path.dirname)
668
+ FileUtils.ln_sf(source, linked_path)
669
+ end
670
+
671
+ relative_path = target.module_map_path.relative_path_from(sandbox.root).to_s
603
672
  native_target.build_configurations.each do |c|
604
- relative_path = path.relative_path_from(sandbox.root)
605
673
  c.build_settings['MODULEMAP_FILE'] = relative_path.to_s
606
674
  end
607
675
  end
608
676
  end
609
677
 
610
678
  def module_map_additional_headers
611
- return [] unless umbrella_headers_by_dir
679
+ return [] unless umbrella_header_paths
612
680
 
613
- other_paths = umbrella_headers_by_dir[target.module_map_path.dirname] - [target.umbrella_header_path]
681
+ other_paths = umbrella_header_paths - [target.umbrella_header_path]
614
682
  other_paths.map do |module_map_path|
615
683
  # exclude other targets umbrella headers, to avoid
616
684
  # incomplete umbrella warnings
@@ -618,8 +686,8 @@ module Pod
618
686
  end
619
687
  end
620
688
 
621
- def create_umbrella_header
622
- return super unless custom_module_map
689
+ def create_umbrella_header(native_target)
690
+ return super(native_target) unless custom_module_map
623
691
  end
624
692
 
625
693
  def custom_module_map
@@ -675,15 +743,59 @@ module Pod
675
743
  project.pod_support_files_group(pod_name, dir)
676
744
  end
677
745
 
746
+ # @param [String] name
747
+ # The name of the app host.
748
+
749
+ # @param [Symbol] test_type
750
+ # The test type this Info.plist path is for.
751
+ #
752
+ # @return [Pathname] The absolute path of the Info.plist to use for an app host.
753
+ #
754
+ def app_host_info_plist_path_for_test_type(name, test_type)
755
+ project.path.dirname.+("#{name}/#{target.app_host_label(test_type)}-Info.plist")
756
+ end
757
+
758
+ def test_native_target_from_spec_consumer(spec_consumer, test_native_targets)
759
+ test_native_targets.find do |test_native_target|
760
+ test_native_target.name == target.test_target_label(spec_consumer.spec)
761
+ end
762
+ end
763
+
764
+ # Adds a placeholder native target for the library to the Pods project with the
765
+ # appropriate build configurations.
766
+ #
767
+ # @return [PBXAggregateTarget] the native target that was added.
768
+ #
769
+ def add_placeholder_target
770
+ native_target = project.new_aggregate_target(target.label, [], target.platform.name, deployment_target)
771
+ target.user_build_configurations.each do |bc_name, type|
772
+ native_target.add_build_configuration(bc_name, type)
773
+ end
774
+ unless target.archs.empty?
775
+ native_target.build_configurations.each do |configuration|
776
+ configuration.build_settings['ARCHS'] = target.archs
777
+ end
778
+ end
779
+ native_target
780
+ end
781
+
678
782
  # Adds a shell script phase, intended only for static library targets that contain swift,
679
783
  # to copy the ObjC compatibility header (the -Swift.h file that the swift compiler generates)
680
784
  # to the built products directory. Additionally, the script phase copies the module map, appending a `.Swift`
681
785
  # submodule that references the (moved) compatibility header. Since the module map has been moved, the umbrella header
682
786
  # is _also_ copied, so that it is sitting next to the module map. This is necessary for a successful archive build.
683
787
  #
788
+ # @param [PBXNativeTarget] native_target
789
+ # the native target to add the Swift static library script phase into.
790
+ #
684
791
  # @return [Void]
685
792
  #
686
- def add_swift_static_library_compatibility_header_phase
793
+ def add_swift_static_library_compatibility_header_phase(native_target)
794
+ if custom_module_map
795
+ raise Informative, 'Using Swift static libraries with custom module maps is currently not supported. ' \
796
+ "Please build `#{target.label}` as a framework or remove the custom module map."
797
+ end
798
+
687
799
  build_phase = native_target.new_shell_script_build_phase('Copy generated compatibility header')
688
800
 
689
801
  relative_module_map_path = target.module_map_path.relative_path_from(target.sandbox.root)
@@ -710,6 +822,13 @@ module Pod
710
822
  )
711
823
  end
712
824
 
825
+ def validate_targets_contain_sources(native_targets)
826
+ native_targets.each do |native_target|
827
+ next unless native_target.source_build_phase.files.empty?
828
+ raise Informative, "Unable to install the `#{target.label}` pod, because the `#{native_target}` target in Xcode would have no sources to compile."
829
+ end
830
+ end
831
+
713
832
  #-----------------------------------------------------------------------#
714
833
  end
715
834
  end