xcocoapods 1.5.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.
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