bundler 2.1.4 → 2.2.33

Sign up to get free protection for your applications and to get access to all the features.
Files changed (251) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +2017 -1430
  3. data/README.md +7 -9
  4. data/bundler.gemspec +5 -6
  5. data/exe/bundle +3 -0
  6. data/lib/bundler/build_metadata.rb +3 -11
  7. data/lib/bundler/cli/add.rb +1 -1
  8. data/lib/bundler/cli/binstubs.rb +6 -2
  9. data/lib/bundler/cli/cache.rb +3 -8
  10. data/lib/bundler/cli/check.rb +4 -2
  11. data/lib/bundler/cli/clean.rb +1 -1
  12. data/lib/bundler/cli/common.rb +29 -2
  13. data/lib/bundler/cli/console.rb +1 -1
  14. data/lib/bundler/cli/doctor.rb +16 -5
  15. data/lib/bundler/cli/exec.rb +5 -10
  16. data/lib/bundler/cli/fund.rb +36 -0
  17. data/lib/bundler/cli/gem.rb +209 -28
  18. data/lib/bundler/cli/info.rb +28 -5
  19. data/lib/bundler/cli/init.rb +2 -2
  20. data/lib/bundler/cli/inject.rb +1 -1
  21. data/lib/bundler/cli/install.rb +22 -34
  22. data/lib/bundler/cli/issue.rb +5 -4
  23. data/lib/bundler/cli/list.rb +19 -11
  24. data/lib/bundler/cli/lock.rb +5 -1
  25. data/lib/bundler/cli/open.rb +1 -2
  26. data/lib/bundler/cli/outdated.rb +95 -75
  27. data/lib/bundler/cli/plugin.rb +10 -0
  28. data/lib/bundler/cli/pristine.rb +5 -0
  29. data/lib/bundler/cli/remove.rb +1 -2
  30. data/lib/bundler/cli/show.rb +1 -1
  31. data/lib/bundler/cli/update.rb +14 -7
  32. data/lib/bundler/cli.rb +89 -66
  33. data/lib/bundler/compact_index_client/cache.rb +6 -14
  34. data/lib/bundler/compact_index_client/gem_parser.rb +28 -0
  35. data/lib/bundler/compact_index_client/updater.rb +13 -22
  36. data/lib/bundler/compact_index_client.rb +3 -3
  37. data/lib/bundler/current_ruby.rb +5 -4
  38. data/lib/bundler/definition.rb +193 -363
  39. data/lib/bundler/dep_proxy.rb +16 -9
  40. data/lib/bundler/dependency.rb +3 -10
  41. data/lib/bundler/digest.rb +71 -0
  42. data/lib/bundler/dsl.rb +71 -47
  43. data/lib/bundler/endpoint_specification.rb +1 -1
  44. data/lib/bundler/env.rb +1 -1
  45. data/lib/bundler/environment_preserver.rb +29 -2
  46. data/lib/bundler/errors.rb +20 -3
  47. data/lib/bundler/feature_flag.rb +0 -8
  48. data/lib/bundler/fetcher/base.rb +1 -1
  49. data/lib/bundler/fetcher/compact_index.rb +2 -2
  50. data/lib/bundler/fetcher/downloader.rb +10 -7
  51. data/lib/bundler/fetcher/index.rb +3 -5
  52. data/lib/bundler/fetcher.rb +7 -5
  53. data/lib/bundler/friendly_errors.rb +25 -43
  54. data/lib/bundler/gem_helper.rb +53 -31
  55. data/lib/bundler/gem_helpers.rb +36 -25
  56. data/lib/bundler/gem_version_promoter.rb +4 -4
  57. data/lib/bundler/graph.rb +1 -1
  58. data/lib/bundler/index.rb +9 -9
  59. data/lib/bundler/injector.rb +23 -5
  60. data/lib/bundler/inline.rb +3 -2
  61. data/lib/bundler/installer/gem_installer.rb +6 -19
  62. data/lib/bundler/installer/parallel_installer.rb +46 -25
  63. data/lib/bundler/installer/standalone.rb +30 -10
  64. data/lib/bundler/installer.rb +36 -56
  65. data/lib/bundler/lazy_specification.rb +62 -26
  66. data/lib/bundler/lockfile_generator.rb +1 -1
  67. data/lib/bundler/lockfile_parser.rb +8 -34
  68. data/lib/bundler/man/.document +1 -0
  69. data/{man → lib/bundler/man}/bundle-add.1 +1 -1
  70. data/{man/bundle-add.ronn → lib/bundler/man/bundle-add.1.ronn} +0 -0
  71. data/{man → lib/bundler/man}/bundle-binstubs.1 +5 -3
  72. data/{man/bundle-binstubs.ronn → lib/bundler/man/bundle-binstubs.1.ronn} +2 -4
  73. data/{man → lib/bundler/man}/bundle-cache.1 +1 -1
  74. data/{man/bundle-cache.ronn → lib/bundler/man/bundle-cache.1.ronn} +0 -0
  75. data/{man → lib/bundler/man}/bundle-check.1 +1 -1
  76. data/{man/bundle-check.ronn → lib/bundler/man/bundle-check.1.ronn} +0 -0
  77. data/{man → lib/bundler/man}/bundle-clean.1 +1 -1
  78. data/{man/bundle-clean.ronn → lib/bundler/man/bundle-clean.1.ronn} +0 -0
  79. data/{man → lib/bundler/man}/bundle-config.1 +40 -41
  80. data/{man/bundle-config.ronn → lib/bundler/man/bundle-config.1.ronn} +50 -53
  81. data/{man → lib/bundler/man}/bundle-doctor.1 +1 -1
  82. data/{man/bundle-doctor.ronn → lib/bundler/man/bundle-doctor.1.ronn} +0 -0
  83. data/{man → lib/bundler/man}/bundle-exec.1 +1 -1
  84. data/{man/bundle-exec.ronn → lib/bundler/man/bundle-exec.1.ronn} +0 -0
  85. data/{man → lib/bundler/man}/bundle-gem.1 +38 -3
  86. data/{man/bundle-gem.ronn → lib/bundler/man/bundle-gem.1.ronn} +46 -7
  87. data/{man → lib/bundler/man}/bundle-info.1 +1 -1
  88. data/{man/bundle-info.ronn → lib/bundler/man/bundle-info.1.ronn} +0 -0
  89. data/{man → lib/bundler/man}/bundle-init.1 +1 -1
  90. data/{man/bundle-init.ronn → lib/bundler/man/bundle-init.1.ronn} +0 -0
  91. data/{man → lib/bundler/man}/bundle-inject.1 +1 -1
  92. data/{man/bundle-inject.ronn → lib/bundler/man/bundle-inject.1.ronn} +0 -0
  93. data/{man → lib/bundler/man}/bundle-install.1 +30 -3
  94. data/{man/bundle-install.ronn → lib/bundler/man/bundle-install.1.ronn} +25 -3
  95. data/{man → lib/bundler/man}/bundle-list.1 +7 -7
  96. data/{man/bundle-list.ronn → lib/bundler/man/bundle-list.1.ronn} +6 -6
  97. data/{man → lib/bundler/man}/bundle-lock.1 +1 -1
  98. data/{man/bundle-lock.ronn → lib/bundler/man/bundle-lock.1.ronn} +0 -0
  99. data/{man → lib/bundler/man}/bundle-open.1 +1 -1
  100. data/{man/bundle-open.ronn → lib/bundler/man/bundle-open.1.ronn} +0 -0
  101. data/{man → lib/bundler/man}/bundle-outdated.1 +1 -1
  102. data/{man/bundle-outdated.ronn → lib/bundler/man/bundle-outdated.1.ronn} +0 -0
  103. data/{man → lib/bundler/man}/bundle-platform.1 +1 -1
  104. data/{man/bundle-platform.ronn → lib/bundler/man/bundle-platform.1.ronn} +0 -0
  105. data/{man → lib/bundler/man}/bundle-pristine.1 +1 -1
  106. data/{man/bundle-pristine.ronn → lib/bundler/man/bundle-pristine.1.ronn} +0 -0
  107. data/{man → lib/bundler/man}/bundle-remove.1 +1 -1
  108. data/{man/bundle-remove.ronn → lib/bundler/man/bundle-remove.1.ronn} +0 -0
  109. data/{man → lib/bundler/man}/bundle-show.1 +1 -1
  110. data/{man/bundle-show.ronn → lib/bundler/man/bundle-show.1.ronn} +0 -0
  111. data/{man → lib/bundler/man}/bundle-update.1 +4 -4
  112. data/{man/bundle-update.ronn → lib/bundler/man/bundle-update.1.ronn} +3 -3
  113. data/{man → lib/bundler/man}/bundle-viz.1 +1 -1
  114. data/{man/bundle-viz.ronn → lib/bundler/man/bundle-viz.1.ronn} +0 -0
  115. data/{man → lib/bundler/man}/bundle.1 +1 -1
  116. data/{man/bundle.ronn → lib/bundler/man/bundle.1.ronn} +0 -0
  117. data/{man → lib/bundler/man}/gemfile.5 +30 -4
  118. data/{man → lib/bundler/man}/gemfile.5.ronn +12 -4
  119. data/{man → lib/bundler/man}/index.txt +0 -0
  120. data/lib/bundler/mirror.rb +2 -2
  121. data/lib/bundler/plugin/api/source.rb +23 -1
  122. data/lib/bundler/plugin/dsl.rb +1 -1
  123. data/lib/bundler/plugin/index.rb +13 -1
  124. data/lib/bundler/plugin/installer/rubygems.rb +1 -1
  125. data/lib/bundler/plugin/installer.rb +11 -11
  126. data/lib/bundler/plugin/source_list.rb +5 -1
  127. data/lib/bundler/plugin.rb +56 -11
  128. data/lib/bundler/psyched_yaml.rb +0 -15
  129. data/lib/bundler/remote_specification.rb +5 -2
  130. data/lib/bundler/resolver/spec_group.rb +56 -53
  131. data/lib/bundler/resolver.rb +94 -128
  132. data/lib/bundler/retry.rb +2 -2
  133. data/lib/bundler/ruby_version.rb +1 -1
  134. data/lib/bundler/rubygems_ext.rb +96 -16
  135. data/lib/bundler/rubygems_gem_installer.rb +69 -8
  136. data/lib/bundler/rubygems_integration.rb +57 -72
  137. data/lib/bundler/runtime.rb +22 -25
  138. data/lib/bundler/settings.rb +142 -64
  139. data/lib/bundler/setup.rb +2 -2
  140. data/lib/bundler/shared_helpers.rb +5 -13
  141. data/lib/bundler/similarity_detector.rb +1 -1
  142. data/lib/bundler/source/git/git_proxy.rb +88 -84
  143. data/lib/bundler/source/git.rb +43 -23
  144. data/lib/bundler/source/metadata.rb +0 -4
  145. data/lib/bundler/source/path/installer.rb +10 -10
  146. data/lib/bundler/source/path.rb +10 -4
  147. data/lib/bundler/source/rubygems/remote.rb +1 -1
  148. data/lib/bundler/source/rubygems.rb +126 -116
  149. data/lib/bundler/source/rubygems_aggregate.rb +68 -0
  150. data/lib/bundler/source.rb +22 -1
  151. data/lib/bundler/source_list.rb +101 -63
  152. data/lib/bundler/source_map.rb +58 -0
  153. data/lib/bundler/spec_set.rb +26 -41
  154. data/lib/bundler/stub_specification.rb +25 -7
  155. data/lib/bundler/templates/Executable.bundler +6 -6
  156. data/lib/bundler/templates/Gemfile +1 -1
  157. data/lib/bundler/templates/gems.rb +1 -1
  158. data/lib/bundler/templates/newgem/CHANGELOG.md.tt +5 -0
  159. data/lib/bundler/templates/newgem/CODE_OF_CONDUCT.md.tt +57 -47
  160. data/lib/bundler/templates/newgem/Gemfile.tt +12 -1
  161. data/lib/bundler/templates/newgem/README.md.tt +6 -5
  162. data/lib/bundler/templates/newgem/Rakefile.tt +23 -5
  163. data/lib/bundler/templates/newgem/bin/console.tt +1 -0
  164. data/lib/bundler/templates/newgem/circleci/config.yml.tt +13 -0
  165. data/lib/bundler/templates/newgem/ext/newgem/extconf.rb.tt +2 -0
  166. data/lib/bundler/templates/newgem/github/workflows/main.yml.tt +27 -0
  167. data/lib/bundler/templates/newgem/gitlab-ci.yml.tt +9 -0
  168. data/lib/bundler/templates/newgem/lib/newgem/version.rb.tt +2 -0
  169. data/lib/bundler/templates/newgem/lib/newgem.rb.tt +4 -2
  170. data/lib/bundler/templates/newgem/newgem.gemspec.tt +27 -17
  171. data/lib/bundler/templates/newgem/rubocop.yml.tt +13 -0
  172. data/lib/bundler/templates/newgem/sig/newgem.rbs.tt +8 -0
  173. data/lib/bundler/templates/newgem/spec/newgem_spec.rb.tt +2 -0
  174. data/lib/bundler/templates/newgem/spec/spec_helper.rb.tt +2 -1
  175. data/lib/bundler/templates/newgem/standard.yml.tt +2 -0
  176. data/lib/bundler/templates/newgem/test/{newgem_test.rb.tt → minitest/newgem_test.rb.tt} +2 -0
  177. data/lib/bundler/templates/newgem/test/{test_helper.rb.tt → minitest/test_helper.rb.tt} +2 -0
  178. data/lib/bundler/templates/newgem/test/test-unit/newgem_test.rb.tt +15 -0
  179. data/lib/bundler/templates/newgem/test/test-unit/test_helper.rb.tt +6 -0
  180. data/lib/bundler/ui/shell.rb +5 -5
  181. data/lib/bundler/uri_credentials_filter.rb +3 -1
  182. data/lib/bundler/vendor/.document +1 -0
  183. data/lib/bundler/vendor/connection_pool/LICENSE +20 -0
  184. data/lib/bundler/vendor/connection_pool/lib/connection_pool/timed_stack.rb +19 -21
  185. data/lib/bundler/vendor/connection_pool/lib/connection_pool/version.rb +1 -1
  186. data/lib/bundler/vendor/connection_pool/lib/connection_pool/wrapper.rb +57 -0
  187. data/lib/bundler/vendor/connection_pool/lib/connection_pool.rb +39 -74
  188. data/lib/bundler/vendor/fileutils/LICENSE.txt +22 -0
  189. data/lib/bundler/vendor/molinillo/LICENSE +9 -0
  190. data/lib/bundler/vendor/molinillo/lib/molinillo/delegates/specification_provider.rb +7 -0
  191. data/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/tag.rb +2 -2
  192. data/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/vertex.rb +11 -5
  193. data/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph.rb +36 -4
  194. data/lib/bundler/vendor/molinillo/lib/molinillo/errors.rb +3 -3
  195. data/lib/bundler/vendor/molinillo/lib/molinillo/gem_metadata.rb +1 -1
  196. data/lib/bundler/vendor/molinillo/lib/molinillo/modules/specification_provider.rb +12 -1
  197. data/lib/bundler/vendor/molinillo/lib/molinillo/resolution.rb +49 -47
  198. data/lib/bundler/vendor/molinillo/lib/molinillo.rb +0 -1
  199. data/lib/bundler/vendor/net-http-persistent/README.rdoc +82 -0
  200. data/lib/bundler/vendor/net-http-persistent/lib/net/http/persistent.rb +82 -189
  201. data/lib/bundler/vendor/thor/LICENSE.md +20 -0
  202. data/lib/bundler/vendor/thor/lib/thor/actions/create_link.rb +2 -1
  203. data/lib/bundler/vendor/thor/lib/thor/actions/file_manipulation.rb +4 -2
  204. data/lib/bundler/vendor/thor/lib/thor/actions.rb +1 -1
  205. data/lib/bundler/vendor/thor/lib/thor/base.rb +9 -0
  206. data/lib/bundler/vendor/thor/lib/thor/error.rb +1 -1
  207. data/lib/bundler/vendor/thor/lib/thor/parser/arguments.rb +5 -1
  208. data/lib/bundler/vendor/thor/lib/thor/parser/options.rb +9 -8
  209. data/lib/bundler/vendor/thor/lib/thor/shell/basic.rb +5 -2
  210. data/lib/bundler/vendor/thor/lib/thor/shell/color.rb +5 -1
  211. data/lib/bundler/vendor/thor/lib/thor/version.rb +1 -1
  212. data/lib/bundler/vendor/thor/lib/thor.rb +5 -13
  213. data/lib/bundler/vendor/tmpdir/lib/tmpdir.rb +154 -0
  214. data/lib/bundler/vendor/tsort/LICENSE.txt +22 -0
  215. data/lib/bundler/vendor/tsort/lib/tsort.rb +453 -0
  216. data/lib/bundler/vendor/uri/LICENSE.txt +22 -0
  217. data/lib/bundler/vendored_persistent.rb +0 -7
  218. data/lib/bundler/vendored_tmpdir.rb +4 -0
  219. data/lib/bundler/vendored_tsort.rb +4 -0
  220. data/lib/bundler/version.rb +1 -1
  221. data/lib/bundler/worker.rb +20 -5
  222. data/lib/bundler/yaml_serializer.rb +1 -1
  223. data/lib/bundler.rb +52 -37
  224. metadata +90 -89
  225. data/lib/bundler/vendor/connection_pool/lib/connection_pool/monotonic_time.rb +0 -66
  226. data/lib/bundler/vendor/molinillo/lib/molinillo/compatibility.rb +0 -26
  227. data/man/bundle-add.1.txt +0 -58
  228. data/man/bundle-binstubs.1.txt +0 -48
  229. data/man/bundle-cache.1.txt +0 -78
  230. data/man/bundle-check.1.txt +0 -33
  231. data/man/bundle-clean.1.txt +0 -26
  232. data/man/bundle-config.1.txt +0 -528
  233. data/man/bundle-doctor.1.txt +0 -44
  234. data/man/bundle-exec.1.txt +0 -178
  235. data/man/bundle-gem.1.txt +0 -91
  236. data/man/bundle-info.1.txt +0 -21
  237. data/man/bundle-init.1.txt +0 -34
  238. data/man/bundle-inject.1.txt +0 -32
  239. data/man/bundle-install.1.txt +0 -401
  240. data/man/bundle-list.1.txt +0 -43
  241. data/man/bundle-lock.1.txt +0 -93
  242. data/man/bundle-open.1.txt +0 -29
  243. data/man/bundle-outdated.1.txt +0 -131
  244. data/man/bundle-platform.1.txt +0 -57
  245. data/man/bundle-pristine.1.txt +0 -44
  246. data/man/bundle-remove.1.txt +0 -34
  247. data/man/bundle-show.1.txt +0 -27
  248. data/man/bundle-update.1.txt +0 -390
  249. data/man/bundle-viz.1.txt +0 -39
  250. data/man/bundle.1.txt +0 -116
  251. data/man/gemfile.5.txt +0 -649
@@ -1,7 +1,7 @@
1
- require "set"
2
1
  require_relative "thor/base"
3
2
 
4
3
  class Bundler::Thor
4
+ $thor_runner ||= false
5
5
  class << self
6
6
  # Allows for custom "Command" package naming.
7
7
  #
@@ -323,7 +323,7 @@ class Bundler::Thor
323
323
  # ==== Parameters
324
324
  # Symbol ...:: A list of commands that should be affected.
325
325
  def stop_on_unknown_option!(*command_names)
326
- stop_on_unknown_option.merge(command_names)
326
+ @stop_on_unknown_option = stop_on_unknown_option | command_names
327
327
  end
328
328
 
329
329
  def stop_on_unknown_option?(command) #:nodoc:
@@ -337,29 +337,22 @@ class Bundler::Thor
337
337
  # ==== Parameters
338
338
  # Symbol ...:: A list of commands that should be affected.
339
339
  def disable_required_check!(*command_names)
340
- disable_required_check.merge(command_names)
340
+ @disable_required_check = disable_required_check | command_names
341
341
  end
342
342
 
343
343
  def disable_required_check?(command) #:nodoc:
344
344
  command && disable_required_check.include?(command.name.to_sym)
345
345
  end
346
346
 
347
- def deprecation_warning(message) #:nodoc:
348
- unless ENV['THOR_SILENCE_DEPRECATION']
349
- warn "Deprecation warning: #{message}\n" +
350
- 'You can silence deprecations warning by setting the environment variable THOR_SILENCE_DEPRECATION.'
351
- end
352
- end
353
-
354
347
  protected
355
348
 
356
349
  def stop_on_unknown_option #:nodoc:
357
- @stop_on_unknown_option ||= Set.new
350
+ @stop_on_unknown_option ||= []
358
351
  end
359
352
 
360
353
  # help command has the required check disabled by default.
361
354
  def disable_required_check #:nodoc:
362
- @disable_required_check ||= Set.new([:help])
355
+ @disable_required_check ||= [:help]
363
356
  end
364
357
 
365
358
  # The method responsible for dispatching given the args.
@@ -405,7 +398,6 @@ class Bundler::Thor
405
398
  # the namespace should be displayed as arguments.
406
399
  #
407
400
  def banner(command, namespace = nil, subcommand = false)
408
- $thor_runner ||= false
409
401
  command.formatted_usage(self, $thor_runner, subcommand).split("\n").map do |formatted_usage|
410
402
  "#{basename} #{formatted_usage}"
411
403
  end.join("\n")
@@ -0,0 +1,154 @@
1
+ # frozen_string_literal: true
2
+ #
3
+ # tmpdir - retrieve temporary directory path
4
+ #
5
+ # $Id$
6
+ #
7
+
8
+ require_relative '../../fileutils/lib/fileutils'
9
+ begin
10
+ require 'etc.so'
11
+ rescue LoadError # rescue LoadError for miniruby
12
+ end
13
+
14
+ class Bundler::Dir < Dir
15
+
16
+ @systmpdir ||= defined?(Etc.systmpdir) ? Etc.systmpdir : '/tmp'
17
+
18
+ ##
19
+ # Returns the operating system's temporary file path.
20
+
21
+ def self.tmpdir
22
+ tmp = nil
23
+ ['TMPDIR', 'TMP', 'TEMP', ['system temporary path', @systmpdir], ['/tmp']*2, ['.']*2].each do |name, dir = ENV[name]|
24
+ next if !dir
25
+ dir = File.expand_path(dir)
26
+ stat = File.stat(dir) rescue next
27
+ case
28
+ when !stat.directory?
29
+ warn "#{name} is not a directory: #{dir}"
30
+ when !stat.writable?
31
+ warn "#{name} is not writable: #{dir}"
32
+ when stat.world_writable? && !stat.sticky?
33
+ warn "#{name} is world-writable: #{dir}"
34
+ else
35
+ tmp = dir
36
+ break
37
+ end
38
+ end
39
+ raise ArgumentError, "could not find a temporary directory" unless tmp
40
+ tmp
41
+ end
42
+
43
+ # Bundler::Dir.mktmpdir creates a temporary directory.
44
+ #
45
+ # The directory is created with 0700 permission.
46
+ # Application should not change the permission to make the temporary directory accessible from other users.
47
+ #
48
+ # The prefix and suffix of the name of the directory is specified by
49
+ # the optional first argument, <i>prefix_suffix</i>.
50
+ # - If it is not specified or nil, "d" is used as the prefix and no suffix is used.
51
+ # - If it is a string, it is used as the prefix and no suffix is used.
52
+ # - If it is an array, first element is used as the prefix and second element is used as a suffix.
53
+ #
54
+ # Bundler::Dir.mktmpdir {|dir| dir is ".../d..." }
55
+ # Bundler::Dir.mktmpdir("foo") {|dir| dir is ".../foo..." }
56
+ # Bundler::Dir.mktmpdir(["foo", "bar"]) {|dir| dir is ".../foo...bar" }
57
+ #
58
+ # The directory is created under Bundler::Dir.tmpdir or
59
+ # the optional second argument <i>tmpdir</i> if non-nil value is given.
60
+ #
61
+ # Bundler::Dir.mktmpdir {|dir| dir is "#{Bundler::Dir.tmpdir}/d..." }
62
+ # Bundler::Dir.mktmpdir(nil, "/var/tmp") {|dir| dir is "/var/tmp/d..." }
63
+ #
64
+ # If a block is given,
65
+ # it is yielded with the path of the directory.
66
+ # The directory and its contents are removed
67
+ # using Bundler::FileUtils.remove_entry before Bundler::Dir.mktmpdir returns.
68
+ # The value of the block is returned.
69
+ #
70
+ # Bundler::Dir.mktmpdir {|dir|
71
+ # # use the directory...
72
+ # open("#{dir}/foo", "w") { ... }
73
+ # }
74
+ #
75
+ # If a block is not given,
76
+ # The path of the directory is returned.
77
+ # In this case, Bundler::Dir.mktmpdir doesn't remove the directory.
78
+ #
79
+ # dir = Bundler::Dir.mktmpdir
80
+ # begin
81
+ # # use the directory...
82
+ # open("#{dir}/foo", "w") { ... }
83
+ # ensure
84
+ # # remove the directory.
85
+ # Bundler::FileUtils.remove_entry dir
86
+ # end
87
+ #
88
+ def self.mktmpdir(prefix_suffix=nil, *rest, **options)
89
+ base = nil
90
+ path = Tmpname.create(prefix_suffix || "d", *rest, **options) {|p, _, _, d|
91
+ base = d
92
+ mkdir(p, 0700)
93
+ }
94
+ if block_given?
95
+ begin
96
+ yield path.dup
97
+ ensure
98
+ unless base
99
+ stat = File.stat(File.dirname(path))
100
+ if stat.world_writable? and !stat.sticky?
101
+ raise ArgumentError, "parent directory is world writable but not sticky"
102
+ end
103
+ end
104
+ Bundler::FileUtils.remove_entry path
105
+ end
106
+ else
107
+ path
108
+ end
109
+ end
110
+
111
+ module Tmpname # :nodoc:
112
+ module_function
113
+
114
+ def tmpdir
115
+ Bundler::Dir.tmpdir
116
+ end
117
+
118
+ UNUSABLE_CHARS = "^,-.0-9A-Z_a-z~"
119
+
120
+ class << (RANDOM = Random.new)
121
+ MAX = 36**6 # < 0x100000000
122
+ def next
123
+ rand(MAX).to_s(36)
124
+ end
125
+ end
126
+ private_constant :RANDOM
127
+
128
+ def create(basename, tmpdir=nil, max_try: nil, **opts)
129
+ origdir = tmpdir
130
+ tmpdir ||= tmpdir()
131
+ n = nil
132
+ prefix, suffix = basename
133
+ prefix = (String.try_convert(prefix) or
134
+ raise ArgumentError, "unexpected prefix: #{prefix.inspect}")
135
+ prefix = prefix.delete(UNUSABLE_CHARS)
136
+ suffix &&= (String.try_convert(suffix) or
137
+ raise ArgumentError, "unexpected suffix: #{suffix.inspect}")
138
+ suffix &&= suffix.delete(UNUSABLE_CHARS)
139
+ begin
140
+ t = Time.now.strftime("%Y%m%d")
141
+ path = "#{prefix}#{t}-#{$$}-#{RANDOM.next}"\
142
+ "#{n ? %[-#{n}] : ''}#{suffix||''}"
143
+ path = File.join(tmpdir, path)
144
+ yield(path, n, opts, origdir)
145
+ rescue Errno::EEXIST
146
+ n ||= 0
147
+ n += 1
148
+ retry if !max_try or n < max_try
149
+ raise "cannot generate temporary name using `#{basename}' under `#{tmpdir}'"
150
+ end
151
+ path
152
+ end
153
+ end
154
+ end
@@ -0,0 +1,22 @@
1
+ Copyright (C) 1993-2013 Yukihiro Matsumoto. All rights reserved.
2
+
3
+ Redistribution and use in source and binary forms, with or without
4
+ modification, are permitted provided that the following conditions
5
+ are met:
6
+ 1. Redistributions of source code must retain the above copyright
7
+ notice, this list of conditions and the following disclaimer.
8
+ 2. Redistributions in binary form must reproduce the above copyright
9
+ notice, this list of conditions and the following disclaimer in the
10
+ documentation and/or other materials provided with the distribution.
11
+
12
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
13
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
14
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
15
+ ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
16
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
17
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
18
+ OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
19
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
20
+ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
21
+ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
22
+ SUCH DAMAGE.
@@ -0,0 +1,453 @@
1
+ # frozen_string_literal: true
2
+
3
+ #--
4
+ # tsort.rb - provides a module for topological sorting and strongly connected components.
5
+ #++
6
+ #
7
+
8
+ #
9
+ # TSort implements topological sorting using Tarjan's algorithm for
10
+ # strongly connected components.
11
+ #
12
+ # TSort is designed to be able to be used with any object which can be
13
+ # interpreted as a directed graph.
14
+ #
15
+ # TSort requires two methods to interpret an object as a graph,
16
+ # tsort_each_node and tsort_each_child.
17
+ #
18
+ # * tsort_each_node is used to iterate for all nodes over a graph.
19
+ # * tsort_each_child is used to iterate for child nodes of a given node.
20
+ #
21
+ # The equality of nodes are defined by eql? and hash since
22
+ # TSort uses Hash internally.
23
+ #
24
+ # == A Simple Example
25
+ #
26
+ # The following example demonstrates how to mix the TSort module into an
27
+ # existing class (in this case, Hash). Here, we're treating each key in
28
+ # the hash as a node in the graph, and so we simply alias the required
29
+ # #tsort_each_node method to Hash's #each_key method. For each key in the
30
+ # hash, the associated value is an array of the node's child nodes. This
31
+ # choice in turn leads to our implementation of the required #tsort_each_child
32
+ # method, which fetches the array of child nodes and then iterates over that
33
+ # array using the user-supplied block.
34
+ #
35
+ # require 'tsort'
36
+ #
37
+ # class Hash
38
+ # include TSort
39
+ # alias tsort_each_node each_key
40
+ # def tsort_each_child(node, &block)
41
+ # fetch(node).each(&block)
42
+ # end
43
+ # end
44
+ #
45
+ # {1=>[2, 3], 2=>[3], 3=>[], 4=>[]}.tsort
46
+ # #=> [3, 2, 1, 4]
47
+ #
48
+ # {1=>[2], 2=>[3, 4], 3=>[2], 4=>[]}.strongly_connected_components
49
+ # #=> [[4], [2, 3], [1]]
50
+ #
51
+ # == A More Realistic Example
52
+ #
53
+ # A very simple `make' like tool can be implemented as follows:
54
+ #
55
+ # require 'tsort'
56
+ #
57
+ # class Make
58
+ # def initialize
59
+ # @dep = {}
60
+ # @dep.default = []
61
+ # end
62
+ #
63
+ # def rule(outputs, inputs=[], &block)
64
+ # triple = [outputs, inputs, block]
65
+ # outputs.each {|f| @dep[f] = [triple]}
66
+ # @dep[triple] = inputs
67
+ # end
68
+ #
69
+ # def build(target)
70
+ # each_strongly_connected_component_from(target) {|ns|
71
+ # if ns.length != 1
72
+ # fs = ns.delete_if {|n| Array === n}
73
+ # raise TSort::Cyclic.new("cyclic dependencies: #{fs.join ', '}")
74
+ # end
75
+ # n = ns.first
76
+ # if Array === n
77
+ # outputs, inputs, block = n
78
+ # inputs_time = inputs.map {|f| File.mtime f}.max
79
+ # begin
80
+ # outputs_time = outputs.map {|f| File.mtime f}.min
81
+ # rescue Errno::ENOENT
82
+ # outputs_time = nil
83
+ # end
84
+ # if outputs_time == nil ||
85
+ # inputs_time != nil && outputs_time <= inputs_time
86
+ # sleep 1 if inputs_time != nil && inputs_time.to_i == Time.now.to_i
87
+ # block.call
88
+ # end
89
+ # end
90
+ # }
91
+ # end
92
+ #
93
+ # def tsort_each_child(node, &block)
94
+ # @dep[node].each(&block)
95
+ # end
96
+ # include TSort
97
+ # end
98
+ #
99
+ # def command(arg)
100
+ # print arg, "\n"
101
+ # system arg
102
+ # end
103
+ #
104
+ # m = Make.new
105
+ # m.rule(%w[t1]) { command 'date > t1' }
106
+ # m.rule(%w[t2]) { command 'date > t2' }
107
+ # m.rule(%w[t3]) { command 'date > t3' }
108
+ # m.rule(%w[t4], %w[t1 t3]) { command 'cat t1 t3 > t4' }
109
+ # m.rule(%w[t5], %w[t4 t2]) { command 'cat t4 t2 > t5' }
110
+ # m.build('t5')
111
+ #
112
+ # == Bugs
113
+ #
114
+ # * 'tsort.rb' is wrong name because this library uses
115
+ # Tarjan's algorithm for strongly connected components.
116
+ # Although 'strongly_connected_components.rb' is correct but too long.
117
+ #
118
+ # == References
119
+ #
120
+ # R. E. Tarjan, "Depth First Search and Linear Graph Algorithms",
121
+ # <em>SIAM Journal on Computing</em>, Vol. 1, No. 2, pp. 146-160, June 1972.
122
+ #
123
+ module Bundler
124
+ module TSort
125
+ class Cyclic < StandardError
126
+ end
127
+
128
+ # Returns a topologically sorted array of nodes.
129
+ # The array is sorted from children to parents, i.e.
130
+ # the first element has no child and the last node has no parent.
131
+ #
132
+ # If there is a cycle, TSort::Cyclic is raised.
133
+ #
134
+ # class G
135
+ # include TSort
136
+ # def initialize(g)
137
+ # @g = g
138
+ # end
139
+ # def tsort_each_child(n, &b) @g[n].each(&b) end
140
+ # def tsort_each_node(&b) @g.each_key(&b) end
141
+ # end
142
+ #
143
+ # graph = G.new({1=>[2, 3], 2=>[4], 3=>[2, 4], 4=>[]})
144
+ # p graph.tsort #=> [4, 2, 3, 1]
145
+ #
146
+ # graph = G.new({1=>[2], 2=>[3, 4], 3=>[2], 4=>[]})
147
+ # p graph.tsort # raises TSort::Cyclic
148
+ #
149
+ def tsort
150
+ each_node = method(:tsort_each_node)
151
+ each_child = method(:tsort_each_child)
152
+ TSort.tsort(each_node, each_child)
153
+ end
154
+
155
+ # Returns a topologically sorted array of nodes.
156
+ # The array is sorted from children to parents, i.e.
157
+ # the first element has no child and the last node has no parent.
158
+ #
159
+ # The graph is represented by _each_node_ and _each_child_.
160
+ # _each_node_ should have +call+ method which yields for each node in the graph.
161
+ # _each_child_ should have +call+ method which takes a node argument and yields for each child node.
162
+ #
163
+ # If there is a cycle, TSort::Cyclic is raised.
164
+ #
165
+ # g = {1=>[2, 3], 2=>[4], 3=>[2, 4], 4=>[]}
166
+ # each_node = lambda {|&b| g.each_key(&b) }
167
+ # each_child = lambda {|n, &b| g[n].each(&b) }
168
+ # p TSort.tsort(each_node, each_child) #=> [4, 2, 3, 1]
169
+ #
170
+ # g = {1=>[2], 2=>[3, 4], 3=>[2], 4=>[]}
171
+ # each_node = lambda {|&b| g.each_key(&b) }
172
+ # each_child = lambda {|n, &b| g[n].each(&b) }
173
+ # p TSort.tsort(each_node, each_child) # raises TSort::Cyclic
174
+ #
175
+ def TSort.tsort(each_node, each_child)
176
+ TSort.tsort_each(each_node, each_child).to_a
177
+ end
178
+
179
+ # The iterator version of the #tsort method.
180
+ # <tt><em>obj</em>.tsort_each</tt> is similar to <tt><em>obj</em>.tsort.each</tt>, but
181
+ # modification of _obj_ during the iteration may lead to unexpected results.
182
+ #
183
+ # #tsort_each returns +nil+.
184
+ # If there is a cycle, TSort::Cyclic is raised.
185
+ #
186
+ # class G
187
+ # include TSort
188
+ # def initialize(g)
189
+ # @g = g
190
+ # end
191
+ # def tsort_each_child(n, &b) @g[n].each(&b) end
192
+ # def tsort_each_node(&b) @g.each_key(&b) end
193
+ # end
194
+ #
195
+ # graph = G.new({1=>[2, 3], 2=>[4], 3=>[2, 4], 4=>[]})
196
+ # graph.tsort_each {|n| p n }
197
+ # #=> 4
198
+ # # 2
199
+ # # 3
200
+ # # 1
201
+ #
202
+ def tsort_each(&block) # :yields: node
203
+ each_node = method(:tsort_each_node)
204
+ each_child = method(:tsort_each_child)
205
+ TSort.tsort_each(each_node, each_child, &block)
206
+ end
207
+
208
+ # The iterator version of the TSort.tsort method.
209
+ #
210
+ # The graph is represented by _each_node_ and _each_child_.
211
+ # _each_node_ should have +call+ method which yields for each node in the graph.
212
+ # _each_child_ should have +call+ method which takes a node argument and yields for each child node.
213
+ #
214
+ # g = {1=>[2, 3], 2=>[4], 3=>[2, 4], 4=>[]}
215
+ # each_node = lambda {|&b| g.each_key(&b) }
216
+ # each_child = lambda {|n, &b| g[n].each(&b) }
217
+ # TSort.tsort_each(each_node, each_child) {|n| p n }
218
+ # #=> 4
219
+ # # 2
220
+ # # 3
221
+ # # 1
222
+ #
223
+ def TSort.tsort_each(each_node, each_child) # :yields: node
224
+ return to_enum(__method__, each_node, each_child) unless block_given?
225
+
226
+ TSort.each_strongly_connected_component(each_node, each_child) {|component|
227
+ if component.size == 1
228
+ yield component.first
229
+ else
230
+ raise Cyclic.new("topological sort failed: #{component.inspect}")
231
+ end
232
+ }
233
+ end
234
+
235
+ # Returns strongly connected components as an array of arrays of nodes.
236
+ # The array is sorted from children to parents.
237
+ # Each elements of the array represents a strongly connected component.
238
+ #
239
+ # class G
240
+ # include TSort
241
+ # def initialize(g)
242
+ # @g = g
243
+ # end
244
+ # def tsort_each_child(n, &b) @g[n].each(&b) end
245
+ # def tsort_each_node(&b) @g.each_key(&b) end
246
+ # end
247
+ #
248
+ # graph = G.new({1=>[2, 3], 2=>[4], 3=>[2, 4], 4=>[]})
249
+ # p graph.strongly_connected_components #=> [[4], [2], [3], [1]]
250
+ #
251
+ # graph = G.new({1=>[2], 2=>[3, 4], 3=>[2], 4=>[]})
252
+ # p graph.strongly_connected_components #=> [[4], [2, 3], [1]]
253
+ #
254
+ def strongly_connected_components
255
+ each_node = method(:tsort_each_node)
256
+ each_child = method(:tsort_each_child)
257
+ TSort.strongly_connected_components(each_node, each_child)
258
+ end
259
+
260
+ # Returns strongly connected components as an array of arrays of nodes.
261
+ # The array is sorted from children to parents.
262
+ # Each elements of the array represents a strongly connected component.
263
+ #
264
+ # The graph is represented by _each_node_ and _each_child_.
265
+ # _each_node_ should have +call+ method which yields for each node in the graph.
266
+ # _each_child_ should have +call+ method which takes a node argument and yields for each child node.
267
+ #
268
+ # g = {1=>[2, 3], 2=>[4], 3=>[2, 4], 4=>[]}
269
+ # each_node = lambda {|&b| g.each_key(&b) }
270
+ # each_child = lambda {|n, &b| g[n].each(&b) }
271
+ # p TSort.strongly_connected_components(each_node, each_child)
272
+ # #=> [[4], [2], [3], [1]]
273
+ #
274
+ # g = {1=>[2], 2=>[3, 4], 3=>[2], 4=>[]}
275
+ # each_node = lambda {|&b| g.each_key(&b) }
276
+ # each_child = lambda {|n, &b| g[n].each(&b) }
277
+ # p TSort.strongly_connected_components(each_node, each_child)
278
+ # #=> [[4], [2, 3], [1]]
279
+ #
280
+ def TSort.strongly_connected_components(each_node, each_child)
281
+ TSort.each_strongly_connected_component(each_node, each_child).to_a
282
+ end
283
+
284
+ # The iterator version of the #strongly_connected_components method.
285
+ # <tt><em>obj</em>.each_strongly_connected_component</tt> is similar to
286
+ # <tt><em>obj</em>.strongly_connected_components.each</tt>, but
287
+ # modification of _obj_ during the iteration may lead to unexpected results.
288
+ #
289
+ # #each_strongly_connected_component returns +nil+.
290
+ #
291
+ # class G
292
+ # include TSort
293
+ # def initialize(g)
294
+ # @g = g
295
+ # end
296
+ # def tsort_each_child(n, &b) @g[n].each(&b) end
297
+ # def tsort_each_node(&b) @g.each_key(&b) end
298
+ # end
299
+ #
300
+ # graph = G.new({1=>[2, 3], 2=>[4], 3=>[2, 4], 4=>[]})
301
+ # graph.each_strongly_connected_component {|scc| p scc }
302
+ # #=> [4]
303
+ # # [2]
304
+ # # [3]
305
+ # # [1]
306
+ #
307
+ # graph = G.new({1=>[2], 2=>[3, 4], 3=>[2], 4=>[]})
308
+ # graph.each_strongly_connected_component {|scc| p scc }
309
+ # #=> [4]
310
+ # # [2, 3]
311
+ # # [1]
312
+ #
313
+ def each_strongly_connected_component(&block) # :yields: nodes
314
+ each_node = method(:tsort_each_node)
315
+ each_child = method(:tsort_each_child)
316
+ TSort.each_strongly_connected_component(each_node, each_child, &block)
317
+ end
318
+
319
+ # The iterator version of the TSort.strongly_connected_components method.
320
+ #
321
+ # The graph is represented by _each_node_ and _each_child_.
322
+ # _each_node_ should have +call+ method which yields for each node in the graph.
323
+ # _each_child_ should have +call+ method which takes a node argument and yields for each child node.
324
+ #
325
+ # g = {1=>[2, 3], 2=>[4], 3=>[2, 4], 4=>[]}
326
+ # each_node = lambda {|&b| g.each_key(&b) }
327
+ # each_child = lambda {|n, &b| g[n].each(&b) }
328
+ # TSort.each_strongly_connected_component(each_node, each_child) {|scc| p scc }
329
+ # #=> [4]
330
+ # # [2]
331
+ # # [3]
332
+ # # [1]
333
+ #
334
+ # g = {1=>[2], 2=>[3, 4], 3=>[2], 4=>[]}
335
+ # each_node = lambda {|&b| g.each_key(&b) }
336
+ # each_child = lambda {|n, &b| g[n].each(&b) }
337
+ # TSort.each_strongly_connected_component(each_node, each_child) {|scc| p scc }
338
+ # #=> [4]
339
+ # # [2, 3]
340
+ # # [1]
341
+ #
342
+ def TSort.each_strongly_connected_component(each_node, each_child) # :yields: nodes
343
+ return to_enum(__method__, each_node, each_child) unless block_given?
344
+
345
+ id_map = {}
346
+ stack = []
347
+ each_node.call {|node|
348
+ unless id_map.include? node
349
+ TSort.each_strongly_connected_component_from(node, each_child, id_map, stack) {|c|
350
+ yield c
351
+ }
352
+ end
353
+ }
354
+ nil
355
+ end
356
+
357
+ # Iterates over strongly connected component in the subgraph reachable from
358
+ # _node_.
359
+ #
360
+ # Return value is unspecified.
361
+ #
362
+ # #each_strongly_connected_component_from doesn't call #tsort_each_node.
363
+ #
364
+ # class G
365
+ # include TSort
366
+ # def initialize(g)
367
+ # @g = g
368
+ # end
369
+ # def tsort_each_child(n, &b) @g[n].each(&b) end
370
+ # def tsort_each_node(&b) @g.each_key(&b) end
371
+ # end
372
+ #
373
+ # graph = G.new({1=>[2, 3], 2=>[4], 3=>[2, 4], 4=>[]})
374
+ # graph.each_strongly_connected_component_from(2) {|scc| p scc }
375
+ # #=> [4]
376
+ # # [2]
377
+ #
378
+ # graph = G.new({1=>[2], 2=>[3, 4], 3=>[2], 4=>[]})
379
+ # graph.each_strongly_connected_component_from(2) {|scc| p scc }
380
+ # #=> [4]
381
+ # # [2, 3]
382
+ #
383
+ def each_strongly_connected_component_from(node, id_map={}, stack=[], &block) # :yields: nodes
384
+ TSort.each_strongly_connected_component_from(node, method(:tsort_each_child), id_map, stack, &block)
385
+ end
386
+
387
+ # Iterates over strongly connected components in a graph.
388
+ # The graph is represented by _node_ and _each_child_.
389
+ #
390
+ # _node_ is the first node.
391
+ # _each_child_ should have +call+ method which takes a node argument
392
+ # and yields for each child node.
393
+ #
394
+ # Return value is unspecified.
395
+ #
396
+ # #TSort.each_strongly_connected_component_from is a class method and
397
+ # it doesn't need a class to represent a graph which includes TSort.
398
+ #
399
+ # graph = {1=>[2], 2=>[3, 4], 3=>[2], 4=>[]}
400
+ # each_child = lambda {|n, &b| graph[n].each(&b) }
401
+ # TSort.each_strongly_connected_component_from(1, each_child) {|scc|
402
+ # p scc
403
+ # }
404
+ # #=> [4]
405
+ # # [2, 3]
406
+ # # [1]
407
+ #
408
+ def TSort.each_strongly_connected_component_from(node, each_child, id_map={}, stack=[]) # :yields: nodes
409
+ return to_enum(__method__, node, each_child, id_map, stack) unless block_given?
410
+
411
+ minimum_id = node_id = id_map[node] = id_map.size
412
+ stack_length = stack.length
413
+ stack << node
414
+
415
+ each_child.call(node) {|child|
416
+ if id_map.include? child
417
+ child_id = id_map[child]
418
+ minimum_id = child_id if child_id && child_id < minimum_id
419
+ else
420
+ sub_minimum_id =
421
+ TSort.each_strongly_connected_component_from(child, each_child, id_map, stack) {|c|
422
+ yield c
423
+ }
424
+ minimum_id = sub_minimum_id if sub_minimum_id < minimum_id
425
+ end
426
+ }
427
+
428
+ if node_id == minimum_id
429
+ component = stack.slice!(stack_length .. -1)
430
+ component.each {|n| id_map[n] = nil}
431
+ yield component
432
+ end
433
+
434
+ minimum_id
435
+ end
436
+
437
+ # Should be implemented by a extended class.
438
+ #
439
+ # #tsort_each_node is used to iterate for all nodes over a graph.
440
+ #
441
+ def tsort_each_node # :yields: node
442
+ raise NotImplementedError.new
443
+ end
444
+
445
+ # Should be implemented by a extended class.
446
+ #
447
+ # #tsort_each_child is used to iterate for child nodes of _node_.
448
+ #
449
+ def tsort_each_child(node) # :yields: child
450
+ raise NotImplementedError.new
451
+ end
452
+ end
453
+ end