cocoapods 0.34.4 → 0.35.0.rc1

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 (36) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +108 -1
  3. data/bin/pod +20 -2
  4. data/lib/cocoapods.rb +1 -0
  5. data/lib/cocoapods/command.rb +17 -11
  6. data/lib/cocoapods/command/repo/push.rb +1 -1
  7. data/lib/cocoapods/command/search.rb +1 -0
  8. data/lib/cocoapods/gem_version.rb +1 -1
  9. data/lib/cocoapods/generator/acknowledgements/plist.rb +4 -10
  10. data/lib/cocoapods/generator/header.rb +75 -0
  11. data/lib/cocoapods/generator/prefix_header.rb +15 -34
  12. data/lib/cocoapods/generator/xcconfig/aggregate_xcconfig.rb +2 -2
  13. data/lib/cocoapods/generator/xcconfig/private_pod_xcconfig.rb +4 -1
  14. data/lib/cocoapods/hooks/library_representation.rb +1 -1
  15. data/lib/cocoapods/installer.rb +3 -3
  16. data/lib/cocoapods/installer/analyzer.rb +35 -37
  17. data/lib/cocoapods/installer/analyzer/locking_dependency_analyzer.rb +72 -0
  18. data/lib/cocoapods/installer/file_references_installer.rb +10 -9
  19. data/lib/cocoapods/installer/target_installer.rb +21 -21
  20. data/lib/cocoapods/installer/target_installer/aggregate_target_installer.rb +17 -17
  21. data/lib/cocoapods/installer/target_installer/pod_target_installer.rb +19 -19
  22. data/lib/cocoapods/installer/user_project_integrator/target_integrator/xcconfig_integrator.rb +7 -3
  23. data/lib/cocoapods/project.rb +1 -1
  24. data/lib/cocoapods/resolver.rb +235 -98
  25. data/lib/cocoapods/resolver/lazy_specification.rb +60 -0
  26. data/lib/cocoapods/sandbox.rb +2 -1
  27. data/lib/cocoapods/sandbox/file_accessor.rb +26 -19
  28. data/lib/cocoapods/sandbox/headers_store.rb +12 -7
  29. data/lib/cocoapods/sources_manager.rb +6 -6
  30. data/lib/cocoapods/target.rb +1 -1
  31. data/lib/cocoapods/target/pod_target.rb +2 -2
  32. data/lib/cocoapods/user_interface.rb +1 -1
  33. data/lib/cocoapods/user_interface/error_report.rb +3 -0
  34. data/lib/cocoapods/validator.rb +2 -2
  35. metadata +21 -26
  36. data/lib/cocoapods/command/push.rb +0 -21
@@ -9,7 +9,7 @@ module Pod
9
9
  # @return [void]
10
10
  #
11
11
  def install!
12
- UI.message "- Installing target `#{library.name}` #{library.platform}" do
12
+ UI.message "- Installing target `#{target.name}` #{target.platform}" do
13
13
  add_target
14
14
  create_support_files_dir
15
15
  add_files_to_build_phases
@@ -33,15 +33,15 @@ module Pod
33
33
  # @return [void]
34
34
  #
35
35
  def add_files_to_build_phases
36
- library.file_accessors.each do |file_accessor|
36
+ target.file_accessors.each do |file_accessor|
37
37
  consumer = file_accessor.spec_consumer
38
38
  flags = compiler_flags_for_consumer(consumer)
39
39
  all_source_files = file_accessor.source_files
40
40
  regular_source_files = all_source_files.reject { |sf| sf.extname == '.d' }
41
41
  regular_file_refs = regular_source_files.map { |sf| project.reference_for_path(sf) }
42
- target.add_file_references(regular_file_refs, flags)
42
+ native_target.add_file_references(regular_file_refs, flags)
43
43
  other_file_refs = (all_source_files - regular_source_files).map { |sf| project.reference_for_path(sf) }
44
- target.add_file_references(other_file_refs, nil)
44
+ native_target.add_file_references(other_file_refs, nil)
45
45
  end
46
46
  end
47
47
 
@@ -53,22 +53,22 @@ module Pod
53
53
  # @return [void]
54
54
  #
55
55
  def add_resources_bundle_targets
56
- library.file_accessors.each do |file_accessor|
56
+ target.file_accessors.each do |file_accessor|
57
57
  file_accessor.resource_bundles.each do |bundle_name, paths|
58
58
  # Add a dependency on an existing Resource Bundle target if possible
59
59
  if bundle_target = project.targets.find { |target| target.name == bundle_name }
60
- target.add_dependency(bundle_target)
60
+ native_target.add_dependency(bundle_target)
61
61
  next
62
62
  end
63
63
  file_references = paths.map { |sf| project.reference_for_path(sf) }
64
64
  bundle_target = project.new_resources_bundle(bundle_name, file_accessor.spec_consumer.platform_name)
65
65
  bundle_target.add_resources(file_references)
66
66
 
67
- library.user_build_configurations.each do |bc_name, type|
67
+ target.user_build_configurations.each do |bc_name, type|
68
68
  bundle_target.add_build_configuration(bc_name, type)
69
69
  end
70
70
 
71
- target.add_dependency(bundle_target)
71
+ native_target.add_dependency(bundle_target)
72
72
  end
73
73
  end
74
74
  end
@@ -78,17 +78,17 @@ module Pod
78
78
  # @return [void]
79
79
  #
80
80
  def create_xcconfig_file
81
- path = library.xcconfig_path
82
- public_gen = Generator::XCConfig::PublicPodXCConfig.new(library)
81
+ path = target.xcconfig_path
82
+ public_gen = Generator::XCConfig::PublicPodXCConfig.new(target)
83
83
  public_gen.save_as(path)
84
84
  add_file_to_support_group(path)
85
85
 
86
- path = library.xcconfig_private_path
87
- private_gen = Generator::XCConfig::PrivatePodXCConfig.new(library, public_gen.xcconfig)
86
+ path = target.xcconfig_private_path
87
+ private_gen = Generator::XCConfig::PrivatePodXCConfig.new(target, public_gen.xcconfig)
88
88
  private_gen.save_as(path)
89
89
  xcconfig_file_ref = add_file_to_support_group(path)
90
90
 
91
- target.build_configurations.each do |c|
91
+ native_target.build_configurations.each do |c|
92
92
  c.base_configuration_reference = xcconfig_file_ref
93
93
  end
94
94
  end
@@ -100,13 +100,13 @@ module Pod
100
100
  # @return [void]
101
101
  #
102
102
  def create_prefix_header
103
- path = library.prefix_header_path
104
- generator = Generator::PrefixHeader.new(library.file_accessors, library.platform)
105
- generator.imports << library.target_environment_header_path.basename
103
+ path = target.prefix_header_path
104
+ generator = Generator::PrefixHeader.new(target.file_accessors, target.platform)
105
+ generator.imports << target.target_environment_header_path.basename
106
106
  generator.save_as(path)
107
107
  add_file_to_support_group(path)
108
108
 
109
- target.build_configurations.each do |c|
109
+ native_target.build_configurations.each do |c|
110
110
  relative_path = path.relative_path_from(project.path.dirname)
111
111
  c.build_settings['GCC_PREFIX_HEADER'] = relative_path.to_s
112
112
  end
@@ -176,8 +176,8 @@ module Pod
176
176
  # @return [PBXFileReference] the file reference of the added file.
177
177
  #
178
178
  def add_file_to_support_group(path)
179
- pod_name = library.pod_name
180
- dir = library.support_files_dir
179
+ pod_name = target.pod_name
180
+ dir = target.support_files_dir
181
181
  group = project.pod_support_files_group(pod_name, dir)
182
182
  group.new_file(path)
183
183
  end
@@ -83,22 +83,26 @@ module Pod
83
83
  # @param [Xcodeproj::XCBuildConfiguration] config
84
84
  # The build configuration.
85
85
  #
86
+ # @return [Boolean] Indicates whether or not any changes were made.
87
+ #
86
88
  def self.set_target_xcconfig(pod_bundle, target, config)
87
89
  path = pod_bundle.xcconfig_relative_path(config.name)
88
90
  group = config.project['Pods'] || config.project.new_group('Pods')
89
91
  file_ref = group.files.find { |f| f.path == path }
90
- if config.base_configuration_reference != file_ref
92
+ if config.base_configuration_reference &&
93
+ config.base_configuration_reference != file_ref
91
94
  UI.warn 'CocoaPods did not set the base configuration of your ' \
92
95
  'project because your project already has a custom ' \
93
96
  'config set. In order for CocoaPods integration to work at ' \
94
97
  'all, please either set the base configurations of the target ' \
95
98
  "`#{target.name}` to `#{path}` or include the `#{path}` in your " \
96
99
  'build configuration.'
97
- false
98
- elsif !file_ref
100
+ elsif config.base_configuration_reference.nil? || file_ref.nil?
99
101
  file_ref ||= group.new_file(path)
100
102
  config.base_configuration_reference = file_ref
103
+ return true
101
104
  end
105
+ false
102
106
  end
103
107
 
104
108
  private
@@ -209,7 +209,7 @@ module Pod
209
209
  #
210
210
  def add_build_configuration(name, type)
211
211
  build_configuration = super
212
- values = ["#{name.gsub(/[^a-zA-Z0-9_]/, '_').upcase}=1"]
212
+ values = ["#{name.gsub(/[^a-zA-Z0-9_]/, '_').sub(/(^[0-9])/, '_\1').upcase}=1"]
213
213
  settings = build_configuration.build_settings
214
214
  definitions = Array(settings['GCC_PREPROCESSOR_DEFINITIONS'])
215
215
  values.each do |value|
@@ -1,18 +1,10 @@
1
+ require 'molinillo'
2
+ require 'cocoapods/resolver/lazy_specification'
3
+
1
4
  module Pod
2
5
  # The resolver is responsible of generating a list of specifications grouped
3
6
  # by target for a given Podfile.
4
7
  #
5
- # @todo Its current implementation is naive, in the sense that it can't do full
6
- # automatic resolves like Bundler:
7
- # [how-does-bundler-bundle](http://patshaughnessy.net/2011/9/24/how-does-bundler-bundle)
8
- #
9
- # @todo Another limitation is that the order of the dependencies matter. The
10
- # current implementation could create issues, for example, if a
11
- # specification is loaded for a target definition and later for another
12
- # target is set in head mode. The first specification will not be in head
13
- # mode.
14
- #
15
- #
16
8
  class Resolver
17
9
  # @return [Sandbox] the Sandbox used by the resolver to find external
18
10
  # dependencies.
@@ -58,23 +50,12 @@ module Pod
58
50
  # definition.
59
51
  #
60
52
  def resolve
61
- @cached_sets = {}
62
- @cached_specs = {}
63
- @specs_by_target = {}
64
-
65
- target_definitions = podfile.target_definition_list
66
- target_definitions.each do |target|
67
- title = "Resolving dependencies for target `#{target.name}' " \
68
- "(#{target.platform})"
69
- UI.section(title) do
70
- @loaded_specs = []
71
- find_dependency_specs(podfile, target.dependencies, target)
72
- specs = cached_specs.values_at(*@loaded_specs).sort_by(&:name)
73
- specs_by_target[target] = specs
74
- end
75
- end
76
-
53
+ dependencies = @podfile.target_definition_list.map(&:dependencies).flatten
54
+ @cached_sets = {}
55
+ @activated = Molinillo::Resolver.new(self, self).resolve(dependencies, locked_dependencies)
77
56
  specs_by_target
57
+ rescue Molinillo::ResolverError => e
58
+ raise Informative, e.message
78
59
  end
79
60
 
80
61
  # @return [Hash{Podfile::TargetDefinition => Array<Specification>}]
@@ -82,113 +63,237 @@ module Pod
82
63
  #
83
64
  # @note The returned specifications can be subspecs.
84
65
  #
85
- attr_reader :specs_by_target
66
+ def specs_by_target
67
+ @specs_by_target ||= begin
68
+ specs_by_target = {}
69
+ podfile.target_definition_list.each do |target|
70
+ specs = target.dependencies.map(&:name).map do |name|
71
+ node = @activated.vertex_named(name)
72
+ valid_dependencies_for_target_from_node(target, node) << node
73
+ end
74
+
75
+ specs_by_target[target] = specs.
76
+ flatten.
77
+ map(&:payload).
78
+ uniq.
79
+ sort_by(&:name).
80
+ each do |spec|
81
+ validate_platform(spec, target)
82
+ sandbox.store_head_pod(spec.name) if spec.version.head
83
+ end
84
+ end
85
+ specs_by_target
86
+ end
87
+ end
86
88
 
87
89
  #-------------------------------------------------------------------------#
88
90
 
89
- private
91
+ public
90
92
 
91
- # !@ Resolution context
93
+ # @!group Specification Provider
92
94
 
93
- # @return [Hash<String => Set>] A cache that keeps tracks of the sets
94
- # loaded by the resolution process.
95
+ include Molinillo::SpecificationProvider
96
+
97
+ # Returns (and caches) the specification that satisfy the given dependency.
95
98
  #
96
- # @note Sets store the resolved dependencies and return the highest
97
- # available specification found in the sources. This is done
98
- # globally and not per target definition because there can be just
99
- # one Pod installation, so different version of the same Pods for
100
- # target definitions are not allowed.
99
+ # @return [Array<Specification>] the specifications that satisfy the given
100
+ # `dependency`.
101
101
  #
102
- attr_accessor :cached_sets
102
+ # @param [Dependency] dependency the dependency that is being searched for.
103
+ #
104
+ def search_for(dependency)
105
+ @search ||= {}
106
+ @search[dependency] ||= begin
107
+ specs = find_cached_set(dependency).
108
+ all_specifications.
109
+ select { |s| dependency.requirement.satisfied_by? s.version }.
110
+ map { |s| s.subspec_by_name(dependency.name, false) }.
111
+ compact
112
+
113
+ specs.
114
+ reverse.
115
+ each { |s| s.version.head = dependency.head? }
116
+ end
117
+ @search[dependency].dup
118
+ end
103
119
 
104
- # @return [Hash<String => Specification>] The loaded specifications grouped
105
- # by name.
120
+ # Returns the dependencies of `specification`.
106
121
  #
107
- attr_accessor :cached_specs
122
+ # @return [Array<Specification>] all dependencies of `specification`.
123
+ #
124
+ # @param [Specification] specification the specification whose own
125
+ # dependencies are being asked for.
126
+ #
127
+ def dependencies_for(specification)
128
+ specification.all_dependencies.map do |dependency|
129
+ if dependency.root_name == Specification.root_name(specification.name)
130
+ dependency.dup.tap { |d| d.specific_version = specification.version }
131
+ else
132
+ dependency
133
+ end
134
+ end
135
+ end
108
136
 
109
- #-------------------------------------------------------------------------#
137
+ # Returns the name for the given `dependency`.
138
+ #
139
+ # @return [String] the name for the given `dependency`.
140
+ #
141
+ # @param [Dependency] dependency the dependency whose name is being
142
+ # queried.
143
+ #
144
+ def name_for(dependency)
145
+ dependency.name
146
+ end
110
147
 
111
- private
148
+ # @return [String] the user-facing name for a {Podfile}.
149
+ #
150
+ def name_for_explicit_dependency_source
151
+ 'Podfile'
152
+ end
112
153
 
113
- # @!group Private helpers
154
+ # @return [String] the user-facing name for a {Lockfile}.
155
+ #
156
+ def name_for_locking_dependency_source
157
+ 'Podfile.lock'
158
+ end
114
159
 
115
- # Resolves recursively the dependencies of a specification and stores them
116
- # in the @cached_specs ivar.
160
+ # Determines whether the given `requirement` is satisfied by the given
161
+ # `spec`, in the context of the current `activated` dependency graph.
162
+ #
163
+ # @return [Boolean] whether `requirement` is satisfied by `spec` in the
164
+ # context of the current `activated` dependency graph.
117
165
  #
118
- # @param [Podfile, Specification, #to_s] dependent_spec
119
- # the specification whose dependencies are being resolved. Used
120
- # only for UI purposes.
166
+ # @param [Dependency] requirement the dependency in question.
121
167
  #
122
- # @param [Array<Dependency>] dependencies
123
- # the dependencies of the specification.
168
+ # @param [Molinillo::DependencyGraph] activated the current dependency
169
+ # graph in the resolution process.
124
170
  #
125
- # @param [TargetDefinition] target_definition
126
- # the target definition that owns the specification.
171
+ # @param [Specification] spec the specification in question.
172
+ #
173
+ def requirement_satisfied_by?(requirement, activated, spec)
174
+ existing_vertices = activated.vertices.values.select do |v|
175
+ Specification.root_name(v.name) == requirement.root_name
176
+ end
177
+ existing = existing_vertices.map(&:payload).compact.first
178
+ requirement_satisfied =
179
+ if existing
180
+ existing.version == spec.version && requirement.requirement.satisfied_by?(spec.version)
181
+ else
182
+ requirement.requirement.satisfied_by? spec.version
183
+ end
184
+ requirement_satisfied && !(spec.version.prerelease? && existing_vertices.flat_map(&:requirements).none?(&:prerelease?))
185
+ end
186
+
187
+ # Sort dependencies so that the ones that are easiest to resolve are first.
188
+ # Easiest to resolve is (usually) defined by:
189
+ # 1) Is this dependency already activated?
190
+ # 2) How relaxed are the requirements?
191
+ # 3) Are there any conflicts for this dependency?
192
+ # 4) How many possibilities are there to satisfy this dependency?
127
193
  #
128
- # @note If there is a locked dependency with the same name of a
129
- # given dependency the locked one is used in place of the
130
- # dependency of the specification. In this way it is possible to
131
- # prevent the update of the version of installed pods not changed
132
- # in the Podfile.
194
+ # @return [Array<Dependency>] the sorted dependencies.
133
195
  #
134
- # @note The recursive process checks if a dependency has already been
135
- # loaded to prevent an infinite loop.
196
+ # @param [Array<Dependency>] dependencies the unsorted dependencies.
136
197
  #
137
- # @note The set class merges all (of all the target definitions) the
138
- # dependencies and thus it keeps track of whether it is in head
139
- # mode or from an external source because {Dependency#merge}
140
- # preserves this information.
198
+ # @param [Molinillo::DependencyGraph] activated the dependency graph of
199
+ # currently activated specs.
141
200
  #
142
- # @return [void]
201
+ # @param [{String => Array<Conflict>}] conflicts the current conflicts.
143
202
  #
144
- def find_dependency_specs(dependent_spec, dependencies, target_definition)
145
- dependencies.each do |dependency|
146
- locked_dep = locked_dependencies.find { |ld| ld.name == dependency.name }
147
- dependency = locked_dep if locked_dep
203
+ def sort_dependencies(dependencies, activated, conflicts)
204
+ dependencies.sort_by do |dependency|
205
+ name = name_for(dependency)
206
+ [
207
+ activated.vertex_named(name).payload ? 0 : 1,
208
+ dependency.prerelease? ? 0 : 1,
209
+ conflicts[name] ? 0 : 1,
210
+ search_for(dependency).count,
211
+ ]
212
+ end
213
+ end
214
+
215
+ #-------------------------------------------------------------------------#
148
216
 
149
- UI.message("- #{dependency}", '', 2) do
150
- set = find_cached_set(dependency, dependent_spec)
151
- set.required_by(dependency, dependent_spec.to_s)
217
+ public
152
218
 
153
- if (paths = set.specification_paths_for_version(set.required_version)).length > 1
154
- UI.warn "Found multiple specifications for #{dependency}:\n" \
155
- "- #{paths.join("\n")}"
156
- end
219
+ # @!group Resolver UI
157
220
 
158
- unless @loaded_specs.include?(dependency.name)
159
- spec = set.specification.subspec_by_name(dependency.name)
160
- @loaded_specs << spec.name
161
- cached_specs[spec.name] = spec
162
- validate_platform(spec, target_definition)
163
- if dependency.head? || sandbox.head_pod?(spec.name)
164
- spec.version.head = true
165
- sandbox.store_head_pod(spec.name)
166
- end
221
+ include Molinillo::UI
167
222
 
168
- spec_dependencies = spec.all_dependencies(target_definition.platform)
169
- find_dependency_specs(spec, spec_dependencies, target_definition)
170
- end
171
- end
172
- end
223
+ include Config::Mixin
224
+
225
+ # The UI object the resolver should use for displaying user-facing output.
226
+ #
227
+ # @return [UserInterface] the normal CocoaPods UI object.
228
+ #
229
+ def output
230
+ UI
173
231
  end
174
232
 
233
+ # Called before resolution starts. We print out `Resolving dependencies` in
234
+ # the analyzer, so here we just want to print out a starting `.` in verbose
235
+ # mode.
236
+ #
237
+ # @return [Void]
238
+ #
239
+ def before_resolution
240
+ UI.print '.' if config.verbose
241
+ end
242
+
243
+ # Called after resolution ends. We don't want to {#indicate_progress}
244
+ # unless in verbose mode, so we only use the default implementation then.
245
+ #
246
+ # @return [Void]
247
+ #
248
+ def after_resolution
249
+ super if config.verbose
250
+ end
251
+
252
+ # Called during resolution to indicate progress.
253
+ # We only use the default implementation in verbose mode.
254
+ #
255
+ # @return [Void]
256
+ #
257
+ def indicate_progress
258
+ super if config.verbose
259
+ end
260
+
261
+ #-------------------------------------------------------------------------#
262
+
263
+ private
264
+
265
+ # !@ Resolution context
266
+
267
+ # @return [Hash<String => Set>] A cache that keeps tracks of the sets
268
+ # loaded by the resolution process.
269
+ #
270
+ # @note Sets store the resolved dependencies and return the highest
271
+ # available specification found in the sources. This is done
272
+ # globally and not per target definition because there can be just
273
+ # one Pod installation, so different version of the same Pods for
274
+ # target definitions are not allowed.
275
+ #
276
+ attr_accessor :cached_sets
277
+
278
+ #-------------------------------------------------------------------------#
279
+
280
+ private
281
+
282
+ # @!group Private helpers
283
+
175
284
  # @return [Set] Loads or returns a previously initialized set for the Pod
176
285
  # of the given dependency.
177
286
  #
178
287
  # @param [Dependency] dependency
179
288
  # The dependency for which the set is needed.
180
289
  #
181
- # @param [#to_s] dependent_spec
182
- # the specification whose dependencies are being resolved. Used
183
- # only for UI purposes.
184
- #
185
290
  # @return [Set] the cached set for a given dependency.
186
291
  #
187
- def find_cached_set(dependency, dependent_spec)
292
+ def find_cached_set(dependency)
188
293
  name = dependency.root_name
189
294
  unless cached_sets[name]
190
295
  if dependency.external_source
191
- spec = sandbox.specification(dependency.root_name)
296
+ spec = sandbox.specification(name)
192
297
  unless spec
193
298
  raise StandardError, '[Bug] Unable to find the specification ' \
194
299
  "for `#{dependency}`."
@@ -199,8 +304,7 @@ module Pod
199
304
  end
200
305
  cached_sets[name] = set
201
306
  unless set
202
- raise Informative, 'Unable to find a specification for ' \
203
- "`#{dependency}` depended upon by #{dependent_spec}."
307
+ raise Molinillo::NoSuchDependencyError.new(dependency) # rubocop:disable Style/RaiseArgs
204
308
  end
205
309
  end
206
310
  cached_sets[name]
@@ -239,5 +343,38 @@ module Pod
239
343
  "a minimum requirement of #{spec.available_platforms.join(' - ')}."
240
344
  end
241
345
  end
346
+
347
+ # Returns the target-appropriate nodes that are `successors` of `node`,
348
+ # rejecting those that are {Dependency#from_subspec_dependency?} and have
349
+ # and incompatible platform.
350
+ #
351
+ # @return [Array<Molinillo::DependencyGraph::Vertex>]
352
+ # An array of target-appropriate nodes whose `payload`s are
353
+ # dependencies for `target`.
354
+ #
355
+ def valid_dependencies_for_target_from_node(target, node)
356
+ dependency_nodes = node.outgoing_edges.select do |edge|
357
+ edge_is_valid_for_target?(edge, target)
358
+ end.map(&:destination)
359
+
360
+ dependency_nodes + dependency_nodes.flat_map { |n| valid_dependencies_for_target_from_node(target, n) }
361
+ end
362
+
363
+ # Whether the given `edge` should be followed to find dependencies for the
364
+ # given `target`.
365
+ #
366
+ # @note At the moment, this method only checks whether the edge's
367
+ # requirements are normal dependencies _or_ whether they are
368
+ # dependencies that come from {Specification#subspec_dependencies}
369
+ # and, if so, that their platforms are compatible with the target's.
370
+ #
371
+ # @return [Bool]
372
+ #
373
+ def edge_is_valid_for_target?(edge, target)
374
+ edge.requirements.any? do |dependency|
375
+ !dependency.from_subspec_dependency? ||
376
+ edge.destination.payload.available_platforms.any? { |p| target.platform.supports?(p) }
377
+ end
378
+ end
242
379
  end
243
380
  end