cocoapods 1.9.1 → 1.10.2

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 (54) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +292 -5
  3. data/README.md +2 -1
  4. data/lib/cocoapods/command/lib/lint.rb +12 -3
  5. data/lib/cocoapods/command/repo/push.rb +1 -1
  6. data/lib/cocoapods/command/repo/update.rb +11 -0
  7. data/lib/cocoapods/command/spec/lint.rb +12 -3
  8. data/lib/cocoapods/command.rb +12 -2
  9. data/lib/cocoapods/config.rb +17 -0
  10. data/lib/cocoapods/downloader/cache.rb +2 -2
  11. data/lib/cocoapods/gem_version.rb +1 -1
  12. data/lib/cocoapods/generator/app_target_helper.rb +10 -2
  13. data/lib/cocoapods/generator/copy_dsyms_script.rb +56 -0
  14. data/lib/cocoapods/generator/copy_resources_script.rb +2 -14
  15. data/lib/cocoapods/generator/copy_xcframework_script.rb +245 -0
  16. data/lib/cocoapods/generator/embed_frameworks_script.rb +125 -212
  17. data/lib/cocoapods/generator/script_phase_constants.rb +99 -0
  18. data/lib/cocoapods/installer/analyzer/target_inspection_result.rb +1 -1
  19. data/lib/cocoapods/installer/analyzer.rb +17 -8
  20. data/lib/cocoapods/installer/base_install_hooks_context.rb +135 -0
  21. data/lib/cocoapods/installer/installation_options.rb +5 -0
  22. data/lib/cocoapods/installer/pod_source_installer.rb +2 -1
  23. data/lib/cocoapods/installer/post_install_hooks_context.rb +1 -127
  24. data/lib/cocoapods/installer/post_integrate_hooks_context.rb +9 -0
  25. data/lib/cocoapods/installer/project_cache/project_metadata_cache.rb +4 -0
  26. data/lib/cocoapods/installer/sandbox_dir_cleaner.rb +2 -1
  27. data/lib/cocoapods/installer/user_project_integrator/target_integrator.rb +132 -111
  28. data/lib/cocoapods/installer/xcode/pods_project_generator/aggregate_target_installer.rb +13 -27
  29. data/lib/cocoapods/installer/xcode/pods_project_generator/app_host_installer.rb +5 -1
  30. data/lib/cocoapods/installer/xcode/pods_project_generator/file_references_installer.rb +2 -1
  31. data/lib/cocoapods/installer/xcode/pods_project_generator/pod_target_dependency_installer.rb +8 -6
  32. data/lib/cocoapods/installer/xcode/pods_project_generator/pod_target_installer.rb +187 -61
  33. data/lib/cocoapods/installer/xcode/pods_project_generator/pod_target_integrator.rb +61 -30
  34. data/lib/cocoapods/installer/xcode/pods_project_generator/project_generator.rb +3 -2
  35. data/lib/cocoapods/installer/xcode/pods_project_generator/target_installation_result.rb +5 -7
  36. data/lib/cocoapods/installer/xcode/pods_project_generator.rb +45 -6
  37. data/lib/cocoapods/installer/xcode/pods_project_generator_result.rb +19 -0
  38. data/lib/cocoapods/installer/xcode/target_validator.rb +1 -1
  39. data/lib/cocoapods/installer.rb +70 -3
  40. data/lib/cocoapods/sandbox/file_accessor.rb +10 -1
  41. data/lib/cocoapods/sources_manager.rb +2 -1
  42. data/lib/cocoapods/target/aggregate_target.rb +35 -0
  43. data/lib/cocoapods/target/build_settings.rb +94 -18
  44. data/lib/cocoapods/target/pod_target.rb +85 -11
  45. data/lib/cocoapods/target.rb +44 -2
  46. data/lib/cocoapods/user_interface/error_report.rb +1 -1
  47. data/lib/cocoapods/user_interface/inspector_reporter.rb +3 -10
  48. data/lib/cocoapods/validator.rb +38 -12
  49. data/lib/cocoapods/xcode/framework_paths.rb +1 -1
  50. data/lib/cocoapods/xcode/xcframework/xcframework_slice.rb +91 -4
  51. data/lib/cocoapods/xcode/xcframework.rb +17 -4
  52. data/lib/cocoapods.rb +3 -1
  53. metadata +31 -53
  54. data/lib/cocoapods/generator/prepare_artifacts_script.rb +0 -257
@@ -103,9 +103,9 @@ module Pod
103
103
  end]
104
104
  end
105
105
 
106
- # @return [Hash{String => (Specification,PodTarget)}] tuples of app specs and pod targets by test spec name.
106
+ # @return [Hash{Specification => (Specification,PodTarget)}] tuples of app specs and pod targets by test spec.
107
107
  #
108
- attr_accessor :test_app_hosts_by_spec_name
108
+ attr_accessor :test_app_hosts_by_spec
109
109
 
110
110
  # @return [Hash{String => BuildSettings}] the test spec build settings for this target.
111
111
  #
@@ -153,7 +153,7 @@ module Pod
153
153
  self.dependent_targets = []
154
154
  self.test_dependent_targets_by_spec_name = Hash[test_specs.map { |ts| [ts.name, []] }]
155
155
  self.app_dependent_targets_by_spec_name = Hash[app_specs.map { |as| [as.name, []] }]
156
- @test_app_hosts_by_spec_name = {}
156
+ @test_app_hosts_by_spec = {}
157
157
  @build_config_cache = {}
158
158
  @test_spec_build_settings_by_config = create_test_build_settings_by_config
159
159
  @app_spec_build_settings_by_config = create_app_build_settings_by_config
@@ -171,7 +171,7 @@ module Pod
171
171
  cache_key = [specs, target_definition]
172
172
  cache[cache_key] ||= begin
173
173
  target = PodTarget.new(sandbox, build_type, user_build_configurations, archs, platform, specs,
174
- [target_definition], file_accessors, target_definition.label)
174
+ [target_definition], file_accessors, target_definition.label, swift_version)
175
175
  scope_dependent_targets = ->(dependent_targets) do
176
176
  dependent_targets.flat_map do |pod_target|
177
177
  pod_target.scoped(cache).select { |pt| pt.target_definitions == [target_definition] }
@@ -185,8 +185,8 @@ module Pod
185
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
186
  [spec_name, Hash[app_pod_targets_by_config.map { |k, v| [k, scope_dependent_targets[v]] }]]
187
187
  end]
188
- target.test_app_hosts_by_spec_name = Hash[test_app_hosts_by_spec_name.map do |spec_name, (app_host_spec, app_pod_target)|
189
- [spec_name, [app_host_spec, app_pod_target.scoped(cache).find { |pt| pt.target_definitions == [target_definition] }]]
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
190
  end]
191
191
  target
192
192
  end
@@ -430,13 +430,22 @@ module Pod
430
430
  end
431
431
 
432
432
  # @return [Hash{String=>Array<String>}] The resource and resource bundle paths this target depends upon keyed by
433
- # spec name. Resources for app specs and test specs are directly added to “Copy Bundle Resources” phase
434
- # from the generated targets for frameworks, but not libraries. Therefore they are not part of the resource paths.
433
+ # spec name. Resource (not resource bundles) paths can vary depending on the type of spec:
434
+ # - App specs _always_ get their resource paths added to "Copy Bundle Resources" phase from
435
+ # [PodTargetInstaller] therefore their resource paths are never included here.
436
+ # - Test specs may have their resource paths added to "Copy Bundle Resources" if the target itself is
437
+ # built as a framework, which is again checked and handled by PodTargetInstaller. If that is true then
438
+ # the resource paths are not included, otherwise they are included and handled via the CocoaPods copy
439
+ # resources script phase.
440
+ # - Library specs _do not_ have per-configuration CocoaPods copy resources script phase and their resource
441
+ # paths will be added to "Copy Bundle Resources" phase if the target is built as a framework because
442
+ # it supports it. We always include the resource paths for library specs because they are also
443
+ # integrated to the user target.
435
444
  #
436
445
  def resource_paths
437
446
  @resource_paths ||= begin
438
447
  file_accessors.each_with_object({}) do |file_accessor, hash|
439
- resource_paths = if file_accessor.spec.non_library_specification? && build_as_framework?
448
+ resource_paths = if file_accessor.spec.app_specification? || (file_accessor.spec.test_specification? && build_as_framework?)
440
449
  []
441
450
  else
442
451
  file_accessor.resources.map do |res|
@@ -582,7 +591,7 @@ module Pod
582
591
  # app host, and the second item is the target name of the app host
583
592
  #
584
593
  def app_host_target_label(test_spec)
585
- app_spec, app_target = test_app_hosts_by_spec_name[test_spec.name]
594
+ app_spec, app_target = test_app_hosts_by_spec[test_spec]
586
595
 
587
596
  if app_spec
588
597
  [app_target.name, app_target.app_target_label(app_spec)]
@@ -601,7 +610,7 @@ module Pod
601
610
  #
602
611
  def app_host_dependent_targets_for_spec(spec, configuration: nil)
603
612
  return [] unless spec.test_specification? && spec.consumer(platform).test_type == :unit
604
- app_host_info = test_app_hosts_by_spec_name[spec.name]
613
+ app_host_info = test_app_hosts_by_spec[spec]
605
614
  if app_host_info.nil?
606
615
  []
607
616
  else
@@ -684,11 +693,33 @@ module Pod
684
693
  support_files_dir + "#{non_library_spec_label(spec)}-frameworks-output-files.xcfilelist"
685
694
  end
686
695
 
696
+ # @return [Pathname] The absolute path of the copy xcframeworks script.
697
+ #
698
+ def copy_xcframeworks_script_path
699
+ support_files_dir + "#{label}-xcframeworks.sh"
700
+ end
701
+
702
+ # @return [String] The path of the copy xcframeworks input files file list
703
+ #
704
+ def copy_xcframeworks_script_input_files_path
705
+ support_files_dir + "#{label}-xcframeworks-input-files.xcfilelist"
706
+ end
707
+
708
+ # @return [String] The path of the copy xcframeworks output files file list
709
+ #
710
+ def copy_xcframeworks_script_output_files_path
711
+ support_files_dir + "#{label}-xcframeworks-output-files.xcfilelist"
712
+ end
713
+
687
714
  # @param [Specification] spec
688
715
  # The spec this script path is for.
689
716
  #
690
717
  # @return [Pathname] The absolute path of the prepare artifacts script for the given spec.
691
718
  #
719
+ # @deprecated
720
+ #
721
+ # @todo Remove in 2.0
722
+ #
692
723
  def prepare_artifacts_script_path_for_spec(spec)
693
724
  support_files_dir + "#{non_library_spec_label(spec)}-artifacts.sh"
694
725
  end
@@ -698,6 +729,10 @@ module Pod
698
729
  #
699
730
  # @return [Pathname] The absolute path of the prepare artifacts script input file list for the given spec.
700
731
  #
732
+ # @deprecated
733
+ #
734
+ # @todo Remove in 2.0
735
+ #
701
736
  def prepare_artifacts_script_input_files_path_for_spec(spec)
702
737
  support_files_dir + "#{non_library_spec_label(spec)}-artifacts-input-files.xcfilelist"
703
738
  end
@@ -707,10 +742,32 @@ module Pod
707
742
  #
708
743
  # @return [Pathname] The absolute path of the prepare artifacts script output file list for the given spec.
709
744
  #
745
+ # @deprecated
746
+ #
747
+ # @todo Remove in 2.0
748
+ #
710
749
  def prepare_artifacts_script_output_files_path_for_spec(spec)
711
750
  support_files_dir + "#{non_library_spec_label(spec)}-artifacts-output-files.xcfilelist"
712
751
  end
713
752
 
753
+ # @return [Pathname] The absolute path of the copy dSYMs script.
754
+ #
755
+ def copy_dsyms_script_path
756
+ support_files_dir + "#{label}-copy-dsyms.sh"
757
+ end
758
+
759
+ # @return [Pathname] The absolute path of the copy dSYM script phase input file list.
760
+ #
761
+ def copy_dsyms_script_input_files_path
762
+ support_files_dir + "#{label}-copy-dsyms-input-files.xcfilelist"
763
+ end
764
+
765
+ # @return [Pathname] The absolute path of the copy dSYM script phase output file list.
766
+ #
767
+ def copy_dsyms_script_output_files_path
768
+ support_files_dir + "#{label}-copy-dsyms-output-files.xcfilelist"
769
+ end
770
+
714
771
  # @param [Specification] spec
715
772
  # The spec this Info.plist path is for.
716
773
  #
@@ -1065,5 +1122,22 @@ module Pod
1065
1122
  end
1066
1123
  mappings
1067
1124
  end
1125
+
1126
+ # @!group Deprecated APIs
1127
+ # ----------------------------------------------------------------------- #
1128
+
1129
+ public
1130
+
1131
+ # @deprecated Use `test_app_hosts_by_spec` instead.
1132
+ #
1133
+ # @todo Remove in 2.0
1134
+ #
1135
+ # @return [Hash{String => (Specification,PodTarget)}] tuples of app specs and pod targets by test spec name.
1136
+ #
1137
+ def test_app_hosts_by_spec_name
1138
+ Hash[test_app_hosts_by_spec.map do |spec, value|
1139
+ [spec.name, value]
1140
+ end]
1141
+ end
1068
1142
  end
1069
1143
  end
@@ -43,6 +43,11 @@ module Pod
43
43
  #
44
44
  attr_reader :application_extension_api_only
45
45
 
46
+ # @return [Boolean] whether the target must be compiled with Swift's library
47
+ # evolution support, necessary for XCFrameworks.
48
+ #
49
+ attr_reader :build_library_for_distribution
50
+
46
51
  # Initialize a new target
47
52
  #
48
53
  # @param [Sandbox] sandbox @see #sandbox
@@ -59,6 +64,7 @@ module Pod
59
64
  @build_type = build_type
60
65
 
61
66
  @application_extension_api_only = false
67
+ @build_library_for_distribution = false
62
68
  @build_settings = create_build_settings
63
69
  end
64
70
 
@@ -298,19 +304,55 @@ module Pod
298
304
  support_files_dir + "#{label}-dummy.m"
299
305
  end
300
306
 
301
- # mark the target as extension-only,
302
- # translates to APPLICATION_EXTENSION_API_ONLY = YES in the build settings
307
+ # Mark the target as extension-only.
308
+ # Translates to APPLICATION_EXTENSION_API_ONLY = YES in the build settings.
303
309
  #
304
310
  def mark_application_extension_api_only
305
311
  @application_extension_api_only = true
306
312
  end
307
313
 
314
+ # Compiles the target with Swift's library evolution support, necessary to
315
+ # build XCFrameworks.
316
+ # Translates to BUILD_LIBRARY_FOR_DISTRIBUTION = YES in the build settings.
317
+ #
318
+ def mark_build_library_for_distribution
319
+ @build_library_for_distribution = true
320
+ end
321
+
308
322
  # @return [Pathname] The absolute path of the prepare artifacts script.
309
323
  #
324
+ # @deprecated
325
+ #
326
+ # @todo Remove in 2.0
327
+ #
310
328
  def prepare_artifacts_script_path
311
329
  support_files_dir + "#{label}-artifacts.sh"
312
330
  end
313
331
 
332
+ # Returns an extension in the target that corresponds to the
333
+ # resource's input extension.
334
+ #
335
+ # @param [String] input_extension
336
+ # The input extension to map to.
337
+ #
338
+ # @return [String] The output extension.
339
+ #
340
+ def self.output_extension_for_resource(input_extension)
341
+ case input_extension
342
+ when '.storyboard' then '.storyboardc'
343
+ when '.xib' then '.nib'
344
+ when '.xcdatamodel' then '.mom'
345
+ when '.xcdatamodeld' then '.momd'
346
+ when '.xcmappingmodel' then '.cdm'
347
+ when '.xcassets' then '.car'
348
+ else input_extension
349
+ end
350
+ end
351
+
352
+ def self.resource_extension_compilable?(input_extension)
353
+ output_extension_for_resource(input_extension) != input_extension && input_extension != '.xcassets'
354
+ end
355
+
314
356
  #-------------------------------------------------------------------------#
315
357
 
316
358
  private
@@ -31,7 +31,7 @@ module Pod
31
31
  ### Error
32
32
 
33
33
  ```
34
- #{exception.class} - #{exception.message}
34
+ #{exception.class} - #{exception.message.force_encoding('UTF-8')}
35
35
  #{exception.backtrace.join("\n") if exception.backtrace}
36
36
  ```
37
37
 
@@ -1,3 +1,4 @@
1
+ require 'addressable'
1
2
  require 'uri'
2
3
 
3
4
  module Pod
@@ -8,8 +9,6 @@ module Pod
8
9
  # Called just as the investigation has begun.
9
10
  # Lets the user know that it's looking for an issue.
10
11
  #
11
- # @param [query] String unused
12
- #
13
12
  # @param [GhInspector::Inspector] inspector
14
13
  # The current inspector
15
14
  #
@@ -25,9 +24,6 @@ module Pod
25
24
  # @param [GhInspector::InspectionReport] report
26
25
  # Report a list of the issues
27
26
  #
28
- # @param [GhInspector::Inspector] inspector
29
- # The current inspector
30
- #
31
27
  # @return [void]
32
28
  #
33
29
  def inspector_successfully_received_report(report, _)
@@ -41,9 +37,6 @@ module Pod
41
37
 
42
38
  # Called once the report has been received, but when there are no issues found.
43
39
  #
44
- # @param [GhInspector::InspectionReport] report
45
- # An empty report
46
- #
47
40
  # @param [GhInspector::Inspector] inspector
48
41
  # The current inspector
49
42
  #
@@ -68,7 +61,7 @@ module Pod
68
61
  # @return [void]
69
62
  #
70
63
  def inspector_could_not_create_report(error, query, inspector)
71
- safe_query = URI.escape query
64
+ safe_query = Addressable::URI.escape query
72
65
  UI.puts 'Could not access the GitHub API, you may have better luck via the website.'
73
66
  UI.puts "https://github.com/#{inspector.repo_owner}/#{inspector.repo_name}/search?q=#{safe_query}&type=Issues&utf8=✓"
74
67
  UI.puts "Error: #{error.name}"
@@ -77,7 +70,7 @@ module Pod
77
70
  private
78
71
 
79
72
  def print_issue_full(issue)
80
- safe_url = URI.escape issue.html_url
73
+ safe_url = Addressable::URI.escape issue.html_url
81
74
  UI.puts " - #{issue.title}"
82
75
  UI.puts " #{safe_url} [#{issue.state}] [#{issue.comments} comment#{issue.comments == 1 ? '' : 's'}]"
83
76
  UI.puts " #{pretty_date(issue.updated_at)}"
@@ -241,6 +241,10 @@ module Pod
241
241
  #
242
242
  attr_accessor :skip_tests
243
243
 
244
+ # @return [Array<String>] List of test_specs to run. If nil, all tests are run (unless skip_tests is specified).
245
+ #
246
+ attr_accessor :test_specs
247
+
244
248
  # @return [Bool] Whether the validator should run Xcode Static Analysis.
245
249
  #
246
250
  attr_accessor :analyze
@@ -253,6 +257,10 @@ module Pod
253
257
  #
254
258
  attr_accessor :use_modular_headers
255
259
 
260
+ # @return [Boolean] Whether static frameworks should be used for the installation.
261
+ #
262
+ attr_accessor :use_static_frameworks
263
+
256
264
  # @return [Boolean] Whether attributes that affect only public sources
257
265
  # Bool be skipped.
258
266
  #
@@ -271,6 +279,8 @@ module Pod
271
279
  attr_accessor :skip_import_validation
272
280
  alias_method :skip_import_validation?, :skip_import_validation
273
281
 
282
+ attr_accessor :configuration
283
+
274
284
  #-------------------------------------------------------------------------#
275
285
 
276
286
  # !@group Lint results
@@ -433,7 +443,7 @@ module Pod
433
443
  if !resp
434
444
  warning('url', "There was a problem validating the URL #{url}.", true)
435
445
  elsif !resp.success?
436
- warning('url', "The URL (#{url}) is not reachable.", true)
446
+ note('url', "The URL (#{url}) is not reachable.", true)
437
447
  end
438
448
 
439
449
  resp
@@ -546,6 +556,8 @@ module Pod
546
556
  validation_dir.rmtree
547
557
  end
548
558
 
559
+ # @return [String] The deployment targret of the library spec.
560
+ #
549
561
  def deployment_target
550
562
  deployment_target = spec.subspec_by_name(subspec_name).deployment_target(consumer.platform_name)
551
563
  if consumer.platform_name == :ios && use_frameworks
@@ -557,7 +569,7 @@ module Pod
557
569
 
558
570
  def download_pod
559
571
  test_spec_names = consumer.spec.test_specs.select { |ts| ts.supported_on_platform?(consumer.platform_name) }.map(&:name)
560
- podfile = podfile_from_spec(consumer.platform_name, deployment_target, use_frameworks, test_spec_names, use_modular_headers)
572
+ podfile = podfile_from_spec(consumer.platform_name, deployment_target, use_frameworks, test_spec_names, use_modular_headers, use_static_frameworks)
561
573
  sandbox = Sandbox.new(config.sandbox_root)
562
574
  @installer = Installer.new(sandbox, podfile)
563
575
  @installer.use_default_plugins = false
@@ -584,7 +596,7 @@ module Pod
584
596
  app_target = app_project.targets.first
585
597
  pod_target = validation_pod_target
586
598
  Pod::Generator::AppTargetHelper.add_app_project_import(app_project, app_target, pod_target, consumer.platform_name)
587
- Pod::Generator::AppTargetHelper.add_xctest_search_paths(app_target) if @installer.pod_targets.any? { |pt| pt.spec_consumers.any? { |c| c.frameworks.include?('XCTest') } }
599
+ Pod::Generator::AppTargetHelper.add_xctest_search_paths(app_target) if @installer.pod_targets.any? { |pt| pt.spec_consumers.any? { |c| c.frameworks.include?('XCTest') || c.weak_frameworks.include?('XCTest') } }
588
600
  Pod::Generator::AppTargetHelper.add_empty_swift_file(app_project, app_target) if @installer.pod_targets.any?(&:uses_swift?)
589
601
  app_project.save
590
602
  Xcodeproj::XCScheme.share_scheme(app_project.path, 'App')
@@ -701,7 +713,7 @@ module Pod
701
713
  UI.warn "Skipping compilation with `xcodebuild` because target contains no sources.\n".yellow
702
714
  else
703
715
  if analyze
704
- output = xcodebuild('analyze', scheme, 'Release')
716
+ output = xcodebuild('analyze', scheme, 'Release', :deployment_target => deployment_target)
705
717
  find_output = Executable.execute_command('find', [validation_dir, '-name', '*.html'], false)
706
718
  if find_output != ''
707
719
  message = 'Static Analysis failed.'
@@ -710,7 +722,7 @@ module Pod
710
722
  error('build_pod', message)
711
723
  end
712
724
  else
713
- output = xcodebuild('build', scheme, 'Release')
725
+ output = xcodebuild('build', scheme, configuration ? configuration : 'Release', :deployment_target => deployment_target)
714
726
  end
715
727
  parsed_output = parse_xcodebuild_output(output)
716
728
  translate_output_to_linter_messages(parsed_output)
@@ -732,12 +744,22 @@ module Pod
732
744
  else
733
745
  UI.message "\nTesting with `xcodebuild`.\n".yellow do
734
746
  pod_target = validation_pod_target
735
- consumer.spec.test_specs.each do |test_spec|
747
+ all_test_specs = consumer.spec.test_specs
748
+ unless test_specs.nil?
749
+ test_spec_names = all_test_specs.map(&:base_name)
750
+ all_test_specs.select! { |test_spec| test_specs.include? test_spec.base_name }
751
+ test_specs.each do |test_spec|
752
+ unless test_spec_names.include? test_spec
753
+ UI.warn "Requested test spec `#{test_spec}` does not exist in the podspec. Existing test specs are `#{test_spec_names}`"
754
+ end
755
+ end
756
+ end
757
+ all_test_specs.each do |test_spec|
736
758
  if !test_spec.supported_on_platform?(consumer.platform_name)
737
759
  UI.warn "Skipping test spec `#{test_spec.name}` on platform `#{consumer.platform_name}` since it is not supported.\n".yellow
738
760
  else
739
761
  scheme = @installer.target_installation_results.first[pod_target.name].native_target_for_spec(test_spec)
740
- output = xcodebuild('test', scheme, 'Debug')
762
+ output = xcodebuild('test', scheme, 'Debug', :deployment_target => test_spec.deployment_target(consumer.platform_name))
741
763
  parsed_output = parse_xcodebuild_output(output)
742
764
  translate_output_to_linter_messages(parsed_output)
743
765
  end
@@ -953,7 +975,7 @@ module Pod
953
975
  # @note The generated podfile takes into account whether the linter is
954
976
  # in local mode.
955
977
  #
956
- def podfile_from_spec(platform_name, deployment_target, use_frameworks = true, test_spec_names = [], use_modular_headers = false)
978
+ def podfile_from_spec(platform_name, deployment_target, use_frameworks = true, test_spec_names = [], use_modular_headers = false, use_static_frameworks = false)
957
979
  name = subspec_name || spec.name
958
980
  podspec = file.realpath
959
981
  local = local?
@@ -963,12 +985,16 @@ module Pod
963
985
  additional_path_pods = (include_podspecs ? Dir.glob(include_podspecs) : []) .select { |path| spec.name != Specification.from_file(path).name } - additional_podspec_pods
964
986
 
965
987
  Pod::Podfile.new do
966
- install! 'cocoapods', :deterministic_uuids => false
988
+ install! 'cocoapods', :deterministic_uuids => false, :warn_for_unused_master_specs_repo => false
967
989
  # By default inhibit warnings for all pods, except the one being validated.
968
990
  inhibit_all_warnings!
969
991
  urls.each { |u| source(u) }
970
992
  target 'App' do
971
- use_frameworks!(use_frameworks)
993
+ if use_static_frameworks
994
+ use_frameworks!(:linkage => :static)
995
+ else
996
+ use_frameworks!(use_frameworks)
997
+ end
972
998
  use_modular_headers! if use_modular_headers
973
999
  platform(platform_name, deployment_target)
974
1000
  if local
@@ -1016,7 +1042,7 @@ module Pod
1016
1042
  l.include?('note: ') && (l !~ /expanded from macro/)
1017
1043
  end
1018
1044
  selected_lines.map do |l|
1019
- new = l.gsub(%r{#{validation_dir}/Pods/}, '')
1045
+ new = l.force_encoding('UTF-8').gsub(%r{#{validation_dir}/Pods/}, '')
1020
1046
  new.gsub!(/^ */, ' ')
1021
1047
  end
1022
1048
  end
@@ -1024,7 +1050,7 @@ module Pod
1024
1050
  # @return [String] Executes xcodebuild in the current working directory and
1025
1051
  # returns its output (both STDOUT and STDERR).
1026
1052
  #
1027
- def xcodebuild(action, scheme, configuration)
1053
+ def xcodebuild(action, scheme, configuration, deployment_target:)
1028
1054
  require 'fourflusher'
1029
1055
  command = %W(clean #{action} -workspace #{File.join(validation_dir, 'App.xcworkspace')} -scheme #{scheme} -configuration #{configuration})
1030
1056
  case consumer.platform_name
@@ -9,7 +9,7 @@ module Pod
9
9
  #
10
10
  attr_reader :dsym_path
11
11
 
12
- # @return [Array, Nil] the bcsymbolmap files path array, if one exists
12
+ # @return [Array<String>, Nil] the bcsymbolmap files path array, if one exists
13
13
  #
14
14
  attr_reader :bcsymbolmap_paths
15
15
 
@@ -1,8 +1,10 @@
1
+ require 'cocoapods/xcode/linkage_analyzer'
2
+
1
3
  module Pod
2
4
  module Xcode
3
5
  class XCFramework
4
6
  class Slice
5
- # @return [Pathname] the path to the .framework root of this framework slice
7
+ # @return [Pathname] the path to the .framework or .a of this slice
6
8
  #
7
9
  attr_reader :path
8
10
 
@@ -22,28 +24,113 @@ module Pod
22
24
  #
23
25
  attr_reader :platform_variant
24
26
 
25
- def initialize(path, identifier, archs, platform, platform_variant = nil)
27
+ # @return [Pathname] the path to the headers
28
+ #
29
+ attr_reader :headers
30
+
31
+ def initialize(path, identifier, archs, platform, platform_variant: nil, headers: path.join('Headers'))
26
32
  @path = path
27
33
  @identifier = identifier
28
34
  @supported_archs = archs
29
35
  @platform = Pod::Platform.new(platform)
30
36
  @platform_variant = platform_variant.to_sym unless platform_variant.nil?
37
+ @headers = headers
31
38
  end
32
39
 
33
40
  # @return [String] the name of the framework
34
41
  #
35
42
  def name
36
- @name ||= File.basename(path, '.framework')
43
+ @name ||= begin
44
+ case package_type
45
+ when :framework
46
+ File.basename(path, '.framework')
47
+ when :library
48
+ result = File.basename(path, '.a').gsub(/^lib/, '')
49
+ result[0] = result.downcase[0]
50
+ result
51
+ else
52
+ raise Informative, "Invalid package type `#{package_type}`"
53
+ end
54
+ end
37
55
  end
38
56
 
57
+ # @return [Boolean] true if this is a slice built for simulator
58
+ #
39
59
  def simulator_variant?
40
60
  @platform_variant == :simulator
41
61
  end
42
62
 
63
+ # @return [Symbol] the package type of the slice - either :framework or :library
64
+ #
65
+ def package_type
66
+ @package_type ||= begin
67
+ ext = File.extname(path)
68
+ case ext
69
+ when '.framework'
70
+ :framework
71
+ when '.a'
72
+ :library
73
+ else
74
+ raise Informative, "Invalid XCFramework slice type `#{ext}`"
75
+ end
76
+ end
77
+ end
78
+
79
+ # @return [Boolean] true if this slice is a framework, not a library
80
+ #
81
+ def framework?
82
+ build_type.framework?
83
+ end
84
+
85
+ # @return [Boolean] true if this slice is a library, not a framework
86
+ #
87
+ def library?
88
+ build_type.library?
89
+ end
90
+
91
+ # @return [Boolean] true if this slice contains a statically-linked binary
92
+ #
93
+ def static?
94
+ build_type.static?
95
+ end
96
+
97
+ # @return [Boolean] true if this slice contains a dynamically-linked binary
98
+ #
99
+ def dynamic?
100
+ build_type.dynamic?
101
+ end
102
+
103
+ # @return [BuildType] the build type of the binary
104
+ #
105
+ def build_type
106
+ @build_type ||= begin
107
+ linkage = Xcode::LinkageAnalyzer.dynamic_binary?(binary_path) ? :dynamic : :static
108
+ ext = File.extname(path)
109
+ packaging = case ext
110
+ when '.framework'
111
+ :framework
112
+ when '.a'
113
+ :library
114
+ else
115
+ raise Informative, "Invalid XCFramework slice type `#{ext}`"
116
+ end
117
+ BuildType.new(:linkage => linkage, :packaging => packaging)
118
+ end
119
+ end
120
+
43
121
  # @return [Pathname] the path to the bundled binary
44
122
  #
45
123
  def binary_path
46
- path + name
124
+ @binary_path ||= begin
125
+ case package_type
126
+ when :framework
127
+ path + name
128
+ when :library
129
+ path
130
+ else
131
+ raise Informative, "Invalid package type `#{package_type}`"
132
+ end
133
+ end
47
134
  end
48
135
  end
49
136
  end
@@ -52,13 +52,22 @@ module Pod
52
52
  # @return [Boolean] true if any slices use dynamic linkage
53
53
  #
54
54
  def includes_dynamic_slices?
55
- slices.any? { |slice| Xcode::LinkageAnalyzer.dynamic_binary?(slice.binary_path) }
55
+ build_type.dynamic?
56
56
  end
57
57
 
58
58
  # @return [Boolean] true if any slices use dynamic linkage
59
59
  #
60
60
  def includes_static_slices?
61
- slices.any? { |slice| !Xcode::LinkageAnalyzer.dynamic_binary?(slice.binary_path) }
61
+ build_type.static?
62
+ end
63
+
64
+ # @return [Pod::BuildType] the build type of the contained slices
65
+ #
66
+ # @note As CocoaPods does not support mixed packaging nor linkage for xcframework slices,
67
+ # we pick the first slice and assume all are the same
68
+ #
69
+ def build_type
70
+ @build_type ||= slices.first.build_type
62
71
  end
63
72
 
64
73
  private
@@ -71,10 +80,14 @@ module Pod
71
80
  archs = library['SupportedArchitectures']
72
81
  platform_name = library['SupportedPlatform']
73
82
  platform_variant = library['SupportedPlatformVariant']
83
+ headers = library['HeadersPath']
74
84
 
75
- slice_path = path.join(identifier).join(relative_path)
76
- XCFramework::Slice.new(slice_path, identifier, archs, platform_name, platform_variant)
85
+ slice_root = path.join(identifier)
86
+ slice_path = slice_root.join(relative_path)
87
+ headers = slice_root.join(headers) unless headers.nil?
88
+ XCFramework::Slice.new(slice_path, identifier, archs, platform_name, :platform_variant => platform_variant, :headers => headers)
77
89
  end
90
+ raise Informative, "XCFramework at #{path} does not contain any frameworks or libraries." if slices.empty?
78
91
  end
79
92
  end
80
93
  end
data/lib/cocoapods.rb CHANGED
@@ -59,10 +59,12 @@ module Pod
59
59
  autoload :Plist, 'cocoapods/generator/acknowledgements/plist'
60
60
  autoload :BridgeSupport, 'cocoapods/generator/bridge_support'
61
61
  autoload :Constant, 'cocoapods/generator/constant'
62
+ autoload :ScriptPhaseConstants, 'cocoapods/generator/script_phase_constants'
62
63
  autoload :CopyResourcesScript, 'cocoapods/generator/copy_resources_script'
64
+ autoload :CopydSYMsScript, 'cocoapods/generator/copy_dsyms_script'
63
65
  autoload :DummySource, 'cocoapods/generator/dummy_source'
64
66
  autoload :EmbedFrameworksScript, 'cocoapods/generator/embed_frameworks_script'
65
- autoload :PrepareArtifactsScript, 'cocoapods/generator/prepare_artifacts_script'
67
+ autoload :CopyXCFrameworksScript, 'cocoapods/generator/copy_xcframework_script'
66
68
  autoload :FileList, 'cocoapods/generator/file_list'
67
69
  autoload :Header, 'cocoapods/generator/header'
68
70
  autoload :InfoPlistFile, 'cocoapods/generator/info_plist_file'