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.
Files changed (124) hide show
  1. checksums.yaml +7 -0
  2. data/lib/cocoapods-tt/command/native/install.rb +56 -0
  3. data/lib/cocoapods-tt/command/native/update.rb +157 -0
  4. data/lib/cocoapods-tt/command/tt/make.rb +92 -0
  5. data/lib/cocoapods-tt/command/tt.rb +115 -0
  6. data/lib/cocoapods-tt/command.rb +1 -0
  7. data/lib/cocoapods-tt/gem_version.rb +3 -0
  8. data/lib/cocoapods-tt/native/command.rb +185 -0
  9. data/lib/cocoapods-tt/native/config.rb +366 -0
  10. data/lib/cocoapods-tt/native/core_overrides.rb +1 -0
  11. data/lib/cocoapods-tt/native/downloader/cache.rb +322 -0
  12. data/lib/cocoapods-tt/native/downloader/request.rb +86 -0
  13. data/lib/cocoapods-tt/native/downloader/response.rb +16 -0
  14. data/lib/cocoapods-tt/native/downloader.rb +192 -0
  15. data/lib/cocoapods-tt/native/executable.rb +247 -0
  16. data/lib/cocoapods-tt/native/external_sources/abstract_external_source.rb +205 -0
  17. data/lib/cocoapods-tt/native/external_sources/downloader_source.rb +30 -0
  18. data/lib/cocoapods-tt/native/external_sources/path_source.rb +55 -0
  19. data/lib/cocoapods-tt/native/external_sources/podspec_source.rb +54 -0
  20. data/lib/cocoapods-tt/native/external_sources.rb +57 -0
  21. data/lib/cocoapods-tt/native/gem_version.rb +5 -0
  22. data/lib/cocoapods-tt/native/generator/acknowledgements/markdown.rb +44 -0
  23. data/lib/cocoapods-tt/native/generator/acknowledgements/plist.rb +94 -0
  24. data/lib/cocoapods-tt/native/generator/acknowledgements.rb +107 -0
  25. data/lib/cocoapods-tt/native/generator/app_target_helper.rb +363 -0
  26. data/lib/cocoapods-tt/native/generator/bridge_support.rb +22 -0
  27. data/lib/cocoapods-tt/native/generator/constant.rb +19 -0
  28. data/lib/cocoapods-tt/native/generator/copy_dsyms_script.rb +56 -0
  29. data/lib/cocoapods-tt/native/generator/copy_resources_script.rb +223 -0
  30. data/lib/cocoapods-tt/native/generator/copy_xcframework_script.rb +227 -0
  31. data/lib/cocoapods-tt/native/generator/dummy_source.rb +31 -0
  32. data/lib/cocoapods-tt/native/generator/embed_frameworks_script.rb +196 -0
  33. data/lib/cocoapods-tt/native/generator/file_list.rb +39 -0
  34. data/lib/cocoapods-tt/native/generator/header.rb +103 -0
  35. data/lib/cocoapods-tt/native/generator/info_plist_file.rb +128 -0
  36. data/lib/cocoapods-tt/native/generator/module_map.rb +99 -0
  37. data/lib/cocoapods-tt/native/generator/prefix_header.rb +60 -0
  38. data/lib/cocoapods-tt/native/generator/script_phase_constants.rb +100 -0
  39. data/lib/cocoapods-tt/native/generator/umbrella_header.rb +46 -0
  40. data/lib/cocoapods-tt/native/hooks_manager.rb +132 -0
  41. data/lib/cocoapods-tt/native/installer/analyzer/analysis_result.rb +87 -0
  42. data/lib/cocoapods-tt/native/installer/analyzer/locking_dependency_analyzer.rb +103 -0
  43. data/lib/cocoapods-tt/native/installer/analyzer/pod_variant.rb +87 -0
  44. data/lib/cocoapods-tt/native/installer/analyzer/pod_variant_set.rb +175 -0
  45. data/lib/cocoapods-tt/native/installer/analyzer/podfile_dependency_cache.rb +55 -0
  46. data/lib/cocoapods-tt/native/installer/analyzer/sandbox_analyzer.rb +268 -0
  47. data/lib/cocoapods-tt/native/installer/analyzer/specs_state.rb +108 -0
  48. data/lib/cocoapods-tt/native/installer/analyzer/target_inspection_result.rb +58 -0
  49. data/lib/cocoapods-tt/native/installer/analyzer/target_inspector.rb +258 -0
  50. data/lib/cocoapods-tt/native/installer/analyzer.rb +1204 -0
  51. data/lib/cocoapods-tt/native/installer/base_install_hooks_context.rb +135 -0
  52. data/lib/cocoapods-tt/native/installer/installation_options.rb +195 -0
  53. data/lib/cocoapods-tt/native/installer/pod_source_installer.rb +224 -0
  54. data/lib/cocoapods-tt/native/installer/pod_source_preparer.rb +77 -0
  55. data/lib/cocoapods-tt/native/installer/podfile_validator.rb +168 -0
  56. data/lib/cocoapods-tt/native/installer/post_install_hooks_context.rb +9 -0
  57. data/lib/cocoapods-tt/native/installer/post_integrate_hooks_context.rb +9 -0
  58. data/lib/cocoapods-tt/native/installer/pre_install_hooks_context.rb +51 -0
  59. data/lib/cocoapods-tt/native/installer/pre_integrate_hooks_context.rb +9 -0
  60. data/lib/cocoapods-tt/native/installer/project_cache/project_cache.rb +11 -0
  61. data/lib/cocoapods-tt/native/installer/project_cache/project_cache_analysis_result.rb +53 -0
  62. data/lib/cocoapods-tt/native/installer/project_cache/project_cache_analyzer.rb +200 -0
  63. data/lib/cocoapods-tt/native/installer/project_cache/project_cache_version.rb +43 -0
  64. data/lib/cocoapods-tt/native/installer/project_cache/project_installation_cache.rb +103 -0
  65. data/lib/cocoapods-tt/native/installer/project_cache/project_metadata_cache.rb +73 -0
  66. data/lib/cocoapods-tt/native/installer/project_cache/target_cache_key.rb +176 -0
  67. data/lib/cocoapods-tt/native/installer/project_cache/target_metadata.rb +74 -0
  68. data/lib/cocoapods-tt/native/installer/sandbox_dir_cleaner.rb +105 -0
  69. data/lib/cocoapods-tt/native/installer/sandbox_header_paths_installer.rb +45 -0
  70. data/lib/cocoapods-tt/native/installer/source_provider_hooks_context.rb +34 -0
  71. data/lib/cocoapods-tt/native/installer/target_uuid_generator.rb +34 -0
  72. data/lib/cocoapods-tt/native/installer/user_project_integrator/target_integrator/xcconfig_integrator.rb +179 -0
  73. data/lib/cocoapods-tt/native/installer/user_project_integrator/target_integrator.rb +815 -0
  74. data/lib/cocoapods-tt/native/installer/user_project_integrator.rb +280 -0
  75. data/lib/cocoapods-tt/native/installer/xcode/multi_pods_project_generator.rb +82 -0
  76. data/lib/cocoapods-tt/native/installer/xcode/pods_project_generator/aggregate_target_dependency_installer.rb +66 -0
  77. data/lib/cocoapods-tt/native/installer/xcode/pods_project_generator/aggregate_target_installer.rb +192 -0
  78. data/lib/cocoapods-tt/native/installer/xcode/pods_project_generator/app_host_installer.rb +154 -0
  79. data/lib/cocoapods-tt/native/installer/xcode/pods_project_generator/file_references_installer.rb +329 -0
  80. data/lib/cocoapods-tt/native/installer/xcode/pods_project_generator/pod_target_dependency_installer.rb +195 -0
  81. data/lib/cocoapods-tt/native/installer/xcode/pods_project_generator/pod_target_installer.rb +1239 -0
  82. data/lib/cocoapods-tt/native/installer/xcode/pods_project_generator/pod_target_integrator.rb +312 -0
  83. data/lib/cocoapods-tt/native/installer/xcode/pods_project_generator/pods_project_writer.rb +90 -0
  84. data/lib/cocoapods-tt/native/installer/xcode/pods_project_generator/project_generator.rb +120 -0
  85. data/lib/cocoapods-tt/native/installer/xcode/pods_project_generator/target_installation_result.rb +140 -0
  86. data/lib/cocoapods-tt/native/installer/xcode/pods_project_generator/target_installer.rb +257 -0
  87. data/lib/cocoapods-tt/native/installer/xcode/pods_project_generator/target_installer_helper.rb +110 -0
  88. data/lib/cocoapods-tt/native/installer/xcode/pods_project_generator.rb +291 -0
  89. data/lib/cocoapods-tt/native/installer/xcode/pods_project_generator_result.rb +54 -0
  90. data/lib/cocoapods-tt/native/installer/xcode/single_pods_project_generator.rb +38 -0
  91. data/lib/cocoapods-tt/native/installer/xcode/target_validator.rb +170 -0
  92. data/lib/cocoapods-tt/native/installer/xcode.rb +11 -0
  93. data/lib/cocoapods-tt/native/installer.rb +1044 -0
  94. data/lib/cocoapods-tt/native/native_target_extension.rb +60 -0
  95. data/lib/cocoapods-tt/native/open-uri.rb +33 -0
  96. data/lib/cocoapods-tt/native/podfile.rb +13 -0
  97. data/lib/cocoapods-tt/native/project.rb +544 -0
  98. data/lib/cocoapods-tt/native/resolver/lazy_specification.rb +88 -0
  99. data/lib/cocoapods-tt/native/resolver/resolver_specification.rb +41 -0
  100. data/lib/cocoapods-tt/native/resolver.rb +600 -0
  101. data/lib/cocoapods-tt/native/sandbox/file_accessor.rb +532 -0
  102. data/lib/cocoapods-tt/native/sandbox/headers_store.rb +163 -0
  103. data/lib/cocoapods-tt/native/sandbox/path_list.rb +242 -0
  104. data/lib/cocoapods-tt/native/sandbox/pod_dir_cleaner.rb +71 -0
  105. data/lib/cocoapods-tt/native/sandbox/podspec_finder.rb +23 -0
  106. data/lib/cocoapods-tt/native/sandbox.rb +470 -0
  107. data/lib/cocoapods-tt/native/sources_manager.rb +221 -0
  108. data/lib/cocoapods-tt/native/target/aggregate_target.rb +558 -0
  109. data/lib/cocoapods-tt/native/target/build_settings.rb +1385 -0
  110. data/lib/cocoapods-tt/native/target/pod_target.rb +1168 -0
  111. data/lib/cocoapods-tt/native/target.rb +378 -0
  112. data/lib/cocoapods-tt/native/user_interface/error_report.rb +204 -0
  113. data/lib/cocoapods-tt/native/user_interface/inspector_reporter.rb +102 -0
  114. data/lib/cocoapods-tt/native/user_interface.rb +463 -0
  115. data/lib/cocoapods-tt/native/validator.rb +1170 -0
  116. data/lib/cocoapods-tt/native/version_metadata.rb +26 -0
  117. data/lib/cocoapods-tt/native/xcode/framework_paths.rb +54 -0
  118. data/lib/cocoapods-tt/native/xcode/linkage_analyzer.rb +22 -0
  119. data/lib/cocoapods-tt/native/xcode/xcframework/xcframework_slice.rb +138 -0
  120. data/lib/cocoapods-tt/native/xcode/xcframework.rb +99 -0
  121. data/lib/cocoapods-tt/native/xcode.rb +7 -0
  122. data/lib/cocoapods-tt.rb +1 -0
  123. data/lib/cocoapods_plugin.rb +17 -0
  124. 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