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

Sign up to get free protection for your applications and to get access to all the features.
@@ -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