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,600 @@
|
|
1
|
+
require 'molinillo'
|
2
|
+
require 'cocoapods/podfile'
|
3
|
+
|
4
|
+
module Pod
|
5
|
+
class NoSpecFoundError < Informative
|
6
|
+
def exit_status
|
7
|
+
@exit_status ||= 31
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
# The resolver is responsible of generating a list of specifications grouped
|
12
|
+
# by target for a given Podfile.
|
13
|
+
#
|
14
|
+
class Resolver
|
15
|
+
require 'cocoapods/resolver/lazy_specification'
|
16
|
+
require 'cocoapods/resolver/resolver_specification'
|
17
|
+
|
18
|
+
# @return [Sandbox] the Sandbox used by the resolver to find external
|
19
|
+
# dependencies.
|
20
|
+
#
|
21
|
+
attr_reader :sandbox
|
22
|
+
|
23
|
+
# @return [Podfile] the Podfile used by the resolver.
|
24
|
+
#
|
25
|
+
attr_reader :podfile
|
26
|
+
|
27
|
+
# @return [Array<Dependency>] the list of dependencies locked to a specific
|
28
|
+
# version.
|
29
|
+
#
|
30
|
+
attr_reader :locked_dependencies
|
31
|
+
|
32
|
+
# @return [Array<Source>] The list of the sources which will be used for
|
33
|
+
# the resolution.
|
34
|
+
#
|
35
|
+
attr_reader :sources
|
36
|
+
|
37
|
+
# @return [Bool] Whether the resolver has sources repositories up-to-date.
|
38
|
+
#
|
39
|
+
attr_reader :specs_updated
|
40
|
+
alias specs_updated? specs_updated
|
41
|
+
|
42
|
+
# @return [Source::Manager] the manager to use for dependency resolution
|
43
|
+
#
|
44
|
+
attr_reader :sources_manager
|
45
|
+
|
46
|
+
# Init a new Resolver
|
47
|
+
#
|
48
|
+
# @param [Sandbox] sandbox @see sandbox
|
49
|
+
# @param [Podfile] podfile @see podfile
|
50
|
+
# @param [Array<Dependency>] locked_dependencies @see locked_dependencies
|
51
|
+
# @param [Array<Source>, Source] sources @see sources
|
52
|
+
# @param [Boolean] specs_updated @see specs_updated
|
53
|
+
# @param [PodfileDependencyCache] podfile_dependency_cache the podfile dependency cache to use
|
54
|
+
# within this Resolver.
|
55
|
+
#
|
56
|
+
def initialize(sandbox, podfile, locked_dependencies, sources, specs_updated,
|
57
|
+
podfile_dependency_cache: Installer::Analyzer::PodfileDependencyCache.from_podfile(podfile),
|
58
|
+
sources_manager: Config.instance.sources_manager)
|
59
|
+
@sandbox = sandbox
|
60
|
+
@podfile = podfile
|
61
|
+
@locked_dependencies = locked_dependencies
|
62
|
+
@sources = Array(sources)
|
63
|
+
@specs_updated = specs_updated
|
64
|
+
@podfile_dependency_cache = podfile_dependency_cache
|
65
|
+
@sources_manager = sources_manager
|
66
|
+
@platforms_by_dependency = Hash.new { |h, k| h[k] = [] }
|
67
|
+
|
68
|
+
@cached_sets = {}
|
69
|
+
@podfile_requirements_by_root_name = @podfile_dependency_cache.podfile_dependencies.group_by(&:root_name).each_value { |a| a.map!(&:requirement).freeze }.freeze
|
70
|
+
@search = {}
|
71
|
+
@validated_platforms = Set.new
|
72
|
+
end
|
73
|
+
|
74
|
+
#-------------------------------------------------------------------------#
|
75
|
+
|
76
|
+
public
|
77
|
+
|
78
|
+
# @!group Resolution
|
79
|
+
|
80
|
+
# Identifies the specifications that should be installed.
|
81
|
+
#
|
82
|
+
# @return [Hash{TargetDefinition => Array<ResolverSpecification>}] resolver_specs_by_target
|
83
|
+
# the resolved specifications that need to be installed grouped by target
|
84
|
+
# definition.
|
85
|
+
#
|
86
|
+
def resolve
|
87
|
+
dependencies = @podfile_dependency_cache.target_definition_list.flat_map do |target|
|
88
|
+
@podfile_dependency_cache.target_definition_dependencies(target).each do |dep|
|
89
|
+
next unless target.platform
|
90
|
+
@platforms_by_dependency[dep].push(target.platform)
|
91
|
+
end
|
92
|
+
end.uniq
|
93
|
+
@platforms_by_dependency.each_value(&:uniq!)
|
94
|
+
@activated = Molinillo::Resolver.new(self, self).resolve(dependencies, locked_dependencies)
|
95
|
+
resolver_specs_by_target
|
96
|
+
rescue Molinillo::ResolverError => e
|
97
|
+
handle_resolver_error(e)
|
98
|
+
end
|
99
|
+
|
100
|
+
# @return [Hash{Podfile::TargetDefinition => Array<ResolverSpecification>}]
|
101
|
+
# returns the resolved specifications grouped by target.
|
102
|
+
#
|
103
|
+
# @note The returned specifications can be subspecs.
|
104
|
+
#
|
105
|
+
def resolver_specs_by_target
|
106
|
+
@resolver_specs_by_target ||= {}.tap do |resolver_specs_by_target|
|
107
|
+
@podfile_dependency_cache.target_definition_list.each do |target|
|
108
|
+
next if target.abstract? && !target.platform
|
109
|
+
|
110
|
+
# can't use vertex.root? since that considers _all_ targets
|
111
|
+
explicit_dependencies = @podfile_dependency_cache.target_definition_dependencies(target).map(&:name).to_set
|
112
|
+
|
113
|
+
used_by_aggregate_target_by_spec_name = {}
|
114
|
+
used_vertices_by_spec_name = {}
|
115
|
+
|
116
|
+
# it's safe to make a single pass here since we iterate in topological order,
|
117
|
+
# so all of the predecessors have been visited before we get to a node.
|
118
|
+
# #tsort returns no-children vertices first, and we want them last (i.e. we want no-parent vertices first)
|
119
|
+
@activated.tsort.reverse_each do |vertex|
|
120
|
+
spec_name = vertex.name
|
121
|
+
explicitly_included = explicit_dependencies.include?(spec_name)
|
122
|
+
if explicitly_included || vertex.incoming_edges.any? { |edge| used_vertices_by_spec_name.key?(edge.origin.name) && edge_is_valid_for_target_platform?(edge, target.platform) }
|
123
|
+
validate_platform(vertex.payload, target)
|
124
|
+
used_vertices_by_spec_name[spec_name] = vertex
|
125
|
+
used_by_aggregate_target_by_spec_name[spec_name] = vertex.payload.library_specification? &&
|
126
|
+
(explicitly_included || vertex.predecessors.any? { |predecessor| used_by_aggregate_target_by_spec_name.fetch(predecessor.name, false) })
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
resolver_specs_by_target[target] = used_vertices_by_spec_name.each_value.
|
131
|
+
map do |vertex|
|
132
|
+
payload = vertex.payload
|
133
|
+
non_library = !used_by_aggregate_target_by_spec_name.fetch(vertex.name)
|
134
|
+
spec_source = payload.respond_to?(:spec_source) && payload.spec_source
|
135
|
+
ResolverSpecification.new(payload, non_library, spec_source)
|
136
|
+
end.
|
137
|
+
sort_by(&:name)
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
#-------------------------------------------------------------------------#
|
143
|
+
|
144
|
+
public
|
145
|
+
|
146
|
+
# @!group Specification Provider
|
147
|
+
|
148
|
+
include Molinillo::SpecificationProvider
|
149
|
+
|
150
|
+
# Returns (and caches) the specification that satisfy the given dependency.
|
151
|
+
#
|
152
|
+
# @return [Array<Specification>] the specifications that satisfy the given
|
153
|
+
# `dependency`.
|
154
|
+
#
|
155
|
+
# @param [Dependency] dependency the dependency that is being searched for.
|
156
|
+
#
|
157
|
+
def search_for(dependency)
|
158
|
+
@search[dependency] ||= begin
|
159
|
+
additional_requirements = if locked_requirement = requirement_for_locked_pod_named(dependency.name)
|
160
|
+
[locked_requirement]
|
161
|
+
else
|
162
|
+
Array(@podfile_requirements_by_root_name[dependency.root_name])
|
163
|
+
end
|
164
|
+
|
165
|
+
specifications_for_dependency(dependency, additional_requirements).freeze
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
# Returns the dependencies of `specification`.
|
170
|
+
#
|
171
|
+
# @return [Array<Specification>] all dependencies of `specification`.
|
172
|
+
#
|
173
|
+
# @param [Specification] specification the specification whose own
|
174
|
+
# dependencies are being asked for.
|
175
|
+
#
|
176
|
+
def dependencies_for(specification)
|
177
|
+
root_name = Specification.root_name(specification.name)
|
178
|
+
specification.all_dependencies.map do |dependency|
|
179
|
+
if dependency.root_name == root_name
|
180
|
+
dependency.dup.tap { |d| d.specific_version = specification.version }
|
181
|
+
else
|
182
|
+
dependency
|
183
|
+
end
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
187
|
+
# Returns the name for the given `dependency`.
|
188
|
+
#
|
189
|
+
# @return [String] the name for the given `dependency`.
|
190
|
+
#
|
191
|
+
# @param [Dependency] dependency the dependency whose name is being
|
192
|
+
# queried.
|
193
|
+
#
|
194
|
+
def name_for(dependency)
|
195
|
+
dependency.name
|
196
|
+
end
|
197
|
+
|
198
|
+
# @return [String] the user-facing name for a {Podfile}.
|
199
|
+
#
|
200
|
+
def name_for_explicit_dependency_source
|
201
|
+
'Podfile'
|
202
|
+
end
|
203
|
+
|
204
|
+
# @return [String] the user-facing name for a {Lockfile}.
|
205
|
+
#
|
206
|
+
def name_for_locking_dependency_source
|
207
|
+
'Podfile.lock'
|
208
|
+
end
|
209
|
+
|
210
|
+
# Determines whether the given `requirement` is satisfied by the given
|
211
|
+
# `spec`, in the context of the current `activated` dependency graph.
|
212
|
+
#
|
213
|
+
# @return [Boolean] whether `requirement` is satisfied by `spec` in the
|
214
|
+
# context of the current `activated` dependency graph.
|
215
|
+
#
|
216
|
+
# @param [Dependency] requirement the dependency in question.
|
217
|
+
#
|
218
|
+
# @param [Molinillo::DependencyGraph] activated the current dependency
|
219
|
+
# graph in the resolution process.
|
220
|
+
#
|
221
|
+
# @param [Specification] spec the specification in question.
|
222
|
+
#
|
223
|
+
def requirement_satisfied_by?(requirement, activated, spec)
|
224
|
+
version = spec.version
|
225
|
+
return false unless requirement.requirement.satisfied_by?(version)
|
226
|
+
return false unless valid_possibility_version_for_root_name?(requirement, activated, spec)
|
227
|
+
return false unless spec_is_platform_compatible?(activated, requirement, spec)
|
228
|
+
true
|
229
|
+
end
|
230
|
+
|
231
|
+
def valid_possibility_version_for_root_name?(requirement, activated, spec)
|
232
|
+
return true if prerelease_requirement = requirement.prerelease? || requirement.external_source || !spec.version.prerelease?
|
233
|
+
|
234
|
+
activated.each do |vertex|
|
235
|
+
next unless vertex.payload
|
236
|
+
next unless Specification.root_name(vertex.name) == requirement.root_name
|
237
|
+
|
238
|
+
prerelease_requirement ||= vertex.requirements.any? { |r| r.prerelease? || r.external_source }
|
239
|
+
|
240
|
+
if vertex.payload.respond_to?(:version)
|
241
|
+
return true if vertex.payload.version == spec.version
|
242
|
+
break
|
243
|
+
end
|
244
|
+
end
|
245
|
+
|
246
|
+
prerelease_requirement
|
247
|
+
end
|
248
|
+
private :valid_possibility_version_for_root_name?
|
249
|
+
|
250
|
+
# Sort dependencies so that the ones that are easiest to resolve are first.
|
251
|
+
# Easiest to resolve is (usually) defined by:
|
252
|
+
# 1) Is this dependency already activated?
|
253
|
+
# 2) How relaxed are the requirements?
|
254
|
+
# 3) Are there any conflicts for this dependency?
|
255
|
+
# 4) How many possibilities are there to satisfy this dependency?
|
256
|
+
#
|
257
|
+
# @return [Array<Dependency>] the sorted dependencies.
|
258
|
+
#
|
259
|
+
# @param [Array<Dependency>] dependencies the unsorted dependencies.
|
260
|
+
#
|
261
|
+
# @param [Molinillo::DependencyGraph] activated the dependency graph of
|
262
|
+
# currently activated specs.
|
263
|
+
#
|
264
|
+
# @param [{String => Array<Conflict>}] conflicts the current conflicts.
|
265
|
+
#
|
266
|
+
def sort_dependencies(dependencies, activated, conflicts)
|
267
|
+
dependencies.sort_by! do |dependency|
|
268
|
+
name = name_for(dependency)
|
269
|
+
[
|
270
|
+
activated.vertex_named(name).payload ? 0 : 1,
|
271
|
+
dependency.external_source ? 0 : 1,
|
272
|
+
dependency.prerelease? ? 0 : 1,
|
273
|
+
conflicts[name] ? 0 : 1,
|
274
|
+
search_for(dependency).count,
|
275
|
+
]
|
276
|
+
end
|
277
|
+
end
|
278
|
+
|
279
|
+
#-------------------------------------------------------------------------#
|
280
|
+
|
281
|
+
public
|
282
|
+
|
283
|
+
# @!group Resolver UI
|
284
|
+
|
285
|
+
include Molinillo::UI
|
286
|
+
|
287
|
+
# The UI object the resolver should use for displaying user-facing output.
|
288
|
+
#
|
289
|
+
# @return [UserInterface] the normal CocoaPods UI object.
|
290
|
+
#
|
291
|
+
def output
|
292
|
+
UI
|
293
|
+
end
|
294
|
+
|
295
|
+
# Called before resolution starts.
|
296
|
+
#
|
297
|
+
# Completely silence this, as we show nothing.
|
298
|
+
#
|
299
|
+
# @return [Void]
|
300
|
+
#
|
301
|
+
def before_resolution
|
302
|
+
end
|
303
|
+
|
304
|
+
# Called after resolution ends.
|
305
|
+
#
|
306
|
+
# Completely silence this, as we show nothing.
|
307
|
+
#
|
308
|
+
# @return [Void]
|
309
|
+
#
|
310
|
+
def after_resolution
|
311
|
+
end
|
312
|
+
|
313
|
+
# Called during resolution to indicate progress.
|
314
|
+
#
|
315
|
+
# Completely silence this, as we show nothing.
|
316
|
+
#
|
317
|
+
# @return [Void]
|
318
|
+
#
|
319
|
+
def indicate_progress
|
320
|
+
end
|
321
|
+
|
322
|
+
#-------------------------------------------------------------------------#
|
323
|
+
|
324
|
+
private
|
325
|
+
|
326
|
+
# !@ Resolution context
|
327
|
+
|
328
|
+
# @return [Hash<String => Set>] A cache that keeps tracks of the sets
|
329
|
+
# loaded by the resolution process.
|
330
|
+
#
|
331
|
+
# @note Sets store the resolved dependencies and return the highest
|
332
|
+
# available specification found in the sources. This is done
|
333
|
+
# globally and not per target definition because there can be just
|
334
|
+
# one Pod installation, so different version of the same Pods for
|
335
|
+
# target definitions are not allowed.
|
336
|
+
#
|
337
|
+
attr_reader :cached_sets
|
338
|
+
|
339
|
+
#-------------------------------------------------------------------------#
|
340
|
+
|
341
|
+
private
|
342
|
+
|
343
|
+
# @!group Private helpers
|
344
|
+
|
345
|
+
# Returns available specifications which satisfy requirements of given dependency
|
346
|
+
# and additional requirements.
|
347
|
+
#
|
348
|
+
# @param [Dependency] dependency
|
349
|
+
# The dependency whose requirements will be satisfied.
|
350
|
+
#
|
351
|
+
# @param [Array<Requirement>] additional_requirements
|
352
|
+
# List of additional requirements which should also be satisfied.
|
353
|
+
#
|
354
|
+
# @return [Array<Specification>] List of specifications satisfying given requirements.
|
355
|
+
#
|
356
|
+
def specifications_for_dependency(dependency, additional_requirements = [])
|
357
|
+
requirement_list = dependency.requirement.as_list + additional_requirements.flat_map(&:as_list)
|
358
|
+
requirement_list.uniq!
|
359
|
+
requirement = Requirement.new(requirement_list)
|
360
|
+
find_cached_set(dependency).
|
361
|
+
all_specifications(warn_for_multiple_pod_sources, requirement).
|
362
|
+
map { |s| s.subspec_by_name(dependency.name, false, true) }.
|
363
|
+
compact
|
364
|
+
end
|
365
|
+
|
366
|
+
# @return [Set] Loads or returns a previously initialized set for the Pod
|
367
|
+
# of the given dependency.
|
368
|
+
#
|
369
|
+
# @param [Dependency] dependency
|
370
|
+
# The dependency for which the set is needed.
|
371
|
+
#
|
372
|
+
# @return [Set] the cached set for a given dependency.
|
373
|
+
#
|
374
|
+
def find_cached_set(dependency)
|
375
|
+
name = dependency.root_name
|
376
|
+
cached_sets[name] ||= begin
|
377
|
+
if dependency.external_source
|
378
|
+
spec = sandbox.specification(name)
|
379
|
+
unless spec
|
380
|
+
raise StandardError, '[Bug] Unable to find the specification ' \
|
381
|
+
"for `#{dependency}`."
|
382
|
+
end
|
383
|
+
set = Specification::Set::External.new(spec)
|
384
|
+
else
|
385
|
+
set = create_set_from_sources(dependency)
|
386
|
+
end
|
387
|
+
|
388
|
+
unless set
|
389
|
+
raise Molinillo::NoSuchDependencyError.new(dependency) # rubocop:disable Style/RaiseArgs
|
390
|
+
end
|
391
|
+
|
392
|
+
set
|
393
|
+
end
|
394
|
+
end
|
395
|
+
|
396
|
+
# @return [Requirement, Nil]
|
397
|
+
# The {Requirement} that locks the dependency with name `name` in
|
398
|
+
# {#locked_dependencies}.
|
399
|
+
#
|
400
|
+
def requirement_for_locked_pod_named(name)
|
401
|
+
if vertex = locked_dependencies.vertex_named(name)
|
402
|
+
if dependency = vertex.payload
|
403
|
+
dependency.requirement
|
404
|
+
end
|
405
|
+
end
|
406
|
+
end
|
407
|
+
|
408
|
+
# @return [Set] Creates a set for the Pod of the given dependency from the
|
409
|
+
# sources. The set will contain all versions from all sources that
|
410
|
+
# include the Pod.
|
411
|
+
#
|
412
|
+
# @param [Dependency] dependency
|
413
|
+
# The dependency for which the set is needed.
|
414
|
+
#
|
415
|
+
def create_set_from_sources(dependency)
|
416
|
+
aggregate_for_dependency(dependency).search(dependency)
|
417
|
+
end
|
418
|
+
|
419
|
+
# @return [Source::Aggregate] The aggregate of the {#sources}.
|
420
|
+
#
|
421
|
+
def aggregate_for_dependency(dependency)
|
422
|
+
if dependency && dependency.podspec_repo
|
423
|
+
sources_manager.aggregate_for_dependency(dependency)
|
424
|
+
elsif (locked_vertex = @locked_dependencies.vertex_named(dependency.name)) && (locked_dependency = locked_vertex.payload) && locked_dependency.podspec_repo
|
425
|
+
sources_manager.aggregate_for_dependency(locked_dependency)
|
426
|
+
else
|
427
|
+
@aggregate ||= Source::Aggregate.new(sources)
|
428
|
+
end
|
429
|
+
end
|
430
|
+
|
431
|
+
# Ensures that a specification is compatible with the platform of a target.
|
432
|
+
#
|
433
|
+
# @raise If the specification is not supported by the target.
|
434
|
+
#
|
435
|
+
# @return [void]
|
436
|
+
#
|
437
|
+
def validate_platform(spec, target)
|
438
|
+
return unless target_platform = target.platform
|
439
|
+
return unless @validated_platforms.add?([spec.object_id, target_platform])
|
440
|
+
unless spec.available_platforms.any? { |p| target_platform.to_sym == p.to_sym }
|
441
|
+
raise Informative, "The platform of the target `#{target.name}` " \
|
442
|
+
"(#{target.platform}) is not compatible with `#{spec}`, which does " \
|
443
|
+
"not support `#{target.platform.string_name}`."
|
444
|
+
end
|
445
|
+
end
|
446
|
+
|
447
|
+
# Handles errors that come out of a {Molinillo::Resolver}.
|
448
|
+
#
|
449
|
+
# @return [void]
|
450
|
+
#
|
451
|
+
# @param [Molinillo::ResolverError] error
|
452
|
+
#
|
453
|
+
def handle_resolver_error(error)
|
454
|
+
message = error.message
|
455
|
+
type = Informative
|
456
|
+
unless specs_updated?
|
457
|
+
specs_update_message = "\n * out-of-date source repos which you can update with `pod repo update` or with `pod install --repo-update`."
|
458
|
+
end
|
459
|
+
case error
|
460
|
+
when Molinillo::VersionConflict
|
461
|
+
message = error.message_with_trees(
|
462
|
+
:solver_name => 'CocoaPods',
|
463
|
+
:possibility_type => 'pod',
|
464
|
+
:version_for_spec => lambda(&:version),
|
465
|
+
:additional_message_for_conflict => lambda do |o, name, conflict|
|
466
|
+
local_pod_parent = conflict.requirement_trees.flatten.reverse.find(&:local?)
|
467
|
+
if local_pod_parent && !specifications_for_dependency(conflict.requirement).empty? && !conflict.possibility && conflict.locked_requirement
|
468
|
+
# Conflict was caused by a requirement from a local dependency.
|
469
|
+
# Tell user to use `pod update`.
|
470
|
+
o << "\n\nYou have either:#{specs_update_message}" \
|
471
|
+
"\n * changed the constraints of dependency `#{name}` inside your development pod `#{local_pod_parent.name}`." \
|
472
|
+
"\n You should run `pod update #{name}` to apply changes you've made."
|
473
|
+
elsif !conflict.possibility && conflict.locked_requirement && conflict.locked_requirement.external_source && conflict.locked_requirement.external_source[:podspec] &&
|
474
|
+
conflict.requirement && conflict.requirement.external_source && conflict.requirement.external_source[:podspec]
|
475
|
+
# The internal version of the Podspec doesn't match the external definition of a podspec
|
476
|
+
o << "\nIt seems like you've changed the version of the dependency `#{name}` " \
|
477
|
+
"and it differs from the version stored in `Pods/Local Podspecs`.\nYou should run `pod update #{name} --no-repo-update` to apply " \
|
478
|
+
'changes made locally.'
|
479
|
+
elsif (conflict.possibility && conflict.possibility.version.prerelease?) &&
|
480
|
+
(conflict.requirement && !(
|
481
|
+
conflict.requirement.prerelease? ||
|
482
|
+
conflict.requirement.external_source)
|
483
|
+
)
|
484
|
+
# Conflict was caused by not specifying an explicit version for the requirement #[name],
|
485
|
+
# and there is no available stable version satisfying constraints for the requirement.
|
486
|
+
o << "\nThere are only pre-release versions available satisfying the following requirements:\n"
|
487
|
+
conflict.requirements.values.flatten.uniq.each do |r|
|
488
|
+
unless search_for(r).empty?
|
489
|
+
o << "\n\t'#{name}', '#{r.requirement}'\n"
|
490
|
+
end
|
491
|
+
end
|
492
|
+
o << "\nYou should explicitly specify the version in order to install a pre-release version"
|
493
|
+
elsif !conflict.existing
|
494
|
+
conflicts = conflict.requirements.values.flatten.uniq
|
495
|
+
found_conflicted_specs = conflicts.reject { |c| search_for(c).empty? }
|
496
|
+
if found_conflicted_specs.empty?
|
497
|
+
# There are no existing specification inside any of the spec repos with given requirements.
|
498
|
+
type = NoSpecFoundError
|
499
|
+
dependencies = conflicts.count == 1 ? 'dependency' : 'dependencies'
|
500
|
+
o << "\nNone of your spec sources contain a spec satisfying "\
|
501
|
+
"the #{dependencies}: `#{conflicts.join(', ')}`." \
|
502
|
+
"\n\nYou have either:#{specs_update_message}" \
|
503
|
+
"\n * mistyped the name or version." \
|
504
|
+
"\n * not added the source repo that hosts the Podspec to your Podfile."
|
505
|
+
|
506
|
+
else
|
507
|
+
o << "\nSpecs satisfying the `#{conflicts.join(', ')}` dependency were found, " \
|
508
|
+
'but they required a higher minimum deployment target.'
|
509
|
+
end
|
510
|
+
end
|
511
|
+
end,
|
512
|
+
)
|
513
|
+
when Molinillo::NoSuchDependencyError
|
514
|
+
message += <<-EOS
|
515
|
+
|
516
|
+
|
517
|
+
You have either:#{specs_update_message}
|
518
|
+
* mistyped the name or version.
|
519
|
+
* not added the source repo that hosts the Podspec to your Podfile.
|
520
|
+
EOS
|
521
|
+
end
|
522
|
+
raise type.new(message).tap { |e| e.set_backtrace(error.backtrace) }
|
523
|
+
end
|
524
|
+
|
525
|
+
# Returns whether the given spec is platform-compatible with the dependency
|
526
|
+
# graph, taking into account the dependency that has required the spec.
|
527
|
+
#
|
528
|
+
# @param [Molinillo::DependencyGraph] dependency_graph
|
529
|
+
#
|
530
|
+
# @param [Dependency] dependency
|
531
|
+
#
|
532
|
+
# @param [Specification] spec
|
533
|
+
#
|
534
|
+
# @return [Bool]
|
535
|
+
#
|
536
|
+
def spec_is_platform_compatible?(dependency_graph, dependency, spec)
|
537
|
+
# This is safe since a pod will only be in locked dependencies if we're
|
538
|
+
# using the same exact version
|
539
|
+
return true if locked_dependencies.vertex_named(spec.name)
|
540
|
+
|
541
|
+
vertex = dependency_graph.vertex_named(dependency.name)
|
542
|
+
predecessors = vertex.recursive_predecessors.select(&:root?)
|
543
|
+
predecessors << vertex if vertex.root?
|
544
|
+
platforms_to_satisfy = predecessors.flat_map(&:explicit_requirements).flat_map { |r| @platforms_by_dependency[r] }.uniq
|
545
|
+
|
546
|
+
available_platforms = spec.available_platforms
|
547
|
+
|
548
|
+
platforms_to_satisfy.all? do |platform_to_satisfy|
|
549
|
+
available_platforms.all? do |spec_platform|
|
550
|
+
next true unless spec_platform.name == platform_to_satisfy.name
|
551
|
+
# For non library specs all we care is to match by the platform name, not to satisfy the version.
|
552
|
+
next true if spec.non_library_specification?
|
553
|
+
platform_to_satisfy.supports?(spec_platform)
|
554
|
+
end
|
555
|
+
end
|
556
|
+
end
|
557
|
+
|
558
|
+
class EdgeAndPlatform
|
559
|
+
def initialize(edge, target_platform)
|
560
|
+
@edge = edge
|
561
|
+
@target_platform = target_platform
|
562
|
+
end
|
563
|
+
attr_reader :edge, :target_platform
|
564
|
+
|
565
|
+
def eql?(other)
|
566
|
+
edge.equal?(other.edge) && target_platform.eql?(other.target_platform)
|
567
|
+
end
|
568
|
+
|
569
|
+
def hash
|
570
|
+
edge.object_id ^ target_platform.hash
|
571
|
+
end
|
572
|
+
end
|
573
|
+
private_constant :EdgeAndPlatform
|
574
|
+
|
575
|
+
# Whether the given `edge` should be followed to find dependencies for the
|
576
|
+
# given `target_platform`.
|
577
|
+
#
|
578
|
+
# @return [Bool]
|
579
|
+
#
|
580
|
+
def edge_is_valid_for_target_platform?(edge, target_platform)
|
581
|
+
@edge_validity ||= Hash.new do |hash, edge_and_platform|
|
582
|
+
e = edge_and_platform.edge
|
583
|
+
platform = edge_and_platform.target_platform
|
584
|
+
requirement_name = e.requirement.name
|
585
|
+
|
586
|
+
hash[edge_and_platform] = e.origin.payload.all_dependencies(platform).any? do |dep|
|
587
|
+
dep.name == requirement_name
|
588
|
+
end
|
589
|
+
end
|
590
|
+
|
591
|
+
@edge_validity[EdgeAndPlatform.new(edge, target_platform)]
|
592
|
+
end
|
593
|
+
|
594
|
+
# @return [Boolean] whether to emit a warning when a pod is found in multiple sources
|
595
|
+
#
|
596
|
+
def warn_for_multiple_pod_sources
|
597
|
+
podfile.installation_options.warn_for_multiple_pod_sources
|
598
|
+
end
|
599
|
+
end
|
600
|
+
end
|