xcocoapods 1.5.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (124) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +6303 -0
  3. data/LICENSE +28 -0
  4. data/README.md +80 -0
  5. data/bin/pod +56 -0
  6. data/bin/sandbox-pod +168 -0
  7. data/lib/cocoapods.rb +73 -0
  8. data/lib/cocoapods/command.rb +175 -0
  9. data/lib/cocoapods/command/cache.rb +28 -0
  10. data/lib/cocoapods/command/cache/clean.rb +90 -0
  11. data/lib/cocoapods/command/cache/list.rb +69 -0
  12. data/lib/cocoapods/command/env.rb +66 -0
  13. data/lib/cocoapods/command/init.rb +128 -0
  14. data/lib/cocoapods/command/install.rb +45 -0
  15. data/lib/cocoapods/command/ipc.rb +19 -0
  16. data/lib/cocoapods/command/ipc/list.rb +40 -0
  17. data/lib/cocoapods/command/ipc/podfile.rb +31 -0
  18. data/lib/cocoapods/command/ipc/podfile_json.rb +30 -0
  19. data/lib/cocoapods/command/ipc/repl.rb +51 -0
  20. data/lib/cocoapods/command/ipc/spec.rb +29 -0
  21. data/lib/cocoapods/command/ipc/update_search_index.rb +24 -0
  22. data/lib/cocoapods/command/lib.rb +11 -0
  23. data/lib/cocoapods/command/lib/create.rb +105 -0
  24. data/lib/cocoapods/command/lib/lint.rb +121 -0
  25. data/lib/cocoapods/command/list.rb +39 -0
  26. data/lib/cocoapods/command/options/project_directory.rb +36 -0
  27. data/lib/cocoapods/command/options/repo_update.rb +34 -0
  28. data/lib/cocoapods/command/outdated.rb +140 -0
  29. data/lib/cocoapods/command/repo.rb +29 -0
  30. data/lib/cocoapods/command/repo/add.rb +103 -0
  31. data/lib/cocoapods/command/repo/lint.rb +82 -0
  32. data/lib/cocoapods/command/repo/list.rb +93 -0
  33. data/lib/cocoapods/command/repo/push.rb +281 -0
  34. data/lib/cocoapods/command/repo/remove.rb +36 -0
  35. data/lib/cocoapods/command/repo/update.rb +28 -0
  36. data/lib/cocoapods/command/setup.rb +103 -0
  37. data/lib/cocoapods/command/spec.rb +112 -0
  38. data/lib/cocoapods/command/spec/cat.rb +51 -0
  39. data/lib/cocoapods/command/spec/create.rb +283 -0
  40. data/lib/cocoapods/command/spec/edit.rb +87 -0
  41. data/lib/cocoapods/command/spec/env_spec.rb +53 -0
  42. data/lib/cocoapods/command/spec/lint.rb +137 -0
  43. data/lib/cocoapods/command/spec/which.rb +43 -0
  44. data/lib/cocoapods/command/update.rb +101 -0
  45. data/lib/cocoapods/config.rb +347 -0
  46. data/lib/cocoapods/core_overrides.rb +1 -0
  47. data/lib/cocoapods/downloader.rb +190 -0
  48. data/lib/cocoapods/downloader/cache.rb +233 -0
  49. data/lib/cocoapods/downloader/request.rb +86 -0
  50. data/lib/cocoapods/downloader/response.rb +16 -0
  51. data/lib/cocoapods/executable.rb +222 -0
  52. data/lib/cocoapods/external_sources.rb +57 -0
  53. data/lib/cocoapods/external_sources/abstract_external_source.rb +205 -0
  54. data/lib/cocoapods/external_sources/downloader_source.rb +30 -0
  55. data/lib/cocoapods/external_sources/path_source.rb +55 -0
  56. data/lib/cocoapods/external_sources/podspec_source.rb +54 -0
  57. data/lib/cocoapods/gem_version.rb +5 -0
  58. data/lib/cocoapods/generator/acknowledgements.rb +107 -0
  59. data/lib/cocoapods/generator/acknowledgements/markdown.rb +44 -0
  60. data/lib/cocoapods/generator/acknowledgements/plist.rb +94 -0
  61. data/lib/cocoapods/generator/app_target_helper.rb +244 -0
  62. data/lib/cocoapods/generator/bridge_support.rb +22 -0
  63. data/lib/cocoapods/generator/constant.rb +19 -0
  64. data/lib/cocoapods/generator/copy_resources_script.rb +230 -0
  65. data/lib/cocoapods/generator/dummy_source.rb +31 -0
  66. data/lib/cocoapods/generator/embed_frameworks_script.rb +215 -0
  67. data/lib/cocoapods/generator/header.rb +103 -0
  68. data/lib/cocoapods/generator/info_plist_file.rb +116 -0
  69. data/lib/cocoapods/generator/module_map.rb +99 -0
  70. data/lib/cocoapods/generator/prefix_header.rb +60 -0
  71. data/lib/cocoapods/generator/umbrella_header.rb +46 -0
  72. data/lib/cocoapods/hooks_manager.rb +132 -0
  73. data/lib/cocoapods/installer.rb +703 -0
  74. data/lib/cocoapods/installer/analyzer.rb +972 -0
  75. data/lib/cocoapods/installer/analyzer/analysis_result.rb +87 -0
  76. data/lib/cocoapods/installer/analyzer/locking_dependency_analyzer.rb +98 -0
  77. data/lib/cocoapods/installer/analyzer/pod_variant.rb +67 -0
  78. data/lib/cocoapods/installer/analyzer/pod_variant_set.rb +157 -0
  79. data/lib/cocoapods/installer/analyzer/podfile_dependency_cache.rb +54 -0
  80. data/lib/cocoapods/installer/analyzer/sandbox_analyzer.rb +240 -0
  81. data/lib/cocoapods/installer/analyzer/specs_state.rb +84 -0
  82. data/lib/cocoapods/installer/analyzer/target_inspection_result.rb +53 -0
  83. data/lib/cocoapods/installer/analyzer/target_inspector.rb +260 -0
  84. data/lib/cocoapods/installer/installation_options.rb +158 -0
  85. data/lib/cocoapods/installer/pod_source_installer.rb +202 -0
  86. data/lib/cocoapods/installer/pod_source_preparer.rb +77 -0
  87. data/lib/cocoapods/installer/podfile_validator.rb +139 -0
  88. data/lib/cocoapods/installer/post_install_hooks_context.rb +132 -0
  89. data/lib/cocoapods/installer/pre_install_hooks_context.rb +51 -0
  90. data/lib/cocoapods/installer/source_provider_hooks_context.rb +34 -0
  91. data/lib/cocoapods/installer/user_project_integrator.rb +250 -0
  92. data/lib/cocoapods/installer/user_project_integrator/target_integrator.rb +463 -0
  93. data/lib/cocoapods/installer/user_project_integrator/target_integrator/xcconfig_integrator.rb +146 -0
  94. data/lib/cocoapods/installer/xcode.rb +8 -0
  95. data/lib/cocoapods/installer/xcode/pods_project_generator.rb +416 -0
  96. data/lib/cocoapods/installer/xcode/pods_project_generator/aggregate_target_installer.rb +181 -0
  97. data/lib/cocoapods/installer/xcode/pods_project_generator/app_host_installer.rb +84 -0
  98. data/lib/cocoapods/installer/xcode/pods_project_generator/file_references_installer.rb +334 -0
  99. data/lib/cocoapods/installer/xcode/pods_project_generator/pod_target_installer.rb +777 -0
  100. data/lib/cocoapods/installer/xcode/pods_project_generator/pod_target_integrator.rb +116 -0
  101. data/lib/cocoapods/installer/xcode/pods_project_generator/target_installation_result.rb +86 -0
  102. data/lib/cocoapods/installer/xcode/pods_project_generator/target_installer.rb +256 -0
  103. data/lib/cocoapods/installer/xcode/pods_project_generator/target_installer_helper.rb +68 -0
  104. data/lib/cocoapods/installer/xcode/target_validator.rb +147 -0
  105. data/lib/cocoapods/open-uri.rb +33 -0
  106. data/lib/cocoapods/project.rb +414 -0
  107. data/lib/cocoapods/resolver.rb +585 -0
  108. data/lib/cocoapods/resolver/lazy_specification.rb +79 -0
  109. data/lib/cocoapods/sandbox.rb +404 -0
  110. data/lib/cocoapods/sandbox/file_accessor.rb +444 -0
  111. data/lib/cocoapods/sandbox/headers_store.rb +146 -0
  112. data/lib/cocoapods/sandbox/path_list.rb +220 -0
  113. data/lib/cocoapods/sandbox/pod_dir_cleaner.rb +85 -0
  114. data/lib/cocoapods/sandbox/podspec_finder.rb +23 -0
  115. data/lib/cocoapods/sources_manager.rb +157 -0
  116. data/lib/cocoapods/target.rb +261 -0
  117. data/lib/cocoapods/target/aggregate_target.rb +338 -0
  118. data/lib/cocoapods/target/build_settings.rb +1075 -0
  119. data/lib/cocoapods/target/pod_target.rb +559 -0
  120. data/lib/cocoapods/user_interface.rb +459 -0
  121. data/lib/cocoapods/user_interface/error_report.rb +187 -0
  122. data/lib/cocoapods/user_interface/inspector_reporter.rb +109 -0
  123. data/lib/cocoapods/validator.rb +981 -0
  124. metadata +533 -0
@@ -0,0 +1,146 @@
1
+ module Pod
2
+ class Installer
3
+ class UserProjectIntegrator
4
+ class TargetIntegrator
5
+ # Configures an user target to use the CocoaPods xcconfigs which allow
6
+ # lo link against the Pods.
7
+ #
8
+ class XCConfigIntegrator
9
+ # Integrates the user target.
10
+ #
11
+ # @param [Target::AggregateTarget] pod_bundle
12
+ # The Pods bundle.
13
+ #
14
+ # @param [Array<PBXNativeTarget>] targets
15
+ # The native targets associated which should be integrated
16
+ # with the Pod bundle.
17
+ #
18
+ def self.integrate(pod_bundle, targets)
19
+ targets.each do |target|
20
+ target.build_configurations.each do |config|
21
+ set_target_xcconfig(pod_bundle, target, config)
22
+ end
23
+ end
24
+ end
25
+
26
+ private
27
+
28
+ # @!group Integration steps
29
+ #-------------------------------------------------------------------#
30
+
31
+ # Creates a file reference to the xcconfig generated by
32
+ # CocoaPods (if needed) and sets it as the base configuration of
33
+ # build configuration of the user target.
34
+ #
35
+ # @param [Target::AggregateTarget] pod_bundle
36
+ # The Pods bundle.
37
+ #
38
+ # @param [PBXNativeTarget] target
39
+ # The native target.
40
+ #
41
+ # @param [Xcodeproj::XCBuildConfiguration] config
42
+ # The build configuration.
43
+ #
44
+ def self.set_target_xcconfig(pod_bundle, target, config)
45
+ path = pod_bundle.xcconfig_relative_path(config.name)
46
+ group = config.project['Pods'] || config.project.new_group('Pods')
47
+ file_ref = group.files.find { |f| f.path == path }
48
+ existing = config.base_configuration_reference
49
+
50
+ set_base_configuration_reference = ->() do
51
+ file_ref ||= group.new_file(path)
52
+ config.base_configuration_reference = file_ref
53
+ end
54
+
55
+ if existing && existing != file_ref
56
+ if existing.real_path.to_path.start_with?(pod_bundle.sandbox.root.to_path << '/')
57
+ set_base_configuration_reference.call
58
+ elsif !xcconfig_includes_target_xcconfig?(config.base_configuration_reference, path)
59
+ unless existing_config_is_identical_to_pod_config?(existing.real_path, pod_bundle.xcconfig_path(config.name))
60
+ UI.warn 'CocoaPods did not set the base configuration of your ' \
61
+ 'project because your project already has a custom ' \
62
+ 'config set. In order for CocoaPods integration to work at ' \
63
+ 'all, please either set the base configurations of the target ' \
64
+ "`#{target.name}` to `#{path}` or include the `#{path}` in your " \
65
+ "build configuration (#{UI.path(existing.real_path)})."
66
+ end
67
+ end
68
+ elsif config.base_configuration_reference.nil? || file_ref.nil?
69
+ set_base_configuration_reference.call
70
+ end
71
+ end
72
+
73
+ private
74
+
75
+ # @!group Private helpers
76
+ #-------------------------------------------------------------------#
77
+
78
+ # Prints a warning informing the user that a build configuration of
79
+ # the integrated target is overriding the CocoaPods build settings.
80
+ #
81
+ # @param [Target::AggregateTarget] pod_bundle
82
+ # The Pods bundle.
83
+ #
84
+ # @param [XcodeProj::PBXNativeTarget] target
85
+ # The native target.
86
+ #
87
+ # @param [Xcodeproj::XCBuildConfiguration] config
88
+ # The build configuration.
89
+ #
90
+ # @param [String] key
91
+ # The key of the overridden build setting.
92
+ #
93
+ def self.print_override_warning(pod_bundle, target, config, key)
94
+ actions = [
95
+ 'Use the `$(inherited)` flag, or',
96
+ 'Remove the build settings from the target.',
97
+ ]
98
+ message = "The `#{target.name} [#{config.name}]` " \
99
+ "target overrides the `#{key}` build setting defined in " \
100
+ "`#{pod_bundle.xcconfig_relative_path(config.name)}'. " \
101
+ 'This can lead to problems with the CocoaPods installation'
102
+ UI.warn(message, actions)
103
+ end
104
+
105
+ # Naively checks to see if a given PBXFileReference imports a given
106
+ # path.
107
+ #
108
+ # @param [PBXFileReference] base_config_ref
109
+ # A file reference to an `.xcconfig` file.
110
+ #
111
+ # @param [String] target_config_path
112
+ # The path to check for.
113
+ #
114
+ SILENCE_WARNINGS_STRING = '// @COCOAPODS_SILENCE_WARNINGS@ //'
115
+ def self.xcconfig_includes_target_xcconfig?(base_config_ref, target_config_path)
116
+ return unless base_config_ref && base_config_ref.real_path.file?
117
+ regex = %r{
118
+ ^(
119
+ (\s* # Possible, but unlikely, space before include statement
120
+ \#include\s+ # Include statement
121
+ ['"] # Open quote
122
+ (.*\/)? # Possible prefix to path
123
+ #{Regexp.quote(target_config_path)} # The path should end in the target_config_path
124
+ ['"] # Close quote
125
+ )
126
+ |
127
+ (#{Regexp.quote(SILENCE_WARNINGS_STRING)}) # Token to treat xcconfig as good and silence pod install warnings
128
+ )
129
+ }x
130
+ base_config_ref.real_path.readlines.find { |line| line =~ regex }
131
+ end
132
+
133
+ # Checks to see if the config files at two paths exist and are identical
134
+ #
135
+ # @param The existing config path
136
+ #
137
+ # @param The pod config path
138
+ #
139
+ def self.existing_config_is_identical_to_pod_config?(existing_config_path, pod_config_path)
140
+ existing_config_path.file? && (!pod_config_path.file? || FileUtils.compare_file(existing_config_path, pod_config_path))
141
+ end
142
+ end
143
+ end
144
+ end
145
+ end
146
+ end
@@ -0,0 +1,8 @@
1
+ module Pod
2
+ class Installer
3
+ class Xcode
4
+ autoload :PodsProjectGenerator, 'cocoapods/installer/xcode/pods_project_generator'
5
+ autoload :TargetValidator, 'cocoapods/installer/xcode/target_validator'
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,416 @@
1
+ module Pod
2
+ class Installer
3
+ class Xcode
4
+ # The {PodsProjectGenerator} handles generation of the 'Pods/Pods.xcodeproj'
5
+ #
6
+ class PodsProjectGenerator
7
+ require 'cocoapods/installer/xcode/pods_project_generator/target_installer_helper'
8
+ require 'cocoapods/installer/xcode/pods_project_generator/pod_target_integrator'
9
+ require 'cocoapods/installer/xcode/pods_project_generator/target_installer'
10
+ require 'cocoapods/installer/xcode/pods_project_generator/target_installation_result'
11
+ require 'cocoapods/installer/xcode/pods_project_generator/pod_target_installer'
12
+ require 'cocoapods/installer/xcode/pods_project_generator/file_references_installer'
13
+ require 'cocoapods/installer/xcode/pods_project_generator/aggregate_target_installer'
14
+ require 'cocoapods/installer/xcode/pods_project_generator/app_host_installer'
15
+
16
+ # @return [Sandbox] The sandbox where the Pods should be installed.
17
+ #
18
+ attr_reader :sandbox
19
+
20
+ # @return [Pod::Project] the `Pods/Pods.xcodeproj` project.
21
+ #
22
+ attr_reader :project
23
+
24
+ # @return [Array<AggregateTarget>] The model representations of an
25
+ # aggregation of pod targets generated for a target definition
26
+ # in the Podfile.
27
+ #
28
+ attr_reader :aggregate_targets
29
+
30
+ # @return [Array<PodTarget>] The model representations of pod targets.
31
+ #
32
+ attr_reader :pod_targets
33
+
34
+ # @return [Analyzer] the analyzer which provides the information about what
35
+ # needs to be installed.
36
+ #
37
+ attr_reader :analysis_result
38
+
39
+ # @return [InstallationOptions] the installation options from the Podfile.
40
+ #
41
+ attr_reader :installation_options
42
+
43
+ # @return [Config] the global CocoaPods configuration.
44
+ #
45
+ attr_reader :config
46
+
47
+ # Initialize a new instance
48
+ #
49
+ # @param [Sandbox] sandbox @see #sandbox
50
+ # @param [Array<AggregateTarget>] aggregate_targets @see #aggregate_targets
51
+ # @param [Array<PodTarget>] pod_targets @see #pod_targets
52
+ # @param [Analyzer] analysis_result @see #analysis_result
53
+ # @param [InstallationOptions] installation_options @see #installation_options
54
+ # @param [Config] config @see #config
55
+ #
56
+ def initialize(sandbox, aggregate_targets, pod_targets, analysis_result, installation_options, config)
57
+ @sandbox = sandbox
58
+ @aggregate_targets = aggregate_targets
59
+ @pod_targets = pod_targets
60
+ @analysis_result = analysis_result
61
+ @installation_options = installation_options
62
+ @config = config
63
+ end
64
+
65
+ def generate!
66
+ prepare
67
+ install_file_references
68
+ @target_installation_results = install_targets
69
+ integrate_targets(@target_installation_results.pod_target_installation_results)
70
+ app_hosts_by_host_key = install_app_hosts
71
+ wire_target_dependencies(@target_installation_results, app_hosts_by_host_key)
72
+ @target_installation_results
73
+ end
74
+
75
+ def write
76
+ UI.message "- Writing Xcode project file to #{UI.path sandbox.project_path}" do
77
+ project.pods.remove_from_project if project.pods.empty?
78
+ project.development_pods.remove_from_project if project.development_pods.empty?
79
+ project.sort(:groups_position => :below)
80
+ if installation_options.deterministic_uuids?
81
+ UI.message('- Generating deterministic UUIDs') { project.predictabilize_uuids }
82
+ end
83
+ library_product_types = [:framework, :dynamic_library, :static_library]
84
+
85
+ pod_target_installation_results = @target_installation_results.pod_target_installation_results
86
+ results_by_native_target = Hash[pod_target_installation_results.map do |_, result|
87
+ [result.native_target, result]
88
+ end]
89
+ project.recreate_user_schemes(false) do |scheme, target|
90
+ next unless target.respond_to?(:symbol_type)
91
+ next unless library_product_types.include? target.symbol_type
92
+ installation_result = results_by_native_target[target]
93
+ next unless installation_result
94
+ installation_result.test_native_targets.each do |test_native_target|
95
+ scheme.add_test_target(test_native_target)
96
+ end
97
+ end
98
+ project.save
99
+ end
100
+ end
101
+
102
+ # Shares schemes of development Pods.
103
+ #
104
+ # @return [void]
105
+ #
106
+ def share_development_pod_schemes
107
+ development_pod_targets.select(&:should_build?).each do |pod_target|
108
+ next unless share_scheme_for_development_pod?(pod_target.pod_name)
109
+ Xcodeproj::XCScheme.share_scheme(project.path, pod_target.label)
110
+ if pod_target.contains_test_specifications?
111
+ pod_target.supported_test_types.each do |test_type|
112
+ Xcodeproj::XCScheme.share_scheme(project.path, pod_target.test_target_label(test_type))
113
+ end
114
+ end
115
+ end
116
+ end
117
+
118
+ private
119
+
120
+ AppHostKey = Struct.new(:test_type, :platform)
121
+ InstallationResults = Struct.new(:pod_target_installation_results, :aggregate_target_installation_results)
122
+
123
+ def create_project
124
+ if object_version = aggregate_targets.map(&:user_project).compact.map { |p| p.object_version.to_i }.min
125
+ Pod::Project.new(sandbox.project_path, false, object_version)
126
+ else
127
+ Pod::Project.new(sandbox.project_path)
128
+ end
129
+ end
130
+
131
+ # Creates the Pods project from scratch if it doesn't exists.
132
+ #
133
+ # @return [void]
134
+ #
135
+ # @todo Clean and modify the project if it exists.
136
+ #
137
+ def prepare
138
+ UI.message '- Creating Pods project' do
139
+ @project = create_project
140
+ analysis_result.all_user_build_configurations.each do |name, type|
141
+ @project.add_build_configuration(name, type)
142
+ end
143
+ # Reset symroot just in case the user has added a new build configuration other than 'Debug' or 'Release'.
144
+ @project.symroot = Pod::Project::LEGACY_BUILD_ROOT
145
+
146
+ pod_names = pod_targets.map(&:pod_name).uniq
147
+ pod_names.each do |pod_name|
148
+ local = sandbox.local?(pod_name)
149
+ path = sandbox.pod_dir(pod_name)
150
+ was_absolute = sandbox.local_path_was_absolute?(pod_name)
151
+ @project.add_pod_group(pod_name, path, local, was_absolute)
152
+ end
153
+
154
+ if config.podfile_path
155
+ @project.add_podfile(config.podfile_path)
156
+ end
157
+
158
+ sandbox.project = @project
159
+ platforms = aggregate_targets.map(&:platform)
160
+ osx_deployment_target = platforms.select { |p| p.name == :osx }.map(&:deployment_target).min
161
+ ios_deployment_target = platforms.select { |p| p.name == :ios }.map(&:deployment_target).min
162
+ watchos_deployment_target = platforms.select { |p| p.name == :watchos }.map(&:deployment_target).min
163
+ tvos_deployment_target = platforms.select { |p| p.name == :tvos }.map(&:deployment_target).min
164
+ @project.build_configurations.each do |build_configuration|
165
+ build_configuration.build_settings['MACOSX_DEPLOYMENT_TARGET'] = osx_deployment_target.to_s if osx_deployment_target
166
+ build_configuration.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = ios_deployment_target.to_s if ios_deployment_target
167
+ build_configuration.build_settings['WATCHOS_DEPLOYMENT_TARGET'] = watchos_deployment_target.to_s if watchos_deployment_target
168
+ build_configuration.build_settings['TVOS_DEPLOYMENT_TARGET'] = tvos_deployment_target.to_s if tvos_deployment_target
169
+ build_configuration.build_settings['STRIP_INSTALLED_PRODUCT'] = 'NO'
170
+ build_configuration.build_settings['CLANG_ENABLE_OBJC_ARC'] = 'YES'
171
+ build_configuration.build_settings['CODE_SIGNING_REQUIRED'] = 'NO'
172
+ build_configuration.build_settings['CODE_SIGNING_ALLOWED'] = 'NO'
173
+ end
174
+ end
175
+ end
176
+
177
+ def install_file_references
178
+ installer = FileReferencesInstaller.new(sandbox, pod_targets, project)
179
+ installer.install!
180
+ end
181
+
182
+ def install_targets
183
+ UI.message '- Installing targets' do
184
+ umbrella_headers_by_dir = pod_targets.map do |pod_target|
185
+ next unless pod_target.should_build? && pod_target.defines_module?
186
+ pod_target.umbrella_header_path
187
+ end.compact.group_by(&:dirname)
188
+
189
+ pod_target_installation_results = Hash[pod_targets.sort_by(&:name).map do |pod_target|
190
+ umbrella_headers_in_header_dir = umbrella_headers_by_dir[pod_target.module_map_path.dirname]
191
+ target_installer = PodTargetInstaller.new(sandbox, @project, pod_target, umbrella_headers_in_header_dir)
192
+ [pod_target.name, target_installer.install!]
193
+ end]
194
+
195
+ # Hook up system framework dependencies for the pod targets that were just installed.
196
+ pod_target_installation_result_values = pod_target_installation_results.values.compact
197
+ unless pod_target_installation_result_values.empty?
198
+ add_system_framework_dependencies(pod_target_installation_result_values)
199
+ end
200
+
201
+ aggregate_target_installation_results = Hash[aggregate_targets.sort_by(&:name).map do |target|
202
+ target_installer = AggregateTargetInstaller.new(sandbox, @project, target)
203
+ [target.name, target_installer.install!]
204
+ end]
205
+
206
+ InstallationResults.new(pod_target_installation_results, aggregate_target_installation_results)
207
+ end
208
+ end
209
+
210
+ def install_app_hosts
211
+ pod_target_with_test_specs = pod_targets.reject do |pod_target|
212
+ pod_target.test_specs.empty? || pod_target.test_spec_consumers.none?(&:requires_app_host?)
213
+ end
214
+
215
+ return if pod_target_with_test_specs.empty?
216
+
217
+ UI.message '- Installing app hosts' do
218
+ app_host_keys = pod_target_with_test_specs.flat_map do |pod_target|
219
+ pod_target.supported_test_types.flat_map do |test_type|
220
+ AppHostKey.new(test_type, pod_target.platform)
221
+ end.uniq
222
+ end
223
+
224
+ app_host_keys_by_test_type = app_host_keys.group_by do |app_host_key|
225
+ [app_host_key.test_type, app_host_key.platform.symbolic_name]
226
+ end
227
+
228
+ app_host_keys_by_test_type.map do |(test_type, platform_symbol), keys|
229
+ deployment_target = keys.map { |k| k.platform.deployment_target }.max
230
+ platform = Platform.new(platform_symbol, deployment_target)
231
+ AppHostKey.new(test_type, platform)
232
+ end
233
+
234
+ Hash[app_host_keys.map do |app_host_key|
235
+ [app_host_key, AppHostInstaller.new(sandbox, project, app_host_key.platform, app_host_key.test_type).install!]
236
+ end]
237
+ end
238
+ end
239
+
240
+ def integrate_targets(pod_target_installation_results)
241
+ pod_installations_to_integrate = pod_target_installation_results.values.select do |pod_target_installation_result|
242
+ pod_target = pod_target_installation_result.target
243
+ !pod_target_installation_result.test_native_targets.empty? || pod_target.contains_script_phases?
244
+ end
245
+ unless pod_installations_to_integrate.empty?
246
+ UI.message '- Integrating targets' do
247
+ pod_installations_to_integrate.each do |pod_target_installation_result|
248
+ PodTargetIntegrator.new(pod_target_installation_result).integrate!
249
+ end
250
+ end
251
+ end
252
+ end
253
+
254
+ def add_system_framework_dependencies(pod_target_installation_results)
255
+ sorted_installation_results = pod_target_installation_results.sort_by do |pod_target_installation_result|
256
+ pod_target_installation_result.target.name
257
+ end
258
+ sorted_installation_results.each do |target_installation_result|
259
+ pod_target = target_installation_result.target
260
+ next unless pod_target.should_build?
261
+ next if !pod_target.requires_frameworks? || pod_target.static_framework?
262
+ pod_target.file_accessors.each do |file_accessor|
263
+ native_target = target_installation_result.native_target_for_spec(file_accessor.spec)
264
+ add_system_frameworks_to_native_target(native_target, file_accessor)
265
+ end
266
+ end
267
+ end
268
+
269
+ # Adds a target dependency for each pod spec to each aggregate target and
270
+ # links the pod targets among each other.
271
+ #
272
+ # @param [Array[Hash{String=>TargetInstallationResult}]] target_installation_results
273
+ # the installation results that were produced when all targets were installed. This includes
274
+ # pod target installation results and aggregate target installation results.
275
+ #
276
+ # @param [Hash{AppHostKey=>Array<PBXNativeTarget>}] app_hosts_by_host_key
277
+ # the app hosts by test type that were installed in #install_app_hosts
278
+ #
279
+ # @return [void]
280
+ #
281
+ def wire_target_dependencies(target_installation_results, app_hosts_by_host_key)
282
+ frameworks_group = project.frameworks_group
283
+ pod_target_installation_results_hash = target_installation_results.pod_target_installation_results
284
+ aggregate_target_installation_results_hash = target_installation_results.aggregate_target_installation_results
285
+
286
+ # Wire up aggregate targets
287
+ aggregate_target_installation_results_hash.values.each do |aggregate_target_installation_result|
288
+ aggregate_target = aggregate_target_installation_result.target
289
+ aggregate_native_target = aggregate_target_installation_result.native_target
290
+ is_app_extension = !(aggregate_target.user_targets.map(&:symbol_type) &
291
+ [:app_extension, :watch_extension, :watch2_extension, :tv_extension, :messages_extension]).empty?
292
+ is_app_extension ||= aggregate_target.user_targets.any? { |ut| ut.common_resolved_build_setting('APPLICATION_EXTENSION_API_ONLY') == 'YES' }
293
+ configure_app_extension_api_only_to_native_target(aggregate_native_target) if is_app_extension
294
+ # Wire up dependencies that are part of inherit search paths for this aggregate target.
295
+ aggregate_target.search_paths_aggregate_targets.each do |search_paths_target|
296
+ aggregate_native_target.add_dependency(aggregate_target_installation_results_hash[search_paths_target.name].native_target)
297
+ end
298
+ # Wire up all pod target dependencies to aggregate target.
299
+ aggregate_target.pod_targets.each do |pod_target|
300
+ pod_target_native_target = pod_target_installation_results_hash[pod_target.name].native_target
301
+ aggregate_native_target.add_dependency(pod_target_native_target)
302
+ configure_app_extension_api_only_to_native_target(pod_target_native_target) if is_app_extension
303
+ end
304
+ end
305
+
306
+ # Wire up pod targets
307
+ pod_target_installation_results_hash.values.each do |pod_target_installation_result|
308
+ pod_target = pod_target_installation_result.target
309
+ native_target = pod_target_installation_result.native_target
310
+ # First, wire up all resource bundles.
311
+ pod_target_installation_result.resource_bundle_targets.each do |resource_bundle_target|
312
+ native_target.add_dependency(resource_bundle_target)
313
+ if pod_target.requires_frameworks? && pod_target.should_build?
314
+ native_target.add_resources([resource_bundle_target.product_reference])
315
+ end
316
+ end
317
+ # Wire up all dependencies to this pod target, if any.
318
+ dependent_targets = pod_target.dependent_targets
319
+ dependent_targets.each do |dependent_target|
320
+ native_target.add_dependency(pod_target_installation_results_hash[dependent_target.name].native_target)
321
+ add_framework_file_reference_to_native_target(native_target, pod_target, dependent_target, frameworks_group)
322
+ end
323
+ # Wire up test native targets.
324
+ unless pod_target_installation_result.test_native_targets.empty?
325
+ pod_target_installation_result.test_specs_by_native_target.each do |test_native_target, test_specs|
326
+ test_dependent_targets = test_specs.flat_map { |s| pod_target.test_dependent_targets_by_spec_name[s.name] }.compact.unshift(pod_target).uniq
327
+ test_dependent_targets.each do |test_dependent_target|
328
+ dependency_installation_result = pod_target_installation_results_hash[test_dependent_target.name]
329
+ dependency_installation_result.test_resource_bundle_targets.values.flatten.each do |test_resource_bundle_target|
330
+ test_native_target.add_dependency(test_resource_bundle_target)
331
+ end
332
+ test_native_target.add_dependency(dependency_installation_result.native_target)
333
+ add_framework_file_reference_to_native_target(test_native_target, pod_target, test_dependent_target, frameworks_group)
334
+ # Wire app host dependencies to test native target
335
+ if pod_target.test_spec_consumers.any?(&:requires_app_host?)
336
+ pod_target.supported_test_types.each do |test_type|
337
+ app_host_target = app_hosts_by_host_key[AppHostKey.new(test_type, pod_target.platform)]
338
+ test_native_target.add_dependency(app_host_target)
339
+ configure_app_host_to_native_target(app_host_target, test_native_target)
340
+ end
341
+ end
342
+ end
343
+ end
344
+ end
345
+ end
346
+ end
347
+
348
+ # @param [String] pod The root name of the development pod.
349
+ #
350
+ # @return [Bool] whether the scheme for the given development pod should be
351
+ # shared.
352
+ #
353
+ def share_scheme_for_development_pod?(pod)
354
+ case dev_pods_to_share = installation_options.share_schemes_for_development_pods
355
+ when TrueClass, FalseClass, NilClass
356
+ dev_pods_to_share
357
+ when Array
358
+ dev_pods_to_share.any? { |dev_pod| dev_pod === pod } # rubocop:disable Style/CaseEquality
359
+ else
360
+ raise Informative, 'Unable to handle share_schemes_for_development_pods ' \
361
+ "being set to #{dev_pods_to_share.inspect} -- please set it to true, " \
362
+ 'false, or an array of pods to share schemes for.'
363
+ end
364
+ end
365
+
366
+ # @return [Array<Library>] The targets of the development pods generated by
367
+ # the installation process.
368
+ #
369
+ def development_pod_targets
370
+ pod_targets.select do |pod_target|
371
+ sandbox.local?(pod_target.pod_name)
372
+ end
373
+ end
374
+
375
+ #------------------------------------------------------------------------#
376
+
377
+ # @! group Private Helpers
378
+
379
+ def add_system_frameworks_to_native_target(native_target, file_accessor)
380
+ file_accessor.spec_consumer.frameworks.each do |framework|
381
+ native_target.add_system_framework(framework)
382
+ end
383
+ end
384
+
385
+ def add_framework_file_reference_to_native_target(native_target, pod_target, dependent_target, frameworks_group)
386
+ if pod_target.should_build? && pod_target.requires_frameworks? && !pod_target.static_framework? && dependent_target.should_build?
387
+ product_ref = frameworks_group.files.find { |f| f.path == dependent_target.product_name } ||
388
+ frameworks_group.new_product_ref_for_target(dependent_target.product_basename, dependent_target.product_type)
389
+ native_target.frameworks_build_phase.add_file_reference(product_ref, true)
390
+ end
391
+ end
392
+
393
+ # Sets the APPLICATION_EXTENSION_API_ONLY build setting to YES for all
394
+ # configurations of the given native target.
395
+ #
396
+ def configure_app_extension_api_only_to_native_target(native_target)
397
+ native_target.build_configurations.each do |config|
398
+ config.build_settings['APPLICATION_EXTENSION_API_ONLY'] = 'YES'
399
+ end
400
+ end
401
+
402
+ def configure_app_host_to_native_target(app_host_target, test_native_target)
403
+ test_native_target.build_configurations.each do |configuration|
404
+ test_host = "$(BUILT_PRODUCTS_DIR)/#{app_host_target.name}.app/"
405
+ test_host << 'Contents/MacOS/' if app_host_target.platform_name == :osx
406
+ test_host << app_host_target.name.to_s
407
+ configuration.build_settings['TEST_HOST'] = test_host
408
+ end
409
+ target_attributes = project.root_object.attributes['TargetAttributes'] || {}
410
+ target_attributes[test_native_target.uuid.to_s] = { 'TestTargetID' => app_host_target.uuid.to_s }
411
+ project.root_object.attributes['TargetAttributes'] = target_attributes
412
+ end
413
+ end
414
+ end
415
+ end
416
+ end