shopify-bundler 1.10.7

Sign up to get free protection for your applications and to get access to all the features.
Files changed (196) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +16 -0
  3. data/.rspec +3 -0
  4. data/.rubocop.yml +96 -0
  5. data/.rubocop_todo.yml +177 -0
  6. data/.travis.yml +104 -0
  7. data/CHANGELOG.md +2131 -0
  8. data/CODE_OF_CONDUCT.md +42 -0
  9. data/CONTRIBUTING.md +32 -0
  10. data/DEVELOPMENT.md +118 -0
  11. data/ISSUES.md +96 -0
  12. data/LICENSE.md +23 -0
  13. data/README.md +40 -0
  14. data/Rakefile +309 -0
  15. data/bin/rake +14 -0
  16. data/bin/rspec +10 -0
  17. data/bin/rubocop +11 -0
  18. data/bundler.gemspec +34 -0
  19. data/exe/bundle +21 -0
  20. data/exe/bundle_ruby +60 -0
  21. data/exe/bundler +21 -0
  22. data/lib/bundler.rb +499 -0
  23. data/lib/bundler/capistrano.rb +16 -0
  24. data/lib/bundler/cli.rb +435 -0
  25. data/lib/bundler/cli/binstubs.rb +37 -0
  26. data/lib/bundler/cli/cache.rb +34 -0
  27. data/lib/bundler/cli/check.rb +37 -0
  28. data/lib/bundler/cli/clean.rb +25 -0
  29. data/lib/bundler/cli/common.rb +56 -0
  30. data/lib/bundler/cli/config.rb +88 -0
  31. data/lib/bundler/cli/console.rb +37 -0
  32. data/lib/bundler/cli/exec.rb +51 -0
  33. data/lib/bundler/cli/gem.rb +208 -0
  34. data/lib/bundler/cli/init.rb +32 -0
  35. data/lib/bundler/cli/inject.rb +32 -0
  36. data/lib/bundler/cli/install.rb +188 -0
  37. data/lib/bundler/cli/lock.rb +35 -0
  38. data/lib/bundler/cli/open.rb +22 -0
  39. data/lib/bundler/cli/outdated.rb +86 -0
  40. data/lib/bundler/cli/package.rb +45 -0
  41. data/lib/bundler/cli/platform.rb +42 -0
  42. data/lib/bundler/cli/show.rb +74 -0
  43. data/lib/bundler/cli/update.rb +72 -0
  44. data/lib/bundler/cli/viz.rb +26 -0
  45. data/lib/bundler/constants.rb +5 -0
  46. data/lib/bundler/current_ruby.rb +218 -0
  47. data/lib/bundler/definition.rb +675 -0
  48. data/lib/bundler/dep_proxy.rb +45 -0
  49. data/lib/bundler/dependency.rb +119 -0
  50. data/lib/bundler/deployment.rb +62 -0
  51. data/lib/bundler/deprecate.rb +17 -0
  52. data/lib/bundler/dsl.rb +478 -0
  53. data/lib/bundler/endpoint_specification.rb +100 -0
  54. data/lib/bundler/env.rb +82 -0
  55. data/lib/bundler/environment.rb +41 -0
  56. data/lib/bundler/fetcher.rb +288 -0
  57. data/lib/bundler/fetcher/base.rb +26 -0
  58. data/lib/bundler/fetcher/dependency.rb +88 -0
  59. data/lib/bundler/fetcher/downloader.rb +60 -0
  60. data/lib/bundler/fetcher/index.rb +32 -0
  61. data/lib/bundler/friendly_errors.rb +92 -0
  62. data/lib/bundler/gem_helper.rb +191 -0
  63. data/lib/bundler/gem_helpers.rb +26 -0
  64. data/lib/bundler/gem_installer.rb +9 -0
  65. data/lib/bundler/gem_path_manipulation.rb +8 -0
  66. data/lib/bundler/gem_tasks.rb +5 -0
  67. data/lib/bundler/graph.rb +173 -0
  68. data/lib/bundler/index.rb +199 -0
  69. data/lib/bundler/injector.rb +62 -0
  70. data/lib/bundler/inline.rb +58 -0
  71. data/lib/bundler/installer.rb +242 -0
  72. data/lib/bundler/installer/parallel_installer.rb +122 -0
  73. data/lib/bundler/installer/standalone.rb +48 -0
  74. data/lib/bundler/lazy_specification.rb +82 -0
  75. data/lib/bundler/lockfile_parser.rb +199 -0
  76. data/lib/bundler/match_platform.rb +13 -0
  77. data/lib/bundler/psyched_yaml.rb +26 -0
  78. data/lib/bundler/remote_specification.rb +82 -0
  79. data/lib/bundler/resolver.rb +350 -0
  80. data/lib/bundler/retry.rb +60 -0
  81. data/lib/bundler/ruby_dsl.rb +11 -0
  82. data/lib/bundler/ruby_version.rb +116 -0
  83. data/lib/bundler/rubygems_ext.rb +175 -0
  84. data/lib/bundler/rubygems_integration.rb +674 -0
  85. data/lib/bundler/runtime.rb +285 -0
  86. data/lib/bundler/settings.rb +263 -0
  87. data/lib/bundler/setup.rb +26 -0
  88. data/lib/bundler/shared_helpers.rb +176 -0
  89. data/lib/bundler/similarity_detector.rb +61 -0
  90. data/lib/bundler/source.rb +35 -0
  91. data/lib/bundler/source/git.rb +286 -0
  92. data/lib/bundler/source/git/git_proxy.rb +190 -0
  93. data/lib/bundler/source/path.rb +224 -0
  94. data/lib/bundler/source/path/installer.rb +43 -0
  95. data/lib/bundler/source/rubygems.rb +436 -0
  96. data/lib/bundler/source/rubygems/remote.rb +38 -0
  97. data/lib/bundler/source_list.rb +101 -0
  98. data/lib/bundler/spec_set.rb +156 -0
  99. data/lib/bundler/ssl_certs/.document +1 -0
  100. data/lib/bundler/ssl_certs/AddTrustExternalCARoot-2048.pem +25 -0
  101. data/lib/bundler/ssl_certs/AddTrustExternalCARoot.pem +32 -0
  102. data/lib/bundler/ssl_certs/Class3PublicPrimaryCertificationAuthority.pem +14 -0
  103. data/lib/bundler/ssl_certs/DigiCertHighAssuranceEVRootCA.pem +23 -0
  104. data/lib/bundler/ssl_certs/EntrustnetSecureServerCertificationAuthority.pem +28 -0
  105. data/lib/bundler/ssl_certs/GeoTrustGlobalCA.pem +20 -0
  106. data/lib/bundler/ssl_certs/certificate_manager.rb +64 -0
  107. data/lib/bundler/stub_specification.rb +23 -0
  108. data/lib/bundler/templates/Executable +16 -0
  109. data/lib/bundler/templates/Executable.standalone +12 -0
  110. data/lib/bundler/templates/Gemfile +4 -0
  111. data/lib/bundler/templates/newgem/.travis.yml.tt +4 -0
  112. data/lib/bundler/templates/newgem/CODE_OF_CONDUCT.md.tt +22 -0
  113. data/lib/bundler/templates/newgem/Gemfile.tt +4 -0
  114. data/lib/bundler/templates/newgem/LICENSE.txt.tt +21 -0
  115. data/lib/bundler/templates/newgem/README.md.tt +41 -0
  116. data/lib/bundler/templates/newgem/Rakefile.tt +29 -0
  117. data/lib/bundler/templates/newgem/bin/console.tt +14 -0
  118. data/lib/bundler/templates/newgem/bin/setup.tt +8 -0
  119. data/lib/bundler/templates/newgem/exe/newgem.tt +3 -0
  120. data/lib/bundler/templates/newgem/ext/newgem/extconf.rb.tt +3 -0
  121. data/lib/bundler/templates/newgem/ext/newgem/newgem.c.tt +9 -0
  122. data/lib/bundler/templates/newgem/ext/newgem/newgem.h.tt +6 -0
  123. data/lib/bundler/templates/newgem/gitignore.tt +16 -0
  124. data/lib/bundler/templates/newgem/lib/newgem.rb.tt +12 -0
  125. data/lib/bundler/templates/newgem/lib/newgem/version.rb.tt +7 -0
  126. data/lib/bundler/templates/newgem/newgem.gemspec.tt +43 -0
  127. data/lib/bundler/templates/newgem/rspec.tt +2 -0
  128. data/lib/bundler/templates/newgem/spec/newgem_spec.rb.tt +11 -0
  129. data/lib/bundler/templates/newgem/spec/spec_helper.rb.tt +2 -0
  130. data/lib/bundler/templates/newgem/test/newgem_test.rb.tt +11 -0
  131. data/lib/bundler/templates/newgem/test/test_helper.rb.tt +4 -0
  132. data/lib/bundler/ui.rb +7 -0
  133. data/lib/bundler/ui/rg_proxy.rb +17 -0
  134. data/lib/bundler/ui/shell.rb +108 -0
  135. data/lib/bundler/ui/silent.rb +44 -0
  136. data/lib/bundler/vendor/molinillo/lib/molinillo.rb +5 -0
  137. data/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph.rb +277 -0
  138. data/lib/bundler/vendor/molinillo/lib/molinillo/errors.rb +69 -0
  139. data/lib/bundler/vendor/molinillo/lib/molinillo/gem_metadata.rb +3 -0
  140. data/lib/bundler/vendor/molinillo/lib/molinillo/modules/specification_provider.rb +99 -0
  141. data/lib/bundler/vendor/molinillo/lib/molinillo/modules/ui.rb +63 -0
  142. data/lib/bundler/vendor/molinillo/lib/molinillo/resolution.rb +434 -0
  143. data/lib/bundler/vendor/molinillo/lib/molinillo/resolver.rb +43 -0
  144. data/lib/bundler/vendor/molinillo/lib/molinillo/state.rb +51 -0
  145. data/lib/bundler/vendor/net/http/faster.rb +26 -0
  146. data/lib/bundler/vendor/net/http/persistent.rb +1230 -0
  147. data/lib/bundler/vendor/net/http/persistent/ssl_reuse.rb +128 -0
  148. data/lib/bundler/vendor/thor/lib/thor.rb +484 -0
  149. data/lib/bundler/vendor/thor/lib/thor/actions.rb +319 -0
  150. data/lib/bundler/vendor/thor/lib/thor/actions/create_file.rb +103 -0
  151. data/lib/bundler/vendor/thor/lib/thor/actions/create_link.rb +59 -0
  152. data/lib/bundler/vendor/thor/lib/thor/actions/directory.rb +118 -0
  153. data/lib/bundler/vendor/thor/lib/thor/actions/empty_directory.rb +135 -0
  154. data/lib/bundler/vendor/thor/lib/thor/actions/file_manipulation.rb +316 -0
  155. data/lib/bundler/vendor/thor/lib/thor/actions/inject_into_file.rb +107 -0
  156. data/lib/bundler/vendor/thor/lib/thor/base.rb +656 -0
  157. data/lib/bundler/vendor/thor/lib/thor/command.rb +133 -0
  158. data/lib/bundler/vendor/thor/lib/thor/core_ext/hash_with_indifferent_access.rb +77 -0
  159. data/lib/bundler/vendor/thor/lib/thor/core_ext/io_binary_read.rb +10 -0
  160. data/lib/bundler/vendor/thor/lib/thor/core_ext/ordered_hash.rb +98 -0
  161. data/lib/bundler/vendor/thor/lib/thor/error.rb +32 -0
  162. data/lib/bundler/vendor/thor/lib/thor/group.rb +281 -0
  163. data/lib/bundler/vendor/thor/lib/thor/invocation.rb +178 -0
  164. data/lib/bundler/vendor/thor/lib/thor/line_editor.rb +17 -0
  165. data/lib/bundler/vendor/thor/lib/thor/line_editor/basic.rb +35 -0
  166. data/lib/bundler/vendor/thor/lib/thor/line_editor/readline.rb +88 -0
  167. data/lib/bundler/vendor/thor/lib/thor/parser.rb +4 -0
  168. data/lib/bundler/vendor/thor/lib/thor/parser/argument.rb +73 -0
  169. data/lib/bundler/vendor/thor/lib/thor/parser/arguments.rb +175 -0
  170. data/lib/bundler/vendor/thor/lib/thor/parser/option.rb +125 -0
  171. data/lib/bundler/vendor/thor/lib/thor/parser/options.rb +218 -0
  172. data/lib/bundler/vendor/thor/lib/thor/rake_compat.rb +71 -0
  173. data/lib/bundler/vendor/thor/lib/thor/runner.rb +322 -0
  174. data/lib/bundler/vendor/thor/lib/thor/shell.rb +81 -0
  175. data/lib/bundler/vendor/thor/lib/thor/shell/basic.rb +421 -0
  176. data/lib/bundler/vendor/thor/lib/thor/shell/color.rb +149 -0
  177. data/lib/bundler/vendor/thor/lib/thor/shell/html.rb +126 -0
  178. data/lib/bundler/vendor/thor/lib/thor/util.rb +267 -0
  179. data/lib/bundler/vendor/thor/lib/thor/version.rb +3 -0
  180. data/lib/bundler/vendored_molinillo.rb +2 -0
  181. data/lib/bundler/vendored_persistent.rb +11 -0
  182. data/lib/bundler/vendored_thor.rb +3 -0
  183. data/lib/bundler/version.rb +6 -0
  184. data/lib/bundler/vlad.rb +11 -0
  185. data/lib/bundler/worker.rb +72 -0
  186. data/man/bundle-config.ronn +187 -0
  187. data/man/bundle-exec.ronn +136 -0
  188. data/man/bundle-gem.ronn +77 -0
  189. data/man/bundle-install.ronn +398 -0
  190. data/man/bundle-package.ronn +66 -0
  191. data/man/bundle-platform.ronn +42 -0
  192. data/man/bundle-update.ronn +188 -0
  193. data/man/bundle.ronn +98 -0
  194. data/man/gemfile.5.ronn +495 -0
  195. data/man/index.txt +8 -0
  196. metadata +346 -0
@@ -0,0 +1,63 @@
1
+ module Bundler::Molinillo
2
+ # Conveys information about the resolution process to a user.
3
+ module UI
4
+ # The {IO} object that should be used to print output. `STDOUT`, by default.
5
+ #
6
+ # @return [IO]
7
+ def output
8
+ STDOUT
9
+ end
10
+
11
+ # Called roughly every {#progress_rate}, this method should convey progress
12
+ # to the user.
13
+ #
14
+ # @return [void]
15
+ def indicate_progress
16
+ output.print '.' unless debug?
17
+ end
18
+
19
+ # How often progress should be conveyed to the user via
20
+ # {#indicate_progress}, in seconds. A third of a second, by default.
21
+ #
22
+ # @return [Float]
23
+ def progress_rate
24
+ 0.33
25
+ end
26
+
27
+ # Called before resolution begins.
28
+ #
29
+ # @return [void]
30
+ def before_resolution
31
+ output.print 'Resolving dependencies...'
32
+ end
33
+
34
+ # Called after resolution ends (either successfully or with an error).
35
+ # By default, prints a newline.
36
+ #
37
+ # @return [void]
38
+ def after_resolution
39
+ output.puts
40
+ end
41
+
42
+ # Conveys debug information to the user.
43
+ #
44
+ # @param [Integer] depth the current depth of the resolution process.
45
+ # @return [void]
46
+ def debug(depth = 0)
47
+ if debug?
48
+ debug_info = yield
49
+ debug_info = debug_info.inspect unless debug_info.is_a?(String)
50
+ output.puts debug_info.split("\n").map { |s| ' ' * depth + s }
51
+ end
52
+ end
53
+
54
+ # Whether or not debug messages should be printed.
55
+ # By default, whether or not the `MOLINILLO_DEBUG` environment variable is
56
+ # set.
57
+ #
58
+ # @return [Boolean]
59
+ def debug?
60
+ @debug_mode ||= ENV['MOLINILLO_DEBUG']
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,434 @@
1
+ module Bundler::Molinillo
2
+ class Resolver
3
+ # A specific resolution from a given {Resolver}
4
+ class Resolution
5
+ # A conflict that the resolution process encountered
6
+ # @attr [Object] requirement the requirement that immediately led to the conflict
7
+ # @attr [{String,Nil=>[Object]}] requirements the requirements that caused the conflict
8
+ # @attr [Object, nil] existing the existing spec that was in conflict with
9
+ # the {#possibility}
10
+ # @attr [Object] possibility the spec that was unable to be activated due
11
+ # to a conflict
12
+ # @attr [Object] locked_requirement the relevant locking requirement.
13
+ # @attr [Array<Array<Object>>] requirement_trees the different requirement
14
+ # trees that led to every requirement for the conflicting name.
15
+ # @attr [{String=>Object}] activated_by_name the already-activated specs.
16
+ Conflict = Struct.new(
17
+ :requirement,
18
+ :requirements,
19
+ :existing,
20
+ :possibility,
21
+ :locked_requirement,
22
+ :requirement_trees,
23
+ :activated_by_name
24
+ )
25
+
26
+ # @return [SpecificationProvider] the provider that knows about
27
+ # dependencies, requirements, specifications, versions, etc.
28
+ attr_reader :specification_provider
29
+
30
+ # @return [UI] the UI that knows how to communicate feedback about the
31
+ # resolution process back to the user
32
+ attr_reader :resolver_ui
33
+
34
+ # @return [DependencyGraph] the base dependency graph to which
35
+ # dependencies should be 'locked'
36
+ attr_reader :base
37
+
38
+ # @return [Array] the dependencies that were explicitly required
39
+ attr_reader :original_requested
40
+
41
+ # @param [SpecificationProvider] specification_provider
42
+ # see {#specification_provider}
43
+ # @param [UI] resolver_ui see {#resolver_ui}
44
+ # @param [Array] requested see {#original_requested}
45
+ # @param [DependencyGraph] base see {#base}
46
+ def initialize(specification_provider, resolver_ui, requested, base)
47
+ @specification_provider = specification_provider
48
+ @resolver_ui = resolver_ui
49
+ @original_requested = requested
50
+ @base = base
51
+ @states = []
52
+ @iteration_counter = 0
53
+ end
54
+
55
+ # Resolves the {#original_requested} dependencies into a full dependency
56
+ # graph
57
+ # @raise [ResolverError] if successful resolution is impossible
58
+ # @return [DependencyGraph] the dependency graph of successfully resolved
59
+ # dependencies
60
+ def resolve
61
+ start_resolution
62
+
63
+ while state
64
+ break unless state.requirements.any? || state.requirement
65
+ indicate_progress
66
+ if state.respond_to?(:pop_possibility_state) # DependencyState
67
+ debug(depth) { "Creating possibility state for #{requirement} (#{possibilities.count} remaining)" }
68
+ state.pop_possibility_state.tap { |s| states.push(s) if s }
69
+ end
70
+ process_topmost_state
71
+ end
72
+
73
+ activated.freeze
74
+ ensure
75
+ end_resolution
76
+ end
77
+
78
+ # @return [Integer] the number of resolver iterations in between calls to
79
+ # {#resolver_ui}'s {UI#indicate_progress} method
80
+ attr_accessor :iteration_rate
81
+ private :iteration_rate
82
+
83
+ # @return [Time] the time at which resolution began
84
+ attr_accessor :started_at
85
+ private :started_at
86
+
87
+ # @return [Array<ResolutionState>] the stack of states for the resolution
88
+ attr_accessor :states
89
+ private :states
90
+
91
+ private
92
+
93
+ # Sets up the resolution process
94
+ # @return [void]
95
+ def start_resolution
96
+ @started_at = Time.now
97
+
98
+ handle_missing_or_push_dependency_state(initial_state)
99
+
100
+ debug { "Starting resolution (#{@started_at})" }
101
+ resolver_ui.before_resolution
102
+ end
103
+
104
+ # Ends the resolution process
105
+ # @return [void]
106
+ def end_resolution
107
+ resolver_ui.after_resolution
108
+ debug do
109
+ "Finished resolution (#{@iteration_counter} steps) " \
110
+ "(Took #{(ended_at = Time.now) - @started_at} seconds) (#{ended_at})"
111
+ end
112
+ debug { 'Unactivated: ' + Hash[activated.vertices.reject { |_n, v| v.payload }].keys.join(', ') } if state
113
+ debug { 'Activated: ' + Hash[activated.vertices.select { |_n, v| v.payload }].keys.join(', ') } if state
114
+ end
115
+
116
+ require 'bundler/vendor/molinillo/lib/molinillo/state'
117
+ require 'bundler/vendor/molinillo/lib/molinillo/modules/specification_provider'
118
+
119
+ ResolutionState.new.members.each do |member|
120
+ define_method member do |*args, &block|
121
+ current_state = state || ResolutionState.empty
122
+ current_state.send(member, *args, &block)
123
+ end
124
+ end
125
+
126
+ SpecificationProvider.instance_methods(false).each do |instance_method|
127
+ define_method instance_method do |*args, &block|
128
+ begin
129
+ specification_provider.send(instance_method, *args, &block)
130
+ rescue NoSuchDependencyError => error
131
+ if state
132
+ vertex = activated.vertex_named(name_for error.dependency)
133
+ error.required_by += vertex.incoming_edges.map { |e| e.origin.name }
134
+ error.required_by << name_for_explicit_dependency_source unless vertex.explicit_requirements.empty?
135
+ end
136
+ raise
137
+ end
138
+ end
139
+ end
140
+
141
+ # Processes the topmost available {RequirementState} on the stack
142
+ # @return [void]
143
+ def process_topmost_state
144
+ if possibility
145
+ attempt_to_activate
146
+ else
147
+ create_conflict if state.is_a? PossibilityState
148
+ unwind_for_conflict until possibility && state.is_a?(DependencyState)
149
+ end
150
+ end
151
+
152
+ # @return [Object] the current possibility that the resolution is trying
153
+ # to activate
154
+ def possibility
155
+ possibilities.last
156
+ end
157
+
158
+ # @return [RequirementState] the current state the resolution is
159
+ # operating upon
160
+ def state
161
+ states.last
162
+ end
163
+
164
+ # Creates the initial state for the resolution, based upon the
165
+ # {#requested} dependencies
166
+ # @return [DependencyState] the initial state for the resolution
167
+ def initial_state
168
+ graph = DependencyGraph.new.tap do |dg|
169
+ original_requested.each { |r| dg.add_vertex(name_for(r), nil, true).tap { |v| v.explicit_requirements << r } }
170
+ end
171
+
172
+ requirements = sort_dependencies(original_requested, graph, {})
173
+ initial_requirement = requirements.shift
174
+ DependencyState.new(
175
+ initial_requirement && name_for(initial_requirement),
176
+ requirements,
177
+ graph,
178
+ initial_requirement,
179
+ initial_requirement && search_for(initial_requirement),
180
+ 0,
181
+ {}
182
+ )
183
+ end
184
+
185
+ # Unwinds the states stack because a conflict has been encountered
186
+ # @return [void]
187
+ def unwind_for_conflict
188
+ debug(depth) { "Unwinding for conflict: #{requirement}" }
189
+ conflicts.tap do |c|
190
+ states.slice!((state_index_for_unwind + 1)..-1)
191
+ raise VersionConflict.new(c) unless state
192
+ state.conflicts = c
193
+ end
194
+ end
195
+
196
+ # @return [Integer] The index to which the resolution should unwind in the
197
+ # case of conflict.
198
+ def state_index_for_unwind
199
+ current_requirement = requirement
200
+ existing_requirement = requirement_for_existing_name(name)
201
+ until current_requirement.nil?
202
+ current_state = find_state_for(current_requirement)
203
+ return states.index(current_state) if state_any?(current_state)
204
+ current_requirement = parent_of(current_requirement)
205
+ end
206
+
207
+ until existing_requirement.nil?
208
+ existing_state = find_state_for(existing_requirement)
209
+ return states.index(existing_state) if state_any?(existing_state)
210
+ existing_requirement = parent_of(existing_requirement)
211
+ end
212
+ -1
213
+ end
214
+
215
+ # @return [Object] the requirement that led to `requirement` being added
216
+ # to the list of requirements.
217
+ def parent_of(requirement)
218
+ return nil unless requirement
219
+ seen = false
220
+ state = states.reverse_each.find do |s|
221
+ seen ||= s.requirement == requirement || s.requirements.include?(requirement)
222
+ seen && s.requirement != requirement && !s.requirements.include?(requirement)
223
+ end
224
+ state && state.requirement
225
+ end
226
+
227
+ # @return [Object] the requirement that led to a version of a possibility
228
+ # with the given name being activated.
229
+ def requirement_for_existing_name(name)
230
+ return nil unless activated.vertex_named(name).payload
231
+ states.reverse_each.find { |s| !s.activated.vertex_named(name).payload }.requirement
232
+ end
233
+
234
+ # @return [ResolutionState] the state whose `requirement` is the given
235
+ # `requirement`.
236
+ def find_state_for(requirement)
237
+ return nil unless requirement
238
+ states.reverse_each.find { |i| requirement == i.requirement && i.is_a?(DependencyState) }
239
+ end
240
+
241
+ # @return [Boolean] whether or not the given state has any possibilities
242
+ # left.
243
+ def state_any?(state)
244
+ state && state.possibilities.any?
245
+ end
246
+
247
+ # @return [Conflict] a {Conflict} that reflects the failure to activate
248
+ # the {#possibility} in conjunction with the current {#state}
249
+ def create_conflict
250
+ vertex = activated.vertex_named(name)
251
+ requirements = {
252
+ name_for_explicit_dependency_source => vertex.explicit_requirements,
253
+ name_for_locking_dependency_source => Array(locked_requirement_named(name)),
254
+ }
255
+ vertex.incoming_edges.each { |edge| (requirements[edge.origin.payload] ||= []).unshift(edge.requirement) }
256
+ conflicts[name] = Conflict.new(
257
+ requirement,
258
+ Hash[requirements.select { |_, r| !r.empty? }],
259
+ vertex.payload,
260
+ possibility,
261
+ locked_requirement_named(name),
262
+ requirement_trees,
263
+ Hash[activated.map { |v| [v.name, v.payload] }.select(&:last)]
264
+ )
265
+ end
266
+
267
+ # @return [Array<Array<Object>>] The different requirement
268
+ # trees that led to every requirement for the current spec.
269
+ def requirement_trees
270
+ vertex = activated.vertex_named(name)
271
+ vertex.requirements.map { |r| requirement_tree_for(r) }
272
+ end
273
+
274
+ # @return [Array<Object>] the list of requirements that led to
275
+ # `requirement` being required.
276
+ def requirement_tree_for(requirement)
277
+ tree = []
278
+ while requirement
279
+ tree.unshift(requirement)
280
+ requirement = parent_of(requirement)
281
+ end
282
+ tree
283
+ end
284
+
285
+ # Indicates progress roughly once every second
286
+ # @return [void]
287
+ def indicate_progress
288
+ @iteration_counter += 1
289
+ @progress_rate ||= resolver_ui.progress_rate
290
+ if iteration_rate.nil?
291
+ if Time.now - started_at >= @progress_rate
292
+ self.iteration_rate = @iteration_counter
293
+ end
294
+ end
295
+
296
+ if iteration_rate && (@iteration_counter % iteration_rate) == 0
297
+ resolver_ui.indicate_progress
298
+ end
299
+ end
300
+
301
+ # Calls the {#resolver_ui}'s {UI#debug} method
302
+ # @param [Integer] depth the depth of the {#states} stack
303
+ # @param [Proc] block a block that yields a {#to_s}
304
+ # @return [void]
305
+ def debug(depth = 0, &block)
306
+ resolver_ui.debug(depth, &block)
307
+ end
308
+
309
+ # Attempts to activate the current {#possibility}
310
+ # @return [void]
311
+ def attempt_to_activate
312
+ debug(depth) { 'Attempting to activate ' + possibility.to_s }
313
+ existing_node = activated.vertex_named(name)
314
+ if existing_node.payload
315
+ debug(depth) { "Found existing spec (#{existing_node.payload})" }
316
+ attempt_to_activate_existing_spec(existing_node)
317
+ else
318
+ attempt_to_activate_new_spec
319
+ end
320
+ end
321
+
322
+ # Attempts to activate the current {#possibility} (given that it has
323
+ # already been activated)
324
+ # @return [void]
325
+ def attempt_to_activate_existing_spec(existing_node)
326
+ existing_spec = existing_node.payload
327
+ if requirement_satisfied_by?(requirement, activated, existing_spec)
328
+ new_requirements = requirements.dup
329
+ push_state_for_requirements(new_requirements, false)
330
+ else
331
+ return if attempt_to_swap_possibility
332
+ create_conflict
333
+ debug(depth) { "Unsatisfied by existing spec (#{existing_node.payload})" }
334
+ unwind_for_conflict
335
+ end
336
+ end
337
+
338
+ # Attempts to swp the current {#possibility} with the already-activated
339
+ # spec with the given name
340
+ # @return [Boolean] Whether the possibility was swapped into {#activated}
341
+ def attempt_to_swap_possibility
342
+ swapped = activated.dup
343
+ swapped.vertex_named(name).payload = possibility
344
+ return unless swapped.vertex_named(name).requirements.
345
+ all? { |r| requirement_satisfied_by?(r, swapped, possibility) }
346
+ attempt_to_activate_new_spec
347
+ end
348
+
349
+ # Attempts to activate the current {#possibility} (given that it hasn't
350
+ # already been activated)
351
+ # @return [void]
352
+ def attempt_to_activate_new_spec
353
+ satisfied = begin
354
+ locked_requirement = locked_requirement_named(name)
355
+ requested_spec_satisfied = requirement_satisfied_by?(requirement, activated, possibility)
356
+ locked_spec_satisfied = !locked_requirement ||
357
+ requirement_satisfied_by?(locked_requirement, activated, possibility)
358
+ debug(depth) { 'Unsatisfied by requested spec' } unless requested_spec_satisfied
359
+ debug(depth) { 'Unsatisfied by locked spec' } unless locked_spec_satisfied
360
+ requested_spec_satisfied && locked_spec_satisfied
361
+ end
362
+ if satisfied
363
+ activate_spec
364
+ else
365
+ create_conflict
366
+ unwind_for_conflict
367
+ end
368
+ end
369
+
370
+ # @param [String] requirement_name the spec name to search for
371
+ # @return [Object] the locked spec named `requirement_name`, if one
372
+ # is found on {#base}
373
+ def locked_requirement_named(requirement_name)
374
+ vertex = base.vertex_named(requirement_name)
375
+ vertex && vertex.payload
376
+ end
377
+
378
+ # Add the current {#possibility} to the dependency graph of the current
379
+ # {#state}
380
+ # @return [void]
381
+ def activate_spec
382
+ conflicts.delete(name)
383
+ debug(depth) { 'Activated ' + name + ' at ' + possibility.to_s }
384
+ vertex = activated.vertex_named(name)
385
+ vertex.payload = possibility
386
+ require_nested_dependencies_for(possibility)
387
+ end
388
+
389
+ # Requires the dependencies that the recently activated spec has
390
+ # @param [Object] activated_spec the specification that has just been
391
+ # activated
392
+ # @return [void]
393
+ def require_nested_dependencies_for(activated_spec)
394
+ nested_dependencies = dependencies_for(activated_spec)
395
+ debug(depth) { "Requiring nested dependencies (#{nested_dependencies.map(&:to_s).join(', ')})" }
396
+ nested_dependencies.each { |d| activated.add_child_vertex(name_for(d), nil, [name_for(activated_spec)], d) }
397
+
398
+ push_state_for_requirements(requirements + nested_dependencies, nested_dependencies.size > 0)
399
+ end
400
+
401
+ # Pushes a new {DependencyState} that encapsulates both existing and new
402
+ # requirements
403
+ # @param [Array] new_requirements
404
+ # @return [void]
405
+ def push_state_for_requirements(new_requirements, requires_sort = true, new_activated = activated.dup)
406
+ new_requirements = sort_dependencies(new_requirements.uniq, new_activated, conflicts) if requires_sort
407
+ new_requirement = new_requirements.shift
408
+ new_name = new_requirement ? name_for(new_requirement) : ''
409
+ possibilities = new_requirement ? search_for(new_requirement) : []
410
+ handle_missing_or_push_dependency_state DependencyState.new(
411
+ new_name, new_requirements, new_activated,
412
+ new_requirement, possibilities, depth, conflicts.dup
413
+ )
414
+ end
415
+
416
+ # Pushes a new {DependencyState}.
417
+ # If the {#specification_provider} says to
418
+ # {SpecificationProvider#allow_missing?} that particular requirement, and
419
+ # there are no possibilities for that requirement, then `state` is not
420
+ # pushed, and the node in {#activated} is removed, and we continue
421
+ # resolving the remaining requirements.
422
+ # @param [DependencyState] state
423
+ # @return [void]
424
+ def handle_missing_or_push_dependency_state(state)
425
+ if state.requirement && state.possibilities.empty? && allow_missing?(state.requirement)
426
+ state.activated.detach_vertex_named(state.name)
427
+ push_state_for_requirements(state.requirements.dup, false, state.activated)
428
+ else
429
+ states.push state
430
+ end
431
+ end
432
+ end
433
+ end
434
+ end