cocoapods 1.3.0.beta.2 → 1.3.0.beta.3

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.
@@ -4,6 +4,7 @@ module Pod
4
4
  # The {PodsProjectGenerator} handles generation of the 'Pods/Pods.xcodeproj'
5
5
  #
6
6
  class PodsProjectGenerator
7
+ require 'cocoapods/installer/pods_project_integrator/pod_target_integrator'
7
8
  require 'cocoapods/installer/xcode/pods_project_generator/target_installer'
8
9
  require 'cocoapods/installer/xcode/pods_project_generator/pod_target_installer'
9
10
  require 'cocoapods/installer/xcode/pods_project_generator/file_references_installer'
@@ -62,6 +63,7 @@ module Pod
62
63
  prepare
63
64
  install_file_references
64
65
  install_libraries
66
+ integrate_test_targets
65
67
  set_target_dependencies
66
68
  end
67
69
 
@@ -73,7 +75,13 @@ module Pod
73
75
  if installation_options.deterministic_uuids?
74
76
  UI.message('- Generating deterministic UUIDs') { project.predictabilize_uuids }
75
77
  end
76
- project.recreate_user_schemes(false)
78
+ library_product_types = [:framework, :dynamic_library, :static_library]
79
+ project.recreate_user_schemes(false) do |scheme, target|
80
+ next unless library_product_types.include? target.symbol_type
81
+ pod_target = pod_targets.find { |pt| pt.native_target == target }
82
+ next if pod_target.nil? || pod_target.test_native_targets.empty?
83
+ pod_target.test_native_targets.each { |test_native_target| scheme.add_test_target(test_native_target) }
84
+ end
77
85
  project.save
78
86
  end
79
87
  end
@@ -169,6 +177,17 @@ module Pod
169
177
  end
170
178
  end
171
179
 
180
+ def integrate_test_targets
181
+ pod_targets_with_test_targets = pod_targets.reject { |pt| pt.test_native_targets.empty? }
182
+ unless pod_targets_with_test_targets.empty?
183
+ UI.message '- Integrating test targets' do
184
+ pod_targets_with_test_targets.each do |pod_target|
185
+ Pod::Installer::PodTargetIntegrator.new(pod_target).integrate!
186
+ end
187
+ end
188
+ end
189
+ end
190
+
172
191
  def add_system_framework_dependencies
173
192
  # @TODO: Add Specs
174
193
  pod_targets.sort_by(&:name).each do |pod_target|
@@ -198,10 +217,8 @@ module Pod
198
217
  configure_app_extension_api_only_for_target(aggregate_target) if is_app_extension
199
218
 
200
219
  unless pod_target.should_build?
201
- pod_target.resource_bundle_targets.each do |resource_bundle_target|
202
- aggregate_target.native_target.add_dependency(resource_bundle_target)
203
- end
204
-
220
+ add_resource_bundles_to_native_target(pod_target, aggregate_target.native_target)
221
+ add_pod_target_test_dependencies(pod_target, frameworks_group)
205
222
  next
206
223
  end
207
224
 
@@ -210,9 +227,7 @@ module Pod
210
227
 
211
228
  add_dependent_targets_to_native_target(pod_target.dependent_targets, pod_target.native_target, is_app_extension, pod_target.requires_frameworks?, frameworks_group)
212
229
 
213
- pod_target.test_native_targets.each do |test_native_target|
214
- add_dependent_targets_to_native_target([pod_target, *pod_target.test_dependent_targets], test_native_target, false, pod_target.requires_frameworks?, frameworks_group)
215
- end
230
+ add_pod_target_test_dependencies(pod_target, frameworks_group)
216
231
  end
217
232
  end
218
233
  end
@@ -250,6 +265,16 @@ module Pod
250
265
 
251
266
  private
252
267
 
268
+ def add_pod_target_test_dependencies(pod_target, frameworks_group)
269
+ test_dependent_targets = [pod_target, *pod_target.test_dependent_targets]
270
+ pod_target.test_native_targets.each do |test_native_target|
271
+ test_dependent_targets.reject(&:should_build?).each do |test_dependent_target|
272
+ add_resource_bundles_to_native_target(test_dependent_target, test_native_target)
273
+ end
274
+ add_dependent_targets_to_native_target(test_dependent_targets, test_native_target, false, pod_target.requires_frameworks?, frameworks_group)
275
+ end
276
+ end
277
+
253
278
  def add_dependent_targets_to_native_target(dependent_targets, native_target, is_app_extension, requires_frameworks, frameworks_group)
254
279
  dependent_targets.each do |pod_dependency_target|
255
280
  next unless pod_dependency_target.should_build?
@@ -264,6 +289,13 @@ module Pod
264
289
  end
265
290
  end
266
291
 
292
+ def add_resource_bundles_to_native_target(dependent_target, native_target)
293
+ resource_bundle_targets = dependent_target.resource_bundle_targets + dependent_target.test_resource_bundle_targets
294
+ resource_bundle_targets.each do |resource_bundle_target|
295
+ native_target.add_dependency(resource_bundle_target)
296
+ end
297
+ end
298
+
267
299
  # Sets the APPLICATION_EXTENSION_API_ONLY build setting to YES for all
268
300
  # configurations of the given target
269
301
  #
@@ -84,7 +84,7 @@ module Pod
84
84
  native_target.build_configurations.each do |configuration|
85
85
  path = target.xcconfig_path(configuration.name)
86
86
  gen = Generator::XCConfig::AggregateXCConfig.new(target, configuration.name)
87
- gen.save_as(path)
87
+ update_changed_file(gen, path)
88
88
  target.xcconfigs[configuration.name] = gen.xcconfig
89
89
  xcconfig_file_ref = add_file_to_support_group(path)
90
90
  configuration.base_configuration_reference = xcconfig_file_ref
@@ -104,7 +104,7 @@ module Pod
104
104
  path = target.bridge_support_path
105
105
  headers = native_target.headers_build_phase.files.map { |bf| sandbox.root + bf.file_ref.path }
106
106
  generator = Generator::BridgeSupport.new(headers)
107
- generator.save_as(path)
107
+ update_changed_file(generator, path)
108
108
  add_file_to_support_group(path)
109
109
  end
110
110
  end
@@ -120,7 +120,7 @@ module Pod
120
120
  def create_copy_resources_script
121
121
  path = target.copy_resources_script_path
122
122
  generator = Generator::CopyResourcesScript.new(target.resource_paths_by_config, target.platform)
123
- generator.save_as(path)
123
+ update_changed_file(generator, path)
124
124
  add_file_to_support_group(path)
125
125
  end
126
126
 
@@ -136,7 +136,7 @@ module Pod
136
136
  def create_embed_frameworks_script
137
137
  path = target.embed_frameworks_script_path
138
138
  generator = Generator::EmbedFrameworksScript.new(target.framework_paths_by_config)
139
- generator.save_as(path)
139
+ update_changed_file(generator, path)
140
140
  add_file_to_support_group(path)
141
141
  end
142
142
 
@@ -150,7 +150,7 @@ module Pod
150
150
  path = generator_class.path_from_basepath(basepath)
151
151
  file_accessors = target.pod_targets.map(&:file_accessors).flatten
152
152
  generator = generator_class.new(file_accessors)
153
- generator.save_as(path)
153
+ update_changed_file(generator, path)
154
154
  add_file_to_support_group(path)
155
155
  end
156
156
  end
@@ -182,9 +182,10 @@ module Pod
182
182
  local = sandbox.local?(pod_name)
183
183
  paths = file_accessor.send(file_accessor_key)
184
184
  paths = allowable_project_paths(paths)
185
+ base_path = local ? common_path(paths) : nil
185
186
  paths.each do |path|
186
187
  group = pods_project.group_for_spec(file_accessor.spec.name, group_key)
187
- pods_project.add_file_reference(path, group, local && reflect_file_system_structure_for_development)
188
+ pods_project.add_file_reference(path, group, local && reflect_file_system_structure_for_development, base_path)
188
189
  end
189
190
  end
190
191
  end
@@ -240,6 +241,29 @@ module Pod
240
241
  allowable_paths + lproj_paths.subtract(lproj_paths_with_files).to_a
241
242
  end
242
243
 
244
+ # Returns a Pathname of the nearest parent from which all the given paths descend.
245
+ # Converts each Pathname to a string and finds the longest common prefix
246
+ #
247
+ # @param [Array<Pathname>] paths
248
+ # The paths to files or directories on disk. Must be absolute paths
249
+ #
250
+ # @return [Pathname] Pathname of the nearest parent shared by paths, or nil if none exists
251
+ #
252
+ def common_path(paths)
253
+ return nil if paths.empty?
254
+ strs = paths.map do |path|
255
+ unless path.absolute?
256
+ raise ArgumentError, "Paths must be absolute #{path}"
257
+ end
258
+ path.dirname.to_s
259
+ end
260
+ min, max = strs.minmax
261
+ idx = min.size.times { |i| break i if min[i] != max[i] }
262
+ result = Pathname.new(min[0...idx])
263
+ # Don't consider "/" a common path
264
+ return result unless result.to_s == '/'
265
+ end
266
+
243
267
  # Computes the destination sub-directory in the sandbox
244
268
  #
245
269
  # @param [Pathname] headers_sandbox
@@ -18,8 +18,8 @@ module Pod
18
18
 
19
19
  UI.message "- Installing target `#{target.name}` #{target.platform}" do
20
20
  add_target
21
- add_test_targets if target.contains_test_specifications?
22
21
  create_support_files_dir
22
+ add_test_targets if target.contains_test_specifications?
23
23
  add_resources_bundle_targets
24
24
  add_files_to_build_phases
25
25
  create_xcconfig_file
@@ -155,7 +155,7 @@ module Pod
155
155
  add_header(build_file, public_headers, private_headers, native_target)
156
156
  end
157
157
 
158
- other_file_refs = other_source_files.map { |sf| project.reference_for_path(sf) }
158
+ other_file_refs = project_file_references_array(other_source_files, 'other source')
159
159
  native_target.add_file_references(other_file_refs, nil)
160
160
 
161
161
  next unless target.requires_frameworks?
@@ -176,9 +176,9 @@ module Pod
176
176
  target.supported_test_types.each do |test_type|
177
177
  product_type = target.product_type_for_test_type(test_type)
178
178
  name = target.test_target_label(test_type)
179
- platform = target.platform.name
179
+ platform_name = target.platform.name
180
180
  language = target.uses_swift? ? :swift : :objc
181
- native_test_target = project.new_target(product_type, name, platform, deployment_target, nil, language)
181
+ native_test_target = project.new_target(product_type, name, platform_name, deployment_target, nil, language)
182
182
  native_test_target.product_reference.name = name
183
183
 
184
184
  target.user_build_configurations.each do |bc_name, type|
@@ -196,6 +196,10 @@ module Pod
196
196
  configuration.build_settings['PRODUCT_NAME'] = name
197
197
  end
198
198
 
199
+ # Test native targets also need frameworks and resources to be copied over to their xctest bundle.
200
+ create_test_target_embed_frameworks_script(test_type)
201
+ create_test_target_copy_resources_script(test_type)
202
+
199
203
  target.test_native_targets << native_test_target
200
204
  end
201
205
  end
@@ -230,7 +234,13 @@ module Pod
230
234
  end
231
235
  bundle_target.deployment_target = deployment_target
232
236
 
233
- target.resource_bundle_targets << bundle_target
237
+ test_specification = file_accessor.spec.test_specification?
238
+
239
+ if test_specification
240
+ target.test_resource_bundle_targets << bundle_target
241
+ else
242
+ target.resource_bundle_targets << bundle_target
243
+ end
234
244
 
235
245
  if target.should_build?
236
246
  native_target.add_dependency(bundle_target)
@@ -244,14 +254,19 @@ module Pod
244
254
  path.dirname.mkdir unless path.dirname.exist?
245
255
  info_plist_path = path.dirname + "ResourceBundle-#{bundle_name}-#{path.basename}"
246
256
  generator = Generator::InfoPlistFile.new(target, :bundle_package_type => :bndl)
247
- generator.save_as(info_plist_path)
257
+ update_changed_file(generator, info_plist_path)
248
258
  add_file_to_support_group(info_plist_path)
249
259
 
250
260
  bundle_target.build_configurations.each do |c|
251
261
  c.build_settings['PRODUCT_NAME'] = bundle_name
252
262
  relative_info_plist_path = info_plist_path.relative_path_from(sandbox.root)
253
263
  c.build_settings['INFOPLIST_FILE'] = relative_info_plist_path.to_s
254
- c.build_settings['CONFIGURATION_BUILD_DIR'] = target.configuration_build_dir('$(BUILD_DIR)/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)')
264
+ # Do not set the CONFIGURATION_BUILD_DIR for resource bundles that are only meant for test targets.
265
+ # This is because the test target itself also does not set this configuration build dir and it expects
266
+ # all bundles to be copied from the default path.
267
+ unless test_specification
268
+ c.build_settings['CONFIGURATION_BUILD_DIR'] = target.configuration_build_dir('$(BUILD_DIR)/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)')
269
+ end
255
270
 
256
271
  # Set the correct device family for this bundle, based on the platform
257
272
  device_family_by_platform = {
@@ -275,19 +290,15 @@ module Pod
275
290
  def create_xcconfig_file
276
291
  path = target.xcconfig_path
277
292
  xcconfig_gen = Generator::XCConfig::PodXCConfig.new(target)
278
- xcconfig_gen.save_as(path)
293
+ update_changed_file(xcconfig_gen, path)
279
294
  xcconfig_file_ref = add_file_to_support_group(path)
280
295
 
281
296
  native_target.build_configurations.each do |c|
282
297
  c.base_configuration_reference = xcconfig_file_ref
283
298
  end
284
299
 
285
- # also apply the private config to resource targets
286
- target.resource_bundle_targets.each do |rsrc_target|
287
- rsrc_target.build_configurations.each do |rsrc_bc|
288
- rsrc_bc.base_configuration_reference = xcconfig_file_ref
289
- end
290
- end
300
+ # also apply the private config to resource bundle targets.
301
+ apply_xcconfig_file_ref_to_resource_bundle_targets(target.resource_bundle_targets, xcconfig_file_ref)
291
302
  end
292
303
 
293
304
  # Generates the contents of the xcconfig file used for each test target type and saves it to disk.
@@ -298,7 +309,7 @@ module Pod
298
309
  target.supported_test_types.each do |test_type|
299
310
  path = target.xcconfig_path(test_type.to_s)
300
311
  xcconfig_gen = Generator::XCConfig::PodXCConfig.new(target, true)
301
- xcconfig_gen.save_as(path)
312
+ update_changed_file(xcconfig_gen, path)
302
313
  xcconfig_file_ref = add_file_to_support_group(path)
303
314
 
304
315
  target.test_native_targets.each do |test_target|
@@ -307,9 +318,44 @@ module Pod
307
318
  test_target_bc.base_configuration_reference = xcconfig_file_ref
308
319
  end
309
320
  end
321
+
322
+ # also apply the private config to resource bundle test targets.
323
+ apply_xcconfig_file_ref_to_resource_bundle_targets(target.test_resource_bundle_targets, xcconfig_file_ref)
310
324
  end
311
325
  end
312
326
 
327
+ # Creates a script that copies the resources to the bundle of the test target.
328
+ #
329
+ # @param [Symbol] test_type
330
+ # The test type to create the script for.
331
+ #
332
+ # @return [void]
333
+ #
334
+ def create_test_target_copy_resources_script(test_type)
335
+ path = target.copy_resources_script_path_for_test_type(test_type)
336
+ pod_targets = [target, *target.test_dependent_targets]
337
+ resource_paths_by_config = { 'Debug' => pod_targets.flat_map(&:resource_paths) }
338
+ generator = Generator::CopyResourcesScript.new(resource_paths_by_config, target.platform)
339
+ update_changed_file(generator, path)
340
+ add_file_to_support_group(path)
341
+ end
342
+
343
+ # Creates a script that embeds the frameworks to the bundle of the test target.
344
+ #
345
+ # @param [Symbol] test_type
346
+ # The test type to create the script for.
347
+ #
348
+ # @return [void]
349
+ #
350
+ def create_test_target_embed_frameworks_script(test_type)
351
+ path = target.embed_frameworks_script_path_for_test_type(test_type)
352
+ pod_targets = [target, *target.test_dependent_targets]
353
+ framework_paths_by_config = { 'Debug' => pod_targets.flat_map(&:framework_paths) }
354
+ generator = Generator::EmbedFrameworksScript.new(framework_paths_by_config)
355
+ update_changed_file(generator, path)
356
+ add_file_to_support_group(path)
357
+ end
358
+
313
359
  # Manually add `libswiftSwiftOnoneSupport.dylib` as it seems there is an issue with tests that do not include it for Debug configurations.
314
360
  # Possibly related to Swift module optimization.
315
361
  #
@@ -351,7 +397,7 @@ module Pod
351
397
  def create_prefix_header
352
398
  path = target.prefix_header_path
353
399
  generator = Generator::PrefixHeader.new(target.file_accessors, target.platform)
354
- generator.save_as(path)
400
+ update_changed_file(generator, path)
355
401
  add_file_to_support_group(path)
356
402
 
357
403
  native_target.build_configurations.each do |c|
@@ -433,11 +479,21 @@ module Pod
433
479
  group.new_file(path)
434
480
  end
435
481
 
482
+ def apply_xcconfig_file_ref_to_resource_bundle_targets(resource_bundle_targets, xcconfig_file_ref)
483
+ resource_bundle_targets.each do |rsrc_target|
484
+ rsrc_target.build_configurations.each do |rsrc_bc|
485
+ rsrc_bc.base_configuration_reference = xcconfig_file_ref
486
+ end
487
+ end
488
+ end
489
+
436
490
  def create_module_map
437
491
  return super unless custom_module_map
438
492
  path = target.module_map_path
439
493
  UI.message "- Copying module map file to #{UI.path(path)}" do
440
- FileUtils.cp(custom_module_map, path)
494
+ unless path.exist? && FileUtils.identical?(custom_module_map, path)
495
+ FileUtils.cp(custom_module_map, path)
496
+ end
441
497
  add_file_to_support_group(path)
442
498
 
443
499
  native_target.build_configurations.each do |c|
@@ -89,10 +89,44 @@ module Pod
89
89
  settings
90
90
  end
91
91
 
92
+ # @param [Generator] generator
93
+ # the generator to use for generating the content.
94
+ #
95
+ # @param [Pathname] path
96
+ # the pathname to save the content into.
97
+ #
98
+ # Saves the content the provided path unless the path exists and the contents are exactly the same.
99
+ #
100
+ # @return [Void]
101
+ #
102
+ def update_changed_file(generator, path)
103
+ if path.exist?
104
+ generator.save_as(support_files_temp_dir)
105
+ unless FileUtils.identical?(support_files_temp_dir, path)
106
+ FileUtils.mv(support_files_temp_dir, path)
107
+ end
108
+ else
109
+ generator.save_as(path)
110
+ end
111
+ clean_support_files_temp_dir if support_files_temp_dir.exist?
112
+ end
113
+
92
114
  # Creates the directory where to store the support files of the target.
93
115
  #
94
116
  def create_support_files_dir
95
- target.support_files_dir.mkdir
117
+ target.support_files_dir.mkpath
118
+ end
119
+
120
+ # Remove temp file whose store .prefix/config/dummy file.
121
+ #
122
+ def clean_support_files_temp_dir
123
+ support_files_temp_dir.rmtree
124
+ end
125
+
126
+ # @return [String] The temp file path to store temporary files.
127
+ #
128
+ def support_files_temp_dir
129
+ sandbox.target_support_files_dir('generated_files_tmp')
96
130
  end
97
131
 
98
132
  # Creates the Info.plist file which sets public framework attributes
@@ -103,7 +137,7 @@ module Pod
103
137
  path = target.info_plist_path
104
138
  UI.message "- Generating Info.plist file at #{UI.path(path)}" do
105
139
  generator = Generator::InfoPlistFile.new(target)
106
- generator.save_as(path)
140
+ update_changed_file(generator, path)
107
141
  add_file_to_support_group(path)
108
142
 
109
143
  native_target.build_configurations.each do |c|
@@ -126,7 +160,7 @@ module Pod
126
160
  UI.message "- Generating module map file at #{UI.path(path)}" do
127
161
  generator = Generator::ModuleMap.new(target)
128
162
  yield generator if block_given?
129
- generator.save_as(path)
163
+ update_changed_file(generator, path)
130
164
  add_file_to_support_group(path)
131
165
 
132
166
  native_target.build_configurations.each do |c|
@@ -147,7 +181,7 @@ module Pod
147
181
  UI.message "- Generating umbrella header at #{UI.path(path)}" do
148
182
  generator = Generator::UmbrellaHeader.new(target)
149
183
  yield generator if block_given?
150
- generator.save_as(path)
184
+ update_changed_file(generator, path)
151
185
 
152
186
  # Add the file to the support group and the native target,
153
187
  # so it will been added to the header build phase
@@ -169,7 +203,7 @@ module Pod
169
203
  def create_dummy_source
170
204
  path = target.dummy_source_path
171
205
  generator = Generator::DummySource.new(target.label)
172
- generator.save_as(path)
206
+ update_changed_file(generator, path)
173
207
  file_reference = add_file_to_support_group(path)
174
208
  native_target.source_build_phase.add_file_reference(file_reference)
175
209
  end