cocoapods-tt 0.0.1
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.
- checksums.yaml +7 -0
- data/lib/cocoapods-tt/command/native/install.rb +56 -0
- data/lib/cocoapods-tt/command/native/update.rb +157 -0
- data/lib/cocoapods-tt/command/tt/make.rb +92 -0
- data/lib/cocoapods-tt/command/tt.rb +115 -0
- data/lib/cocoapods-tt/command.rb +1 -0
- data/lib/cocoapods-tt/gem_version.rb +3 -0
- data/lib/cocoapods-tt/native/command.rb +185 -0
- data/lib/cocoapods-tt/native/config.rb +366 -0
- data/lib/cocoapods-tt/native/core_overrides.rb +1 -0
- data/lib/cocoapods-tt/native/downloader/cache.rb +322 -0
- data/lib/cocoapods-tt/native/downloader/request.rb +86 -0
- data/lib/cocoapods-tt/native/downloader/response.rb +16 -0
- data/lib/cocoapods-tt/native/downloader.rb +192 -0
- data/lib/cocoapods-tt/native/executable.rb +247 -0
- data/lib/cocoapods-tt/native/external_sources/abstract_external_source.rb +205 -0
- data/lib/cocoapods-tt/native/external_sources/downloader_source.rb +30 -0
- data/lib/cocoapods-tt/native/external_sources/path_source.rb +55 -0
- data/lib/cocoapods-tt/native/external_sources/podspec_source.rb +54 -0
- data/lib/cocoapods-tt/native/external_sources.rb +57 -0
- data/lib/cocoapods-tt/native/gem_version.rb +5 -0
- data/lib/cocoapods-tt/native/generator/acknowledgements/markdown.rb +44 -0
- data/lib/cocoapods-tt/native/generator/acknowledgements/plist.rb +94 -0
- data/lib/cocoapods-tt/native/generator/acknowledgements.rb +107 -0
- data/lib/cocoapods-tt/native/generator/app_target_helper.rb +363 -0
- data/lib/cocoapods-tt/native/generator/bridge_support.rb +22 -0
- data/lib/cocoapods-tt/native/generator/constant.rb +19 -0
- data/lib/cocoapods-tt/native/generator/copy_dsyms_script.rb +56 -0
- data/lib/cocoapods-tt/native/generator/copy_resources_script.rb +223 -0
- data/lib/cocoapods-tt/native/generator/copy_xcframework_script.rb +227 -0
- data/lib/cocoapods-tt/native/generator/dummy_source.rb +31 -0
- data/lib/cocoapods-tt/native/generator/embed_frameworks_script.rb +196 -0
- data/lib/cocoapods-tt/native/generator/file_list.rb +39 -0
- data/lib/cocoapods-tt/native/generator/header.rb +103 -0
- data/lib/cocoapods-tt/native/generator/info_plist_file.rb +128 -0
- data/lib/cocoapods-tt/native/generator/module_map.rb +99 -0
- data/lib/cocoapods-tt/native/generator/prefix_header.rb +60 -0
- data/lib/cocoapods-tt/native/generator/script_phase_constants.rb +100 -0
- data/lib/cocoapods-tt/native/generator/umbrella_header.rb +46 -0
- data/lib/cocoapods-tt/native/hooks_manager.rb +132 -0
- data/lib/cocoapods-tt/native/installer/analyzer/analysis_result.rb +87 -0
- data/lib/cocoapods-tt/native/installer/analyzer/locking_dependency_analyzer.rb +103 -0
- data/lib/cocoapods-tt/native/installer/analyzer/pod_variant.rb +87 -0
- data/lib/cocoapods-tt/native/installer/analyzer/pod_variant_set.rb +175 -0
- data/lib/cocoapods-tt/native/installer/analyzer/podfile_dependency_cache.rb +55 -0
- data/lib/cocoapods-tt/native/installer/analyzer/sandbox_analyzer.rb +268 -0
- data/lib/cocoapods-tt/native/installer/analyzer/specs_state.rb +108 -0
- data/lib/cocoapods-tt/native/installer/analyzer/target_inspection_result.rb +58 -0
- data/lib/cocoapods-tt/native/installer/analyzer/target_inspector.rb +258 -0
- data/lib/cocoapods-tt/native/installer/analyzer.rb +1204 -0
- data/lib/cocoapods-tt/native/installer/base_install_hooks_context.rb +135 -0
- data/lib/cocoapods-tt/native/installer/installation_options.rb +195 -0
- data/lib/cocoapods-tt/native/installer/pod_source_installer.rb +224 -0
- data/lib/cocoapods-tt/native/installer/pod_source_preparer.rb +77 -0
- data/lib/cocoapods-tt/native/installer/podfile_validator.rb +168 -0
- data/lib/cocoapods-tt/native/installer/post_install_hooks_context.rb +9 -0
- data/lib/cocoapods-tt/native/installer/post_integrate_hooks_context.rb +9 -0
- data/lib/cocoapods-tt/native/installer/pre_install_hooks_context.rb +51 -0
- data/lib/cocoapods-tt/native/installer/pre_integrate_hooks_context.rb +9 -0
- data/lib/cocoapods-tt/native/installer/project_cache/project_cache.rb +11 -0
- data/lib/cocoapods-tt/native/installer/project_cache/project_cache_analysis_result.rb +53 -0
- data/lib/cocoapods-tt/native/installer/project_cache/project_cache_analyzer.rb +200 -0
- data/lib/cocoapods-tt/native/installer/project_cache/project_cache_version.rb +43 -0
- data/lib/cocoapods-tt/native/installer/project_cache/project_installation_cache.rb +103 -0
- data/lib/cocoapods-tt/native/installer/project_cache/project_metadata_cache.rb +73 -0
- data/lib/cocoapods-tt/native/installer/project_cache/target_cache_key.rb +176 -0
- data/lib/cocoapods-tt/native/installer/project_cache/target_metadata.rb +74 -0
- data/lib/cocoapods-tt/native/installer/sandbox_dir_cleaner.rb +105 -0
- data/lib/cocoapods-tt/native/installer/sandbox_header_paths_installer.rb +45 -0
- data/lib/cocoapods-tt/native/installer/source_provider_hooks_context.rb +34 -0
- data/lib/cocoapods-tt/native/installer/target_uuid_generator.rb +34 -0
- data/lib/cocoapods-tt/native/installer/user_project_integrator/target_integrator/xcconfig_integrator.rb +179 -0
- data/lib/cocoapods-tt/native/installer/user_project_integrator/target_integrator.rb +815 -0
- data/lib/cocoapods-tt/native/installer/user_project_integrator.rb +280 -0
- data/lib/cocoapods-tt/native/installer/xcode/multi_pods_project_generator.rb +82 -0
- data/lib/cocoapods-tt/native/installer/xcode/pods_project_generator/aggregate_target_dependency_installer.rb +66 -0
- data/lib/cocoapods-tt/native/installer/xcode/pods_project_generator/aggregate_target_installer.rb +192 -0
- data/lib/cocoapods-tt/native/installer/xcode/pods_project_generator/app_host_installer.rb +154 -0
- data/lib/cocoapods-tt/native/installer/xcode/pods_project_generator/file_references_installer.rb +329 -0
- data/lib/cocoapods-tt/native/installer/xcode/pods_project_generator/pod_target_dependency_installer.rb +195 -0
- data/lib/cocoapods-tt/native/installer/xcode/pods_project_generator/pod_target_installer.rb +1239 -0
- data/lib/cocoapods-tt/native/installer/xcode/pods_project_generator/pod_target_integrator.rb +312 -0
- data/lib/cocoapods-tt/native/installer/xcode/pods_project_generator/pods_project_writer.rb +90 -0
- data/lib/cocoapods-tt/native/installer/xcode/pods_project_generator/project_generator.rb +120 -0
- data/lib/cocoapods-tt/native/installer/xcode/pods_project_generator/target_installation_result.rb +140 -0
- data/lib/cocoapods-tt/native/installer/xcode/pods_project_generator/target_installer.rb +257 -0
- data/lib/cocoapods-tt/native/installer/xcode/pods_project_generator/target_installer_helper.rb +110 -0
- data/lib/cocoapods-tt/native/installer/xcode/pods_project_generator.rb +291 -0
- data/lib/cocoapods-tt/native/installer/xcode/pods_project_generator_result.rb +54 -0
- data/lib/cocoapods-tt/native/installer/xcode/single_pods_project_generator.rb +38 -0
- data/lib/cocoapods-tt/native/installer/xcode/target_validator.rb +170 -0
- data/lib/cocoapods-tt/native/installer/xcode.rb +11 -0
- data/lib/cocoapods-tt/native/installer.rb +1044 -0
- data/lib/cocoapods-tt/native/native_target_extension.rb +60 -0
- data/lib/cocoapods-tt/native/open-uri.rb +33 -0
- data/lib/cocoapods-tt/native/podfile.rb +13 -0
- data/lib/cocoapods-tt/native/project.rb +544 -0
- data/lib/cocoapods-tt/native/resolver/lazy_specification.rb +88 -0
- data/lib/cocoapods-tt/native/resolver/resolver_specification.rb +41 -0
- data/lib/cocoapods-tt/native/resolver.rb +600 -0
- data/lib/cocoapods-tt/native/sandbox/file_accessor.rb +532 -0
- data/lib/cocoapods-tt/native/sandbox/headers_store.rb +163 -0
- data/lib/cocoapods-tt/native/sandbox/path_list.rb +242 -0
- data/lib/cocoapods-tt/native/sandbox/pod_dir_cleaner.rb +71 -0
- data/lib/cocoapods-tt/native/sandbox/podspec_finder.rb +23 -0
- data/lib/cocoapods-tt/native/sandbox.rb +470 -0
- data/lib/cocoapods-tt/native/sources_manager.rb +221 -0
- data/lib/cocoapods-tt/native/target/aggregate_target.rb +558 -0
- data/lib/cocoapods-tt/native/target/build_settings.rb +1385 -0
- data/lib/cocoapods-tt/native/target/pod_target.rb +1168 -0
- data/lib/cocoapods-tt/native/target.rb +378 -0
- data/lib/cocoapods-tt/native/user_interface/error_report.rb +204 -0
- data/lib/cocoapods-tt/native/user_interface/inspector_reporter.rb +102 -0
- data/lib/cocoapods-tt/native/user_interface.rb +463 -0
- data/lib/cocoapods-tt/native/validator.rb +1170 -0
- data/lib/cocoapods-tt/native/version_metadata.rb +26 -0
- data/lib/cocoapods-tt/native/xcode/framework_paths.rb +54 -0
- data/lib/cocoapods-tt/native/xcode/linkage_analyzer.rb +22 -0
- data/lib/cocoapods-tt/native/xcode/xcframework/xcframework_slice.rb +138 -0
- data/lib/cocoapods-tt/native/xcode/xcframework.rb +99 -0
- data/lib/cocoapods-tt/native/xcode.rb +7 -0
- data/lib/cocoapods-tt.rb +1 -0
- data/lib/cocoapods_plugin.rb +17 -0
- metadata +193 -0
@@ -0,0 +1,1204 @@
|
|
1
|
+
require 'cocoapods/podfile'
|
2
|
+
|
3
|
+
module Pod
|
4
|
+
class Installer
|
5
|
+
# Analyzes the Podfile, the Lockfile, and the sandbox manifest to generate
|
6
|
+
# the information relative to a CocoaPods installation.
|
7
|
+
#
|
8
|
+
class Analyzer
|
9
|
+
include Config::Mixin
|
10
|
+
|
11
|
+
autoload :AnalysisResult, 'cocoapods/installer/analyzer/analysis_result'
|
12
|
+
autoload :LockingDependencyAnalyzer, 'cocoapods/installer/analyzer/locking_dependency_analyzer'
|
13
|
+
autoload :PodfileDependencyCache, 'cocoapods/installer/analyzer/podfile_dependency_cache'
|
14
|
+
autoload :PodVariant, 'cocoapods/installer/analyzer/pod_variant'
|
15
|
+
autoload :PodVariantSet, 'cocoapods/installer/analyzer/pod_variant_set'
|
16
|
+
autoload :SandboxAnalyzer, 'cocoapods/installer/analyzer/sandbox_analyzer'
|
17
|
+
autoload :SpecsState, 'cocoapods/installer/analyzer/specs_state'
|
18
|
+
autoload :TargetInspectionResult, 'cocoapods/installer/analyzer/target_inspection_result'
|
19
|
+
autoload :TargetInspector, 'cocoapods/installer/analyzer/target_inspector'
|
20
|
+
|
21
|
+
# @return [String] The version of iOS which requires binaries with only 64-bit architectures
|
22
|
+
#
|
23
|
+
IOS_64_BIT_ONLY_VERSION = Version.new('11.0')
|
24
|
+
|
25
|
+
# @return [Integer] The Xcode object version until which 64-bit architectures should be manually specified
|
26
|
+
#
|
27
|
+
# Xcode 10 will automatically select the correct architectures based on deployment target
|
28
|
+
IOS_64_BIT_ONLY_PROJECT_VERSION = 50
|
29
|
+
|
30
|
+
# @return [Sandbox] The sandbox to use for this analysis.
|
31
|
+
#
|
32
|
+
attr_reader :sandbox
|
33
|
+
|
34
|
+
# @return [Podfile] The Podfile specification that contains the information of the Pods that should be installed.
|
35
|
+
#
|
36
|
+
attr_reader :podfile
|
37
|
+
|
38
|
+
# @return [Lockfile, nil] The Lockfile, if available, that stores the information about the Pods previously installed.
|
39
|
+
#
|
40
|
+
attr_reader :lockfile
|
41
|
+
|
42
|
+
# @return [Array<Source>] Sources provided by plugins or `nil`.
|
43
|
+
#
|
44
|
+
attr_reader :plugin_sources
|
45
|
+
|
46
|
+
# @return [Bool] Whether the analysis has dependencies and thus sources must be configured.
|
47
|
+
#
|
48
|
+
# @note This is used by the `pod lib lint` command to prevent update of specs when not needed.
|
49
|
+
#
|
50
|
+
attr_reader :has_dependencies
|
51
|
+
alias_method :has_dependencies?, :has_dependencies
|
52
|
+
|
53
|
+
# @return [Hash, Boolean, nil] Pods that have been requested to be updated or true if all Pods should be updated.
|
54
|
+
# This can be false if no pods should be updated.
|
55
|
+
#
|
56
|
+
attr_reader :pods_to_update
|
57
|
+
|
58
|
+
# @return [InstallationOptions] the installation options specified by the Podfile
|
59
|
+
#
|
60
|
+
attr_reader :installation_options
|
61
|
+
|
62
|
+
# @return [Source::Manager] the sources manager to use when resolving dependencies
|
63
|
+
#
|
64
|
+
attr_reader :sources_manager
|
65
|
+
|
66
|
+
# Initialize a new instance
|
67
|
+
#
|
68
|
+
# @param [Sandbox] sandbox @see #sandbox
|
69
|
+
# @param [Podfile] podfile @see #podfile
|
70
|
+
# @param [Lockfile, nil] lockfile @see #lockfile
|
71
|
+
# @param [Array<Source>] plugin_sources @see #plugin_sources
|
72
|
+
# @param [Boolean] has_dependencies @see #has_dependencies
|
73
|
+
# @param [Hash, Boolean, nil] pods_to_update @see #pods_to_update
|
74
|
+
# @param [Source::Manager] sources_manager @see #sources_manager
|
75
|
+
#
|
76
|
+
def initialize(sandbox, podfile, lockfile = nil, plugin_sources = nil, has_dependencies = true,
|
77
|
+
pods_to_update = false, sources_manager = Source::Manager.new(config.repos_dir))
|
78
|
+
@sandbox = sandbox
|
79
|
+
@podfile = podfile
|
80
|
+
@lockfile = lockfile
|
81
|
+
@plugin_sources = plugin_sources
|
82
|
+
@has_dependencies = has_dependencies
|
83
|
+
@pods_to_update = pods_to_update
|
84
|
+
@installation_options = podfile.installation_options
|
85
|
+
@podfile_dependency_cache = PodfileDependencyCache.from_podfile(podfile)
|
86
|
+
@sources_manager = sources_manager
|
87
|
+
@result = nil
|
88
|
+
end
|
89
|
+
|
90
|
+
# Performs the analysis.
|
91
|
+
#
|
92
|
+
# The Podfile and the Lockfile provide the information necessary to
|
93
|
+
# compute which specification should be installed. The manifest of the
|
94
|
+
# sandbox returns which specifications are installed.
|
95
|
+
#
|
96
|
+
# @param [Bool] allow_fetches
|
97
|
+
# whether external sources may be fetched
|
98
|
+
#
|
99
|
+
# @return [AnalysisResult]
|
100
|
+
#
|
101
|
+
def analyze(allow_fetches = true)
|
102
|
+
return @result if @result
|
103
|
+
validate_podfile!
|
104
|
+
validate_lockfile_version!
|
105
|
+
if installation_options.integrate_targets?
|
106
|
+
target_inspections = inspect_targets_to_integrate
|
107
|
+
else
|
108
|
+
verify_platforms_specified!
|
109
|
+
target_inspections = {}
|
110
|
+
end
|
111
|
+
podfile_state = generate_podfile_state
|
112
|
+
|
113
|
+
store_existing_checkout_options
|
114
|
+
if allow_fetches == :outdated
|
115
|
+
# special-cased -- we're only really resolving for outdated, rather than doing a full analysis
|
116
|
+
elsif allow_fetches == true
|
117
|
+
fetch_external_sources(podfile_state)
|
118
|
+
elsif !dependencies_to_fetch(podfile_state).all?(&:local?)
|
119
|
+
raise Informative, 'Cannot analyze without fetching dependencies since the sandbox is not up-to-date. Run `pod install` to ensure all dependencies have been fetched.' \
|
120
|
+
"\n The missing dependencies are:\n \t#{dependencies_to_fetch(podfile_state).reject(&:local?).join("\n \t")}"
|
121
|
+
end
|
122
|
+
|
123
|
+
locked_dependencies = generate_version_locking_dependencies(podfile_state)
|
124
|
+
resolver_specs_by_target = resolve_dependencies(locked_dependencies)
|
125
|
+
validate_platforms(resolver_specs_by_target)
|
126
|
+
specifications = generate_specifications(resolver_specs_by_target)
|
127
|
+
aggregate_targets, pod_targets = generate_targets(resolver_specs_by_target, target_inspections)
|
128
|
+
sandbox_state = generate_sandbox_state(specifications)
|
129
|
+
specs_by_target = resolver_specs_by_target.each_with_object({}) do |rspecs_by_target, hash|
|
130
|
+
hash[rspecs_by_target[0]] = rspecs_by_target[1].map(&:spec)
|
131
|
+
end
|
132
|
+
specs_by_source = Hash[resolver_specs_by_target.values.flatten(1).group_by(&:source).map do |source, specs|
|
133
|
+
[source, specs.map(&:spec).uniq]
|
134
|
+
end]
|
135
|
+
sources.each { |s| specs_by_source[s] ||= [] }
|
136
|
+
@result = AnalysisResult.new(podfile_state, specs_by_target, specs_by_source, specifications, sandbox_state,
|
137
|
+
aggregate_targets, pod_targets, @podfile_dependency_cache)
|
138
|
+
end
|
139
|
+
|
140
|
+
# Updates the git source repositories.
|
141
|
+
#
|
142
|
+
def update_repositories
|
143
|
+
sources.each do |source|
|
144
|
+
if source.updateable?
|
145
|
+
sources_manager.update(source.name, true)
|
146
|
+
else
|
147
|
+
UI.message "Skipping `#{source.name}` update because the repository is not an updateable repository."
|
148
|
+
end
|
149
|
+
end
|
150
|
+
@specs_updated = true
|
151
|
+
end
|
152
|
+
|
153
|
+
# Returns the sources used to query for specifications.
|
154
|
+
#
|
155
|
+
# When no explicit Podfile sources or plugin sources are defined, this defaults to the master spec repository.
|
156
|
+
#
|
157
|
+
# @return [Array<Source>] the sources to be used in finding specifications, as specified by the podfile or all
|
158
|
+
# sources.
|
159
|
+
#
|
160
|
+
def sources
|
161
|
+
@sources ||= begin
|
162
|
+
sources = podfile.sources
|
163
|
+
plugin_sources = @plugin_sources || []
|
164
|
+
|
165
|
+
# Add any sources specified using the :source flag on individual dependencies.
|
166
|
+
dependency_sources = podfile_dependencies.map(&:podspec_repo).compact
|
167
|
+
all_dependencies_have_sources = dependency_sources.count == podfile_dependencies.count
|
168
|
+
|
169
|
+
if all_dependencies_have_sources
|
170
|
+
sources = dependency_sources
|
171
|
+
elsif has_dependencies? && sources.empty? && plugin_sources.empty?
|
172
|
+
sources = [Pod::TrunkSource::TRUNK_REPO_URL] + dependency_sources
|
173
|
+
else
|
174
|
+
sources += dependency_sources
|
175
|
+
end
|
176
|
+
|
177
|
+
result = sources.uniq.map do |source_url|
|
178
|
+
sources_manager.find_or_create_source_with_url(source_url)
|
179
|
+
end
|
180
|
+
unless plugin_sources.empty?
|
181
|
+
result.insert(0, *plugin_sources)
|
182
|
+
plugin_sources.each do |source|
|
183
|
+
sources_manager.add_source(source)
|
184
|
+
end
|
185
|
+
end
|
186
|
+
result
|
187
|
+
end
|
188
|
+
end
|
189
|
+
|
190
|
+
#-----------------------------------------------------------------------#
|
191
|
+
|
192
|
+
private
|
193
|
+
|
194
|
+
# @!group Configuration
|
195
|
+
|
196
|
+
# @return [Bool] Whether the version of the dependencies which did not
|
197
|
+
# change in the Podfile should be locked.
|
198
|
+
#
|
199
|
+
def update_mode?
|
200
|
+
pods_to_update != nil
|
201
|
+
end
|
202
|
+
|
203
|
+
# @return [Symbol] Whether and how the dependencies in the Podfile
|
204
|
+
# should be updated.
|
205
|
+
#
|
206
|
+
def update_mode
|
207
|
+
if !pods_to_update
|
208
|
+
:none
|
209
|
+
elsif pods_to_update == true
|
210
|
+
:all
|
211
|
+
elsif !pods_to_update[:pods].nil?
|
212
|
+
:selected
|
213
|
+
end
|
214
|
+
end
|
215
|
+
|
216
|
+
def podfile_dependencies
|
217
|
+
@podfile_dependency_cache.podfile_dependencies
|
218
|
+
end
|
219
|
+
|
220
|
+
#-----------------------------------------------------------------------#
|
221
|
+
|
222
|
+
def validate_podfile!
|
223
|
+
validator = Installer::PodfileValidator.new(podfile, @podfile_dependency_cache)
|
224
|
+
validator.validate
|
225
|
+
|
226
|
+
unless validator.valid?
|
227
|
+
raise Informative, validator.message
|
228
|
+
end
|
229
|
+
validator.warnings.uniq.each { |w| UI.warn(w) }
|
230
|
+
end
|
231
|
+
|
232
|
+
# @!group Analysis steps
|
233
|
+
|
234
|
+
# @note The warning about the version of the Lockfile doesn't use the
|
235
|
+
# `UI.warn` method because it prints the output only at the end
|
236
|
+
# of the installation. At that time CocoaPods could have crashed.
|
237
|
+
#
|
238
|
+
def validate_lockfile_version!
|
239
|
+
if lockfile && lockfile.cocoapods_version > Version.new(VERSION)
|
240
|
+
STDERR.puts '[!] The version of CocoaPods used to generate ' \
|
241
|
+
"the lockfile (#{lockfile.cocoapods_version}) is "\
|
242
|
+
"higher than the version of the current executable (#{VERSION}). " \
|
243
|
+
'Incompatibility issues may arise.'.yellow
|
244
|
+
end
|
245
|
+
end
|
246
|
+
|
247
|
+
# Compares the {Podfile} with the {Lockfile} in order to detect which
|
248
|
+
# dependencies should be locked.
|
249
|
+
#
|
250
|
+
# @return [SpecsState] the states of the Podfile specs.
|
251
|
+
#
|
252
|
+
# @note As the target definitions share the same sandbox they should have
|
253
|
+
# the same version of a Pod. For this reason this method returns
|
254
|
+
# the name of the Pod (root name of the dependencies) and doesn't
|
255
|
+
# group them by target definition.
|
256
|
+
#
|
257
|
+
# @return [SpecState]
|
258
|
+
#
|
259
|
+
def generate_podfile_state
|
260
|
+
if lockfile
|
261
|
+
pods_state = nil
|
262
|
+
UI.section 'Finding Podfile changes' do
|
263
|
+
pods_by_state = lockfile.detect_changes_with_podfile(podfile)
|
264
|
+
pods_state = SpecsState.new(pods_by_state)
|
265
|
+
pods_state.print if config.verbose?
|
266
|
+
end
|
267
|
+
pods_state
|
268
|
+
else
|
269
|
+
state = SpecsState.new
|
270
|
+
state.added.merge(podfile_dependencies.map(&:root_name))
|
271
|
+
state
|
272
|
+
end
|
273
|
+
end
|
274
|
+
|
275
|
+
# Copies the pod targets of any of the app embedded aggregate targets into
|
276
|
+
# their potential host aggregate target, if that potential host aggregate target's
|
277
|
+
# user_target hosts any of the app embedded aggregate targets' user_targets
|
278
|
+
#
|
279
|
+
# @param [AggregateTarget] aggregate_target the aggregate target whose user_target
|
280
|
+
# might host one or more of the embedded aggregate targets' user_targets
|
281
|
+
#
|
282
|
+
# @param [Array<AggregateTarget>] embedded_aggregate_targets the aggregate targets
|
283
|
+
# representing the embedded targets to be integrated
|
284
|
+
#
|
285
|
+
# @param [Boolean] libraries_only if true, only library-type embedded
|
286
|
+
# targets are considered, otherwise, all other types are have
|
287
|
+
# their pods copied to their host targets as well (extensions, etc.)
|
288
|
+
#
|
289
|
+
# @return [Hash{String=>Array<PodTarget>}] the additional pod targets to include to the host
|
290
|
+
# keyed by their configuration.
|
291
|
+
#
|
292
|
+
def embedded_target_pod_targets_by_host(aggregate_target, embedded_aggregate_targets, libraries_only)
|
293
|
+
return {} if aggregate_target.requires_host_target?
|
294
|
+
aggregate_user_target_uuids = Set.new(aggregate_target.user_targets.map(&:uuid))
|
295
|
+
embedded_pod_targets_by_build_config = Hash.new([].freeze)
|
296
|
+
embedded_aggregate_targets.each do |embedded_aggregate_target|
|
297
|
+
# Skip non libraries in library-only mode
|
298
|
+
next if libraries_only && !embedded_aggregate_target.library?
|
299
|
+
next if aggregate_target.search_paths_aggregate_targets.include?(embedded_aggregate_target)
|
300
|
+
next unless embedded_aggregate_target.user_targets.any? do |embedded_user_target|
|
301
|
+
# You have to ask the host target's project for the host targets of
|
302
|
+
# the embedded target, as opposed to asking user_project for the
|
303
|
+
# embedded targets of the host target. The latter doesn't work when
|
304
|
+
# the embedded target lives in a sub-project. The lines below get
|
305
|
+
# the host target uuids for the embedded target and checks to see if
|
306
|
+
# those match to any of the user_target uuids in the aggregate_target.
|
307
|
+
host_target_uuids = Set.new(aggregate_target.user_project.host_targets_for_embedded_target(embedded_user_target).map(&:uuid))
|
308
|
+
!aggregate_user_target_uuids.intersection(host_target_uuids).empty?
|
309
|
+
end
|
310
|
+
embedded_aggregate_target.user_build_configurations.each_key do |configuration_name|
|
311
|
+
pod_target_names = Set.new(aggregate_target.pod_targets_for_build_configuration(configuration_name).map(&:name))
|
312
|
+
embedded_pod_targets = embedded_aggregate_target.pod_targets_for_build_configuration(configuration_name).select do |pod_target|
|
313
|
+
if !pod_target_names.include?(pod_target.name) &&
|
314
|
+
aggregate_target.pod_targets.none? { |aggregate_pod_target| (pod_target.specs - aggregate_pod_target.specs).empty? } &&
|
315
|
+
(libraries_only || pod_target.build_as_dynamic?)
|
316
|
+
pod_target.name
|
317
|
+
end
|
318
|
+
end
|
319
|
+
embedded_pod_targets_by_build_config[configuration_name] += embedded_pod_targets
|
320
|
+
end
|
321
|
+
end
|
322
|
+
embedded_pod_targets_by_build_config
|
323
|
+
end
|
324
|
+
|
325
|
+
# Raises an error if there are embedded targets in the Podfile, but
|
326
|
+
# their host targets have not been declared in the Podfile. As it
|
327
|
+
# finds host targets, it collection information on host target types.
|
328
|
+
#
|
329
|
+
# @param [Array<AggregateTarget>] aggregate_targets the generated
|
330
|
+
# aggregate targets
|
331
|
+
#
|
332
|
+
# @param [Array<AggregateTarget>] embedded_aggregate_targets the aggregate targets
|
333
|
+
# representing the embedded targets to be integrated
|
334
|
+
#
|
335
|
+
def analyze_host_targets_in_podfile(aggregate_targets, embedded_aggregate_targets)
|
336
|
+
target_definitions_by_uuid = {}
|
337
|
+
cli_host_with_dynamic_linkage = []
|
338
|
+
cli_product_type = 'com.apple.product-type.tool'
|
339
|
+
# Collect aggregate target definitions by uuid to later lookup host target
|
340
|
+
# definitions and verify their compatibility with their embedded targets
|
341
|
+
aggregate_targets.each do |target|
|
342
|
+
target.user_targets.each do |user_target|
|
343
|
+
target_definition = target.target_definition
|
344
|
+
target_definitions_by_uuid[user_target.uuid] = target_definition
|
345
|
+
if user_target.product_type == cli_product_type && target_definition.build_type.linkage == :dynamic
|
346
|
+
cli_host_with_dynamic_linkage << user_target
|
347
|
+
end
|
348
|
+
end
|
349
|
+
end
|
350
|
+
aggregate_target_user_projects = aggregate_targets.map(&:user_project)
|
351
|
+
embedded_targets_missing_hosts = []
|
352
|
+
host_uuid_to_embedded_target_definitions = {}
|
353
|
+
# Search all of the known user projects for each embedded target's hosts
|
354
|
+
embedded_aggregate_targets.each do |target|
|
355
|
+
host_uuids = aggregate_target_user_projects.product(target.user_targets).flat_map do |user_project, user_target|
|
356
|
+
user_project.host_targets_for_embedded_target(user_target).map(&:uuid)
|
357
|
+
end
|
358
|
+
# For each host, keep track of its embedded target definitions
|
359
|
+
# to later verify each embedded target's compatiblity with its host,
|
360
|
+
# ignoring the hosts that aren't known to CocoaPods (no target
|
361
|
+
# definitions in the Podfile)
|
362
|
+
host_uuids.each do |uuid|
|
363
|
+
(host_uuid_to_embedded_target_definitions[uuid] ||= []) << target.target_definition if target_definitions_by_uuid.key? uuid
|
364
|
+
end
|
365
|
+
# If none of the hosts are known to CocoaPods (no target definitions
|
366
|
+
# in the Podfile), add it to the list of targets missing hosts
|
367
|
+
embedded_targets_missing_hosts << target unless host_uuids.any? do |uuid|
|
368
|
+
target_definitions_by_uuid.key? uuid
|
369
|
+
end
|
370
|
+
end
|
371
|
+
|
372
|
+
unless cli_host_with_dynamic_linkage.empty?
|
373
|
+
UI.warn "The Podfile contains command line tool target(s) (#{cli_host_with_dynamic_linkage.map(&:name).to_sentence}) which are attempting to integrate dynamic frameworks or libraries." \
|
374
|
+
"\n" \
|
375
|
+
'This may not behave as expected, because command line tools are usually distributed as a single binary and cannot contain their own dynamic dependencies.'
|
376
|
+
end
|
377
|
+
|
378
|
+
unless embedded_targets_missing_hosts.empty?
|
379
|
+
embedded_targets_missing_hosts_product_types = Set.new embedded_targets_missing_hosts.flat_map(&:user_targets).map(&:symbol_type)
|
380
|
+
target_names = embedded_targets_missing_hosts.map do |target|
|
381
|
+
target.name.sub('Pods-', '') # Make the target names more recognizable to the user
|
382
|
+
end.join ', '
|
383
|
+
# If the targets missing hosts are only frameworks, then this is likely
|
384
|
+
# a project for doing framework development. In that case, just warn that
|
385
|
+
# the frameworks that these targets depend on won't be integrated anywhere
|
386
|
+
if embedded_targets_missing_hosts_product_types.subset?(Set.new([:framework, :static_library]))
|
387
|
+
UI.warn "The Podfile contains framework or static library targets (#{target_names}), for which the Podfile does not contain host targets (targets which embed the framework)." \
|
388
|
+
"\n" \
|
389
|
+
'If this project is for doing framework development, you can ignore this message. Otherwise, add a target to the Podfile that embeds these frameworks to make this message go away (e.g. a test target).'
|
390
|
+
else
|
391
|
+
raise Informative, "Unable to find host target(s) for #{target_names}. Please add the host targets for the embedded targets to the Podfile." \
|
392
|
+
"\n" \
|
393
|
+
'Certain kinds of targets require a host target. A host target is a "parent" target which embeds a "child" target. These are example types of targets that need a host target:' \
|
394
|
+
"\n- Framework" \
|
395
|
+
"\n- App Extension" \
|
396
|
+
"\n- Watch OS 1 Extension" \
|
397
|
+
"\n- Messages Extension (except when used with a Messages Application)"
|
398
|
+
end
|
399
|
+
end
|
400
|
+
|
401
|
+
target_mismatches = []
|
402
|
+
host_uuid_to_embedded_target_definitions.each do |uuid, target_definitions|
|
403
|
+
host_target_definition = target_definitions_by_uuid[uuid]
|
404
|
+
target_definitions.each do |target_definition|
|
405
|
+
unless host_target_definition.uses_frameworks? == target_definition.uses_frameworks?
|
406
|
+
target_mismatches << "- #{host_target_definition.name} (#{host_target_definition.uses_frameworks?}) and #{target_definition.name} (#{target_definition.uses_frameworks?}) do not both set use_frameworks!."
|
407
|
+
end
|
408
|
+
end
|
409
|
+
end
|
410
|
+
|
411
|
+
unless target_mismatches.empty?
|
412
|
+
heading = 'Unable to integrate the following embedded targets with their respective host targets (a host target is a "parent" target which embeds a "child" target like a framework or extension):'
|
413
|
+
raise Informative, heading + "\n\n" + target_mismatches.sort.uniq.join("\n")
|
414
|
+
end
|
415
|
+
end
|
416
|
+
|
417
|
+
# Creates the models that represent the targets generated by CocoaPods.
|
418
|
+
#
|
419
|
+
# @param [Hash{TargetDefinition => Array<ResolvedSpecification>}] resolver_specs_by_target
|
420
|
+
# mapping of targets to resolved specs (containing information about test usage)
|
421
|
+
# aggregate targets
|
422
|
+
#
|
423
|
+
# @param [Hash{TargetDefinition => TargetInspectionResult}] target_inspections
|
424
|
+
# the user target inspections used to construct the aggregate and pod targets.
|
425
|
+
#
|
426
|
+
# @return [(Array<AggregateTarget>, Array<PodTarget>)] the list of aggregate targets generated,
|
427
|
+
# and the list of pod targets generated.
|
428
|
+
#
|
429
|
+
def generate_targets(resolver_specs_by_target, target_inspections)
|
430
|
+
resolver_specs_by_target = resolver_specs_by_target.reject { |td, _| td.abstract? && !td.platform }
|
431
|
+
pod_targets = generate_pod_targets(resolver_specs_by_target, target_inspections)
|
432
|
+
pod_targets_by_target_definition = group_pod_targets_by_target_definition(pod_targets, resolver_specs_by_target)
|
433
|
+
aggregate_targets = resolver_specs_by_target.keys.reject(&:abstract?).map do |target_definition|
|
434
|
+
generate_aggregate_target(target_definition, target_inspections, pod_targets_by_target_definition)
|
435
|
+
end
|
436
|
+
aggregate_targets.each do |target|
|
437
|
+
search_paths_aggregate_targets = aggregate_targets.select do |aggregate_target|
|
438
|
+
target.target_definition.targets_to_inherit_search_paths.include?(aggregate_target.target_definition)
|
439
|
+
end
|
440
|
+
target.search_paths_aggregate_targets.concat(search_paths_aggregate_targets).freeze
|
441
|
+
end
|
442
|
+
|
443
|
+
aggregate_targets.each do |aggregate_target|
|
444
|
+
is_app_extension = !(aggregate_target.user_targets.map(&:symbol_type) &
|
445
|
+
[:app_extension, :watch_extension, :watch2_extension, :tv_extension, :messages_extension]).empty?
|
446
|
+
is_app_extension ||= aggregate_target.user_targets.any? do |user_target|
|
447
|
+
user_target.common_resolved_build_setting('APPLICATION_EXTENSION_API_ONLY', :resolve_against_xcconfig => true) == 'YES'
|
448
|
+
end
|
449
|
+
if is_app_extension
|
450
|
+
aggregate_target.mark_application_extension_api_only
|
451
|
+
aggregate_target.pod_targets.each(&:mark_application_extension_api_only)
|
452
|
+
end
|
453
|
+
|
454
|
+
build_library_for_distribution = aggregate_target.user_targets.any? do |user_target|
|
455
|
+
user_target.common_resolved_build_setting('BUILD_LIBRARY_FOR_DISTRIBUTION', :resolve_against_xcconfig => true) == 'YES'
|
456
|
+
end
|
457
|
+
if build_library_for_distribution
|
458
|
+
aggregate_target.mark_build_library_for_distribution
|
459
|
+
aggregate_target.pod_targets.each(&:mark_build_library_for_distribution)
|
460
|
+
end
|
461
|
+
end
|
462
|
+
|
463
|
+
if installation_options.integrate_targets?
|
464
|
+
# Copy embedded target pods that cannot have their pods embedded as frameworks to
|
465
|
+
# their host targets, and ensure we properly link library pods to their host targets
|
466
|
+
embedded_targets = aggregate_targets.select(&:requires_host_target?)
|
467
|
+
analyze_host_targets_in_podfile(aggregate_targets, embedded_targets)
|
468
|
+
|
469
|
+
use_frameworks_embedded_targets, non_use_frameworks_embedded_targets = embedded_targets.partition(&:build_as_framework?)
|
470
|
+
aggregate_targets = aggregate_targets.map do |aggregate_target|
|
471
|
+
# For targets that require dynamic frameworks, we always have to copy their pods to their
|
472
|
+
# host targets because those frameworks will all be loaded from the host target's bundle
|
473
|
+
embedded_pod_targets = embedded_target_pod_targets_by_host(aggregate_target, use_frameworks_embedded_targets, false)
|
474
|
+
|
475
|
+
# For targets that don't require dynamic frameworks, we only have to consider library-type
|
476
|
+
# targets because their host targets will still need to link their pods
|
477
|
+
embedded_pod_targets.merge!(embedded_target_pod_targets_by_host(aggregate_target, non_use_frameworks_embedded_targets, true))
|
478
|
+
|
479
|
+
next aggregate_target if embedded_pod_targets.empty?
|
480
|
+
aggregate_target.merge_embedded_pod_targets(embedded_pod_targets)
|
481
|
+
end
|
482
|
+
end
|
483
|
+
[aggregate_targets, pod_targets]
|
484
|
+
end
|
485
|
+
|
486
|
+
# Setup the aggregate target for a single user target
|
487
|
+
#
|
488
|
+
# @param [TargetDefinition] target_definition
|
489
|
+
# the target definition for the user target.
|
490
|
+
#
|
491
|
+
# @param [Hash{TargetDefinition => TargetInspectionResult}] target_inspections
|
492
|
+
# the user target inspections used to construct the aggregate and pod targets.
|
493
|
+
#
|
494
|
+
# @param [Hash{TargetDefinition => Array<PodTarget>}] pod_targets_by_target_definition
|
495
|
+
# the pod targets grouped by target.
|
496
|
+
#
|
497
|
+
# @return [AggregateTarget]
|
498
|
+
#
|
499
|
+
def generate_aggregate_target(target_definition, target_inspections, pod_targets_by_target_definition)
|
500
|
+
if installation_options.integrate_targets?
|
501
|
+
target_inspection = target_inspections[target_definition]
|
502
|
+
raise "missing inspection for #{target_definition.inspect}" unless target_inspection
|
503
|
+
target_requires_64_bit = Analyzer.requires_64_bit_archs?(target_definition.platform, target_inspection.project.object_version)
|
504
|
+
user_project = target_inspection.project
|
505
|
+
client_root = target_inspection.client_root
|
506
|
+
user_target_uuids = target_inspection.project_target_uuids
|
507
|
+
user_build_configurations = target_inspection.build_configurations
|
508
|
+
archs = target_requires_64_bit ? ['$(ARCHS_STANDARD_64_BIT)'] : target_inspection.archs
|
509
|
+
else
|
510
|
+
target_requires_64_bit = Analyzer.requires_64_bit_archs?(target_definition.platform, nil)
|
511
|
+
user_project = nil
|
512
|
+
client_root = config.installation_root.realpath
|
513
|
+
user_target_uuids = []
|
514
|
+
user_build_configurations = target_definition.build_configurations || Target::DEFAULT_BUILD_CONFIGURATIONS
|
515
|
+
archs = target_requires_64_bit ? ['$(ARCHS_STANDARD_64_BIT)'] : []
|
516
|
+
end
|
517
|
+
platform = target_definition.platform
|
518
|
+
build_configurations = user_build_configurations.keys.concat(target_definition.all_whitelisted_configurations).uniq
|
519
|
+
pod_targets_for_build_configuration = filter_pod_targets_for_target_definition(target_definition,
|
520
|
+
pod_targets_by_target_definition,
|
521
|
+
build_configurations)
|
522
|
+
build_type = target_definition.uses_frameworks? ? BuildType.static_framework : BuildType.static_library
|
523
|
+
AggregateTarget.new(sandbox, build_type, user_build_configurations, archs, platform, target_definition,
|
524
|
+
client_root, user_project, user_target_uuids, pod_targets_for_build_configuration)
|
525
|
+
end
|
526
|
+
|
527
|
+
# Returns a filtered list of pod targets that should or should not be part of the target definition. Pod targets
|
528
|
+
# used by tests only are filtered.
|
529
|
+
#
|
530
|
+
# @return [Hash{TargetDefinition => Array<PodTarget>}]
|
531
|
+
#
|
532
|
+
def group_pod_targets_by_target_definition(pod_targets, resolver_specs_by_target)
|
533
|
+
pod_targets_by_target_definition = Hash.new { |h, td| h[td] = [] }
|
534
|
+
pod_targets.each do |pod_target|
|
535
|
+
pod_target.target_definitions.each do |td|
|
536
|
+
pod_targets_by_target_definition[td] << pod_target
|
537
|
+
end
|
538
|
+
end
|
539
|
+
resolver_specs_by_target.each do |td, resolver_specs|
|
540
|
+
specs_by_pod_name = resolver_specs.group_by { |s| s.root.name }
|
541
|
+
specs_by_pod_name.reject! { |_, specs| specs.all?(&:used_by_non_library_targets_only?) }
|
542
|
+
pod_targets_by_target_definition[td].keep_if { |pod_target| specs_by_pod_name.key?(pod_target.pod_name) }
|
543
|
+
end
|
544
|
+
|
545
|
+
pod_targets_by_target_definition
|
546
|
+
end
|
547
|
+
|
548
|
+
# Returns a filtered list of pod targets that should or should not be part of the target definition. Pod targets
|
549
|
+
# used by tests only are filtered.
|
550
|
+
#
|
551
|
+
# @param [TargetDefinition] target_definition
|
552
|
+
# the target definition to use as the base for filtering
|
553
|
+
#
|
554
|
+
# @param [Hash{TargetDefinition => Array<PodTarget>}] pod_targets_by_target_definition
|
555
|
+
# the pod targets grouped by target.
|
556
|
+
#
|
557
|
+
# @param [Array<String>] build_configurations
|
558
|
+
# The list of all build configurations the targets will be built for.
|
559
|
+
#
|
560
|
+
# @return [Hash{String => Array<PodTarget>}]
|
561
|
+
# the filtered list of pod targets, grouped by build configuration.
|
562
|
+
#
|
563
|
+
def filter_pod_targets_for_target_definition(target_definition, pod_targets_by_target_definition,
|
564
|
+
build_configurations)
|
565
|
+
pod_targets_by_build_config = Hash.new([].freeze)
|
566
|
+
build_configurations.each { |config| pod_targets_by_build_config[config] = [] }
|
567
|
+
|
568
|
+
dependencies_by_root_name = @podfile_dependency_cache.target_definition_dependencies(target_definition).group_by(&:root_name)
|
569
|
+
|
570
|
+
pod_targets_by_target_definition[target_definition].each do |pod_target|
|
571
|
+
pod_name = pod_target.pod_name
|
572
|
+
dependencies = dependencies_by_root_name[pod_name] || []
|
573
|
+
|
574
|
+
build_configurations.each do |configuration_name|
|
575
|
+
whitelists = dependencies.map do |dependency|
|
576
|
+
target_definition.pod_whitelisted_for_configuration?(dependency.name, configuration_name)
|
577
|
+
end.uniq
|
578
|
+
|
579
|
+
case whitelists
|
580
|
+
when [], [true] then nil
|
581
|
+
when [false] then next
|
582
|
+
else
|
583
|
+
raise Informative, "The subspecs of `#{pod_name}` are linked to " \
|
584
|
+
"different build configurations for the `#{target_definition}` " \
|
585
|
+
'target. CocoaPods does not currently support subspecs across ' \
|
586
|
+
'different build configurations.'
|
587
|
+
end
|
588
|
+
|
589
|
+
pod_targets_by_build_config[configuration_name] << pod_target
|
590
|
+
end
|
591
|
+
end
|
592
|
+
|
593
|
+
pod_targets_by_build_config
|
594
|
+
end
|
595
|
+
|
596
|
+
# Setup the pod targets for an aggregate target. Deduplicates resulting
|
597
|
+
# targets by grouping by platform and subspec by their root
|
598
|
+
# to create a {PodTarget} for each spec.
|
599
|
+
#
|
600
|
+
# @param [Hash{TargetDefinition => Array<ResolvedSpecification>}] resolver_specs_by_target
|
601
|
+
# the resolved specifications grouped by target.
|
602
|
+
#
|
603
|
+
# @param [Hash{TargetDefinition => TargetInspectionResult}] target_inspections
|
604
|
+
# the user target inspections used to construct the aggregate and pod targets.
|
605
|
+
#
|
606
|
+
# @return [Array<PodTarget>]
|
607
|
+
#
|
608
|
+
def generate_pod_targets(resolver_specs_by_target, target_inspections)
|
609
|
+
if installation_options.deduplicate_targets?
|
610
|
+
distinct_targets = resolver_specs_by_target.each_with_object({}) do |dependency, hash|
|
611
|
+
target_definition, dependent_specs = *dependency
|
612
|
+
dependent_specs.group_by(&:root).each do |root_spec, resolver_specs|
|
613
|
+
all_specs = resolver_specs.map(&:spec)
|
614
|
+
all_specs_by_type = all_specs.group_by(&:spec_type)
|
615
|
+
library_specs = all_specs_by_type[:library] || []
|
616
|
+
test_specs = all_specs_by_type[:test] || []
|
617
|
+
app_specs = all_specs_by_type[:app] || []
|
618
|
+
build_type = determine_build_type(root_spec, target_definition.build_type)
|
619
|
+
pod_variant = PodVariant.new(library_specs, test_specs, app_specs, target_definition.platform, build_type)
|
620
|
+
hash[root_spec] ||= {}
|
621
|
+
(hash[root_spec][pod_variant] ||= []) << target_definition
|
622
|
+
pod_variant_spec = hash[root_spec].keys.find { |k| k == pod_variant }
|
623
|
+
pod_variant_spec.test_specs.concat(test_specs).uniq!
|
624
|
+
pod_variant_spec.app_specs.concat(app_specs).uniq!
|
625
|
+
end
|
626
|
+
end
|
627
|
+
|
628
|
+
# Remap pod variants to a new instance that includes the Swift version since we now have the full set
|
629
|
+
# of target definitions.
|
630
|
+
distinct_targets = Hash[distinct_targets.map do |root, target_definitions_by_variant|
|
631
|
+
variants = Hash[target_definitions_by_variant.map do |variant, target_definitions|
|
632
|
+
swift_version = determine_swift_version(variant.root_spec, target_definitions)
|
633
|
+
[variant.scoped_with_swift_version(swift_version), target_definitions]
|
634
|
+
end]
|
635
|
+
[root, variants]
|
636
|
+
end]
|
637
|
+
|
638
|
+
pod_targets = distinct_targets.flat_map do |_root, target_definitions_by_variant|
|
639
|
+
target_definitions_by_variant.each_value do |target_definitions|
|
640
|
+
target_definitions.reject!(&:abstract?) unless target_definitions.all?(&:abstract?)
|
641
|
+
end
|
642
|
+
suffixes = PodVariantSet.new(target_definitions_by_variant.keys).scope_suffixes
|
643
|
+
target_definitions_by_variant.map do |variant, target_definitions|
|
644
|
+
all_specs = variant.specs + variant.test_specs + variant.app_specs
|
645
|
+
generate_pod_target(target_definitions, variant.build_type, target_inspections, all_specs,
|
646
|
+
:scope_suffix => suffixes[variant], :swift_version => variant.swift_version)
|
647
|
+
end
|
648
|
+
end
|
649
|
+
|
650
|
+
all_specs = resolver_specs_by_target.values.flatten.map(&:spec).uniq.group_by(&:name)
|
651
|
+
compute_pod_target_dependencies(pod_targets, all_specs)
|
652
|
+
else
|
653
|
+
dedupe_cache = {}
|
654
|
+
resolver_specs_by_target.flat_map do |target_definition, specs|
|
655
|
+
grouped_specs = specs.group_by(&:root).values.uniq
|
656
|
+
pod_targets = grouped_specs.flat_map do |pod_specs|
|
657
|
+
build_type = determine_build_type(pod_specs.first.spec, target_definition.build_type)
|
658
|
+
swift_version = determine_swift_version(pod_specs.first.spec, [target_definition])
|
659
|
+
generate_pod_target([target_definition], build_type, target_inspections, pod_specs.map(&:spec),
|
660
|
+
:swift_version => swift_version).scoped(dedupe_cache)
|
661
|
+
end
|
662
|
+
|
663
|
+
compute_pod_target_dependencies(pod_targets, specs.map(&:spec).group_by(&:name))
|
664
|
+
end
|
665
|
+
end
|
666
|
+
end
|
667
|
+
|
668
|
+
# Compute the dependencies for the set of pod targets.
|
669
|
+
#
|
670
|
+
# @param [Array<PodTarget>] pod_targets
|
671
|
+
# pod targets.
|
672
|
+
#
|
673
|
+
# @param [Hash{String => Array<Specification>}] all_specs
|
674
|
+
# specifications grouped by name.
|
675
|
+
#
|
676
|
+
# @return [Array<PodTarget>]
|
677
|
+
#
|
678
|
+
def compute_pod_target_dependencies(pod_targets, all_specs)
|
679
|
+
pod_targets_by_name = pod_targets.group_by(&:pod_name).each_with_object({}) do |(name, values), hash|
|
680
|
+
# Sort the target by the number of activated subspecs, so that
|
681
|
+
# we prefer a minimal target as transitive dependency.
|
682
|
+
hash[name] = values.sort_by { |pt| pt.specs.count }
|
683
|
+
end
|
684
|
+
|
685
|
+
pod_targets.each do |target|
|
686
|
+
dependencies_by_config = dependencies_for_specs(target.library_specs, target.platform, all_specs)
|
687
|
+
target.dependent_targets_by_config = Hash[dependencies_by_config.map { |k, v| [k, filter_dependencies(v, pod_targets_by_name, target)] }]
|
688
|
+
|
689
|
+
target.test_dependent_targets_by_spec_name_by_config = target.test_specs.each_with_object({}) do |test_spec, hash|
|
690
|
+
test_dependencies_by_config = dependencies_for_specs([test_spec], target.platform, all_specs)
|
691
|
+
test_dependencies_by_config.each { |config, deps| deps.delete_if { |k, _| dependencies_by_config[config].key? k } }
|
692
|
+
hash[test_spec.name] = Hash[test_dependencies_by_config.map { |k, v| [k, filter_dependencies(v, pod_targets_by_name, target)] }]
|
693
|
+
end
|
694
|
+
|
695
|
+
target.app_dependent_targets_by_spec_name_by_config = target.app_specs.each_with_object({}) do |app_spec, hash|
|
696
|
+
app_dependencies_by_config = dependencies_for_specs([app_spec], target.platform, all_specs)
|
697
|
+
app_dependencies_by_config.each { |config, deps| deps.delete_if { |k, _| dependencies_by_config[config].key? k } }
|
698
|
+
hash[app_spec.name] = Hash[app_dependencies_by_config.map { |k, v| [k, filter_dependencies(v, pod_targets_by_name, target)] }]
|
699
|
+
end
|
700
|
+
|
701
|
+
target.test_app_hosts_by_spec = target.test_specs.each_with_object({}) do |test_spec, hash|
|
702
|
+
next unless app_host_name = test_spec.consumer(target.platform).app_host_name
|
703
|
+
app_host_spec = pod_targets_by_name[Specification.root_name(app_host_name)].flat_map(&:app_specs).find do |pt|
|
704
|
+
pt.name == app_host_name
|
705
|
+
end
|
706
|
+
app_host_dependencies = { app_host_spec.root => [app_host_spec] }
|
707
|
+
hash[test_spec] = [app_host_spec, filter_dependencies(app_host_dependencies, pod_targets_by_name, target).first]
|
708
|
+
end
|
709
|
+
end
|
710
|
+
end
|
711
|
+
|
712
|
+
def filter_dependencies(dependencies, pod_targets_by_name, target)
|
713
|
+
dependencies.map do |root_spec, deps|
|
714
|
+
pod_targets_by_name[root_spec.name].find do |t|
|
715
|
+
next false if t.platform.symbolic_name != target.platform.symbolic_name ||
|
716
|
+
# In the case of variants we must ensure that the platform this target is meant for is the same
|
717
|
+
# as the one we are interested in.
|
718
|
+
t.target_definitions.first.platform != target.target_definitions.first.platform ||
|
719
|
+
# rather than target type or requires_frameworks? since we want to group by what was specified in that
|
720
|
+
# _target definition_.
|
721
|
+
t.build_as_framework? != target.build_as_framework?
|
722
|
+
spec_names = t.specs.map(&:name)
|
723
|
+
deps.all? { |dep| spec_names.include?(dep.name) }
|
724
|
+
end
|
725
|
+
end
|
726
|
+
end
|
727
|
+
|
728
|
+
# Returns the specs upon which the given specs _directly_ depend.
|
729
|
+
#
|
730
|
+
# @note: This is implemented in the analyzer, because we don't have to
|
731
|
+
# care about the requirements after dependency resolution.
|
732
|
+
#
|
733
|
+
# @param [Array<Specification>] specs
|
734
|
+
# The specs, whose dependencies should be returned.
|
735
|
+
#
|
736
|
+
# @param [Platform] platform
|
737
|
+
# The platform for which the dependencies should be returned.
|
738
|
+
#
|
739
|
+
# @param [Hash{String => Array<Specification>}] all_specs
|
740
|
+
# All specifications which are installed alongside.
|
741
|
+
#
|
742
|
+
# @return [Hash{Symbol => Set<Specification>}]
|
743
|
+
#
|
744
|
+
def dependencies_for_specs(specs, platform, all_specs)
|
745
|
+
dependent_specs = {
|
746
|
+
:debug => Set.new,
|
747
|
+
:release => Set.new,
|
748
|
+
}
|
749
|
+
|
750
|
+
if !specs.empty? && !all_specs.empty?
|
751
|
+
specs.each do |s|
|
752
|
+
s.dependencies(platform).each do |dep|
|
753
|
+
all_specs[dep.name].each do |spec|
|
754
|
+
if spec.non_library_specification?
|
755
|
+
if s.test_specification? && spec.name == s.consumer(platform).app_host_name && spec.app_specification?
|
756
|
+
# This needs to be handled separately, since we _don't_ want to treat this as a "normal" dependency
|
757
|
+
next
|
758
|
+
end
|
759
|
+
raise Informative, "`#{s}` depends upon `#{spec}`, which is a `#{spec.spec_type}` spec."
|
760
|
+
end
|
761
|
+
|
762
|
+
dependent_specs.each do |config, set|
|
763
|
+
next unless s.dependency_whitelisted_for_configuration?(dep, config)
|
764
|
+
set << spec
|
765
|
+
end
|
766
|
+
end
|
767
|
+
end
|
768
|
+
end
|
769
|
+
end
|
770
|
+
|
771
|
+
Hash[dependent_specs.map { |k, v| [k, (v - specs).group_by(&:root)] }].freeze
|
772
|
+
end
|
773
|
+
|
774
|
+
# Create a target for each spec group
|
775
|
+
#
|
776
|
+
# @param [Array<TargetDefinition>] target_definitions
|
777
|
+
# the target definitions of the pod target
|
778
|
+
#
|
779
|
+
# @param [BuildType] build_type
|
780
|
+
# the BuildType to use for this pod target.
|
781
|
+
#
|
782
|
+
# @param [Hash{TargetDefinition => TargetInspectionResult}] target_inspections
|
783
|
+
# the user target inspections used to construct the aggregate and pod targets.
|
784
|
+
#
|
785
|
+
# @param [Array<Specification>] specs
|
786
|
+
# the specifications of an equal root.
|
787
|
+
#
|
788
|
+
# @param [String] scope_suffix
|
789
|
+
# @see PodTarget#scope_suffix
|
790
|
+
#
|
791
|
+
# @param [String] swift_version
|
792
|
+
# @see PodTarget#swift_version
|
793
|
+
#
|
794
|
+
# @return [PodTarget]
|
795
|
+
#
|
796
|
+
def generate_pod_target(target_definitions, build_type, target_inspections, specs, scope_suffix: nil,
|
797
|
+
swift_version: nil)
|
798
|
+
target_inspections = target_inspections.select { |t, _| target_definitions.include?(t) }.values
|
799
|
+
object_version = target_inspections.map { |ti| ti.project.object_version }.min
|
800
|
+
target_requires_64_bit = target_definitions.all? { |td| Analyzer.requires_64_bit_archs?(td.platform, object_version) }
|
801
|
+
if !target_inspections.empty?
|
802
|
+
user_build_configurations = target_inspections.map(&:build_configurations).reduce({}, &:merge)
|
803
|
+
archs = if target_requires_64_bit
|
804
|
+
['$(ARCHS_STANDARD_64_BIT)']
|
805
|
+
else
|
806
|
+
target_inspections.flat_map(&:archs).compact.uniq.sort
|
807
|
+
end
|
808
|
+
else
|
809
|
+
user_build_configurations = Target::DEFAULT_BUILD_CONFIGURATIONS.merge(
|
810
|
+
target_definitions.map { |td| td.build_configurations || {} }.reduce({}, &:merge),
|
811
|
+
)
|
812
|
+
archs = target_requires_64_bit ? ['$(ARCHS_STANDARD_64_BIT)'] : []
|
813
|
+
end
|
814
|
+
platform = determine_platform(specs, target_definitions, build_type)
|
815
|
+
file_accessors = create_file_accessors(specs, platform)
|
816
|
+
PodTarget.new(sandbox, build_type, user_build_configurations, archs, platform, specs, target_definitions,
|
817
|
+
file_accessors, scope_suffix, swift_version)
|
818
|
+
end
|
819
|
+
|
820
|
+
# Creates the file accessors for a given pod.
|
821
|
+
#
|
822
|
+
# @param [Array<Specification>] specs
|
823
|
+
# the specs to map each file accessor to.
|
824
|
+
#
|
825
|
+
# @param [Platform] platform
|
826
|
+
# the platform to use when generating each file accessor.
|
827
|
+
#
|
828
|
+
# @return [Array<FileAccessor>]
|
829
|
+
#
|
830
|
+
def create_file_accessors(specs, platform)
|
831
|
+
name = specs.first.name
|
832
|
+
pod_root = sandbox.pod_dir(name)
|
833
|
+
path_list = Sandbox::PathList.new(pod_root)
|
834
|
+
specs.map do |spec|
|
835
|
+
Sandbox::FileAccessor.new(path_list, spec.consumer(platform))
|
836
|
+
end
|
837
|
+
end
|
838
|
+
|
839
|
+
# Calculates and returns the platform to use for the given list specs and target definitions.
|
840
|
+
#
|
841
|
+
# @note The platform is only determined by all library specs and ignores non library ones. Subspecs are always
|
842
|
+
# integrated in the same target as the root spec therefore the max deployment target is always returned
|
843
|
+
# across the specs passed.
|
844
|
+
#
|
845
|
+
# @param [Array<Specification>] specs
|
846
|
+
# the specs to inspect and calculate the platform for.
|
847
|
+
#
|
848
|
+
# @param [Array<TargetDefinition>] target_definitions
|
849
|
+
# the target definitions these specs are part of.
|
850
|
+
#
|
851
|
+
# @param [BuildType] build_type
|
852
|
+
# the #BuildType used for calculating the platform.
|
853
|
+
#
|
854
|
+
# @return [Platform]
|
855
|
+
#
|
856
|
+
def determine_platform(specs, target_definitions, build_type)
|
857
|
+
library_specs = specs.select(&:library_specification?)
|
858
|
+
platform_name = target_definitions.first.platform.name
|
859
|
+
default = Podfile::TargetDefinition::PLATFORM_DEFAULTS[platform_name]
|
860
|
+
deployment_target = library_specs.map do |library_spec|
|
861
|
+
Version.new(library_spec.deployment_target(platform_name) || default)
|
862
|
+
end.max
|
863
|
+
if platform_name == :ios && build_type.framework?
|
864
|
+
minimum = Version.new('8.0')
|
865
|
+
deployment_target = [deployment_target, minimum].max
|
866
|
+
end
|
867
|
+
Platform.new(platform_name, deployment_target)
|
868
|
+
end
|
869
|
+
|
870
|
+
# Determines the Swift version for the given spec within a list of target definitions. If the pod author has
|
871
|
+
# provided a set of Swift versions supported by their pod then the max Swift version is chosen, unless the target
|
872
|
+
# definitions specify explicit requirements for supported Swift versions. Otherwise the Swift version is derived
|
873
|
+
# by the target definitions that integrate this pod.
|
874
|
+
#
|
875
|
+
# @param [Specification] spec
|
876
|
+
# the specs to inspect and determine what Swift version to use.
|
877
|
+
#
|
878
|
+
# @param [Array<TargetDefinition>] target_definitions
|
879
|
+
# the target definitions the spec is part of.
|
880
|
+
#
|
881
|
+
# @return [String, nil] the computed Swift version or `nil` if the Swift version could not be determined.
|
882
|
+
#
|
883
|
+
def determine_swift_version(spec, target_definitions)
|
884
|
+
if spec.swift_versions.empty?
|
885
|
+
target_definitions.map(&:swift_version).compact.uniq.first
|
886
|
+
else
|
887
|
+
spec.swift_versions.sort.reverse_each.find do |swift_version|
|
888
|
+
target_definitions.all? do |td|
|
889
|
+
td.supports_swift_version?(swift_version)
|
890
|
+
end
|
891
|
+
end.to_s
|
892
|
+
end
|
893
|
+
end
|
894
|
+
|
895
|
+
# Calculates and returns the #BuildType to use for the given spec. If the spec specifies `static_framework` then
|
896
|
+
# it is honored as long as the host #BuildType also requires its pods to be integrated as frameworks.
|
897
|
+
#
|
898
|
+
# @param [Specification] spec
|
899
|
+
# the spec to determine the #BuildType for.
|
900
|
+
#
|
901
|
+
# @param [BuildType] target_definition_build_type
|
902
|
+
# The desired #BuildType by the target definition that integrates this target. If the pod target spec does
|
903
|
+
# not specify explicitly a `static_framework` #BuildType then the one from the target definition is used.
|
904
|
+
#
|
905
|
+
# @return [BuildType]
|
906
|
+
#
|
907
|
+
def determine_build_type(spec, target_definition_build_type)
|
908
|
+
if target_definition_build_type.framework?
|
909
|
+
root_spec = spec.root
|
910
|
+
root_spec.static_framework ? BuildType.static_framework : target_definition_build_type
|
911
|
+
else
|
912
|
+
BuildType.static_library
|
913
|
+
end
|
914
|
+
end
|
915
|
+
|
916
|
+
# Generates dependencies that require the specific version of the Pods
|
917
|
+
# that haven't changed in the {Lockfile}.
|
918
|
+
#
|
919
|
+
# These dependencies are passed to the {Resolver}, unless the installer
|
920
|
+
# is in update mode, to prevent it from upgrading the Pods that weren't
|
921
|
+
# changed in the {Podfile}.
|
922
|
+
#
|
923
|
+
# @param [SpecState] podfile_state
|
924
|
+
# the state of the podfile for which dependencies have or have not changed, added, deleted or updated.
|
925
|
+
#
|
926
|
+
# @return [Molinillo::DependencyGraph<Dependency>] the dependencies
|
927
|
+
# generated by the lockfile that prevent the resolver to update
|
928
|
+
# a Pod.
|
929
|
+
#
|
930
|
+
def generate_version_locking_dependencies(podfile_state)
|
931
|
+
if update_mode == :all || !lockfile
|
932
|
+
LockingDependencyAnalyzer.unlocked_dependency_graph
|
933
|
+
else
|
934
|
+
deleted_and_changed = podfile_state.changed + podfile_state.deleted
|
935
|
+
deleted_and_changed += pods_to_update[:pods] if update_mode == :selected
|
936
|
+
local_pod_names = podfile_dependencies.select(&:local?).map(&:root_name)
|
937
|
+
pods_to_unlock = local_pod_names.to_set.delete_if do |pod_name|
|
938
|
+
next unless sandbox_specification = sandbox.specification(pod_name)
|
939
|
+
sandbox_specification.checksum == lockfile.checksum(pod_name)
|
940
|
+
end
|
941
|
+
LockingDependencyAnalyzer.generate_version_locking_dependencies(lockfile, deleted_and_changed, pods_to_unlock)
|
942
|
+
end
|
943
|
+
end
|
944
|
+
|
945
|
+
# Fetches the podspecs of external sources if modifications to the
|
946
|
+
# sandbox are allowed.
|
947
|
+
#
|
948
|
+
# @note In update mode all the external sources are refreshed while in
|
949
|
+
# normal mode they are refreshed only if added or changed in the
|
950
|
+
# Podfile. Moreover, in normal specifications for unchanged Pods
|
951
|
+
# which are missing or are generated from an local source are
|
952
|
+
# fetched as well.
|
953
|
+
#
|
954
|
+
# @note It is possible to perform this step before the resolution
|
955
|
+
# process because external sources identify a single specific
|
956
|
+
# version (checkout). If the other dependencies are not
|
957
|
+
# compatible with the version reported by the podspec of the
|
958
|
+
# external source the resolver will raise.
|
959
|
+
#
|
960
|
+
# @param [SpecState] podfile_state
|
961
|
+
# the state of the podfile for which dependencies have or have not changed, added, deleted or updated.
|
962
|
+
#
|
963
|
+
# @return [void]
|
964
|
+
#
|
965
|
+
def fetch_external_sources(podfile_state)
|
966
|
+
verify_no_pods_with_different_sources!
|
967
|
+
deps = dependencies_to_fetch(podfile_state)
|
968
|
+
pods = pods_to_fetch(podfile_state)
|
969
|
+
return if deps.empty?
|
970
|
+
UI.section 'Fetching external sources' do
|
971
|
+
deps.sort.each do |dependency|
|
972
|
+
fetch_external_source(dependency, !pods.include?(dependency.root_name))
|
973
|
+
end
|
974
|
+
end
|
975
|
+
end
|
976
|
+
|
977
|
+
def verify_no_pods_with_different_sources!
|
978
|
+
deps_with_different_sources = podfile_dependencies.group_by(&:root_name).
|
979
|
+
select { |_root_name, dependencies| dependencies.map(&:external_source).uniq.count > 1 }
|
980
|
+
deps_with_different_sources.each do |root_name, dependencies|
|
981
|
+
raise Informative, 'There are multiple dependencies with different ' \
|
982
|
+
"sources for `#{root_name}` in #{UI.path podfile.defined_in_file}:" \
|
983
|
+
"\n\n- #{dependencies.map(&:to_s).join("\n- ")}"
|
984
|
+
end
|
985
|
+
end
|
986
|
+
|
987
|
+
def fetch_external_source(dependency, use_lockfile_options)
|
988
|
+
source = if use_lockfile_options && lockfile && checkout_options = lockfile.checkout_options_for_pod_named(dependency.root_name)
|
989
|
+
ExternalSources.from_params(checkout_options, dependency, podfile.defined_in_file, installation_options.clean?)
|
990
|
+
else
|
991
|
+
ExternalSources.from_dependency(dependency, podfile.defined_in_file, installation_options.clean?)
|
992
|
+
end
|
993
|
+
source.fetch(sandbox)
|
994
|
+
end
|
995
|
+
|
996
|
+
def dependencies_to_fetch(podfile_state)
|
997
|
+
@deps_to_fetch ||= begin
|
998
|
+
deps_to_fetch = []
|
999
|
+
deps_with_external_source = podfile_dependencies.select(&:external_source)
|
1000
|
+
|
1001
|
+
if update_mode == :all
|
1002
|
+
deps_to_fetch = deps_with_external_source
|
1003
|
+
else
|
1004
|
+
deps_to_fetch = deps_with_external_source.select { |dep| pods_to_fetch(podfile_state).include?(dep.root_name) }
|
1005
|
+
deps_to_fetch_if_needed = deps_with_external_source.select { |dep| podfile_state.unchanged.include?(dep.root_name) }
|
1006
|
+
deps_to_fetch += deps_to_fetch_if_needed.select do |dep|
|
1007
|
+
sandbox.specification_path(dep.root_name).nil? ||
|
1008
|
+
!dep.external_source[:path].nil? ||
|
1009
|
+
!sandbox.pod_dir(dep.root_name).directory? ||
|
1010
|
+
checkout_requires_update?(dep)
|
1011
|
+
end
|
1012
|
+
end
|
1013
|
+
deps_to_fetch.uniq(&:root_name)
|
1014
|
+
end
|
1015
|
+
end
|
1016
|
+
|
1017
|
+
def checkout_requires_update?(dependency)
|
1018
|
+
return true unless lockfile && sandbox.manifest
|
1019
|
+
locked_checkout_options = lockfile.checkout_options_for_pod_named(dependency.root_name)
|
1020
|
+
sandbox_checkout_options = sandbox.manifest.checkout_options_for_pod_named(dependency.root_name)
|
1021
|
+
locked_checkout_options != sandbox_checkout_options
|
1022
|
+
end
|
1023
|
+
|
1024
|
+
def pods_to_fetch(podfile_state)
|
1025
|
+
@pods_to_fetch ||= begin
|
1026
|
+
pods_to_fetch = podfile_state.added + podfile_state.changed
|
1027
|
+
if update_mode == :selected
|
1028
|
+
pods_to_fetch += pods_to_update[:pods]
|
1029
|
+
elsif update_mode == :all
|
1030
|
+
pods_to_fetch += podfile_state.unchanged + podfile_state.deleted
|
1031
|
+
end
|
1032
|
+
pods_to_fetch += podfile_dependencies.
|
1033
|
+
select { |dep| Hash(dep.external_source).key?(:podspec) && sandbox.specification_path(dep.root_name).nil? }.
|
1034
|
+
map(&:root_name)
|
1035
|
+
pods_to_fetch
|
1036
|
+
end
|
1037
|
+
end
|
1038
|
+
|
1039
|
+
def store_existing_checkout_options
|
1040
|
+
return unless lockfile
|
1041
|
+
podfile_dependencies.select(&:external_source).each do |dep|
|
1042
|
+
if checkout_options = lockfile.checkout_options_for_pod_named(dep.root_name)
|
1043
|
+
sandbox.store_checkout_source(dep.root_name, checkout_options)
|
1044
|
+
end
|
1045
|
+
end
|
1046
|
+
end
|
1047
|
+
|
1048
|
+
# Converts the Podfile in a list of specifications grouped by target.
|
1049
|
+
#
|
1050
|
+
# @note As some dependencies might have external sources the resolver
|
1051
|
+
# is aware of the {Sandbox} and interacts with it to download the
|
1052
|
+
# podspecs of the external sources. This is necessary because the
|
1053
|
+
# resolver needs their specifications to analyze their
|
1054
|
+
# dependencies.
|
1055
|
+
#
|
1056
|
+
# @note The specifications of the external sources which are added,
|
1057
|
+
# modified or removed need to deleted from the sandbox before the
|
1058
|
+
# resolution process. Otherwise the resolver might use an
|
1059
|
+
# incorrect specification instead of pre-downloading it.
|
1060
|
+
#
|
1061
|
+
# @note In update mode the resolver is set to always update the specs
|
1062
|
+
# from external sources.
|
1063
|
+
#
|
1064
|
+
# @return [Hash{TargetDefinition => Array<Spec>}] the specifications
|
1065
|
+
# grouped by target.
|
1066
|
+
#
|
1067
|
+
def resolve_dependencies(locked_dependencies)
|
1068
|
+
duplicate_dependencies = podfile_dependencies.group_by(&:name).
|
1069
|
+
select { |_name, dependencies| dependencies.count > 1 }
|
1070
|
+
duplicate_dependencies.each do |name, dependencies|
|
1071
|
+
UI.warn "There are duplicate dependencies on `#{name}` in #{UI.path podfile.defined_in_file}:\n\n" \
|
1072
|
+
"- #{dependencies.map(&:to_s).join("\n- ")}"
|
1073
|
+
end
|
1074
|
+
|
1075
|
+
resolver_specs_by_target = nil
|
1076
|
+
UI.section "Resolving dependencies of #{UI.path(podfile.defined_in_file) || 'Podfile'}" do
|
1077
|
+
resolver = Pod::Resolver.new(sandbox, podfile, locked_dependencies, sources, @specs_updated, :sources_manager => sources_manager)
|
1078
|
+
resolver_specs_by_target = resolver.resolve
|
1079
|
+
resolver_specs_by_target.values.flatten(1).map(&:spec).each(&:validate_cocoapods_version)
|
1080
|
+
end
|
1081
|
+
resolver_specs_by_target
|
1082
|
+
end
|
1083
|
+
|
1084
|
+
# Warns for any specification that is incompatible with its target.
|
1085
|
+
#
|
1086
|
+
# @param [Hash{TargetDefinition => Array<Specification>}] resolver_specs_by_target
|
1087
|
+
# the resolved specifications grouped by target.
|
1088
|
+
#
|
1089
|
+
def validate_platforms(resolver_specs_by_target)
|
1090
|
+
resolver_specs_by_target.each do |target, specs|
|
1091
|
+
specs.map(&:spec).each do |spec|
|
1092
|
+
next unless target_platform = target.platform
|
1093
|
+
unless spec.available_platforms.any? { |p| target_platform.supports?(p) }
|
1094
|
+
UI.warn "The platform of the target `#{target.name}` " \
|
1095
|
+
"(#{target.platform}) may not be compatible with `#{spec}` which has " \
|
1096
|
+
"a minimum requirement of #{spec.available_platforms.join(' - ')}."
|
1097
|
+
end
|
1098
|
+
end
|
1099
|
+
end
|
1100
|
+
end
|
1101
|
+
|
1102
|
+
# Returns the list of all the resolved specifications.
|
1103
|
+
#
|
1104
|
+
# @param [Hash{TargetDefinition => Array<Specification>}] resolver_specs_by_target
|
1105
|
+
# the resolved specifications grouped by target.
|
1106
|
+
#
|
1107
|
+
# @return [Array<Specification>] the list of the specifications.
|
1108
|
+
#
|
1109
|
+
def generate_specifications(resolver_specs_by_target)
|
1110
|
+
resolver_specs_by_target.values.flatten.map(&:spec).uniq
|
1111
|
+
end
|
1112
|
+
|
1113
|
+
# Computes the state of the sandbox respect to the resolved
|
1114
|
+
# specifications.
|
1115
|
+
#
|
1116
|
+
# @return [SpecsState] the representation of the state of the manifest
|
1117
|
+
# specifications.
|
1118
|
+
#
|
1119
|
+
def generate_sandbox_state(specifications)
|
1120
|
+
sandbox_state = nil
|
1121
|
+
UI.section 'Comparing resolved specification to the sandbox manifest' do
|
1122
|
+
sandbox_analyzer = SandboxAnalyzer.new(sandbox, podfile, specifications, update_mode?)
|
1123
|
+
sandbox_state = sandbox_analyzer.analyze
|
1124
|
+
sandbox_state.print
|
1125
|
+
end
|
1126
|
+
sandbox_state
|
1127
|
+
end
|
1128
|
+
|
1129
|
+
class << self
|
1130
|
+
# @param [Platform] platform
|
1131
|
+
# The platform to build against
|
1132
|
+
#
|
1133
|
+
# @param [String, Nil] object_version
|
1134
|
+
# The user project's object version, or nil if not available
|
1135
|
+
#
|
1136
|
+
# @return [Boolean] Whether the platform requires 64-bit architectures
|
1137
|
+
#
|
1138
|
+
def requires_64_bit_archs?(platform, object_version)
|
1139
|
+
return false unless platform
|
1140
|
+
case platform.name
|
1141
|
+
when :osx
|
1142
|
+
true
|
1143
|
+
when :ios
|
1144
|
+
if (version = object_version)
|
1145
|
+
platform.deployment_target >= IOS_64_BIT_ONLY_VERSION && version.to_i < IOS_64_BIT_ONLY_PROJECT_VERSION
|
1146
|
+
else
|
1147
|
+
platform.deployment_target >= IOS_64_BIT_ONLY_VERSION
|
1148
|
+
end
|
1149
|
+
when :watchos
|
1150
|
+
false
|
1151
|
+
when :tvos
|
1152
|
+
false
|
1153
|
+
end
|
1154
|
+
end
|
1155
|
+
end
|
1156
|
+
|
1157
|
+
#-----------------------------------------------------------------------#
|
1158
|
+
|
1159
|
+
# @!group Analysis sub-steps
|
1160
|
+
|
1161
|
+
# Checks whether the platform is specified if not integrating
|
1162
|
+
#
|
1163
|
+
# @return [void]
|
1164
|
+
#
|
1165
|
+
def verify_platforms_specified!
|
1166
|
+
return if installation_options.integrate_targets?
|
1167
|
+
@podfile_dependency_cache.target_definition_list.each do |target_definition|
|
1168
|
+
if !target_definition.empty? && target_definition.platform.nil?
|
1169
|
+
raise Informative, 'It is necessary to specify the platform in the Podfile if not integrating.'
|
1170
|
+
end
|
1171
|
+
end
|
1172
|
+
end
|
1173
|
+
|
1174
|
+
# Precompute information for each target_definition in the Podfile
|
1175
|
+
#
|
1176
|
+
# @note The platforms are computed and added to each target_definition
|
1177
|
+
# because it might be necessary to infer the platform from the
|
1178
|
+
# user targets.
|
1179
|
+
#
|
1180
|
+
# @return [Hash{TargetDefinition => TargetInspectionResult}]
|
1181
|
+
#
|
1182
|
+
def inspect_targets_to_integrate
|
1183
|
+
inspection_result = {}
|
1184
|
+
UI.section 'Inspecting targets to integrate' do
|
1185
|
+
inspectors = @podfile_dependency_cache.target_definition_list.map do |target_definition|
|
1186
|
+
next if target_definition.abstract?
|
1187
|
+
TargetInspector.new(target_definition, config.installation_root)
|
1188
|
+
end.compact
|
1189
|
+
inspectors.group_by(&:compute_project_path).each do |project_path, target_inspectors|
|
1190
|
+
project = Xcodeproj::Project.open(project_path)
|
1191
|
+
target_inspectors.each do |inspector|
|
1192
|
+
target_definition = inspector.target_definition
|
1193
|
+
results = inspector.compute_results(project)
|
1194
|
+
inspection_result[target_definition] = results
|
1195
|
+
UI.message('Using `ARCHS` setting to build architectures of ' \
|
1196
|
+
"target `#{target_definition.label}`: (`#{results.archs.join('`, `')}`)")
|
1197
|
+
end
|
1198
|
+
end
|
1199
|
+
end
|
1200
|
+
inspection_result
|
1201
|
+
end
|
1202
|
+
end
|
1203
|
+
end
|
1204
|
+
end
|