bundler 2.0.2

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of bundler might be problematic. Click here for more details.

Files changed (303) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +3111 -0
  3. data/LICENSE.md +23 -0
  4. data/README.md +63 -0
  5. data/bundler.gemspec +65 -0
  6. data/exe/bundle +31 -0
  7. data/exe/bundle_ruby +60 -0
  8. data/exe/bundler +4 -0
  9. data/lib/bundler.rb +567 -0
  10. data/lib/bundler/build_metadata.rb +53 -0
  11. data/lib/bundler/capistrano.rb +22 -0
  12. data/lib/bundler/cli.rb +792 -0
  13. data/lib/bundler/cli/add.rb +35 -0
  14. data/lib/bundler/cli/binstubs.rb +49 -0
  15. data/lib/bundler/cli/cache.rb +36 -0
  16. data/lib/bundler/cli/check.rb +38 -0
  17. data/lib/bundler/cli/clean.rb +25 -0
  18. data/lib/bundler/cli/common.rb +102 -0
  19. data/lib/bundler/cli/config.rb +119 -0
  20. data/lib/bundler/cli/console.rb +43 -0
  21. data/lib/bundler/cli/doctor.rb +140 -0
  22. data/lib/bundler/cli/exec.rb +105 -0
  23. data/lib/bundler/cli/gem.rb +252 -0
  24. data/lib/bundler/cli/info.rb +50 -0
  25. data/lib/bundler/cli/init.rb +47 -0
  26. data/lib/bundler/cli/inject.rb +60 -0
  27. data/lib/bundler/cli/install.rb +218 -0
  28. data/lib/bundler/cli/issue.rb +40 -0
  29. data/lib/bundler/cli/list.rb +58 -0
  30. data/lib/bundler/cli/lock.rb +63 -0
  31. data/lib/bundler/cli/open.rb +26 -0
  32. data/lib/bundler/cli/outdated.rb +266 -0
  33. data/lib/bundler/cli/package.rb +49 -0
  34. data/lib/bundler/cli/platform.rb +46 -0
  35. data/lib/bundler/cli/plugin.rb +24 -0
  36. data/lib/bundler/cli/pristine.rb +47 -0
  37. data/lib/bundler/cli/remove.rb +18 -0
  38. data/lib/bundler/cli/show.rb +75 -0
  39. data/lib/bundler/cli/update.rb +91 -0
  40. data/lib/bundler/cli/viz.rb +31 -0
  41. data/lib/bundler/compact_index_client.rb +109 -0
  42. data/lib/bundler/compact_index_client/cache.rb +118 -0
  43. data/lib/bundler/compact_index_client/updater.rb +116 -0
  44. data/lib/bundler/compatibility_guard.rb +13 -0
  45. data/lib/bundler/constants.rb +7 -0
  46. data/lib/bundler/current_ruby.rb +94 -0
  47. data/lib/bundler/definition.rb +995 -0
  48. data/lib/bundler/dep_proxy.rb +48 -0
  49. data/lib/bundler/dependency.rb +139 -0
  50. data/lib/bundler/deployment.rb +69 -0
  51. data/lib/bundler/deprecate.rb +44 -0
  52. data/lib/bundler/dsl.rb +615 -0
  53. data/lib/bundler/endpoint_specification.rb +141 -0
  54. data/lib/bundler/env.rb +149 -0
  55. data/lib/bundler/environment_preserver.rb +59 -0
  56. data/lib/bundler/errors.rb +158 -0
  57. data/lib/bundler/feature_flag.rb +75 -0
  58. data/lib/bundler/fetcher.rb +312 -0
  59. data/lib/bundler/fetcher/base.rb +52 -0
  60. data/lib/bundler/fetcher/compact_index.rb +126 -0
  61. data/lib/bundler/fetcher/dependency.rb +82 -0
  62. data/lib/bundler/fetcher/downloader.rb +84 -0
  63. data/lib/bundler/fetcher/index.rb +52 -0
  64. data/lib/bundler/friendly_errors.rb +131 -0
  65. data/lib/bundler/gem_helper.rb +217 -0
  66. data/lib/bundler/gem_helpers.rb +101 -0
  67. data/lib/bundler/gem_remote_fetcher.rb +43 -0
  68. data/lib/bundler/gem_tasks.rb +7 -0
  69. data/lib/bundler/gem_version_promoter.rb +190 -0
  70. data/lib/bundler/gemdeps.rb +29 -0
  71. data/lib/bundler/graph.rb +152 -0
  72. data/lib/bundler/index.rb +213 -0
  73. data/lib/bundler/injector.rb +253 -0
  74. data/lib/bundler/inline.rb +74 -0
  75. data/lib/bundler/installer.rb +318 -0
  76. data/lib/bundler/installer/gem_installer.rb +85 -0
  77. data/lib/bundler/installer/parallel_installer.rb +229 -0
  78. data/lib/bundler/installer/standalone.rb +53 -0
  79. data/lib/bundler/lazy_specification.rb +123 -0
  80. data/lib/bundler/lockfile_generator.rb +95 -0
  81. data/lib/bundler/lockfile_parser.rb +256 -0
  82. data/lib/bundler/match_platform.rb +24 -0
  83. data/lib/bundler/mirror.rb +223 -0
  84. data/lib/bundler/plugin.rb +294 -0
  85. data/lib/bundler/plugin/api.rb +81 -0
  86. data/lib/bundler/plugin/api/source.rb +306 -0
  87. data/lib/bundler/plugin/dsl.rb +53 -0
  88. data/lib/bundler/plugin/events.rb +61 -0
  89. data/lib/bundler/plugin/index.rb +165 -0
  90. data/lib/bundler/plugin/installer.rb +96 -0
  91. data/lib/bundler/plugin/installer/git.rb +38 -0
  92. data/lib/bundler/plugin/installer/rubygems.rb +27 -0
  93. data/lib/bundler/plugin/source_list.rb +27 -0
  94. data/lib/bundler/process_lock.rb +24 -0
  95. data/lib/bundler/psyched_yaml.rb +37 -0
  96. data/lib/bundler/remote_specification.rb +114 -0
  97. data/lib/bundler/resolver.rb +373 -0
  98. data/lib/bundler/resolver/spec_group.rb +106 -0
  99. data/lib/bundler/retry.rb +66 -0
  100. data/lib/bundler/ruby_dsl.rb +18 -0
  101. data/lib/bundler/ruby_version.rb +152 -0
  102. data/lib/bundler/rubygems_ext.rb +209 -0
  103. data/lib/bundler/rubygems_gem_installer.rb +99 -0
  104. data/lib/bundler/rubygems_integration.rb +915 -0
  105. data/lib/bundler/runtime.rb +322 -0
  106. data/lib/bundler/settings.rb +464 -0
  107. data/lib/bundler/settings/validator.rb +102 -0
  108. data/lib/bundler/setup.rb +28 -0
  109. data/lib/bundler/shared_helpers.rb +386 -0
  110. data/lib/bundler/similarity_detector.rb +63 -0
  111. data/lib/bundler/source.rb +94 -0
  112. data/lib/bundler/source/gemspec.rb +18 -0
  113. data/lib/bundler/source/git.rb +329 -0
  114. data/lib/bundler/source/git/git_proxy.rb +262 -0
  115. data/lib/bundler/source/metadata.rb +62 -0
  116. data/lib/bundler/source/path.rb +249 -0
  117. data/lib/bundler/source/path/installer.rb +74 -0
  118. data/lib/bundler/source/rubygems.rb +539 -0
  119. data/lib/bundler/source/rubygems/remote.rb +69 -0
  120. data/lib/bundler/source_list.rb +186 -0
  121. data/lib/bundler/spec_set.rb +208 -0
  122. data/lib/bundler/ssl_certs/.document +1 -0
  123. data/lib/bundler/ssl_certs/certificate_manager.rb +66 -0
  124. data/lib/bundler/ssl_certs/index.rubygems.org/GlobalSignRootCA.pem +21 -0
  125. data/lib/bundler/ssl_certs/rubygems.global.ssl.fastly.net/DigiCertHighAssuranceEVRootCA.pem +23 -0
  126. data/lib/bundler/ssl_certs/rubygems.org/AddTrustExternalCARoot.pem +25 -0
  127. data/lib/bundler/stub_specification.rb +108 -0
  128. data/lib/bundler/templates/.document +1 -0
  129. data/lib/bundler/templates/Executable +29 -0
  130. data/lib/bundler/templates/Executable.bundler +105 -0
  131. data/lib/bundler/templates/Executable.standalone +14 -0
  132. data/lib/bundler/templates/Gemfile +7 -0
  133. data/lib/bundler/templates/gems.rb +8 -0
  134. data/lib/bundler/templates/newgem/CODE_OF_CONDUCT.md.tt +74 -0
  135. data/lib/bundler/templates/newgem/Gemfile.tt +4 -0
  136. data/lib/bundler/templates/newgem/LICENSE.txt.tt +21 -0
  137. data/lib/bundler/templates/newgem/README.md.tt +47 -0
  138. data/lib/bundler/templates/newgem/Rakefile.tt +29 -0
  139. data/lib/bundler/templates/newgem/bin/console.tt +14 -0
  140. data/lib/bundler/templates/newgem/bin/setup.tt +8 -0
  141. data/lib/bundler/templates/newgem/exe/newgem.tt +3 -0
  142. data/lib/bundler/templates/newgem/ext/newgem/extconf.rb.tt +3 -0
  143. data/lib/bundler/templates/newgem/ext/newgem/newgem.c.tt +9 -0
  144. data/lib/bundler/templates/newgem/ext/newgem/newgem.h.tt +6 -0
  145. data/lib/bundler/templates/newgem/gitignore.tt +20 -0
  146. data/lib/bundler/templates/newgem/lib/newgem.rb.tt +13 -0
  147. data/lib/bundler/templates/newgem/lib/newgem/version.rb.tt +7 -0
  148. data/lib/bundler/templates/newgem/newgem.gemspec.tt +50 -0
  149. data/lib/bundler/templates/newgem/rspec.tt +3 -0
  150. data/lib/bundler/templates/newgem/spec/newgem_spec.rb.tt +9 -0
  151. data/lib/bundler/templates/newgem/spec/spec_helper.rb.tt +14 -0
  152. data/lib/bundler/templates/newgem/test/newgem_test.rb.tt +11 -0
  153. data/lib/bundler/templates/newgem/test/test_helper.rb.tt +8 -0
  154. data/lib/bundler/templates/newgem/travis.yml.tt +7 -0
  155. data/lib/bundler/ui.rb +9 -0
  156. data/lib/bundler/ui/rg_proxy.rb +19 -0
  157. data/lib/bundler/ui/shell.rb +146 -0
  158. data/lib/bundler/ui/silent.rb +69 -0
  159. data/lib/bundler/uri_credentials_filter.rb +37 -0
  160. data/lib/bundler/vendor/fileutils/lib/fileutils.rb +1741 -0
  161. data/lib/bundler/vendor/fileutils/lib/fileutils/version.rb +5 -0
  162. data/lib/bundler/vendor/molinillo/lib/molinillo.rb +12 -0
  163. data/lib/bundler/vendor/molinillo/lib/molinillo/compatibility.rb +26 -0
  164. data/lib/bundler/vendor/molinillo/lib/molinillo/delegates/resolution_state.rb +57 -0
  165. data/lib/bundler/vendor/molinillo/lib/molinillo/delegates/specification_provider.rb +81 -0
  166. data/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph.rb +223 -0
  167. data/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/action.rb +36 -0
  168. data/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/add_edge_no_circular.rb +66 -0
  169. data/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/add_vertex.rb +62 -0
  170. data/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/delete_edge.rb +63 -0
  171. data/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/detach_vertex_named.rb +61 -0
  172. data/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/log.rb +126 -0
  173. data/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/set_payload.rb +46 -0
  174. data/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/tag.rb +36 -0
  175. data/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/vertex.rb +136 -0
  176. data/lib/bundler/vendor/molinillo/lib/molinillo/errors.rb +143 -0
  177. data/lib/bundler/vendor/molinillo/lib/molinillo/gem_metadata.rb +6 -0
  178. data/lib/bundler/vendor/molinillo/lib/molinillo/modules/specification_provider.rb +101 -0
  179. data/lib/bundler/vendor/molinillo/lib/molinillo/modules/ui.rb +67 -0
  180. data/lib/bundler/vendor/molinillo/lib/molinillo/resolution.rb +837 -0
  181. data/lib/bundler/vendor/molinillo/lib/molinillo/resolver.rb +46 -0
  182. data/lib/bundler/vendor/molinillo/lib/molinillo/state.rb +58 -0
  183. data/lib/bundler/vendor/net-http-persistent/lib/net/http/faster.rb +27 -0
  184. data/lib/bundler/vendor/net-http-persistent/lib/net/http/persistent.rb +1233 -0
  185. data/lib/bundler/vendor/net-http-persistent/lib/net/http/persistent/ssl_reuse.rb +129 -0
  186. data/lib/bundler/vendor/thor/lib/thor.rb +509 -0
  187. data/lib/bundler/vendor/thor/lib/thor/actions.rb +331 -0
  188. data/lib/bundler/vendor/thor/lib/thor/actions/create_file.rb +104 -0
  189. data/lib/bundler/vendor/thor/lib/thor/actions/create_link.rb +60 -0
  190. data/lib/bundler/vendor/thor/lib/thor/actions/directory.rb +118 -0
  191. data/lib/bundler/vendor/thor/lib/thor/actions/empty_directory.rb +143 -0
  192. data/lib/bundler/vendor/thor/lib/thor/actions/file_manipulation.rb +373 -0
  193. data/lib/bundler/vendor/thor/lib/thor/actions/inject_into_file.rb +109 -0
  194. data/lib/bundler/vendor/thor/lib/thor/base.rb +678 -0
  195. data/lib/bundler/vendor/thor/lib/thor/command.rb +135 -0
  196. data/lib/bundler/vendor/thor/lib/thor/core_ext/hash_with_indifferent_access.rb +97 -0
  197. data/lib/bundler/vendor/thor/lib/thor/core_ext/io_binary_read.rb +12 -0
  198. data/lib/bundler/vendor/thor/lib/thor/core_ext/ordered_hash.rb +129 -0
  199. data/lib/bundler/vendor/thor/lib/thor/error.rb +114 -0
  200. data/lib/bundler/vendor/thor/lib/thor/group.rb +281 -0
  201. data/lib/bundler/vendor/thor/lib/thor/invocation.rb +177 -0
  202. data/lib/bundler/vendor/thor/lib/thor/line_editor.rb +17 -0
  203. data/lib/bundler/vendor/thor/lib/thor/line_editor/basic.rb +37 -0
  204. data/lib/bundler/vendor/thor/lib/thor/line_editor/readline.rb +88 -0
  205. data/lib/bundler/vendor/thor/lib/thor/parser.rb +4 -0
  206. data/lib/bundler/vendor/thor/lib/thor/parser/argument.rb +70 -0
  207. data/lib/bundler/vendor/thor/lib/thor/parser/arguments.rb +175 -0
  208. data/lib/bundler/vendor/thor/lib/thor/parser/option.rb +146 -0
  209. data/lib/bundler/vendor/thor/lib/thor/parser/options.rb +226 -0
  210. data/lib/bundler/vendor/thor/lib/thor/rake_compat.rb +71 -0
  211. data/lib/bundler/vendor/thor/lib/thor/runner.rb +324 -0
  212. data/lib/bundler/vendor/thor/lib/thor/shell.rb +81 -0
  213. data/lib/bundler/vendor/thor/lib/thor/shell/basic.rb +482 -0
  214. data/lib/bundler/vendor/thor/lib/thor/shell/color.rb +149 -0
  215. data/lib/bundler/vendor/thor/lib/thor/shell/html.rb +126 -0
  216. data/lib/bundler/vendor/thor/lib/thor/util.rb +268 -0
  217. data/lib/bundler/vendor/thor/lib/thor/version.rb +3 -0
  218. data/lib/bundler/vendored_fileutils.rb +9 -0
  219. data/lib/bundler/vendored_molinillo.rb +4 -0
  220. data/lib/bundler/vendored_persistent.rb +52 -0
  221. data/lib/bundler/vendored_thor.rb +8 -0
  222. data/lib/bundler/version.rb +28 -0
  223. data/lib/bundler/version_ranges.rb +76 -0
  224. data/lib/bundler/vlad.rb +17 -0
  225. data/lib/bundler/worker.rb +106 -0
  226. data/lib/bundler/yaml_serializer.rb +90 -0
  227. data/man/bundle-add.1 +58 -0
  228. data/man/bundle-add.1.txt +52 -0
  229. data/man/bundle-add.ronn +40 -0
  230. data/man/bundle-binstubs.1 +40 -0
  231. data/man/bundle-binstubs.1.txt +48 -0
  232. data/man/bundle-binstubs.ronn +43 -0
  233. data/man/bundle-check.1 +31 -0
  234. data/man/bundle-check.1.txt +33 -0
  235. data/man/bundle-check.ronn +26 -0
  236. data/man/bundle-clean.1 +24 -0
  237. data/man/bundle-clean.1.txt +26 -0
  238. data/man/bundle-clean.ronn +18 -0
  239. data/man/bundle-config.1 +497 -0
  240. data/man/bundle-config.1.txt +529 -0
  241. data/man/bundle-config.ronn +397 -0
  242. data/man/bundle-doctor.1 +44 -0
  243. data/man/bundle-doctor.1.txt +44 -0
  244. data/man/bundle-doctor.ronn +33 -0
  245. data/man/bundle-exec.1 +165 -0
  246. data/man/bundle-exec.1.txt +178 -0
  247. data/man/bundle-exec.ronn +152 -0
  248. data/man/bundle-gem.1 +80 -0
  249. data/man/bundle-gem.1.txt +91 -0
  250. data/man/bundle-gem.ronn +78 -0
  251. data/man/bundle-info.1 +20 -0
  252. data/man/bundle-info.1.txt +21 -0
  253. data/man/bundle-info.ronn +17 -0
  254. data/man/bundle-init.1 +25 -0
  255. data/man/bundle-init.1.txt +34 -0
  256. data/man/bundle-init.ronn +29 -0
  257. data/man/bundle-inject.1 +33 -0
  258. data/man/bundle-inject.1.txt +32 -0
  259. data/man/bundle-inject.ronn +22 -0
  260. data/man/bundle-install.1 +308 -0
  261. data/man/bundle-install.1.txt +396 -0
  262. data/man/bundle-install.ronn +378 -0
  263. data/man/bundle-list.1 +50 -0
  264. data/man/bundle-list.1.txt +43 -0
  265. data/man/bundle-list.ronn +33 -0
  266. data/man/bundle-lock.1 +84 -0
  267. data/man/bundle-lock.1.txt +93 -0
  268. data/man/bundle-lock.ronn +94 -0
  269. data/man/bundle-open.1 +32 -0
  270. data/man/bundle-open.1.txt +29 -0
  271. data/man/bundle-open.ronn +19 -0
  272. data/man/bundle-outdated.1 +155 -0
  273. data/man/bundle-outdated.1.txt +131 -0
  274. data/man/bundle-outdated.ronn +111 -0
  275. data/man/bundle-package.1 +55 -0
  276. data/man/bundle-package.1.txt +79 -0
  277. data/man/bundle-package.ronn +72 -0
  278. data/man/bundle-platform.1 +61 -0
  279. data/man/bundle-platform.1.txt +57 -0
  280. data/man/bundle-platform.ronn +42 -0
  281. data/man/bundle-pristine.1 +34 -0
  282. data/man/bundle-pristine.1.txt +44 -0
  283. data/man/bundle-pristine.ronn +34 -0
  284. data/man/bundle-remove.1 +31 -0
  285. data/man/bundle-remove.1.txt +34 -0
  286. data/man/bundle-remove.ronn +23 -0
  287. data/man/bundle-show.1 +23 -0
  288. data/man/bundle-show.1.txt +27 -0
  289. data/man/bundle-show.ronn +21 -0
  290. data/man/bundle-update.1 +394 -0
  291. data/man/bundle-update.1.txt +391 -0
  292. data/man/bundle-update.ronn +350 -0
  293. data/man/bundle-viz.1 +39 -0
  294. data/man/bundle-viz.1.txt +39 -0
  295. data/man/bundle-viz.ronn +30 -0
  296. data/man/bundle.1 +136 -0
  297. data/man/bundle.1.txt +116 -0
  298. data/man/bundle.ronn +111 -0
  299. data/man/gemfile.5 +689 -0
  300. data/man/gemfile.5.ronn +521 -0
  301. data/man/gemfile.5.txt +653 -0
  302. data/man/index.txt +25 -0
  303. metadata +463 -0
@@ -0,0 +1,116 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "bundler/vendored_fileutils"
4
+ require "stringio"
5
+ require "zlib"
6
+
7
+ module Bundler
8
+ class CompactIndexClient
9
+ class Updater
10
+ class MisMatchedChecksumError < Error
11
+ def initialize(path, server_checksum, local_checksum)
12
+ @path = path
13
+ @server_checksum = server_checksum
14
+ @local_checksum = local_checksum
15
+ end
16
+
17
+ def message
18
+ "The checksum of /#{@path} does not match the checksum provided by the server! Something is wrong " \
19
+ "(local checksum is #{@local_checksum.inspect}, was expecting #{@server_checksum.inspect})."
20
+ end
21
+ end
22
+
23
+ def initialize(fetcher)
24
+ @fetcher = fetcher
25
+ require "tmpdir"
26
+ end
27
+
28
+ def update(local_path, remote_path, retrying = nil)
29
+ headers = {}
30
+
31
+ Dir.mktmpdir("bundler-compact-index-") do |local_temp_dir|
32
+ local_temp_path = Pathname.new(local_temp_dir).join(local_path.basename)
33
+
34
+ # first try to fetch any new bytes on the existing file
35
+ if retrying.nil? && local_path.file?
36
+ SharedHelpers.filesystem_access(local_temp_path) do
37
+ FileUtils.cp local_path, local_temp_path
38
+ end
39
+ headers["If-None-Match"] = etag_for(local_temp_path)
40
+ headers["Range"] =
41
+ if local_temp_path.size.nonzero?
42
+ # Subtract a byte to ensure the range won't be empty.
43
+ # Avoids 416 (Range Not Satisfiable) responses.
44
+ "bytes=#{local_temp_path.size - 1}-"
45
+ else
46
+ "bytes=#{local_temp_path.size}-"
47
+ end
48
+ else
49
+ # Fastly ignores Range when Accept-Encoding: gzip is set
50
+ headers["Accept-Encoding"] = "gzip"
51
+ end
52
+
53
+ response = @fetcher.call(remote_path, headers)
54
+ return nil if response.is_a?(Net::HTTPNotModified)
55
+
56
+ content = response.body
57
+ if response["Content-Encoding"] == "gzip"
58
+ content = Zlib::GzipReader.new(StringIO.new(content)).read
59
+ end
60
+
61
+ SharedHelpers.filesystem_access(local_temp_path) do
62
+ if response.is_a?(Net::HTTPPartialContent) && local_temp_path.size.nonzero?
63
+ local_temp_path.open("a") {|f| f << slice_body(content, 1..-1) }
64
+ else
65
+ local_temp_path.open("w") {|f| f << content }
66
+ end
67
+ end
68
+
69
+ response_etag = (response["ETag"] || "").gsub(%r{\AW/}, "")
70
+ if etag_for(local_temp_path) == response_etag
71
+ SharedHelpers.filesystem_access(local_path) do
72
+ FileUtils.mv(local_temp_path, local_path)
73
+ end
74
+ return nil
75
+ end
76
+
77
+ if retrying
78
+ raise MisMatchedChecksumError.new(remote_path, response_etag, etag_for(local_temp_path))
79
+ end
80
+
81
+ update(local_path, remote_path, :retrying)
82
+ end
83
+ rescue Errno::EACCES
84
+ raise Bundler::PermissionError,
85
+ "Bundler does not have write access to create a temp directory " \
86
+ "within #{Dir.tmpdir}. Bundler must have write access to your " \
87
+ "systems temp directory to function properly. "
88
+ rescue Zlib::GzipFile::Error
89
+ raise Bundler::HTTPError
90
+ end
91
+
92
+ def etag_for(path)
93
+ sum = checksum_for_file(path)
94
+ sum ? %("#{sum}") : nil
95
+ end
96
+
97
+ def slice_body(body, range)
98
+ if body.respond_to?(:byteslice)
99
+ body.byteslice(range)
100
+ else # pre-1.9.3
101
+ body.unpack("@#{range.first}a#{range.end + 1}").first
102
+ end
103
+ end
104
+
105
+ def checksum_for_file(path)
106
+ return nil unless path.file?
107
+ # This must use IO.read instead of Digest.file().hexdigest
108
+ # because we need to preserve \n line endings on windows when calculating
109
+ # the checksum
110
+ SharedHelpers.filesystem_access(path, :read) do
111
+ SharedHelpers.digest(:MD5).hexdigest(IO.read(path))
112
+ end
113
+ end
114
+ end
115
+ end
116
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: false
2
+
3
+ require "bundler/version"
4
+
5
+ if Bundler::VERSION.split(".").first.to_i >= 2
6
+ if Gem::Version.new(Object::RUBY_VERSION.dup) < Gem::Version.new("2.3")
7
+ abort "Bundler 2 requires Ruby 2.3 or later. Either install bundler 1 or update to a supported Ruby version."
8
+ end
9
+
10
+ if Gem::Version.new(Gem::VERSION.dup) < Gem::Version.new("2.5")
11
+ abort "Bundler 2 requires RubyGems 2.5 or later. Either install bundler 1 or update to a supported RubyGems version."
12
+ end
13
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Bundler
4
+ WINDOWS = RbConfig::CONFIG["host_os"] =~ /(msdos|mswin|djgpp|mingw)/
5
+ FREEBSD = RbConfig::CONFIG["host_os"] =~ /bsd/
6
+ NULL = WINDOWS ? "NUL" : "/dev/null"
7
+ end
@@ -0,0 +1,94 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Bundler
4
+ # Returns current version of Ruby
5
+ #
6
+ # @return [CurrentRuby] Current version of Ruby
7
+ def self.current_ruby
8
+ @current_ruby ||= CurrentRuby.new
9
+ end
10
+
11
+ class CurrentRuby
12
+ KNOWN_MINOR_VERSIONS = %w[
13
+ 1.8
14
+ 1.9
15
+ 2.0
16
+ 2.1
17
+ 2.2
18
+ 2.3
19
+ 2.4
20
+ 2.5
21
+ 2.6
22
+ 2.7
23
+ ].freeze
24
+
25
+ KNOWN_MAJOR_VERSIONS = KNOWN_MINOR_VERSIONS.map {|v| v.split(".", 2).first }.uniq.freeze
26
+
27
+ KNOWN_PLATFORMS = %w[
28
+ jruby
29
+ maglev
30
+ mingw
31
+ mri
32
+ mswin
33
+ mswin64
34
+ rbx
35
+ ruby
36
+ truffleruby
37
+ x64_mingw
38
+ ].freeze
39
+
40
+ def ruby?
41
+ !mswin? && (!defined?(RUBY_ENGINE) || RUBY_ENGINE == "ruby" ||
42
+ RUBY_ENGINE == "rbx" || RUBY_ENGINE == "maglev" || RUBY_ENGINE == "truffleruby")
43
+ end
44
+
45
+ def mri?
46
+ !mswin? && (!defined?(RUBY_ENGINE) || RUBY_ENGINE == "ruby")
47
+ end
48
+
49
+ def rbx?
50
+ ruby? && defined?(RUBY_ENGINE) && RUBY_ENGINE == "rbx"
51
+ end
52
+
53
+ def jruby?
54
+ defined?(RUBY_ENGINE) && RUBY_ENGINE == "jruby"
55
+ end
56
+
57
+ def maglev?
58
+ defined?(RUBY_ENGINE) && RUBY_ENGINE == "maglev"
59
+ end
60
+
61
+ def truffleruby?
62
+ defined?(RUBY_ENGINE) && RUBY_ENGINE == "truffleruby"
63
+ end
64
+
65
+ def mswin?
66
+ Bundler::WINDOWS
67
+ end
68
+
69
+ def mswin64?
70
+ Bundler::WINDOWS && Bundler.local_platform != Gem::Platform::RUBY && Bundler.local_platform.os == "mswin64" && Bundler.local_platform.cpu == "x64"
71
+ end
72
+
73
+ def mingw?
74
+ Bundler::WINDOWS && Bundler.local_platform != Gem::Platform::RUBY && Bundler.local_platform.os == "mingw32" && Bundler.local_platform.cpu != "x64"
75
+ end
76
+
77
+ def x64_mingw?
78
+ Bundler::WINDOWS && Bundler.local_platform != Gem::Platform::RUBY && Bundler.local_platform.os == "mingw32" && Bundler.local_platform.cpu == "x64"
79
+ end
80
+
81
+ (KNOWN_MINOR_VERSIONS + KNOWN_MAJOR_VERSIONS).each do |version|
82
+ trimmed_version = version.tr(".", "")
83
+ define_method(:"on_#{trimmed_version}?") do
84
+ RUBY_VERSION.start_with?("#{version}.")
85
+ end
86
+
87
+ KNOWN_PLATFORMS.each do |platform|
88
+ define_method(:"#{platform}_#{trimmed_version}?") do
89
+ send(:"#{platform}?") && send(:"on_#{trimmed_version}?")
90
+ end
91
+ end
92
+ end
93
+ end
94
+ end
@@ -0,0 +1,995 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "bundler/lockfile_parser"
4
+ require "set"
5
+
6
+ module Bundler
7
+ class Definition
8
+ include GemHelpers
9
+
10
+ attr_reader(
11
+ :dependencies,
12
+ :locked_deps,
13
+ :locked_gems,
14
+ :platforms,
15
+ :requires,
16
+ :ruby_version,
17
+ :lockfile,
18
+ :gemfiles
19
+ )
20
+
21
+ # Given a gemfile and lockfile creates a Bundler definition
22
+ #
23
+ # @param gemfile [Pathname] Path to Gemfile
24
+ # @param lockfile [Pathname,nil] Path to Gemfile.lock
25
+ # @param unlock [Hash, Boolean, nil] Gems that have been requested
26
+ # to be updated or true if all gems should be updated
27
+ # @return [Bundler::Definition]
28
+ def self.build(gemfile, lockfile, unlock)
29
+ unlock ||= {}
30
+ gemfile = Pathname.new(gemfile).expand_path
31
+
32
+ raise GemfileNotFound, "#{gemfile} not found" unless gemfile.file?
33
+
34
+ Dsl.evaluate(gemfile, lockfile, unlock)
35
+ end
36
+
37
+ #
38
+ # How does the new system work?
39
+ #
40
+ # * Load information from Gemfile and Lockfile
41
+ # * Invalidate stale locked specs
42
+ # * All specs from stale source are stale
43
+ # * All specs that are reachable only through a stale
44
+ # dependency are stale.
45
+ # * If all fresh dependencies are satisfied by the locked
46
+ # specs, then we can try to resolve locally.
47
+ #
48
+ # @param lockfile [Pathname] Path to Gemfile.lock
49
+ # @param dependencies [Array(Bundler::Dependency)] array of dependencies from Gemfile
50
+ # @param sources [Bundler::SourceList]
51
+ # @param unlock [Hash, Boolean, nil] Gems that have been requested
52
+ # to be updated or true if all gems should be updated
53
+ # @param ruby_version [Bundler::RubyVersion, nil] Requested Ruby Version
54
+ # @param optional_groups [Array(String)] A list of optional groups
55
+ def initialize(lockfile, dependencies, sources, unlock, ruby_version = nil, optional_groups = [], gemfiles = [])
56
+ if [true, false].include?(unlock)
57
+ @unlocking_bundler = false
58
+ @unlocking = unlock
59
+ else
60
+ unlock = unlock.dup
61
+ @unlocking_bundler = unlock.delete(:bundler)
62
+ unlock.delete_if {|_k, v| Array(v).empty? }
63
+ @unlocking = !unlock.empty?
64
+ end
65
+
66
+ @dependencies = dependencies
67
+ @sources = sources
68
+ @unlock = unlock
69
+ @optional_groups = optional_groups
70
+ @remote = false
71
+ @specs = nil
72
+ @ruby_version = ruby_version
73
+ @gemfiles = gemfiles
74
+
75
+ @lockfile = lockfile
76
+ @lockfile_contents = String.new
77
+ @locked_bundler_version = nil
78
+ @locked_ruby_version = nil
79
+ @locked_specs_incomplete_for_platform = false
80
+
81
+ if lockfile && File.exist?(lockfile)
82
+ @lockfile_contents = Bundler.read_file(lockfile)
83
+ @locked_gems = LockfileParser.new(@lockfile_contents)
84
+ @locked_platforms = @locked_gems.platforms
85
+ @platforms = @locked_platforms.dup
86
+ @locked_bundler_version = @locked_gems.bundler_version
87
+ @locked_ruby_version = @locked_gems.ruby_version
88
+
89
+ if unlock != true
90
+ @locked_deps = @locked_gems.dependencies
91
+ @locked_specs = SpecSet.new(@locked_gems.specs)
92
+ @locked_sources = @locked_gems.sources
93
+ else
94
+ @unlock = {}
95
+ @locked_deps = {}
96
+ @locked_specs = SpecSet.new([])
97
+ @locked_sources = []
98
+ end
99
+ else
100
+ @unlock = {}
101
+ @platforms = []
102
+ @locked_gems = nil
103
+ @locked_deps = {}
104
+ @locked_specs = SpecSet.new([])
105
+ @locked_sources = []
106
+ @locked_platforms = []
107
+ end
108
+
109
+ @unlock[:gems] ||= []
110
+ @unlock[:sources] ||= []
111
+ @unlock[:ruby] ||= if @ruby_version && locked_ruby_version_object
112
+ @ruby_version.diff(locked_ruby_version_object)
113
+ end
114
+ @unlocking ||= @unlock[:ruby] ||= (!@locked_ruby_version ^ !@ruby_version)
115
+
116
+ add_current_platform unless Bundler.frozen_bundle?
117
+
118
+ converge_path_sources_to_gemspec_sources
119
+ @path_changes = converge_paths
120
+ @source_changes = converge_sources
121
+
122
+ unless @unlock[:lock_shared_dependencies]
123
+ eager_unlock = expand_dependencies(@unlock[:gems], true)
124
+ @unlock[:gems] = @locked_specs.for(eager_unlock, [], false, false, false).map(&:name)
125
+ end
126
+
127
+ @dependency_changes = converge_dependencies
128
+ @local_changes = converge_locals
129
+
130
+ @requires = compute_requires
131
+ end
132
+
133
+ def gem_version_promoter
134
+ @gem_version_promoter ||= begin
135
+ locked_specs =
136
+ if unlocking? && @locked_specs.empty? && !@lockfile_contents.empty?
137
+ # Definition uses an empty set of locked_specs to indicate all gems
138
+ # are unlocked, but GemVersionPromoter needs the locked_specs
139
+ # for conservative comparison.
140
+ Bundler::SpecSet.new(@locked_gems.specs)
141
+ else
142
+ @locked_specs
143
+ end
144
+ GemVersionPromoter.new(locked_specs, @unlock[:gems])
145
+ end
146
+ end
147
+
148
+ def resolve_with_cache!
149
+ raise "Specs already loaded" if @specs
150
+ sources.cached!
151
+ specs
152
+ end
153
+
154
+ def resolve_remotely!
155
+ raise "Specs already loaded" if @specs
156
+ @remote = true
157
+ sources.remote!
158
+ specs
159
+ end
160
+
161
+ # For given dependency list returns a SpecSet with Gemspec of all the required
162
+ # dependencies.
163
+ # 1. The method first resolves the dependencies specified in Gemfile
164
+ # 2. After that it tries and fetches gemspec of resolved dependencies
165
+ #
166
+ # @return [Bundler::SpecSet]
167
+ def specs
168
+ @specs ||= begin
169
+ begin
170
+ specs = resolve.materialize(Bundler.settings[:cache_all_platforms] ? dependencies : requested_dependencies)
171
+ rescue GemNotFound => e # Handle yanked gem
172
+ gem_name, gem_version = extract_gem_info(e)
173
+ locked_gem = @locked_specs[gem_name].last
174
+ raise if locked_gem.nil? || locked_gem.version.to_s != gem_version || !@remote
175
+ raise GemNotFound, "Your bundle is locked to #{locked_gem}, but that version could not " \
176
+ "be found in any of the sources listed in your Gemfile. If you haven't changed sources, " \
177
+ "that means the author of #{locked_gem} has removed it. You'll need to update your bundle " \
178
+ "to a version other than #{locked_gem} that hasn't been removed in order to install."
179
+ end
180
+ unless specs["bundler"].any?
181
+ bundler = sources.metadata_source.specs.search(Gem::Dependency.new("bundler", VERSION)).last
182
+ specs["bundler"] = bundler
183
+ end
184
+
185
+ specs
186
+ end
187
+ end
188
+
189
+ def new_specs
190
+ specs - @locked_specs
191
+ end
192
+
193
+ def removed_specs
194
+ @locked_specs - specs
195
+ end
196
+
197
+ def new_platform?
198
+ @new_platform
199
+ end
200
+
201
+ def missing_specs
202
+ missing = []
203
+ resolve.materialize(requested_dependencies, missing)
204
+ missing
205
+ end
206
+
207
+ def missing_specs?
208
+ missing = missing_specs
209
+ return false if missing.empty?
210
+ Bundler.ui.debug "The definition is missing #{missing.map(&:full_name)}"
211
+ true
212
+ rescue BundlerError => e
213
+ @index = nil
214
+ @resolve = nil
215
+ @specs = nil
216
+ @gem_version_promoter = nil
217
+
218
+ Bundler.ui.debug "The definition is missing dependencies, failed to resolve & materialize locally (#{e})"
219
+ true
220
+ end
221
+
222
+ def requested_specs
223
+ @requested_specs ||= begin
224
+ groups = requested_groups
225
+ groups.map!(&:to_sym)
226
+ specs_for(groups)
227
+ end
228
+ end
229
+
230
+ def current_dependencies
231
+ dependencies.select(&:should_include?)
232
+ end
233
+
234
+ def specs_for(groups)
235
+ deps = dependencies.select {|d| (d.groups & groups).any? }
236
+ deps.delete_if {|d| !d.should_include? }
237
+ specs.for(expand_dependencies(deps))
238
+ end
239
+
240
+ # Resolve all the dependencies specified in Gemfile. It ensures that
241
+ # dependencies that have been already resolved via locked file and are fresh
242
+ # are reused when resolving dependencies
243
+ #
244
+ # @return [SpecSet] resolved dependencies
245
+ def resolve
246
+ @resolve ||= begin
247
+ last_resolve = converge_locked_specs
248
+ resolve =
249
+ if Bundler.frozen_bundle?
250
+ Bundler.ui.debug "Frozen, using resolution from the lockfile"
251
+ last_resolve
252
+ elsif !unlocking? && nothing_changed?
253
+ Bundler.ui.debug("Found no changes, using resolution from the lockfile")
254
+ last_resolve
255
+ else
256
+ # Run a resolve against the locally available gems
257
+ Bundler.ui.debug("Found changes from the lockfile, re-resolving dependencies because #{change_reason}")
258
+ last_resolve.merge Resolver.resolve(expanded_dependencies, index, source_requirements, last_resolve, gem_version_promoter, additional_base_requirements_for_resolve, platforms)
259
+ end
260
+
261
+ # filter out gems that _can_ be installed on multiple platforms, but don't need
262
+ # to be
263
+ resolve.for(expand_dependencies(dependencies, true), [], false, false, false)
264
+ end
265
+ end
266
+
267
+ def index
268
+ @index ||= Index.build do |idx|
269
+ dependency_names = @dependencies.map(&:name)
270
+
271
+ sources.all_sources.each do |source|
272
+ source.dependency_names = dependency_names - pinned_spec_names(source)
273
+ idx.add_source source.specs
274
+ dependency_names.concat(source.unmet_deps).uniq!
275
+ end
276
+
277
+ double_check_for_index(idx, dependency_names)
278
+ end
279
+ end
280
+
281
+ # Suppose the gem Foo depends on the gem Bar. Foo exists in Source A. Bar has some versions that exist in both
282
+ # sources A and B. At this point, the API request will have found all the versions of Bar in source A,
283
+ # but will not have found any versions of Bar from source B, which is a problem if the requested version
284
+ # of Foo specifically depends on a version of Bar that is only found in source B. This ensures that for
285
+ # each spec we found, we add all possible versions from all sources to the index.
286
+ def double_check_for_index(idx, dependency_names)
287
+ pinned_names = pinned_spec_names
288
+ loop do
289
+ idxcount = idx.size
290
+
291
+ names = :names # do this so we only have to traverse to get dependency_names from the index once
292
+ unmet_dependency_names = lambda do
293
+ return names unless names == :names
294
+ new_names = sources.all_sources.map(&:dependency_names_to_double_check)
295
+ return names = nil if new_names.compact!
296
+ names = new_names.flatten(1).concat(dependency_names)
297
+ names.uniq!
298
+ names -= pinned_names
299
+ names
300
+ end
301
+
302
+ sources.all_sources.each do |source|
303
+ source.double_check_for(unmet_dependency_names)
304
+ end
305
+
306
+ break if idxcount == idx.size
307
+ end
308
+ end
309
+ private :double_check_for_index
310
+
311
+ def has_rubygems_remotes?
312
+ sources.rubygems_sources.any? {|s| s.remotes.any? }
313
+ end
314
+
315
+ def has_local_dependencies?
316
+ !sources.path_sources.empty? || !sources.git_sources.empty?
317
+ end
318
+
319
+ def spec_git_paths
320
+ sources.git_sources.map {|s| s.path.to_s }
321
+ end
322
+
323
+ def groups
324
+ dependencies.map(&:groups).flatten.uniq
325
+ end
326
+
327
+ def lock(file, preserve_unknown_sections = false)
328
+ contents = to_lock
329
+
330
+ # Convert to \r\n if the existing lock has them
331
+ # i.e., Windows with `git config core.autocrlf=true`
332
+ contents.gsub!(/\n/, "\r\n") if @lockfile_contents.match("\r\n")
333
+
334
+ if @locked_bundler_version && Bundler.feature_flag.lockfile_upgrade_warning?
335
+ locked_major = @locked_bundler_version.segments.first
336
+ current_major = Gem::Version.create(Bundler::VERSION).segments.first
337
+
338
+ if updating_major = locked_major < current_major
339
+ Bundler.ui.warn "Warning: the lockfile is being updated to Bundler #{current_major}, " \
340
+ "after which you will be unable to return to Bundler #{@locked_bundler_version.segments.first}."
341
+ end
342
+ end
343
+
344
+ preserve_unknown_sections ||= !updating_major && (Bundler.frozen_bundle? || !(unlocking? || @unlocking_bundler))
345
+
346
+ return if file && File.exist?(file) && lockfiles_equal?(@lockfile_contents, contents, preserve_unknown_sections)
347
+
348
+ if Bundler.frozen_bundle?
349
+ Bundler.ui.error "Cannot write a changed lockfile while frozen."
350
+ return
351
+ end
352
+
353
+ SharedHelpers.filesystem_access(file) do |p|
354
+ File.open(p, "wb") {|f| f.puts(contents) }
355
+ end
356
+ end
357
+
358
+ def locked_bundler_version
359
+ if @locked_bundler_version && @locked_bundler_version < Gem::Version.new(Bundler::VERSION)
360
+ new_version = Bundler::VERSION
361
+ end
362
+
363
+ new_version || @locked_bundler_version || Bundler::VERSION
364
+ end
365
+
366
+ def locked_ruby_version
367
+ return unless ruby_version
368
+ if @unlock[:ruby] || !@locked_ruby_version
369
+ Bundler::RubyVersion.system
370
+ else
371
+ @locked_ruby_version
372
+ end
373
+ end
374
+
375
+ def locked_ruby_version_object
376
+ return unless @locked_ruby_version
377
+ @locked_ruby_version_object ||= begin
378
+ unless version = RubyVersion.from_string(@locked_ruby_version)
379
+ raise LockfileError, "The Ruby version #{@locked_ruby_version} from " \
380
+ "#{@lockfile} could not be parsed. " \
381
+ "Try running bundle update --ruby to resolve this."
382
+ end
383
+ version
384
+ end
385
+ end
386
+
387
+ def to_lock
388
+ require "bundler/lockfile_generator"
389
+ LockfileGenerator.generate(self)
390
+ end
391
+
392
+ def ensure_equivalent_gemfile_and_lockfile(explicit_flag = false)
393
+ msg = String.new
394
+ msg << "You are trying to install in deployment mode after changing\n" \
395
+ "your Gemfile. Run `bundle install` elsewhere and add the\n" \
396
+ "updated #{Bundler.default_lockfile.relative_path_from(SharedHelpers.pwd)} to version control."
397
+
398
+ unless explicit_flag
399
+ suggested_command = if Bundler.settings.locations("frozen")[:global]
400
+ "bundle config --delete frozen"
401
+ elsif Bundler.settings.locations("deployment").keys.&([:global, :local]).any?
402
+ "bundle config --delete deployment"
403
+ else
404
+ "bundle install --no-deployment"
405
+ end
406
+ msg << "\n\nIf this is a development machine, remove the #{Bundler.default_gemfile} " \
407
+ "freeze \nby running `#{suggested_command}`."
408
+ end
409
+
410
+ added = []
411
+ deleted = []
412
+ changed = []
413
+
414
+ new_platforms = @platforms - @locked_platforms
415
+ deleted_platforms = @locked_platforms - @platforms
416
+ added.concat new_platforms.map {|p| "* platform: #{p}" }
417
+ deleted.concat deleted_platforms.map {|p| "* platform: #{p}" }
418
+
419
+ gemfile_sources = sources.lock_sources
420
+
421
+ new_sources = gemfile_sources - @locked_sources
422
+ deleted_sources = @locked_sources - gemfile_sources
423
+
424
+ new_deps = @dependencies - @locked_deps.values
425
+ deleted_deps = @locked_deps.values - @dependencies
426
+
427
+ # Check if it is possible that the source is only changed thing
428
+ if (new_deps.empty? && deleted_deps.empty?) && (!new_sources.empty? && !deleted_sources.empty?)
429
+ new_sources.reject! {|source| (source.path? && source.path.exist?) || equivalent_rubygems_remotes?(source) }
430
+ deleted_sources.reject! {|source| (source.path? && source.path.exist?) || equivalent_rubygems_remotes?(source) }
431
+ end
432
+
433
+ if @locked_sources != gemfile_sources
434
+ if new_sources.any?
435
+ added.concat new_sources.map {|source| "* source: #{source}" }
436
+ end
437
+
438
+ if deleted_sources.any?
439
+ deleted.concat deleted_sources.map {|source| "* source: #{source}" }
440
+ end
441
+ end
442
+
443
+ added.concat new_deps.map {|d| "* #{pretty_dep(d)}" } if new_deps.any?
444
+ if deleted_deps.any?
445
+ deleted.concat deleted_deps.map {|d| "* #{pretty_dep(d)}" }
446
+ end
447
+
448
+ both_sources = Hash.new {|h, k| h[k] = [] }
449
+ @dependencies.each {|d| both_sources[d.name][0] = d }
450
+ @locked_deps.each {|name, d| both_sources[name][1] = d.source }
451
+
452
+ both_sources.each do |name, (dep, lock_source)|
453
+ next unless (dep.nil? && !lock_source.nil?) || (!dep.nil? && !lock_source.nil? && !lock_source.can_lock?(dep))
454
+ gemfile_source_name = (dep && dep.source) || "no specified source"
455
+ lockfile_source_name = lock_source || "no specified source"
456
+ changed << "* #{name} from `#{gemfile_source_name}` to `#{lockfile_source_name}`"
457
+ end
458
+
459
+ reason = change_reason
460
+ msg << "\n\n#{reason.split(", ").map(&:capitalize).join("\n")}" unless reason.strip.empty?
461
+ msg << "\n\nYou have added to the Gemfile:\n" << added.join("\n") if added.any?
462
+ msg << "\n\nYou have deleted from the Gemfile:\n" << deleted.join("\n") if deleted.any?
463
+ msg << "\n\nYou have changed in the Gemfile:\n" << changed.join("\n") if changed.any?
464
+ msg << "\n"
465
+
466
+ raise ProductionError, msg if added.any? || deleted.any? || changed.any? || !nothing_changed?
467
+ end
468
+
469
+ def validate_runtime!
470
+ validate_ruby!
471
+ validate_platforms!
472
+ end
473
+
474
+ def validate_ruby!
475
+ return unless ruby_version
476
+
477
+ if diff = ruby_version.diff(Bundler::RubyVersion.system)
478
+ problem, expected, actual = diff
479
+
480
+ msg = case problem
481
+ when :engine
482
+ "Your Ruby engine is #{actual}, but your Gemfile specified #{expected}"
483
+ when :version
484
+ "Your Ruby version is #{actual}, but your Gemfile specified #{expected}"
485
+ when :engine_version
486
+ "Your #{Bundler::RubyVersion.system.engine} version is #{actual}, but your Gemfile specified #{ruby_version.engine} #{expected}"
487
+ when :patchlevel
488
+ if !expected.is_a?(String)
489
+ "The Ruby patchlevel in your Gemfile must be a string"
490
+ else
491
+ "Your Ruby patchlevel is #{actual}, but your Gemfile specified #{expected}"
492
+ end
493
+ end
494
+
495
+ raise RubyVersionMismatch, msg
496
+ end
497
+ end
498
+
499
+ def validate_platforms!
500
+ return if @platforms.any? do |bundle_platform|
501
+ Bundler.rubygems.platforms.any? do |local_platform|
502
+ MatchPlatform.platforms_match?(bundle_platform, local_platform)
503
+ end
504
+ end
505
+
506
+ raise ProductionError, "Your bundle only supports platforms #{@platforms.map(&:to_s)} " \
507
+ "but your local platforms are #{Bundler.rubygems.platforms.map(&:to_s)}, and " \
508
+ "there's no compatible match between those two lists."
509
+ end
510
+
511
+ def add_platform(platform)
512
+ @new_platform ||= !@platforms.include?(platform)
513
+ @platforms |= [platform]
514
+ end
515
+
516
+ def remove_platform(platform)
517
+ return if @platforms.delete(Gem::Platform.new(platform))
518
+ raise InvalidOption, "Unable to remove the platform `#{platform}` since the only platforms are #{@platforms.join ", "}"
519
+ end
520
+
521
+ def add_current_platform
522
+ current_platform = Bundler.local_platform
523
+ add_platform(current_platform) if Bundler.feature_flag.specific_platform?
524
+ add_platform(generic(current_platform))
525
+ end
526
+
527
+ def find_resolved_spec(current_spec)
528
+ specs.find_by_name_and_platform(current_spec.name, current_spec.platform)
529
+ end
530
+
531
+ def find_indexed_specs(current_spec)
532
+ index[current_spec.name].select {|spec| spec.match_platform(current_spec.platform) }.sort_by(&:version)
533
+ end
534
+
535
+ attr_reader :sources
536
+ private :sources
537
+
538
+ def nothing_changed?
539
+ !@source_changes && !@dependency_changes && !@new_platform && !@path_changes && !@local_changes && !@locked_specs_incomplete_for_platform
540
+ end
541
+
542
+ def unlocking?
543
+ @unlocking
544
+ end
545
+
546
+ private
547
+
548
+ def change_reason
549
+ if unlocking?
550
+ unlock_reason = @unlock.reject {|_k, v| Array(v).empty? }.map do |k, v|
551
+ if v == true
552
+ k.to_s
553
+ else
554
+ v = Array(v)
555
+ "#{k}: (#{v.join(", ")})"
556
+ end
557
+ end.join(", ")
558
+ return "bundler is unlocking #{unlock_reason}"
559
+ end
560
+ [
561
+ [@source_changes, "the list of sources changed"],
562
+ [@dependency_changes, "the dependencies in your gemfile changed"],
563
+ [@new_platform, "you added a new platform to your gemfile"],
564
+ [@path_changes, "the gemspecs for path gems changed"],
565
+ [@local_changes, "the gemspecs for git local gems changed"],
566
+ [@locked_specs_incomplete_for_platform, "the lockfile does not have all gems needed for the current platform"],
567
+ ].select(&:first).map(&:last).join(", ")
568
+ end
569
+
570
+ def pretty_dep(dep, source = false)
571
+ SharedHelpers.pretty_dependency(dep, source)
572
+ end
573
+
574
+ # Check if the specs of the given source changed
575
+ # according to the locked source.
576
+ def specs_changed?(source)
577
+ locked = @locked_sources.find {|s| s == source }
578
+
579
+ !locked || dependencies_for_source_changed?(source, locked) || specs_for_source_changed?(source)
580
+ end
581
+
582
+ def dependencies_for_source_changed?(source, locked_source = source)
583
+ deps_for_source = @dependencies.select {|s| s.source == source }
584
+ locked_deps_for_source = @locked_deps.values.select {|dep| dep.source == locked_source }
585
+
586
+ Set.new(deps_for_source) != Set.new(locked_deps_for_source)
587
+ end
588
+
589
+ def specs_for_source_changed?(source)
590
+ locked_index = Index.new
591
+ locked_index.use(@locked_specs.select {|s| source.can_lock?(s) })
592
+
593
+ # order here matters, since Index#== is checking source.specs.include?(locked_index)
594
+ locked_index != source.specs
595
+ rescue PathError, GitError => e
596
+ Bundler.ui.debug "Assuming that #{source} has not changed since fetching its specs errored (#{e})"
597
+ false
598
+ end
599
+
600
+ # Get all locals and override their matching sources.
601
+ # Return true if any of the locals changed (for example,
602
+ # they point to a new revision) or depend on new specs.
603
+ def converge_locals
604
+ locals = []
605
+
606
+ Bundler.settings.local_overrides.map do |k, v|
607
+ spec = @dependencies.find {|s| s.name == k }
608
+ source = spec && spec.source
609
+ if source && source.respond_to?(:local_override!)
610
+ source.unlock! if @unlock[:gems].include?(spec.name)
611
+ locals << [source, source.local_override!(v)]
612
+ end
613
+ end
614
+
615
+ sources_with_changes = locals.select do |source, changed|
616
+ changed || specs_changed?(source)
617
+ end.map(&:first)
618
+ !sources_with_changes.each {|source| @unlock[:sources] << source.name }.empty?
619
+ end
620
+
621
+ def converge_paths
622
+ sources.path_sources.any? do |source|
623
+ specs_changed?(source)
624
+ end
625
+ end
626
+
627
+ def converge_path_source_to_gemspec_source(source)
628
+ return source unless source.instance_of?(Source::Path)
629
+ gemspec_source = sources.path_sources.find {|s| s.is_a?(Source::Gemspec) && s.as_path_source == source }
630
+ gemspec_source || source
631
+ end
632
+
633
+ def converge_path_sources_to_gemspec_sources
634
+ @locked_sources.map! do |source|
635
+ converge_path_source_to_gemspec_source(source)
636
+ end
637
+ @locked_specs.each do |spec|
638
+ spec.source &&= converge_path_source_to_gemspec_source(spec.source)
639
+ end
640
+ @locked_deps.each do |_, dep|
641
+ dep.source &&= converge_path_source_to_gemspec_source(dep.source)
642
+ end
643
+ end
644
+
645
+ def converge_rubygems_sources
646
+ return false if Bundler.feature_flag.lockfile_uses_separate_rubygems_sources?
647
+
648
+ changes = false
649
+
650
+ # Get the RubyGems sources from the Gemfile.lock
651
+ locked_gem_sources = @locked_sources.select {|s| s.is_a?(Source::Rubygems) }
652
+ # Get the RubyGems remotes from the Gemfile
653
+ actual_remotes = sources.rubygems_remotes
654
+
655
+ # If there is a RubyGems source in both
656
+ if !locked_gem_sources.empty? && !actual_remotes.empty?
657
+ locked_gem_sources.each do |locked_gem|
658
+ # Merge the remotes from the Gemfile into the Gemfile.lock
659
+ changes |= locked_gem.replace_remotes(actual_remotes, Bundler.settings[:allow_deployment_source_credential_changes])
660
+ end
661
+ end
662
+
663
+ changes
664
+ end
665
+
666
+ def converge_sources
667
+ changes = false
668
+
669
+ changes |= converge_rubygems_sources
670
+
671
+ # Replace the sources from the Gemfile with the sources from the Gemfile.lock,
672
+ # if they exist in the Gemfile.lock and are `==`. If you can't find an equivalent
673
+ # source in the Gemfile.lock, use the one from the Gemfile.
674
+ changes |= sources.replace_sources!(@locked_sources)
675
+
676
+ sources.all_sources.each do |source|
677
+ # If the source is unlockable and the current command allows an unlock of
678
+ # the source (for example, you are doing a `bundle update <foo>` of a git-pinned
679
+ # gem), unlock it. For git sources, this means to unlock the revision, which
680
+ # will cause the `ref` used to be the most recent for the branch (or master) if
681
+ # an explicit `ref` is not used.
682
+ if source.respond_to?(:unlock!) && @unlock[:sources].include?(source.name)
683
+ source.unlock!
684
+ changes = true
685
+ end
686
+ end
687
+
688
+ changes
689
+ end
690
+
691
+ def converge_dependencies
692
+ frozen = Bundler.frozen_bundle?
693
+ (@dependencies + @locked_deps.values).each do |dep|
694
+ locked_source = @locked_deps[dep.name]
695
+ # This is to make sure that if bundler is installing in deployment mode and
696
+ # after locked_source and sources don't match, we still use locked_source.
697
+ if frozen && !locked_source.nil? &&
698
+ locked_source.respond_to?(:source) && locked_source.source.instance_of?(Source::Path) && locked_source.source.path.exist?
699
+ dep.source = locked_source.source
700
+ elsif dep.source
701
+ dep.source = sources.get(dep.source)
702
+ end
703
+ if dep.source.is_a?(Source::Gemspec)
704
+ dep.platforms.concat(@platforms.map {|p| Dependency::REVERSE_PLATFORM_MAP[p] }.flatten(1)).uniq!
705
+ end
706
+ end
707
+
708
+ changes = false
709
+ # We want to know if all match, but don't want to check all entries
710
+ # This means we need to return false if any dependency doesn't match
711
+ # the lock or doesn't exist in the lock.
712
+ @dependencies.each do |dependency|
713
+ unless locked_dep = @locked_deps[dependency.name]
714
+ changes = true
715
+ next
716
+ end
717
+
718
+ # Gem::Dependency#== matches Gem::Dependency#type. As the lockfile
719
+ # doesn't carry a notion of the dependency type, if you use
720
+ # add_development_dependency in a gemspec that's loaded with the gemspec
721
+ # directive, the lockfile dependencies and resolved dependencies end up
722
+ # with a mismatch on #type. Work around that by setting the type on the
723
+ # dep from the lockfile.
724
+ locked_dep.instance_variable_set(:@type, dependency.type)
725
+
726
+ # We already know the name matches from the hash lookup
727
+ # so we only need to check the requirement now
728
+ changes ||= dependency.requirement != locked_dep.requirement
729
+ end
730
+
731
+ changes
732
+ end
733
+
734
+ # Remove elements from the locked specs that are expired. This will most
735
+ # commonly happen if the Gemfile has changed since the lockfile was last
736
+ # generated
737
+ def converge_locked_specs
738
+ deps = []
739
+
740
+ # Build a list of dependencies that are the same in the Gemfile
741
+ # and Gemfile.lock. If the Gemfile modified a dependency, but
742
+ # the gem in the Gemfile.lock still satisfies it, this is fine
743
+ # too.
744
+ @dependencies.each do |dep|
745
+ locked_dep = @locked_deps[dep.name]
746
+
747
+ # If the locked_dep doesn't match the dependency we're looking for then we ignore the locked_dep
748
+ locked_dep = nil unless locked_dep == dep
749
+
750
+ if in_locked_deps?(dep, locked_dep) || satisfies_locked_spec?(dep)
751
+ deps << dep
752
+ elsif dep.source.is_a?(Source::Path) && dep.current_platform? && (!locked_dep || dep.source != locked_dep.source)
753
+ @locked_specs.each do |s|
754
+ @unlock[:gems] << s.name if s.source == dep.source
755
+ end
756
+
757
+ dep.source.unlock! if dep.source.respond_to?(:unlock!)
758
+ dep.source.specs.each {|s| @unlock[:gems] << s.name }
759
+ end
760
+ end
761
+
762
+ unlock_source_unlocks_spec = Bundler.feature_flag.unlock_source_unlocks_spec?
763
+
764
+ converged = []
765
+ @locked_specs.each do |s|
766
+ # Replace the locked dependency's source with the equivalent source from the Gemfile
767
+ dep = @dependencies.find {|d| s.satisfies?(d) }
768
+ s.source = (dep && dep.source) || sources.get(s.source)
769
+
770
+ # Don't add a spec to the list if its source is expired. For example,
771
+ # if you change a Git gem to RubyGems.
772
+ next if s.source.nil?
773
+ next if @unlock[:sources].include?(s.source.name)
774
+
775
+ # XXX This is a backwards-compatibility fix to preserve the ability to
776
+ # unlock a single gem by passing its name via `--source`. See issue #3759
777
+ # TODO: delete in Bundler 2
778
+ next if unlock_source_unlocks_spec && @unlock[:sources].include?(s.name)
779
+
780
+ # If the spec is from a path source and it doesn't exist anymore
781
+ # then we unlock it.
782
+
783
+ # Path sources have special logic
784
+ if s.source.instance_of?(Source::Path) || s.source.instance_of?(Source::Gemspec)
785
+ other_sources_specs = begin
786
+ s.source.specs
787
+ rescue PathError, GitError
788
+ # if we won't need the source (according to the lockfile),
789
+ # don't error if the path/git source isn't available
790
+ next if @locked_specs.
791
+ for(requested_dependencies, [], false, true, false).
792
+ none? {|locked_spec| locked_spec.source == s.source }
793
+
794
+ raise
795
+ end
796
+
797
+ other = other_sources_specs[s].first
798
+
799
+ # If the spec is no longer in the path source, unlock it. This
800
+ # commonly happens if the version changed in the gemspec
801
+ next unless other
802
+
803
+ deps2 = other.dependencies.select {|d| d.type != :development }
804
+ runtime_dependencies = s.dependencies.select {|d| d.type != :development }
805
+ # If the dependencies of the path source have changed, unlock it
806
+ next unless runtime_dependencies.sort == deps2.sort
807
+ end
808
+
809
+ converged << s
810
+ end
811
+
812
+ resolve = SpecSet.new(converged)
813
+ expanded_deps = expand_dependencies(deps, true)
814
+ @locked_specs_incomplete_for_platform = !resolve.for(expanded_deps, @unlock[:gems], true, true)
815
+ resolve = resolve.for(expanded_deps, @unlock[:gems], false, false, false)
816
+ diff = nil
817
+
818
+ # Now, we unlock any sources that do not have anymore gems pinned to it
819
+ sources.all_sources.each do |source|
820
+ next unless source.respond_to?(:unlock!)
821
+
822
+ unless resolve.any? {|s| s.source == source }
823
+ diff ||= @locked_specs.to_a - resolve.to_a
824
+ source.unlock! if diff.any? {|s| s.source == source }
825
+ end
826
+ end
827
+
828
+ resolve
829
+ end
830
+
831
+ def in_locked_deps?(dep, locked_dep)
832
+ # Because the lockfile can't link a dep to a specific remote, we need to
833
+ # treat sources as equivalent anytime the locked dep has all the remotes
834
+ # that the Gemfile dep does.
835
+ locked_dep && locked_dep.source && dep.source && locked_dep.source.include?(dep.source)
836
+ end
837
+
838
+ def satisfies_locked_spec?(dep)
839
+ @locked_specs[dep].any? {|s| s.satisfies?(dep) && (!dep.source || s.source.include?(dep.source)) }
840
+ end
841
+
842
+ # This list of dependencies is only used in #resolve, so it's OK to add
843
+ # the metadata dependencies here
844
+ def expanded_dependencies
845
+ @expanded_dependencies ||= begin
846
+ expand_dependencies(dependencies + metadata_dependencies, @remote)
847
+ end
848
+ end
849
+
850
+ def metadata_dependencies
851
+ @metadata_dependencies ||= begin
852
+ ruby_versions = concat_ruby_version_requirements(@ruby_version)
853
+ if ruby_versions.empty? || !@ruby_version.exact?
854
+ concat_ruby_version_requirements(RubyVersion.system)
855
+ concat_ruby_version_requirements(locked_ruby_version_object) unless @unlock[:ruby]
856
+ end
857
+ [
858
+ Dependency.new("ruby\0", ruby_versions),
859
+ Dependency.new("rubygems\0", Gem::VERSION),
860
+ ]
861
+ end
862
+ end
863
+
864
+ def concat_ruby_version_requirements(ruby_version, ruby_versions = [])
865
+ return ruby_versions unless ruby_version
866
+ if ruby_version.patchlevel
867
+ ruby_versions << ruby_version.to_gem_version_with_patchlevel
868
+ else
869
+ ruby_versions.concat(ruby_version.versions.map do |version|
870
+ requirement = Gem::Requirement.new(version)
871
+ if requirement.exact?
872
+ "~> #{version}.0"
873
+ else
874
+ requirement
875
+ end
876
+ end)
877
+ end
878
+ end
879
+
880
+ def expand_dependencies(dependencies, remote = false)
881
+ sorted_platforms = Resolver.sort_platforms(@platforms)
882
+ deps = []
883
+ dependencies.each do |dep|
884
+ dep = Dependency.new(dep, ">= 0") unless dep.respond_to?(:name)
885
+ next if !remote && !dep.current_platform?
886
+ platforms = dep.gem_platforms(sorted_platforms)
887
+ if platforms.empty? && !Bundler.settings[:disable_platform_warnings]
888
+ mapped_platforms = dep.platforms.map {|p| Dependency::PLATFORM_MAP[p] }
889
+ Bundler.ui.warn \
890
+ "The dependency #{dep} will be unused by any of the platforms Bundler is installing for. " \
891
+ "Bundler is installing for #{@platforms.join ", "} but the dependency " \
892
+ "is only for #{mapped_platforms.join ", "}. " \
893
+ "To add those platforms to the bundle, " \
894
+ "run `bundle lock --add-platform #{mapped_platforms.join " "}`."
895
+ end
896
+ platforms.each do |p|
897
+ deps << DepProxy.new(dep, p) if remote || p == generic_local_platform
898
+ end
899
+ end
900
+ deps
901
+ end
902
+
903
+ def requested_dependencies
904
+ groups = requested_groups
905
+ groups.map!(&:to_sym)
906
+ dependencies.reject {|d| !d.should_include? || (d.groups & groups).empty? }
907
+ end
908
+
909
+ def source_requirements
910
+ # Load all specs from remote sources
911
+ index
912
+
913
+ # Record the specs available in each gem's source, so that those
914
+ # specs will be available later when the resolver knows where to
915
+ # look for that gemspec (or its dependencies)
916
+ default = sources.default_source
917
+ source_requirements = { :default => default }
918
+ default = nil unless Bundler.feature_flag.lockfile_uses_separate_rubygems_sources?
919
+ dependencies.each do |dep|
920
+ next unless source = dep.source || default
921
+ source_requirements[dep.name] = source
922
+ end
923
+ metadata_dependencies.each do |dep|
924
+ source_requirements[dep.name] = sources.metadata_source
925
+ end
926
+ source_requirements["bundler"] = sources.metadata_source # needs to come last to override
927
+ source_requirements
928
+ end
929
+
930
+ def pinned_spec_names(skip = nil)
931
+ pinned_names = []
932
+ default = Bundler.feature_flag.lockfile_uses_separate_rubygems_sources? && sources.default_source
933
+ @dependencies.each do |dep|
934
+ next unless dep_source = dep.source || default
935
+ next if dep_source == skip
936
+ pinned_names << dep.name
937
+ end
938
+ pinned_names
939
+ end
940
+
941
+ def requested_groups
942
+ groups - Bundler.settings[:without] - @optional_groups + Bundler.settings[:with]
943
+ end
944
+
945
+ def lockfiles_equal?(current, proposed, preserve_unknown_sections)
946
+ if preserve_unknown_sections
947
+ sections_to_ignore = LockfileParser.sections_to_ignore(@locked_bundler_version)
948
+ sections_to_ignore += LockfileParser.unknown_sections_in_lockfile(current)
949
+ sections_to_ignore += LockfileParser::ENVIRONMENT_VERSION_SECTIONS
950
+ pattern = /#{Regexp.union(sections_to_ignore)}\n(\s{2,}.*\n)+/
951
+ whitespace_cleanup = /\n{2,}/
952
+ current = current.gsub(pattern, "\n").gsub(whitespace_cleanup, "\n\n").strip
953
+ proposed = proposed.gsub(pattern, "\n").gsub(whitespace_cleanup, "\n\n").strip
954
+ end
955
+ current == proposed
956
+ end
957
+
958
+ def extract_gem_info(error)
959
+ # This method will extract the error message like "Could not find foo-1.2.3 in any of the sources"
960
+ # to an array. The first element will be the gem name (e.g. foo), the second will be the version number.
961
+ error.message.scan(/Could not find (\w+)-(\d+(?:\.\d+)+)/).flatten
962
+ end
963
+
964
+ def compute_requires
965
+ dependencies.reduce({}) do |requires, dep|
966
+ next requires unless dep.should_include?
967
+ requires[dep.name] = Array(dep.autorequire || dep.name).map do |file|
968
+ # Allow `require: true` as an alias for `require: <name>`
969
+ file == true ? dep.name : file
970
+ end
971
+ requires
972
+ end
973
+ end
974
+
975
+ def additional_base_requirements_for_resolve
976
+ return [] unless @locked_gems && Bundler.feature_flag.only_update_to_newer_versions?
977
+ dependencies_by_name = dependencies.inject({}) {|memo, dep| memo.update(dep.name => dep) }
978
+ @locked_gems.specs.reduce({}) do |requirements, locked_spec|
979
+ name = locked_spec.name
980
+ dependency = dependencies_by_name[name]
981
+ next requirements if @locked_gems.dependencies[name] != dependency
982
+ next requirements if dependency && dependency.source.is_a?(Source::Path)
983
+ dep = Gem::Dependency.new(name, ">= #{locked_spec.version}")
984
+ requirements[name] = DepProxy.new(dep, locked_spec.platform)
985
+ requirements
986
+ end.values
987
+ end
988
+
989
+ def equivalent_rubygems_remotes?(source)
990
+ return false unless source.is_a?(Source::Rubygems)
991
+
992
+ Bundler.settings[:allow_deployment_source_credential_changes] && source.equivalent_remotes?(sources.rubygems_remotes)
993
+ end
994
+ end
995
+ end