bundler 1.13.6 → 1.17.3

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 (323) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +554 -9
  3. data/README.md +28 -5
  4. data/bundler.gemspec +40 -11
  5. data/exe/bundle +4 -8
  6. data/exe/bundle_ruby +4 -3
  7. data/lib/bundler.rb +162 -68
  8. data/lib/bundler/build_metadata.rb +53 -0
  9. data/lib/bundler/capistrano.rb +5 -0
  10. data/lib/bundler/cli.rb +360 -118
  11. data/lib/bundler/cli/add.rb +35 -0
  12. data/lib/bundler/cli/binstubs.rb +18 -10
  13. data/lib/bundler/cli/cache.rb +6 -5
  14. data/lib/bundler/cli/check.rb +4 -6
  15. data/lib/bundler/cli/clean.rb +6 -7
  16. data/lib/bundler/cli/common.rb +47 -1
  17. data/lib/bundler/cli/config.rb +26 -7
  18. data/lib/bundler/cli/console.rb +2 -1
  19. data/lib/bundler/cli/doctor.rb +63 -18
  20. data/lib/bundler/cli/exec.rb +12 -5
  21. data/lib/bundler/cli/gem.rb +59 -21
  22. data/lib/bundler/cli/info.rb +50 -0
  23. data/lib/bundler/cli/init.rb +21 -7
  24. data/lib/bundler/cli/inject.rb +13 -4
  25. data/lib/bundler/cli/install.rb +72 -101
  26. data/lib/bundler/cli/issue.rb +40 -0
  27. data/lib/bundler/cli/list.rb +58 -0
  28. data/lib/bundler/cli/lock.rb +9 -6
  29. data/lib/bundler/cli/open.rb +4 -3
  30. data/lib/bundler/cli/outdated.rb +175 -60
  31. data/lib/bundler/cli/package.rb +9 -6
  32. data/lib/bundler/cli/platform.rb +2 -1
  33. data/lib/bundler/cli/plugin.rb +1 -0
  34. data/lib/bundler/cli/pristine.rb +47 -0
  35. data/lib/bundler/cli/remove.rb +18 -0
  36. data/lib/bundler/cli/show.rb +2 -2
  37. data/lib/bundler/cli/update.rb +44 -34
  38. data/lib/bundler/cli/viz.rb +5 -1
  39. data/lib/bundler/compact_index_client.rb +109 -0
  40. data/lib/bundler/compact_index_client/cache.rb +118 -0
  41. data/lib/bundler/compact_index_client/updater.rb +116 -0
  42. data/lib/bundler/compatibility_guard.rb +14 -0
  43. data/lib/bundler/constants.rb +1 -0
  44. data/lib/bundler/current_ruby.rb +17 -8
  45. data/lib/bundler/definition.rb +353 -182
  46. data/lib/bundler/dep_proxy.rb +3 -1
  47. data/lib/bundler/dependency.rb +22 -10
  48. data/lib/bundler/deployment.rb +1 -1
  49. data/lib/bundler/deprecate.rb +15 -3
  50. data/lib/bundler/dsl.rb +122 -64
  51. data/lib/bundler/endpoint_specification.rb +13 -3
  52. data/lib/bundler/env.rb +110 -38
  53. data/lib/bundler/environment_preserver.rb +27 -6
  54. data/lib/bundler/errors.rb +24 -0
  55. data/lib/bundler/feature_flag.rb +74 -0
  56. data/lib/bundler/fetcher.rb +18 -11
  57. data/lib/bundler/fetcher/base.rb +1 -0
  58. data/lib/bundler/fetcher/compact_index.rb +7 -5
  59. data/lib/bundler/fetcher/dependency.rb +3 -2
  60. data/lib/bundler/fetcher/downloader.rb +25 -7
  61. data/lib/bundler/fetcher/index.rb +3 -2
  62. data/lib/bundler/friendly_errors.rb +33 -7
  63. data/lib/bundler/gem_helper.rb +25 -11
  64. data/lib/bundler/gem_helpers.rb +70 -1
  65. data/lib/bundler/gem_remote_fetcher.rb +1 -0
  66. data/lib/bundler/gem_tasks.rb +1 -0
  67. data/lib/bundler/gem_version_promoter.rb +17 -2
  68. data/lib/bundler/gemdeps.rb +29 -0
  69. data/lib/bundler/graph.rb +1 -0
  70. data/lib/bundler/index.rb +28 -15
  71. data/lib/bundler/injector.rb +216 -33
  72. data/lib/bundler/inline.rb +12 -12
  73. data/lib/bundler/installer.rb +139 -53
  74. data/lib/bundler/installer/gem_installer.rb +15 -5
  75. data/lib/bundler/installer/parallel_installer.rb +113 -28
  76. data/lib/bundler/installer/standalone.rb +1 -0
  77. data/lib/bundler/lazy_specification.rb +31 -3
  78. data/lib/bundler/lockfile_generator.rb +95 -0
  79. data/lib/bundler/lockfile_parser.rb +50 -37
  80. data/lib/bundler/match_platform.rb +13 -3
  81. data/lib/bundler/mirror.rb +10 -5
  82. data/lib/bundler/plugin.rb +22 -8
  83. data/lib/bundler/plugin/api.rb +2 -1
  84. data/lib/bundler/plugin/api/source.rb +17 -4
  85. data/lib/bundler/plugin/events.rb +61 -0
  86. data/lib/bundler/plugin/index.rb +9 -2
  87. data/lib/bundler/plugin/installer.rb +7 -6
  88. data/lib/bundler/plugin/source_list.rb +7 -8
  89. data/lib/bundler/process_lock.rb +24 -0
  90. data/lib/bundler/psyched_yaml.rb +10 -0
  91. data/lib/bundler/remote_specification.rb +30 -1
  92. data/lib/bundler/resolver.rb +187 -194
  93. data/lib/bundler/resolver/spec_group.rb +106 -0
  94. data/lib/bundler/retry.rb +5 -1
  95. data/lib/bundler/ruby_dsl.rb +1 -0
  96. data/lib/bundler/ruby_version.rb +12 -2
  97. data/lib/bundler/rubygems_ext.rb +23 -8
  98. data/lib/bundler/rubygems_gem_installer.rb +90 -0
  99. data/lib/bundler/rubygems_integration.rb +193 -70
  100. data/lib/bundler/runtime.rb +39 -22
  101. data/lib/bundler/settings.rb +245 -85
  102. data/lib/bundler/settings/validator.rb +102 -0
  103. data/lib/bundler/setup.rb +4 -7
  104. data/lib/bundler/shared_helpers.rb +183 -40
  105. data/lib/bundler/similarity_detector.rb +1 -0
  106. data/lib/bundler/source.rb +58 -1
  107. data/lib/bundler/source/gemspec.rb +1 -0
  108. data/lib/bundler/source/git.rb +52 -23
  109. data/lib/bundler/source/git/git_proxy.rb +30 -14
  110. data/lib/bundler/source/metadata.rb +62 -0
  111. data/lib/bundler/source/path.rb +42 -16
  112. data/lib/bundler/source/path/installer.rb +4 -2
  113. data/lib/bundler/source/rubygems.rb +171 -82
  114. data/lib/bundler/source/rubygems/remote.rb +12 -2
  115. data/lib/bundler/source_list.rb +75 -15
  116. data/lib/bundler/spec_set.rb +67 -32
  117. data/lib/bundler/ssl_certs/certificate_manager.rb +2 -1
  118. data/lib/bundler/stub_specification.rb +86 -2
  119. data/lib/bundler/templates/.document +1 -0
  120. data/lib/bundler/templates/Executable +13 -1
  121. data/lib/bundler/templates/Executable.bundler +105 -0
  122. data/lib/bundler/templates/Executable.standalone +5 -5
  123. data/lib/bundler/templates/Gemfile +3 -0
  124. data/lib/bundler/templates/gems.rb +8 -0
  125. data/lib/bundler/templates/newgem/Gemfile.tt +4 -2
  126. data/lib/bundler/templates/newgem/LICENSE.txt.tt +1 -1
  127. data/lib/bundler/templates/newgem/README.md.tt +14 -8
  128. data/lib/bundler/templates/newgem/Rakefile.tt +5 -5
  129. data/lib/bundler/templates/newgem/bin/console.tt +1 -1
  130. data/lib/bundler/templates/newgem/ext/newgem/newgem.c.tt +4 -4
  131. data/lib/bundler/templates/newgem/ext/newgem/newgem.h.tt +3 -3
  132. data/lib/bundler/templates/newgem/gitignore.tt +5 -1
  133. data/lib/bundler/templates/newgem/lib/newgem.rb.tt +7 -6
  134. data/lib/bundler/templates/newgem/lib/newgem/version.rb.tt +4 -4
  135. data/lib/bundler/templates/newgem/newgem.gemspec.tt +21 -12
  136. data/lib/bundler/templates/newgem/rspec.tt +1 -0
  137. data/lib/bundler/templates/newgem/spec/newgem_spec.rb.tt +1 -3
  138. data/lib/bundler/templates/newgem/spec/spec_helper.rb.tt +13 -1
  139. data/lib/bundler/templates/newgem/test/newgem_test.rb.tt +1 -1
  140. data/lib/bundler/templates/newgem/test/test_helper.rb.tt +3 -3
  141. data/lib/bundler/templates/newgem/{.travis.yml.tt → travis.yml.tt} +2 -0
  142. data/lib/bundler/ui.rb +1 -0
  143. data/lib/bundler/ui/rg_proxy.rb +1 -0
  144. data/lib/bundler/ui/shell.rb +30 -10
  145. data/lib/bundler/ui/silent.rb +21 -1
  146. data/lib/bundler/uri_credentials_filter.rb +1 -0
  147. data/lib/bundler/vendor/fileutils/lib/fileutils.rb +1638 -0
  148. data/lib/bundler/vendor/molinillo/lib/molinillo.rb +2 -0
  149. data/lib/bundler/vendor/molinillo/lib/molinillo/compatibility.rb +26 -0
  150. data/lib/bundler/vendor/molinillo/lib/molinillo/delegates/resolution_state.rb +7 -0
  151. data/lib/bundler/vendor/molinillo/lib/molinillo/delegates/specification_provider.rb +1 -0
  152. data/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph.rb +26 -6
  153. data/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/action.rb +2 -1
  154. data/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/add_edge_no_circular.rb +12 -4
  155. data/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/add_vertex.rb +3 -2
  156. data/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/delete_edge.rb +63 -0
  157. data/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/detach_vertex_named.rb +11 -3
  158. data/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/log.rb +13 -1
  159. data/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/set_payload.rb +3 -2
  160. data/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/tag.rb +3 -2
  161. data/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/vertex.rb +18 -5
  162. data/lib/bundler/vendor/molinillo/lib/molinillo/errors.rb +75 -7
  163. data/lib/bundler/vendor/molinillo/lib/molinillo/gem_metadata.rb +2 -1
  164. data/lib/bundler/vendor/molinillo/lib/molinillo/modules/specification_provider.rb +1 -0
  165. data/lib/bundler/vendor/molinillo/lib/molinillo/modules/ui.rb +3 -1
  166. data/lib/bundler/vendor/molinillo/lib/molinillo/resolution.rb +499 -128
  167. data/lib/bundler/vendor/molinillo/lib/molinillo/resolver.rb +1 -0
  168. data/lib/bundler/vendor/molinillo/lib/molinillo/state.rb +8 -4
  169. data/lib/bundler/vendor/{net → net-http-persistent/lib/net}/http/faster.rb +1 -0
  170. data/lib/bundler/vendor/{net → net-http-persistent/lib/net}/http/persistent.rb +27 -24
  171. data/lib/bundler/vendor/{net → net-http-persistent/lib/net}/http/persistent/ssl_reuse.rb +2 -1
  172. data/lib/bundler/vendor/thor/lib/thor.rb +46 -21
  173. data/lib/bundler/vendor/thor/lib/thor/actions.rb +24 -22
  174. data/lib/bundler/vendor/thor/lib/thor/actions/create_file.rb +2 -1
  175. data/lib/bundler/vendor/thor/lib/thor/actions/create_link.rb +2 -1
  176. data/lib/bundler/vendor/thor/lib/thor/actions/directory.rb +2 -2
  177. data/lib/bundler/vendor/thor/lib/thor/actions/empty_directory.rb +16 -8
  178. data/lib/bundler/vendor/thor/lib/thor/actions/file_manipulation.rb +66 -18
  179. data/lib/bundler/vendor/thor/lib/thor/actions/inject_into_file.rb +17 -15
  180. data/lib/bundler/vendor/thor/lib/thor/base.rb +55 -32
  181. data/lib/bundler/vendor/thor/lib/thor/command.rb +13 -11
  182. data/lib/bundler/vendor/thor/lib/thor/core_ext/hash_with_indifferent_access.rb +21 -1
  183. data/lib/bundler/vendor/thor/lib/thor/core_ext/io_binary_read.rb +7 -5
  184. data/lib/bundler/vendor/thor/lib/thor/core_ext/ordered_hash.rb +94 -63
  185. data/lib/bundler/vendor/thor/lib/thor/error.rb +3 -3
  186. data/lib/bundler/vendor/thor/lib/thor/group.rb +13 -13
  187. data/lib/bundler/vendor/thor/lib/thor/invocation.rb +4 -5
  188. data/lib/bundler/vendor/thor/lib/thor/line_editor/basic.rb +2 -0
  189. data/lib/bundler/vendor/thor/lib/thor/parser/argument.rb +4 -7
  190. data/lib/bundler/vendor/thor/lib/thor/parser/arguments.rb +16 -16
  191. data/lib/bundler/vendor/thor/lib/thor/parser/option.rb +42 -21
  192. data/lib/bundler/vendor/thor/lib/thor/parser/options.rb +13 -10
  193. data/lib/bundler/vendor/thor/lib/thor/runner.rb +31 -29
  194. data/lib/bundler/vendor/thor/lib/thor/shell.rb +1 -1
  195. data/lib/bundler/vendor/thor/lib/thor/shell/basic.rb +49 -33
  196. data/lib/bundler/vendor/thor/lib/thor/shell/color.rb +1 -1
  197. data/lib/bundler/vendor/thor/lib/thor/shell/html.rb +4 -4
  198. data/lib/bundler/vendor/thor/lib/thor/util.rb +8 -7
  199. data/lib/bundler/vendor/thor/lib/thor/version.rb +1 -1
  200. data/lib/bundler/vendored_fileutils.rb +9 -0
  201. data/lib/bundler/vendored_molinillo.rb +1 -0
  202. data/lib/bundler/vendored_persistent.rb +43 -3
  203. data/lib/bundler/vendored_thor.rb +6 -2
  204. data/lib/bundler/version.rb +19 -2
  205. data/lib/bundler/version_ranges.rb +76 -0
  206. data/lib/bundler/vlad.rb +5 -0
  207. data/lib/bundler/worker.rb +30 -6
  208. data/lib/bundler/yaml_serializer.rb +4 -4
  209. data/man/bundle-add.1 +58 -0
  210. data/man/bundle-add.1.txt +52 -0
  211. data/man/bundle-add.ronn +40 -0
  212. data/{lib/bundler/man/bundle-binstubs → man/bundle-binstubs.1} +11 -1
  213. data/man/bundle-binstubs.1.txt +48 -0
  214. data/man/bundle-binstubs.ronn +15 -1
  215. data/man/bundle-check.1 +31 -0
  216. data/man/bundle-check.1.txt +33 -0
  217. data/man/bundle-check.ronn +26 -0
  218. data/man/bundle-clean.1 +24 -0
  219. data/man/bundle-clean.1.txt +26 -0
  220. data/man/bundle-clean.ronn +18 -0
  221. data/man/bundle-config.1 +497 -0
  222. data/man/bundle-config.1.txt +529 -0
  223. data/man/bundle-config.ronn +233 -61
  224. data/man/bundle-doctor.1 +44 -0
  225. data/man/bundle-doctor.1.txt +44 -0
  226. data/man/bundle-doctor.ronn +33 -0
  227. data/{lib/bundler/man/bundle-exec → man/bundle-exec.1} +6 -3
  228. data/man/bundle-exec.1.txt +178 -0
  229. data/man/bundle-exec.ronn +10 -3
  230. data/{lib/bundler/man/bundle-gem → man/bundle-gem.1} +4 -4
  231. data/man/bundle-gem.1.txt +91 -0
  232. data/man/bundle-gem.ronn +3 -2
  233. data/man/bundle-info.1 +20 -0
  234. data/man/bundle-info.1.txt +21 -0
  235. data/man/bundle-info.ronn +17 -0
  236. data/man/bundle-init.1 +25 -0
  237. data/man/bundle-init.1.txt +34 -0
  238. data/man/bundle-init.ronn +29 -0
  239. data/man/bundle-inject.1 +33 -0
  240. data/man/bundle-inject.1.txt +32 -0
  241. data/man/bundle-inject.ronn +22 -0
  242. data/{lib/bundler/man/bundle-install → man/bundle-install.1} +32 -29
  243. data/man/bundle-install.1.txt +396 -0
  244. data/man/bundle-install.ronn +45 -36
  245. data/man/bundle-list.1 +50 -0
  246. data/man/bundle-list.1.txt +43 -0
  247. data/man/bundle-list.ronn +33 -0
  248. data/{lib/bundler/man/bundle-lock → man/bundle-lock.1} +43 -2
  249. data/man/bundle-lock.1.txt +93 -0
  250. data/man/bundle-lock.ronn +47 -0
  251. data/man/bundle-open.1 +32 -0
  252. data/man/bundle-open.1.txt +29 -0
  253. data/man/bundle-open.ronn +19 -0
  254. data/man/bundle-outdated.1 +155 -0
  255. data/man/bundle-outdated.1.txt +131 -0
  256. data/man/bundle-outdated.ronn +111 -0
  257. data/{lib/bundler/man/bundle-package → man/bundle-package.1} +6 -3
  258. data/man/bundle-package.1.txt +79 -0
  259. data/man/bundle-package.ronn +7 -2
  260. data/{lib/bundler/man/bundle-platform → man/bundle-platform.1} +1 -1
  261. data/man/bundle-platform.1.txt +57 -0
  262. data/man/bundle-pristine.1 +34 -0
  263. data/man/bundle-pristine.1.txt +44 -0
  264. data/man/bundle-pristine.ronn +34 -0
  265. data/man/bundle-remove.1 +31 -0
  266. data/man/bundle-remove.1.txt +34 -0
  267. data/man/bundle-remove.ronn +23 -0
  268. data/man/bundle-show.1 +23 -0
  269. data/man/bundle-show.1.txt +27 -0
  270. data/man/bundle-show.ronn +21 -0
  271. data/man/bundle-update.1 +394 -0
  272. data/man/bundle-update.1.txt +391 -0
  273. data/man/bundle-update.ronn +172 -16
  274. data/man/bundle-viz.1 +39 -0
  275. data/man/bundle-viz.1.txt +39 -0
  276. data/man/bundle-viz.ronn +30 -0
  277. data/{lib/bundler/man/bundle → man/bundle.1} +44 -28
  278. data/man/bundle.1.txt +116 -0
  279. data/man/bundle.ronn +39 -27
  280. data/{lib/bundler/man → man}/gemfile.5 +67 -84
  281. data/man/gemfile.5.ronn +77 -55
  282. data/man/gemfile.5.txt +653 -0
  283. data/man/index.txt +25 -8
  284. metadata +118 -58
  285. data/.codeclimate.yml +0 -25
  286. data/.gitignore +0 -16
  287. data/.rspec +0 -3
  288. data/.rubocop.yml +0 -128
  289. data/.rubocop_todo.yml +0 -248
  290. data/.travis.yml +0 -108
  291. data/CODE_OF_CONDUCT.md +0 -42
  292. data/CONTRIBUTING.md +0 -36
  293. data/DEVELOPMENT.md +0 -148
  294. data/ISSUES.md +0 -100
  295. data/Rakefile +0 -333
  296. data/bin/rake +0 -19
  297. data/bin/rspec +0 -15
  298. data/bin/rubocop +0 -17
  299. data/bin/with_rubygems +0 -39
  300. data/lib/bundler/man/bundle-binstubs.txt +0 -33
  301. data/lib/bundler/man/bundle-config +0 -254
  302. data/lib/bundler/man/bundle-config.txt +0 -282
  303. data/lib/bundler/man/bundle-exec.txt +0 -171
  304. data/lib/bundler/man/bundle-gem.txt +0 -90
  305. data/lib/bundler/man/bundle-install.txt +0 -385
  306. data/lib/bundler/man/bundle-lock.txt +0 -52
  307. data/lib/bundler/man/bundle-package.txt +0 -74
  308. data/lib/bundler/man/bundle-platform.txt +0 -57
  309. data/lib/bundler/man/bundle-update +0 -221
  310. data/lib/bundler/man/bundle-update.txt +0 -227
  311. data/lib/bundler/man/bundle.txt +0 -104
  312. data/lib/bundler/man/gemfile.5.txt +0 -636
  313. data/lib/bundler/postit_trampoline.rb +0 -68
  314. data/lib/bundler/vendor/compact_index_client/lib/compact_index_client.rb +0 -79
  315. data/lib/bundler/vendor/compact_index_client/lib/compact_index_client/cache.rb +0 -112
  316. data/lib/bundler/vendor/compact_index_client/lib/compact_index_client/updater.rb +0 -80
  317. data/lib/bundler/vendor/compact_index_client/lib/compact_index_client/version.rb +0 -4
  318. data/lib/bundler/vendor/postit/lib/postit.rb +0 -15
  319. data/lib/bundler/vendor/postit/lib/postit/environment.rb +0 -44
  320. data/lib/bundler/vendor/postit/lib/postit/installer.rb +0 -28
  321. data/lib/bundler/vendor/postit/lib/postit/parser.rb +0 -21
  322. data/lib/bundler/vendor/postit/lib/postit/setup.rb +0 -12
  323. data/lib/bundler/vendor/postit/lib/postit/version.rb +0 -3
@@ -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,14 @@
1
+ # frozen_string_literal: false
2
+
3
+ require "rubygems"
4
+ require "bundler/version"
5
+
6
+ if Bundler::VERSION.split(".").first.to_i >= 2
7
+ if Gem::Version.new(Object::RUBY_VERSION.dup) < Gem::Version.new("2.3")
8
+ abort "Bundler 2 requires Ruby 2.3 or later. Either install bundler 1 or update to a supported Ruby version."
9
+ end
10
+
11
+ if Gem::Version.new(Gem::VERSION.dup) < Gem::Version.new("2.5")
12
+ abort "Bundler 2 requires RubyGems 2.5 or later. Either install bundler 1 or update to a supported RubyGems version."
13
+ end
14
+ end
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  module Bundler
3
4
  WINDOWS = RbConfig::CONFIG["host_os"] =~ /(msdos|mswin|djgpp|mingw)/
4
5
  FREEBSD = RbConfig::CONFIG["host_os"] =~ /bsd/
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  module Bundler
3
4
  # Returns current version of Ruby
4
5
  #
@@ -8,7 +9,7 @@ module Bundler
8
9
  end
9
10
 
10
11
  class CurrentRuby
11
- KNOWN_MINOR_VERSIONS = %w(
12
+ KNOWN_MINOR_VERSIONS = %w[
12
13
  1.8
13
14
  1.9
14
15
  2.0
@@ -16,11 +17,13 @@ module Bundler
16
17
  2.2
17
18
  2.3
18
19
  2.4
19
- ).freeze
20
+ 2.5
21
+ 2.6
22
+ ].freeze
20
23
 
21
24
  KNOWN_MAJOR_VERSIONS = KNOWN_MINOR_VERSIONS.map {|v| v.split(".", 2).first }.uniq.freeze
22
25
 
23
- KNOWN_PLATFORMS = %w(
26
+ KNOWN_PLATFORMS = %w[
24
27
  jruby
25
28
  maglev
26
29
  mingw
@@ -29,11 +32,13 @@ module Bundler
29
32
  mswin64
30
33
  rbx
31
34
  ruby
35
+ truffleruby
32
36
  x64_mingw
33
- ).freeze
37
+ ].freeze
34
38
 
35
39
  def ruby?
36
- !mswin? && (!defined?(RUBY_ENGINE) || RUBY_ENGINE == "ruby" || RUBY_ENGINE == "rbx" || RUBY_ENGINE == "maglev")
40
+ !mswin? && (!defined?(RUBY_ENGINE) || RUBY_ENGINE == "ruby" ||
41
+ RUBY_ENGINE == "rbx" || RUBY_ENGINE == "maglev" || RUBY_ENGINE == "truffleruby")
37
42
  end
38
43
 
39
44
  def mri?
@@ -52,20 +57,24 @@ module Bundler
52
57
  defined?(RUBY_ENGINE) && RUBY_ENGINE == "maglev"
53
58
  end
54
59
 
60
+ def truffleruby?
61
+ defined?(RUBY_ENGINE) && RUBY_ENGINE == "truffleruby"
62
+ end
63
+
55
64
  def mswin?
56
65
  Bundler::WINDOWS
57
66
  end
58
67
 
59
68
  def mswin64?
60
- Bundler::WINDOWS && Gem::Platform.local.os == "mswin64" && Gem::Platform.local.cpu == "x64"
69
+ Bundler::WINDOWS && Bundler.local_platform != Gem::Platform::RUBY && Bundler.local_platform.os == "mswin64" && Bundler.local_platform.cpu == "x64"
61
70
  end
62
71
 
63
72
  def mingw?
64
- Bundler::WINDOWS && Gem::Platform.local.os == "mingw32" && Gem::Platform.local.cpu != "x64"
73
+ Bundler::WINDOWS && Bundler.local_platform != Gem::Platform::RUBY && Bundler.local_platform.os == "mingw32" && Bundler.local_platform.cpu != "x64"
65
74
  end
66
75
 
67
76
  def x64_mingw?
68
- Bundler::WINDOWS && Gem::Platform.local.os == "mingw32" && Gem::Platform.local.cpu == "x64"
77
+ Bundler::WINDOWS && Bundler.local_platform != Gem::Platform::RUBY && Bundler.local_platform.os == "mingw32" && Bundler.local_platform.cpu == "x64"
69
78
  end
70
79
 
71
80
  (KNOWN_MINOR_VERSIONS + KNOWN_MAJOR_VERSIONS).each do |version|
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  require "bundler/lockfile_parser"
3
- require "digest/sha1"
4
4
  require "set"
5
5
 
6
6
  module Bundler
@@ -9,12 +9,13 @@ module Bundler
9
9
 
10
10
  attr_reader(
11
11
  :dependencies,
12
- :gem_version_promoter,
13
12
  :locked_deps,
14
13
  :locked_gems,
15
14
  :platforms,
16
15
  :requires,
17
- :ruby_version
16
+ :ruby_version,
17
+ :lockfile,
18
+ :gemfiles
18
19
  )
19
20
 
20
21
  # Given a gemfile and lockfile creates a Bundler definition
@@ -51,8 +52,16 @@ module Bundler
51
52
  # to be updated or true if all gems should be updated
52
53
  # @param ruby_version [Bundler::RubyVersion, nil] Requested Ruby Version
53
54
  # @param optional_groups [Array(String)] A list of optional groups
54
- def initialize(lockfile, dependencies, sources, unlock, ruby_version = nil, optional_groups = [])
55
- @unlocking = unlock == true || !unlock.empty?
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
56
65
 
57
66
  @dependencies = dependencies
58
67
  @sources = sources
@@ -61,15 +70,19 @@ module Bundler
61
70
  @remote = false
62
71
  @specs = nil
63
72
  @ruby_version = ruby_version
73
+ @gemfiles = gemfiles
64
74
 
75
+ @lockfile = lockfile
65
76
  @lockfile_contents = String.new
66
77
  @locked_bundler_version = nil
67
78
  @locked_ruby_version = nil
79
+ @locked_specs_incomplete_for_platform = false
68
80
 
69
81
  if lockfile && File.exist?(lockfile)
70
82
  @lockfile_contents = Bundler.read_file(lockfile)
71
83
  @locked_gems = LockfileParser.new(@lockfile_contents)
72
- @platforms = @locked_gems.platforms
84
+ @locked_platforms = @locked_gems.platforms
85
+ @platforms = @locked_platforms.dup
73
86
  @locked_bundler_version = @locked_gems.bundler_version
74
87
  @locked_ruby_version = @locked_gems.ruby_version
75
88
 
@@ -79,7 +92,7 @@ module Bundler
79
92
  @locked_sources = @locked_gems.sources
80
93
  else
81
94
  @unlock = {}
82
- @locked_deps = []
95
+ @locked_deps = {}
83
96
  @locked_specs = SpecSet.new([])
84
97
  @locked_sources = []
85
98
  end
@@ -87,68 +100,51 @@ module Bundler
87
100
  @unlock = {}
88
101
  @platforms = []
89
102
  @locked_gems = nil
90
- @locked_deps = []
103
+ @locked_deps = {}
91
104
  @locked_specs = SpecSet.new([])
92
105
  @locked_sources = []
106
+ @locked_platforms = []
93
107
  end
94
108
 
95
109
  @unlock[:gems] ||= []
96
110
  @unlock[:sources] ||= []
97
- @unlock[:ruby] ||= if @ruby_version && @locked_ruby_version
98
- unless locked_ruby_version_object = RubyVersion.from_string(@locked_ruby_version)
99
- raise LockfileError, "Failed to create a `RubyVersion` object from " \
100
- "`#{@locked_ruby_version}` found in #{lockfile} -- try running `bundle update --ruby`."
101
- end
111
+ @unlock[:ruby] ||= if @ruby_version && locked_ruby_version_object
102
112
  @ruby_version.diff(locked_ruby_version_object)
103
113
  end
104
114
  @unlocking ||= @unlock[:ruby] ||= (!@locked_ruby_version ^ !@ruby_version)
105
115
 
106
- current_platform = Bundler.rubygems.platforms.map {|p| generic(p) }.compact.last
107
- add_platform(current_platform)
116
+ add_current_platform unless Bundler.frozen_bundle?
108
117
 
118
+ converge_path_sources_to_gemspec_sources
109
119
  @path_changes = converge_paths
110
- eager_unlock = expand_dependencies(@unlock[:gems])
111
- @unlock[:gems] = @locked_specs.for(eager_unlock).map(&:name)
120
+ @source_changes = converge_sources
112
121
 
113
- @gem_version_promoter = create_gem_version_promoter
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
114
126
 
115
- @source_changes = converge_sources
116
127
  @dependency_changes = converge_dependencies
117
128
  @local_changes = converge_locals
118
129
 
119
130
  @requires = compute_requires
120
-
121
- fixup_dependency_types!
122
131
  end
123
132
 
124
- def fixup_dependency_types!
125
- # XXX This is a temporary workaround for a bug when using rubygems 1.8.15
126
- # where Gem::Dependency#== matches Gem::Dependency#type. As the lockfile
127
- # doesn't carry a notion of the dependency type, if you use
128
- # add_development_dependency in a gemspec that's loaded with the gemspec
129
- # directive, the lockfile dependencies and resolved dependencies end up
130
- # with a mismatch on #type.
131
- # Test coverage to catch a regression on this is in gemspec_spec.rb
132
- @dependencies.each do |d|
133
- if ld = @locked_deps.find {|l| l.name == d.name }
134
- ld.instance_variable_set(:@type, d.type)
135
- end
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])
136
145
  end
137
146
  end
138
147
 
139
- def create_gem_version_promoter
140
- locked_specs =
141
- if @unlocking && @locked_specs.empty? && !@lockfile_contents.empty?
142
- # Definition uses an empty set of locked_specs to indicate all gems
143
- # are unlocked, but GemVersionPromoter needs the locked_specs
144
- # for conservative comparison.
145
- Bundler::SpecSet.new(@locked_gems.specs)
146
- else
147
- @locked_specs
148
- end
149
- GemVersionPromoter.new(locked_specs, @unlock[:gems])
150
- end
151
-
152
148
  def resolve_with_cache!
153
149
  raise "Specs already loaded" if @specs
154
150
  sources.cached!
@@ -175,16 +171,15 @@ module Bundler
175
171
  rescue GemNotFound => e # Handle yanked gem
176
172
  gem_name, gem_version = extract_gem_info(e)
177
173
  locked_gem = @locked_specs[gem_name].last
178
- raise if locked_gem.nil? || locked_gem.version.to_s != gem_version
174
+ raise if locked_gem.nil? || locked_gem.version.to_s != gem_version || !@remote
179
175
  raise GemNotFound, "Your bundle is locked to #{locked_gem}, but that version could not " \
180
176
  "be found in any of the sources listed in your Gemfile. If you haven't changed sources, " \
181
177
  "that means the author of #{locked_gem} has removed it. You'll need to update your bundle " \
182
- "to a different version of #{locked_gem} that hasn't been removed in order to install."
178
+ "to a version other than #{locked_gem} that hasn't been removed in order to install."
183
179
  end
184
180
  unless specs["bundler"].any?
185
- local = Bundler.settings[:frozen] ? rubygems_index : index
186
- bundler = local.search(Gem::Dependency.new("bundler", VERSION)).last
187
- specs["bundler"] = bundler if bundler
181
+ bundler = sources.metadata_source.specs.search(Gem::Dependency.new("bundler", VERSION)).last
182
+ specs["bundler"] = bundler
188
183
  end
189
184
 
190
185
  specs
@@ -209,10 +204,19 @@ module Bundler
209
204
  missing
210
205
  end
211
206
 
212
- def missing_dependencies
213
- missing = []
214
- resolve.materialize(current_dependencies, missing)
215
- missing
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
216
220
  end
217
221
 
218
222
  def requested_specs
@@ -241,14 +245,22 @@ module Bundler
241
245
  def resolve
242
246
  @resolve ||= begin
243
247
  last_resolve = converge_locked_specs
244
- if Bundler.settings[:frozen] || (!@unlocking && nothing_changed?)
245
- Bundler.ui.debug("Found no changes, using resolution from the lockfile")
246
- last_resolve
247
- else
248
- # Run a resolve against the locally available gems
249
- Bundler.ui.debug("Found changes from the lockfile, re-resolving dependencies because #{change_reason}")
250
- last_resolve.merge Resolver.resolve(expanded_dependencies, index, source_requirements, last_resolve, ruby_version, gem_version_promoter, additional_base_requirements_for_resolve)
251
- end
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)
252
264
  end
253
265
  end
254
266
 
@@ -257,23 +269,44 @@ module Bundler
257
269
  dependency_names = @dependencies.map(&:name)
258
270
 
259
271
  sources.all_sources.each do |source|
260
- source.dependency_names = dependency_names.dup
272
+ source.dependency_names = dependency_names - pinned_spec_names(source)
261
273
  idx.add_source source.specs
262
- dependency_names -= pinned_spec_names(source.specs)
263
274
  dependency_names.concat(source.unmet_deps).uniq!
264
275
  end
265
- end
266
- end
267
276
 
268
- # used when frozen is enabled so we can find the bundler
269
- # spec, even if (say) a git gem is not checked out.
270
- def rubygems_index
271
- @rubygems_index ||= Index.build do |idx|
272
- sources.rubygems_sources.each do |rubygems|
273
- idx.add_source rubygems.specs
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
274
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
275
307
  end
276
308
  end
309
+ private :double_check_for_index
277
310
 
278
311
  def has_rubygems_remotes?
279
312
  sources.rubygems_sources.any? {|s| s.remotes.any? }
@@ -308,10 +341,11 @@ module Bundler
308
341
  end
309
342
  end
310
343
 
311
- preserve_unknown_sections ||= !updating_major && (Bundler.settings[:frozen] || !@unlocking)
312
- return if lockfiles_equal?(@lockfile_contents, contents, preserve_unknown_sections)
344
+ preserve_unknown_sections ||= !updating_major && (Bundler.frozen_bundle? || !(unlocking? || @unlocking_bundler))
313
345
 
314
- if Bundler.settings[:frozen]
346
+ return if file && File.exist?(file) && lockfiles_equal?(@lockfile_contents, contents, preserve_unknown_sections)
347
+
348
+ if Bundler.frozen_bundle?
315
349
  Bundler.ui.error "Cannot write a changed lockfile while frozen."
316
350
  return
317
351
  end
@@ -338,52 +372,21 @@ module Bundler
338
372
  end
339
373
  end
340
374
 
341
- def to_lock
342
- out = String.new
343
-
344
- sources.lock_sources.each do |source|
345
- # Add the source header
346
- out << source.to_lock
347
- # Find all specs for this source
348
- resolve.
349
- select {|s| source.can_lock?(s) }.
350
- # This needs to be sorted by full name so that
351
- # gems with the same name, but different platform
352
- # are ordered consistently
353
- sort_by(&:full_name).
354
- each do |spec|
355
- next if spec.name == "bundler"
356
- out << spec.to_lock
357
- end
358
- out << "\n"
359
- end
360
-
361
- out << "PLATFORMS\n"
362
-
363
- platforms.map(&:to_s).sort.each do |p|
364
- out << " #{p}\n"
365
- end
366
-
367
- out << "\n"
368
- out << "DEPENDENCIES\n"
369
-
370
- handled = []
371
- dependencies.sort_by(&:to_s).each do |dep|
372
- next if handled.include?(dep.name)
373
- out << dep.to_lock
374
- handled << dep.name
375
- end
376
-
377
- if locked_ruby_version
378
- out << "\nRUBY VERSION\n"
379
- out << " #{locked_ruby_version}\n"
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
380
384
  end
385
+ end
381
386
 
382
- # Record the version of Bundler that was used to create the lockfile
383
- out << "\nBUNDLED WITH\n"
384
- out << " #{locked_bundler_version}\n"
385
-
386
- out
387
+ def to_lock
388
+ require "bundler/lockfile_generator"
389
+ LockfileGenerator.generate(self)
387
390
  end
388
391
 
389
392
  def ensure_equivalent_gemfile_and_lockfile(explicit_flag = false)
@@ -393,26 +396,38 @@ module Bundler
393
396
  "updated #{Bundler.default_lockfile.relative_path_from(SharedHelpers.pwd)} to version control."
394
397
 
395
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
396
406
  msg << "\n\nIf this is a development machine, remove the #{Bundler.default_gemfile} " \
397
- "freeze \nby running `bundle install --no-deployment`."
407
+ "freeze \nby running `#{suggested_command}`."
398
408
  end
399
409
 
400
410
  added = []
401
411
  deleted = []
402
412
  changed = []
403
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
+
404
419
  gemfile_sources = sources.lock_sources
405
420
 
406
421
  new_sources = gemfile_sources - @locked_sources
407
422
  deleted_sources = @locked_sources - gemfile_sources
408
423
 
409
- new_deps = @dependencies - @locked_deps
410
- deleted_deps = @locked_deps - @dependencies
424
+ new_deps = @dependencies - @locked_deps.values
425
+ deleted_deps = @locked_deps.values - @dependencies
411
426
 
412
427
  # Check if it is possible that the source is only changed thing
413
428
  if (new_deps.empty? && deleted_deps.empty?) && (!new_sources.empty? && !deleted_sources.empty?)
414
- new_sources.reject! {|source| source.is_a_path? && source.path.exist? }
415
- deleted_sources.reject! {|source| source.is_a_path? && source.path.exist? }
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) }
416
431
  end
417
432
 
418
433
  if @locked_sources != gemfile_sources
@@ -432,7 +447,7 @@ module Bundler
432
447
 
433
448
  both_sources = Hash.new {|h, k| h[k] = [] }
434
449
  @dependencies.each {|d| both_sources[d.name][0] = d }
435
- @locked_deps.each {|d| both_sources[d.name][1] = d.source }
450
+ @locked_deps.each {|name, d| both_sources[name][1] = d.source }
436
451
 
437
452
  both_sources.each do |name, (dep, lock_source)|
438
453
  next unless (dep.nil? && !lock_source.nil?) || (!dep.nil? && !lock_source.nil? && !lock_source.can_lock?(dep))
@@ -441,12 +456,19 @@ module Bundler
441
456
  changed << "* #{name} from `#{gemfile_source_name}` to `#{lockfile_source_name}`"
442
457
  end
443
458
 
459
+ reason = change_reason
460
+ msg << "\n\n#{reason.split(", ").map(&:capitalize).join("\n")}" unless reason.strip.empty?
444
461
  msg << "\n\nYou have added to the Gemfile:\n" << added.join("\n") if added.any?
445
462
  msg << "\n\nYou have deleted from the Gemfile:\n" << deleted.join("\n") if deleted.any?
446
463
  msg << "\n\nYou have changed in the Gemfile:\n" << changed.join("\n") if changed.any?
447
464
  msg << "\n"
448
465
 
449
- raise ProductionError, msg if added.any? || deleted.any? || changed.any?
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!
450
472
  end
451
473
 
452
474
  def validate_ruby!
@@ -474,6 +496,18 @@ module Bundler
474
496
  end
475
497
  end
476
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
+
477
511
  def add_platform(platform)
478
512
  @new_platform ||= !@platforms.include?(platform)
479
513
  @platforms |= [platform]
@@ -484,17 +518,35 @@ module Bundler
484
518
  raise InvalidOption, "Unable to remove the platform `#{platform}` since the only platforms are #{@platforms.join ", "}"
485
519
  end
486
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
+
487
535
  attr_reader :sources
488
536
  private :sources
489
537
 
490
- private
491
-
492
538
  def nothing_changed?
493
- !@source_changes && !@dependency_changes && !@new_platform && !@path_changes && !@local_changes
539
+ !@source_changes && !@dependency_changes && !@new_platform && !@path_changes && !@local_changes && !@locked_specs_incomplete_for_platform
540
+ end
541
+
542
+ def unlocking?
543
+ @unlocking
494
544
  end
495
545
 
546
+ private
547
+
496
548
  def change_reason
497
- if @unlocking
549
+ if unlocking?
498
550
  unlock_reason = @unlock.reject {|_k, v| Array(v).empty? }.map do |k, v|
499
551
  if v == true
500
552
  k.to_s
@@ -511,14 +563,12 @@ module Bundler
511
563
  [@new_platform, "you added a new platform to your gemfile"],
512
564
  [@path_changes, "the gemspecs for path gems changed"],
513
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"],
514
567
  ].select(&:first).map(&:last).join(", ")
515
568
  end
516
569
 
517
570
  def pretty_dep(dep, source = false)
518
- msg = String.new(dep.name)
519
- msg << " (#{dep.requirement})" unless dep.requirement == Gem::Requirement.default
520
- msg << " from the `#{dep.source}` source" if source && dep.source
521
- msg
571
+ SharedHelpers.pretty_dependency(dep, source)
522
572
  end
523
573
 
524
574
  # Check if the specs of the given source changed
@@ -531,7 +581,7 @@ module Bundler
531
581
 
532
582
  def dependencies_for_source_changed?(source, locked_source = source)
533
583
  deps_for_source = @dependencies.select {|s| s.source == source }
534
- locked_deps_for_source = @locked_deps.select {|s| s.source == locked_source }
584
+ locked_deps_for_source = @locked_deps.values.select {|dep| dep.source == locked_source }
535
585
 
536
586
  Set.new(deps_for_source) != Set.new(locked_deps_for_source)
537
587
  end
@@ -540,7 +590,11 @@ module Bundler
540
590
  locked_index = Index.new
541
591
  locked_index.use(@locked_specs.select {|s| source.can_lock?(s) })
542
592
 
543
- source.specs != locked_index
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
544
598
  end
545
599
 
546
600
  # Get all locals and override their matching sources.
@@ -576,29 +630,44 @@ module Bundler
576
630
  gemspec_source || source
577
631
  end
578
632
 
579
- def converge_sources
580
- changes = false
581
-
633
+ def converge_path_sources_to_gemspec_sources
582
634
  @locked_sources.map! do |source|
583
635
  converge_path_source_to_gemspec_source(source)
584
636
  end
585
637
  @locked_specs.each do |spec|
586
638
  spec.source &&= converge_path_source_to_gemspec_source(spec.source)
587
639
  end
640
+ @locked_deps.each do |_, dep|
641
+ dep.source &&= converge_path_source_to_gemspec_source(dep.source)
642
+ end
643
+ end
588
644
 
589
- # Get the Rubygems sources from the Gemfile.lock
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
590
651
  locked_gem_sources = @locked_sources.select {|s| s.is_a?(Source::Rubygems) }
591
- # Get the Rubygems remotes from the Gemfile
652
+ # Get the RubyGems remotes from the Gemfile
592
653
  actual_remotes = sources.rubygems_remotes
593
654
 
594
- # If there is a Rubygems source in both
655
+ # If there is a RubyGems source in both
595
656
  if !locked_gem_sources.empty? && !actual_remotes.empty?
596
657
  locked_gem_sources.each do |locked_gem|
597
658
  # Merge the remotes from the Gemfile into the Gemfile.lock
598
- changes |= locked_gem.replace_remotes(actual_remotes)
659
+ changes |= locked_gem.replace_remotes(actual_remotes, Bundler.settings[:allow_deployment_source_credential_changes])
599
660
  end
600
661
  end
601
662
 
663
+ changes
664
+ end
665
+
666
+ def converge_sources
667
+ changes = false
668
+
669
+ changes |= converge_rubygems_sources
670
+
602
671
  # Replace the sources from the Gemfile with the sources from the Gemfile.lock,
603
672
  # if they exist in the Gemfile.lock and are `==`. If you can't find an equivalent
604
673
  # source in the Gemfile.lock, use the one from the Gemfile.
@@ -620,11 +689,12 @@ module Bundler
620
689
  end
621
690
 
622
691
  def converge_dependencies
623
- (@dependencies + @locked_deps).each do |dep|
624
- locked_source = @locked_deps.select {|d| d.name == dep.name }.last
692
+ frozen = Bundler.frozen_bundle?
693
+ (@dependencies + @locked_deps.values).each do |dep|
694
+ locked_source = @locked_deps[dep.name]
625
695
  # This is to make sure that if bundler is installing in deployment mode and
626
696
  # after locked_source and sources don't match, we still use locked_source.
627
- if Bundler.settings[:frozen] && !locked_source.nil? &&
697
+ if frozen && !locked_source.nil? &&
628
698
  locked_source.respond_to?(:source) && locked_source.source.instance_of?(Source::Path) && locked_source.source.path.exist?
629
699
  dep.source = locked_source.source
630
700
  elsif dep.source
@@ -634,7 +704,31 @@ module Bundler
634
704
  dep.platforms.concat(@platforms.map {|p| Dependency::REVERSE_PLATFORM_MAP[p] }.flatten(1)).uniq!
635
705
  end
636
706
  end
637
- Set.new(@dependencies) != Set.new(@locked_deps)
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
638
732
  end
639
733
 
640
734
  # Remove elements from the locked specs that are expired. This will most
@@ -647,12 +741,11 @@ module Bundler
647
741
  # and Gemfile.lock. If the Gemfile modified a dependency, but
648
742
  # the gem in the Gemfile.lock still satisfies it, this is fine
649
743
  # too.
650
- locked_deps_hash = @locked_deps.inject({}) do |hsh, dep|
651
- hsh[dep] = dep
652
- hsh
653
- end
654
744
  @dependencies.each do |dep|
655
- locked_dep = locked_deps_hash[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
656
749
 
657
750
  if in_locked_deps?(dep, locked_dep) || satisfies_locked_spec?(dep)
658
751
  deps << dep
@@ -666,6 +759,8 @@ module Bundler
666
759
  end
667
760
  end
668
761
 
762
+ unlock_source_unlocks_spec = Bundler.feature_flag.unlock_source_unlocks_spec?
763
+
669
764
  converged = []
670
765
  @locked_specs.each do |s|
671
766
  # Replace the locked dependency's source with the equivalent source from the Gemfile
@@ -673,42 +768,60 @@ module Bundler
673
768
  s.source = (dep && dep.source) || sources.get(s.source)
674
769
 
675
770
  # Don't add a spec to the list if its source is expired. For example,
676
- # if you change a Git gem to Rubygems.
677
- next if s.source.nil? || @unlock[:sources].include?(s.source.name)
771
+ # if you change a Git gem to RubyGems.
772
+ next if s.source.nil?
773
+ next if @unlock[:sources].include?(s.source.name)
678
774
 
679
775
  # XXX This is a backwards-compatibility fix to preserve the ability to
680
776
  # unlock a single gem by passing its name via `--source`. See issue #3759
681
- next if s.source.nil? || @unlock[:sources].include?(s.name)
777
+ # TODO: delete in Bundler 2
778
+ next if unlock_source_unlocks_spec && @unlock[:sources].include?(s.name)
682
779
 
683
780
  # If the spec is from a path source and it doesn't exist anymore
684
781
  # then we unlock it.
685
782
 
686
783
  # Path sources have special logic
687
784
  if s.source.instance_of?(Source::Path) || s.source.instance_of?(Source::Gemspec)
688
- other = s.source.specs[s].first
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
689
798
 
690
799
  # If the spec is no longer in the path source, unlock it. This
691
800
  # commonly happens if the version changed in the gemspec
692
801
  next unless other
693
802
 
694
803
  deps2 = other.dependencies.select {|d| d.type != :development }
804
+ runtime_dependencies = s.dependencies.select {|d| d.type != :development }
695
805
  # If the dependencies of the path source have changed, unlock it
696
- next unless s.dependencies.sort == deps2.sort
806
+ next unless runtime_dependencies.sort == deps2.sort
697
807
  end
698
808
 
699
809
  converged << s
700
810
  end
701
811
 
702
812
  resolve = SpecSet.new(converged)
703
- resolve = resolve.for(expand_dependencies(deps, true), @unlock[:gems])
704
- diff = @locked_specs.to_a - resolve.to_a
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
705
817
 
706
818
  # Now, we unlock any sources that do not have anymore gems pinned to it
707
819
  sources.all_sources.each do |source|
708
820
  next unless source.respond_to?(:unlock!)
709
821
 
710
822
  unless resolve.any? {|s| s.source == source }
711
- source.unlock! if !diff.empty? && diff.any? {|s| s.source == source }
823
+ diff ||= @locked_specs.to_a - resolve.to_a
824
+ source.unlock! if diff.any? {|s| s.source == source }
712
825
  end
713
826
  end
714
827
 
@@ -723,19 +836,64 @@ module Bundler
723
836
  end
724
837
 
725
838
  def satisfies_locked_spec?(dep)
726
- @locked_specs.any? {|s| s.satisfies?(dep) && (!dep.source || s.source.include?(dep.source)) }
839
+ @locked_specs[dep].any? {|s| s.satisfies?(dep) && (!dep.source || s.source.include?(dep.source)) }
727
840
  end
728
841
 
842
+ # This list of dependencies is only used in #resolve, so it's OK to add
843
+ # the metadata dependencies here
729
844
  def expanded_dependencies
730
- @expanded_dependencies ||= expand_dependencies(dependencies, @remote)
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
731
878
  end
732
879
 
733
880
  def expand_dependencies(dependencies, remote = false)
881
+ sorted_platforms = Resolver.sort_platforms(@platforms)
734
882
  deps = []
735
883
  dependencies.each do |dep|
736
884
  dep = Dependency.new(dep, ">= 0") unless dep.respond_to?(:name)
737
- next unless remote || dep.current_platform?
738
- dep.gem_platforms(@platforms).each do |p|
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|
739
897
  deps << DepProxy.new(dep, p) if remote || p == generic_local_platform
740
898
  end
741
899
  end
@@ -755,30 +913,33 @@ module Bundler
755
913
  # Record the specs available in each gem's source, so that those
756
914
  # specs will be available later when the resolver knows where to
757
915
  # look for that gemspec (or its dependencies)
758
- source_requirements = {}
916
+ default = sources.default_source
917
+ source_requirements = { :default => default }
918
+ default = nil unless Bundler.feature_flag.lockfile_uses_separate_rubygems_sources?
759
919
  dependencies.each do |dep|
760
- next unless dep.source
761
- source_requirements[dep.name] = dep.source.specs
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
762
925
  end
926
+ source_requirements["bundler"] = sources.metadata_source # needs to come last to override
763
927
  source_requirements
764
928
  end
765
929
 
766
- def pinned_spec_names(specs)
767
- names = []
768
- specs.each do |s|
769
- # TODO: when two sources without blocks is an error, we can change
770
- # this check to !s.source.is_a?(Source::LocalRubygems). For now,
771
- # we need to ask every Rubygems for every gem name.
772
- if s.source.is_a?(Source::Git) || s.source.is_a?(Source::Path)
773
- names << s.name
774
- end
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
775
937
  end
776
- names.uniq!
777
- names
938
+ pinned_names
778
939
  end
779
940
 
780
941
  def requested_groups
781
- groups - Bundler.settings.without - @optional_groups + Bundler.settings.with
942
+ groups - Bundler.settings[:without] - @optional_groups + Bundler.settings[:with]
782
943
  end
783
944
 
784
945
  def lockfiles_equal?(current, proposed, preserve_unknown_sections)
@@ -812,11 +973,21 @@ module Bundler
812
973
  end
813
974
 
814
975
  def additional_base_requirements_for_resolve
815
- return [] unless @locked_gems && Bundler.settings[:only_update_to_newer_versions]
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) }
816
978
  @locked_gems.specs.reduce({}) do |requirements, locked_spec|
817
- requirements[locked_spec.name] = Gem::Dependency.new(locked_spec.name, ">= #{locked_spec.version}")
979
+ name = locked_spec.name
980
+ next requirements if @locked_gems.dependencies[name] != dependencies_by_name[name]
981
+ dep = Gem::Dependency.new(name, ">= #{locked_spec.version}")
982
+ requirements[name] = DepProxy.new(dep, locked_spec.platform)
818
983
  requirements
819
984
  end.values
820
985
  end
986
+
987
+ def equivalent_rubygems_remotes?(source)
988
+ return false unless source.is_a?(Source::Rubygems)
989
+
990
+ Bundler.settings[:allow_deployment_source_credential_changes] && source.equivalent_remotes?(sources.rubygems_remotes)
991
+ end
821
992
  end
822
993
  end