bundler 1.9.0 → 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 (328) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +1157 -6
  3. data/README.md +33 -6
  4. data/bundler.gemspec +51 -18
  5. data/exe/bundle +31 -0
  6. data/{bin → exe}/bundle_ruby +10 -6
  7. data/exe/bundler +4 -0
  8. data/lib/bundler.rb +326 -207
  9. data/lib/bundler/build_metadata.rb +53 -0
  10. data/lib/bundler/capistrano.rb +9 -3
  11. data/lib/bundler/cli.rb +522 -141
  12. data/lib/bundler/cli/add.rb +35 -0
  13. data/lib/bundler/cli/binstubs.rb +22 -11
  14. data/lib/bundler/cli/cache.rb +7 -6
  15. data/lib/bundler/cli/check.rb +11 -8
  16. data/lib/bundler/cli/clean.rb +7 -8
  17. data/lib/bundler/cli/common.rb +53 -7
  18. data/lib/bundler/cli/config.rb +84 -49
  19. data/lib/bundler/cli/console.rb +13 -8
  20. data/lib/bundler/cli/doctor.rb +140 -0
  21. data/lib/bundler/cli/exec.rb +77 -16
  22. data/lib/bundler/cli/gem.rb +120 -52
  23. data/lib/bundler/cli/info.rb +50 -0
  24. data/lib/bundler/cli/init.rb +21 -7
  25. data/lib/bundler/cli/inject.rb +37 -10
  26. data/lib/bundler/cli/install.rb +139 -78
  27. data/lib/bundler/cli/issue.rb +40 -0
  28. data/lib/bundler/cli/list.rb +58 -0
  29. data/lib/bundler/cli/lock.rb +63 -0
  30. data/lib/bundler/cli/open.rb +9 -6
  31. data/lib/bundler/cli/outdated.rb +221 -35
  32. data/lib/bundler/cli/package.rb +11 -7
  33. data/lib/bundler/cli/platform.rb +7 -4
  34. data/lib/bundler/cli/plugin.rb +24 -0
  35. data/lib/bundler/cli/pristine.rb +47 -0
  36. data/lib/bundler/cli/remove.rb +18 -0
  37. data/lib/bundler/cli/show.rb +11 -10
  38. data/lib/bundler/cli/update.rb +47 -29
  39. data/lib/bundler/cli/viz.rb +12 -8
  40. data/lib/bundler/compact_index_client.rb +109 -0
  41. data/lib/bundler/compact_index_client/cache.rb +118 -0
  42. data/lib/bundler/compact_index_client/updater.rb +116 -0
  43. data/lib/bundler/compatibility_guard.rb +14 -0
  44. data/lib/bundler/constants.rb +3 -1
  45. data/lib/bundler/current_ruby.rb +47 -137
  46. data/lib/bundler/definition.rb +599 -230
  47. data/lib/bundler/dep_proxy.rb +15 -10
  48. data/lib/bundler/dependency.rb +54 -25
  49. data/lib/bundler/deployment.rb +12 -2
  50. data/lib/bundler/deprecate.rb +33 -4
  51. data/lib/bundler/dsl.rb +383 -99
  52. data/lib/bundler/endpoint_specification.rb +72 -7
  53. data/lib/bundler/env.rb +121 -41
  54. data/lib/bundler/environment_preserver.rb +59 -0
  55. data/lib/bundler/errors.rb +158 -0
  56. data/lib/bundler/feature_flag.rb +74 -0
  57. data/lib/bundler/fetcher.rb +171 -280
  58. data/lib/bundler/fetcher/base.rb +52 -0
  59. data/lib/bundler/fetcher/compact_index.rb +126 -0
  60. data/lib/bundler/fetcher/dependency.rb +82 -0
  61. data/lib/bundler/fetcher/downloader.rb +84 -0
  62. data/lib/bundler/fetcher/index.rb +52 -0
  63. data/lib/bundler/friendly_errors.rb +113 -58
  64. data/lib/bundler/gem_helper.rb +73 -46
  65. data/lib/bundler/gem_helpers.rb +85 -9
  66. data/lib/bundler/gem_remote_fetcher.rb +43 -0
  67. data/lib/bundler/gem_tasks.rb +6 -1
  68. data/lib/bundler/gem_version_promoter.rb +190 -0
  69. data/lib/bundler/gemdeps.rb +29 -0
  70. data/lib/bundler/graph.rb +32 -49
  71. data/lib/bundler/index.rb +79 -67
  72. data/lib/bundler/injector.rb +219 -30
  73. data/lib/bundler/inline.rb +74 -0
  74. data/lib/bundler/installer.rb +191 -206
  75. data/lib/bundler/installer/gem_installer.rb +85 -0
  76. data/lib/bundler/installer/parallel_installer.rb +233 -0
  77. data/lib/bundler/installer/standalone.rb +53 -0
  78. data/lib/bundler/lazy_specification.rb +53 -13
  79. data/lib/bundler/lockfile_generator.rb +95 -0
  80. data/lib/bundler/lockfile_parser.rb +157 -62
  81. data/lib/bundler/match_platform.rb +15 -4
  82. data/lib/bundler/mirror.rb +223 -0
  83. data/lib/bundler/plugin.rb +292 -0
  84. data/lib/bundler/plugin/api.rb +81 -0
  85. data/lib/bundler/plugin/api/source.rb +306 -0
  86. data/lib/bundler/plugin/dsl.rb +53 -0
  87. data/lib/bundler/plugin/events.rb +61 -0
  88. data/lib/bundler/plugin/index.rb +162 -0
  89. data/lib/bundler/plugin/installer.rb +96 -0
  90. data/lib/bundler/plugin/installer/git.rb +38 -0
  91. data/lib/bundler/plugin/installer/rubygems.rb +27 -0
  92. data/lib/bundler/plugin/source_list.rb +27 -0
  93. data/lib/bundler/process_lock.rb +24 -0
  94. data/lib/bundler/psyched_yaml.rb +17 -6
  95. data/lib/bundler/remote_specification.rb +68 -11
  96. data/lib/bundler/resolver.rb +263 -229
  97. data/lib/bundler/resolver/spec_group.rb +106 -0
  98. data/lib/bundler/retry.rb +25 -19
  99. data/lib/bundler/ruby_dsl.rb +9 -2
  100. data/lib/bundler/ruby_version.rb +101 -66
  101. data/lib/bundler/rubygems_ext.rb +77 -37
  102. data/lib/bundler/rubygems_gem_installer.rb +106 -0
  103. data/lib/bundler/rubygems_integration.rb +450 -163
  104. data/lib/bundler/runtime.rb +133 -103
  105. data/lib/bundler/settings.rb +344 -83
  106. data/lib/bundler/settings/validator.rb +102 -0
  107. data/lib/bundler/setup.rb +7 -3
  108. data/lib/bundler/shared_helpers.rb +284 -54
  109. data/lib/bundler/similarity_detector.rb +21 -21
  110. data/lib/bundler/source.rb +68 -15
  111. data/lib/bundler/source/gemspec.rb +18 -0
  112. data/lib/bundler/source/git.rb +90 -55
  113. data/lib/bundler/source/git/git_proxy.rb +135 -35
  114. data/lib/bundler/source/metadata.rb +62 -0
  115. data/lib/bundler/source/path.rb +84 -61
  116. data/lib/bundler/source/path/installer.rb +53 -17
  117. data/lib/bundler/source/rubygems.rb +282 -122
  118. data/lib/bundler/source/rubygems/remote.rb +69 -0
  119. data/lib/bundler/source_list.rb +107 -22
  120. data/lib/bundler/spec_set.rb +83 -45
  121. data/lib/bundler/ssl_certs/certificate_manager.rb +8 -7
  122. data/lib/bundler/ssl_certs/index.rubygems.org/GlobalSignRootCA.pem +21 -0
  123. data/lib/bundler/ssl_certs/{DigiCertHighAssuranceEVRootCA.pem → rubygems.global.ssl.fastly.net/DigiCertHighAssuranceEVRootCA.pem} +0 -0
  124. data/lib/bundler/ssl_certs/{AddTrustExternalCARoot-2048.pem → rubygems.org/AddTrustExternalCARoot.pem} +0 -0
  125. data/lib/bundler/stub_specification.rb +108 -0
  126. data/lib/bundler/templates/.document +1 -0
  127. data/lib/bundler/templates/Executable +19 -6
  128. data/lib/bundler/templates/Executable.bundler +105 -0
  129. data/lib/bundler/templates/Executable.standalone +6 -4
  130. data/lib/bundler/templates/Gemfile +4 -1
  131. data/lib/bundler/templates/gems.rb +8 -0
  132. data/lib/bundler/templates/newgem/CODE_OF_CONDUCT.md.tt +68 -7
  133. data/lib/bundler/templates/newgem/Gemfile.tt +4 -2
  134. data/lib/bundler/templates/newgem/LICENSE.txt.tt +1 -1
  135. data/lib/bundler/templates/newgem/README.md.tt +19 -11
  136. data/lib/bundler/templates/newgem/Rakefile.tt +10 -6
  137. data/lib/bundler/templates/newgem/bin/console.tt +1 -1
  138. data/lib/bundler/templates/newgem/bin/setup.tt +2 -1
  139. data/lib/bundler/templates/newgem/ext/newgem/newgem.c.tt +4 -4
  140. data/lib/bundler/templates/newgem/ext/newgem/newgem.h.tt +3 -3
  141. data/lib/bundler/templates/newgem/gitignore.tt +5 -1
  142. data/lib/bundler/templates/newgem/lib/newgem.rb.tt +7 -6
  143. data/lib/bundler/templates/newgem/lib/newgem/version.rb.tt +4 -4
  144. data/lib/bundler/templates/newgem/newgem.gemspec.tt +31 -15
  145. data/lib/bundler/templates/newgem/rspec.tt +1 -0
  146. data/lib/bundler/templates/newgem/spec/newgem_spec.rb.tt +3 -5
  147. data/lib/bundler/templates/newgem/spec/spec_helper.rb.tt +14 -2
  148. data/lib/bundler/templates/newgem/test/{test_newgem.rb.tt → newgem_test.rb.tt} +2 -2
  149. data/lib/bundler/templates/newgem/test/test_helper.rb.tt +4 -0
  150. data/lib/bundler/templates/newgem/travis.yml.tt +7 -0
  151. data/lib/bundler/ui.rb +5 -3
  152. data/lib/bundler/ui/rg_proxy.rb +5 -7
  153. data/lib/bundler/ui/shell.rb +69 -18
  154. data/lib/bundler/ui/silent.rb +26 -1
  155. data/lib/bundler/uri_credentials_filter.rb +37 -0
  156. data/lib/bundler/vendor/fileutils/lib/fileutils.rb +1638 -0
  157. data/lib/bundler/vendor/molinillo/lib/molinillo.rb +12 -0
  158. data/lib/bundler/vendor/molinillo/lib/molinillo/compatibility.rb +26 -0
  159. data/lib/bundler/vendor/molinillo/lib/molinillo/delegates/resolution_state.rb +57 -0
  160. data/lib/bundler/vendor/molinillo/lib/molinillo/delegates/specification_provider.rb +81 -0
  161. data/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph.rb +223 -0
  162. data/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/action.rb +36 -0
  163. data/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/add_edge_no_circular.rb +66 -0
  164. data/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/add_vertex.rb +62 -0
  165. data/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/delete_edge.rb +63 -0
  166. data/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/detach_vertex_named.rb +61 -0
  167. data/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/log.rb +126 -0
  168. data/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/set_payload.rb +46 -0
  169. data/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/tag.rb +36 -0
  170. data/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/vertex.rb +136 -0
  171. data/lib/bundler/vendor/molinillo/lib/molinillo/errors.rb +143 -0
  172. data/lib/bundler/vendor/molinillo/lib/molinillo/gem_metadata.rb +6 -0
  173. data/lib/bundler/vendor/{Molinillo-0.2.1 → molinillo}/lib/molinillo/modules/specification_provider.rb +11 -0
  174. data/lib/bundler/vendor/{Molinillo-0.2.1 → molinillo}/lib/molinillo/modules/ui.rb +6 -2
  175. data/lib/bundler/vendor/molinillo/lib/molinillo/resolution.rb +837 -0
  176. data/lib/bundler/vendor/{Molinillo-0.2.1 → molinillo}/lib/molinillo/resolver.rb +6 -3
  177. data/lib/bundler/vendor/molinillo/lib/molinillo/state.rb +58 -0
  178. data/lib/bundler/vendor/{net → net-http-persistent/lib/net}/http/faster.rb +1 -0
  179. data/lib/bundler/vendor/{net → net-http-persistent/lib/net}/http/persistent.rb +27 -24
  180. data/lib/bundler/vendor/{net → net-http-persistent/lib/net}/http/persistent/ssl_reuse.rb +2 -1
  181. data/lib/bundler/vendor/{thor-0.19.1 → thor}/lib/thor.rb +47 -22
  182. data/lib/bundler/vendor/{thor-0.19.1 → thor}/lib/thor/actions.rb +31 -29
  183. data/lib/bundler/vendor/{thor-0.19.1 → thor}/lib/thor/actions/create_file.rb +3 -2
  184. data/lib/bundler/vendor/{thor-0.19.1 → thor}/lib/thor/actions/create_link.rb +3 -2
  185. data/lib/bundler/vendor/{thor-0.19.1 → thor}/lib/thor/actions/directory.rb +3 -3
  186. data/lib/bundler/vendor/{thor-0.19.1 → thor}/lib/thor/actions/empty_directory.rb +16 -8
  187. data/lib/bundler/vendor/{thor-0.19.1 → thor}/lib/thor/actions/file_manipulation.rb +66 -18
  188. data/lib/bundler/vendor/{thor-0.19.1 → thor}/lib/thor/actions/inject_into_file.rb +18 -16
  189. data/lib/bundler/vendor/{thor-0.19.1 → thor}/lib/thor/base.rb +67 -44
  190. data/lib/bundler/vendor/{thor-0.19.1 → thor}/lib/thor/command.rb +13 -11
  191. data/lib/bundler/vendor/{thor-0.19.1 → thor}/lib/thor/core_ext/hash_with_indifferent_access.rb +21 -1
  192. data/lib/bundler/vendor/thor/lib/thor/core_ext/io_binary_read.rb +12 -0
  193. data/lib/bundler/vendor/thor/lib/thor/core_ext/ordered_hash.rb +129 -0
  194. data/lib/bundler/vendor/{thor-0.19.1 → thor}/lib/thor/error.rb +3 -3
  195. data/lib/bundler/vendor/{thor-0.19.1 → thor}/lib/thor/group.rb +14 -14
  196. data/lib/bundler/vendor/{thor-0.19.1 → thor}/lib/thor/invocation.rb +4 -5
  197. data/lib/bundler/vendor/{thor-0.19.1 → thor}/lib/thor/line_editor.rb +2 -2
  198. data/lib/bundler/vendor/{thor-0.19.1 → thor}/lib/thor/line_editor/basic.rb +2 -0
  199. data/lib/bundler/vendor/{thor-0.19.1 → thor}/lib/thor/line_editor/readline.rb +0 -0
  200. data/lib/bundler/vendor/thor/lib/thor/parser.rb +4 -0
  201. data/lib/bundler/vendor/{thor-0.19.1 → thor}/lib/thor/parser/argument.rb +4 -7
  202. data/lib/bundler/vendor/{thor-0.19.1 → thor}/lib/thor/parser/arguments.rb +16 -16
  203. data/lib/bundler/vendor/{thor-0.19.1 → thor}/lib/thor/parser/option.rb +42 -21
  204. data/lib/bundler/vendor/{thor-0.19.1 → thor}/lib/thor/parser/options.rb +13 -10
  205. data/lib/bundler/vendor/{thor-0.19.1 → thor}/lib/thor/rake_compat.rb +1 -1
  206. data/lib/bundler/vendor/{thor-0.19.1 → thor}/lib/thor/runner.rb +35 -33
  207. data/lib/bundler/vendor/{thor-0.19.1 → thor}/lib/thor/shell.rb +4 -4
  208. data/lib/bundler/vendor/{thor-0.19.1 → thor}/lib/thor/shell/basic.rb +49 -33
  209. data/lib/bundler/vendor/{thor-0.19.1 → thor}/lib/thor/shell/color.rb +2 -2
  210. data/lib/bundler/vendor/{thor-0.19.1 → thor}/lib/thor/shell/html.rb +5 -5
  211. data/lib/bundler/vendor/{thor-0.19.1 → thor}/lib/thor/util.rb +8 -7
  212. data/lib/bundler/vendor/{thor-0.19.1 → thor}/lib/thor/version.rb +1 -1
  213. data/lib/bundler/vendored_fileutils.rb +9 -0
  214. data/lib/bundler/vendored_molinillo.rb +4 -5
  215. data/lib/bundler/vendored_persistent.rb +45 -4
  216. data/lib/bundler/vendored_thor.rb +8 -5
  217. data/lib/bundler/version.rb +23 -1
  218. data/lib/bundler/version_ranges.rb +76 -0
  219. data/lib/bundler/vlad.rb +8 -2
  220. data/lib/bundler/worker.rb +39 -6
  221. data/lib/bundler/yaml_serializer.rb +90 -0
  222. data/man/bundle-add.1 +58 -0
  223. data/man/bundle-add.1.txt +52 -0
  224. data/man/bundle-add.ronn +40 -0
  225. data/man/bundle-binstubs.1 +40 -0
  226. data/man/bundle-binstubs.1.txt +48 -0
  227. data/man/bundle-binstubs.ronn +43 -0
  228. data/man/bundle-check.1 +31 -0
  229. data/man/bundle-check.1.txt +33 -0
  230. data/man/bundle-check.ronn +26 -0
  231. data/man/bundle-clean.1 +24 -0
  232. data/man/bundle-clean.1.txt +26 -0
  233. data/man/bundle-clean.ronn +18 -0
  234. data/man/bundle-config.1 +497 -0
  235. data/man/bundle-config.1.txt +529 -0
  236. data/man/bundle-config.ronn +256 -31
  237. data/man/bundle-doctor.1 +44 -0
  238. data/man/bundle-doctor.1.txt +44 -0
  239. data/man/bundle-doctor.ronn +33 -0
  240. data/man/bundle-exec.1 +165 -0
  241. data/man/bundle-exec.1.txt +178 -0
  242. data/man/bundle-exec.ronn +19 -3
  243. data/man/bundle-gem.1 +80 -0
  244. data/man/bundle-gem.1.txt +91 -0
  245. data/man/bundle-gem.ronn +78 -0
  246. data/man/bundle-info.1 +20 -0
  247. data/man/bundle-info.1.txt +21 -0
  248. data/man/bundle-info.ronn +17 -0
  249. data/man/bundle-init.1 +25 -0
  250. data/man/bundle-init.1.txt +34 -0
  251. data/man/bundle-init.ronn +29 -0
  252. data/man/bundle-inject.1 +33 -0
  253. data/man/bundle-inject.1.txt +32 -0
  254. data/man/bundle-inject.ronn +22 -0
  255. data/man/bundle-install.1 +308 -0
  256. data/man/bundle-install.1.txt +396 -0
  257. data/man/bundle-install.ronn +64 -67
  258. data/man/bundle-list.1 +50 -0
  259. data/man/bundle-list.1.txt +43 -0
  260. data/man/bundle-list.ronn +33 -0
  261. data/man/bundle-lock.1 +84 -0
  262. data/man/bundle-lock.1.txt +93 -0
  263. data/man/bundle-lock.ronn +94 -0
  264. data/man/bundle-open.1 +32 -0
  265. data/man/bundle-open.1.txt +29 -0
  266. data/man/bundle-open.ronn +19 -0
  267. data/man/bundle-outdated.1 +155 -0
  268. data/man/bundle-outdated.1.txt +131 -0
  269. data/man/bundle-outdated.ronn +111 -0
  270. data/man/bundle-package.1 +55 -0
  271. data/man/bundle-package.1.txt +79 -0
  272. data/man/bundle-package.ronn +14 -8
  273. data/man/bundle-platform.1 +61 -0
  274. data/man/bundle-platform.1.txt +57 -0
  275. data/man/bundle-platform.ronn +1 -1
  276. data/man/bundle-pristine.1 +34 -0
  277. data/man/bundle-pristine.1.txt +44 -0
  278. data/man/bundle-pristine.ronn +34 -0
  279. data/man/bundle-remove.1 +31 -0
  280. data/man/bundle-remove.1.txt +34 -0
  281. data/man/bundle-remove.ronn +23 -0
  282. data/man/bundle-show.1 +23 -0
  283. data/man/bundle-show.1.txt +27 -0
  284. data/man/bundle-show.ronn +21 -0
  285. data/man/bundle-update.1 +394 -0
  286. data/man/bundle-update.1.txt +391 -0
  287. data/man/bundle-update.ronn +180 -18
  288. data/man/bundle-viz.1 +39 -0
  289. data/man/bundle-viz.1.txt +39 -0
  290. data/man/bundle-viz.ronn +30 -0
  291. data/man/bundle.1 +136 -0
  292. data/man/bundle.1.txt +116 -0
  293. data/man/bundle.ronn +46 -33
  294. data/man/gemfile.5 +689 -0
  295. data/man/gemfile.5.ronn +127 -79
  296. data/man/gemfile.5.txt +653 -0
  297. data/man/index.txt +25 -7
  298. metadata +242 -95
  299. data/.gitignore +0 -16
  300. data/.rspec +0 -3
  301. data/.travis.yml +0 -110
  302. data/CODE_OF_CONDUCT.md +0 -40
  303. data/CONTRIBUTING.md +0 -32
  304. data/DEVELOPMENT.md +0 -119
  305. data/ISSUES.md +0 -96
  306. data/Rakefile +0 -302
  307. data/UPGRADING.md +0 -103
  308. data/bin/bundle +0 -21
  309. data/bin/bundler +0 -21
  310. data/lib/bundler/anonymizable_uri.rb +0 -32
  311. data/lib/bundler/environment.rb +0 -42
  312. data/lib/bundler/gem_installer.rb +0 -9
  313. data/lib/bundler/gem_path_manipulation.rb +0 -8
  314. data/lib/bundler/ssl_certs/AddTrustExternalCARoot.pem +0 -32
  315. data/lib/bundler/ssl_certs/Class3PublicPrimaryCertificationAuthority.pem +0 -14
  316. data/lib/bundler/ssl_certs/EntrustnetSecureServerCertificationAuthority.pem +0 -28
  317. data/lib/bundler/ssl_certs/GeoTrustGlobalCA.pem +0 -20
  318. data/lib/bundler/templates/newgem/.travis.yml.tt +0 -3
  319. data/lib/bundler/templates/newgem/test/minitest_helper.rb.tt +0 -4
  320. data/lib/bundler/vendor/Molinillo-0.2.1/lib/molinillo.rb +0 -5
  321. data/lib/bundler/vendor/Molinillo-0.2.1/lib/molinillo/dependency_graph.rb +0 -266
  322. data/lib/bundler/vendor/Molinillo-0.2.1/lib/molinillo/errors.rb +0 -69
  323. data/lib/bundler/vendor/Molinillo-0.2.1/lib/molinillo/gem_metadata.rb +0 -3
  324. data/lib/bundler/vendor/Molinillo-0.2.1/lib/molinillo/resolution.rb +0 -412
  325. data/lib/bundler/vendor/Molinillo-0.2.1/lib/molinillo/state.rb +0 -43
  326. data/lib/bundler/vendor/thor-0.19.1/lib/thor/core_ext/io_binary_read.rb +0 -10
  327. data/lib/bundler/vendor/thor-0.19.1/lib/thor/core_ext/ordered_hash.rb +0 -98
  328. data/lib/bundler/vendor/thor-0.19.1/lib/thor/parser.rb +0 -4
@@ -1,38 +1,74 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Bundler
2
4
  class Source
3
5
  class Path
6
+ class Installer < Bundler::RubyGemsGemInstaller
7
+ attr_reader :spec
4
8
 
5
- class Installer < Bundler::GemInstaller
6
9
  def initialize(spec, options = {})
7
- @spec = spec
8
- @tmp_bin_dir = "#{Bundler.tmp(spec.full_name)}/bin"
9
- @gem_bin_dir = "#{Bundler.rubygems.gem_dir}/bin"
10
- @bin_dir = Bundler.requires_sudo? ? @tmp_bin_dir : @gem_bin_dir
11
- @gem_dir = Bundler.rubygems.path(spec.full_gem_path)
12
- @wrappers = options[:wrappers] || true
13
- @env_shebang = options[:env_shebang] || true
14
- @format_executable = options[:format_executable] || false
15
- @build_args = options[:build_args] || Bundler.rubygems.build_args
10
+ @options = options
11
+ @spec = spec
12
+ @gem_dir = Bundler.rubygems.path(spec.full_gem_path)
13
+ @wrappers = true
14
+ @env_shebang = true
15
+ @format_executable = options[:format_executable] || false
16
+ @build_args = options[:build_args] || Bundler.rubygems.build_args
17
+ @gem_bin_dir = "#{Bundler.rubygems.gem_dir}/bin"
18
+ @disable_extensions = options[:disable_extensions]
19
+
20
+ if Bundler.requires_sudo?
21
+ @tmp_dir = Bundler.tmp(spec.full_name).to_s
22
+ @bin_dir = "#{@tmp_dir}/bin"
23
+ else
24
+ @bin_dir = @gem_bin_dir
25
+ end
16
26
  end
17
27
 
18
- def generate_bin
19
- return if spec.executables.nil? || spec.executables.empty?
28
+ def post_install
29
+ SharedHelpers.chdir(@gem_dir) do
30
+ run_hooks(:pre_install)
20
31
 
21
- if Bundler.requires_sudo?
22
- FileUtils.mkdir_p(@tmp_bin_dir) unless File.exist?(@tmp_bin_dir)
32
+ unless @disable_extensions
33
+ build_extensions
34
+ run_hooks(:post_build)
35
+ end
36
+
37
+ generate_bin unless spec.executables.nil? || spec.executables.empty?
38
+
39
+ run_hooks(:post_install)
23
40
  end
41
+ ensure
42
+ Bundler.rm_rf(@tmp_dir) if Bundler.requires_sudo?
43
+ end
44
+
45
+ private
24
46
 
47
+ def generate_bin
25
48
  super
26
49
 
27
50
  if Bundler.requires_sudo?
28
- Bundler.mkdir_p @gem_bin_dir
51
+ SharedHelpers.filesystem_access(@gem_bin_dir) do |p|
52
+ Bundler.mkdir_p(p)
53
+ end
29
54
  spec.executables.each do |exe|
30
- Bundler.sudo "cp -R #{@tmp_bin_dir}/#{exe} #{@gem_bin_dir}"
55
+ Bundler.sudo "cp -R #{@bin_dir}/#{exe} #{@gem_bin_dir}"
31
56
  end
32
57
  end
33
58
  end
34
- end
35
59
 
60
+ def run_hooks(type)
61
+ hooks_meth = "#{type}_hooks"
62
+ return unless Gem.respond_to?(hooks_meth)
63
+ Gem.send(hooks_meth).each do |hook|
64
+ result = hook.call(self)
65
+ next unless result == false
66
+ location = " at #{$1}" if hook.inspect =~ /@(.*:\d+)/
67
+ message = "#{type} hook#{location} failed for #{spec.full_name}"
68
+ raise InstallHookError, message
69
+ end
70
+ end
71
+ end
36
72
  end
37
73
  end
38
74
  end
@@ -1,10 +1,13 @@
1
- require 'uri'
2
- require 'rubygems/user_interaction'
3
- require 'rubygems/spec_fetcher'
1
+ # frozen_string_literal: true
2
+
3
+ require "uri"
4
+ require "rubygems/user_interaction"
4
5
 
5
6
  module Bundler
6
7
  class Source
7
8
  class Rubygems < Source
9
+ autoload :Remote, "bundler/source/rubygems/remote"
10
+
8
11
  # Use the API when installing less than X gems
9
12
  API_REQUEST_LIMIT = 500
10
13
  # Ask for X gems per API request
@@ -18,16 +21,18 @@ module Bundler
18
21
  @dependency_names = []
19
22
  @allow_remote = false
20
23
  @allow_cached = false
21
- @caches = [Bundler.app_cache, *Bundler.rubygems.gem_cache]
24
+ @caches = [cache_path, *Bundler.rubygems.gem_cache]
22
25
 
23
- Array(options["remotes"] || []).reverse_each{|r| add_remote(r) }
26
+ Array(options["remotes"] || []).reverse_each {|r| add_remote(r) }
24
27
  end
25
28
 
26
29
  def remote!
30
+ @specs = nil
27
31
  @allow_remote = true
28
32
  end
29
33
 
30
34
  def cached!
35
+ @specs = nil
31
36
  @allow_cached = true
32
37
  end
33
38
 
@@ -35,18 +40,23 @@ module Bundler
35
40
  @remotes.hash
36
41
  end
37
42
 
38
- def eql?(o)
39
- o.is_a?(Rubygems) && remotes_equal?(o.remotes)
43
+ def eql?(other)
44
+ other.is_a?(Rubygems) && other.credless_remotes == credless_remotes
40
45
  end
41
46
 
42
- alias == eql?
47
+ alias_method :==, :eql?
48
+
49
+ def include?(o)
50
+ o.is_a?(Rubygems) && (o.credless_remotes - credless_remotes).empty?
51
+ end
43
52
 
44
53
  def can_lock?(spec)
54
+ return super if Bundler.feature_flag.lockfile_uses_separate_rubygems_sources?
45
55
  spec.source.is_a?(Rubygems)
46
56
  end
47
57
 
48
58
  def options
49
- { "remotes" => @remotes.map { |r| r.to_s } }
59
+ { "remotes" => @remotes.map(&:to_s) }
50
60
  end
51
61
 
52
62
  def self.from_lock(options)
@@ -54,7 +64,7 @@ module Bundler
54
64
  end
55
65
 
56
66
  def to_lock
57
- out = "GEM\n"
67
+ out = String.new("GEM\n")
58
68
  remotes.reverse_each do |remote|
59
69
  out << " remote: #{suppress_configured_credentials remote}\n"
60
70
  end
@@ -62,8 +72,12 @@ module Bundler
62
72
  end
63
73
 
64
74
  def to_s
65
- remote_names = self.remotes.map { |r| r.to_s }.join(', ')
66
- "rubygems repository #{remote_names}"
75
+ if remotes.empty?
76
+ "locally installed gems"
77
+ else
78
+ remote_names = remotes.map(&:to_s).join(", ")
79
+ "rubygems repository #{remote_names} or installed locally"
80
+ end
67
81
  end
68
82
  alias_method :name, :to_s
69
83
 
@@ -79,15 +93,30 @@ module Bundler
79
93
  end
80
94
  end
81
95
 
82
- def install(spec)
83
- return ["Using #{version_message(spec)}", nil] if installed_specs[spec].any?
96
+ def install(spec, opts = {})
97
+ force = opts[:force]
98
+ ensure_builtin_gems_cached = opts[:ensure_builtin_gems_cached]
99
+
100
+ if ensure_builtin_gems_cached && builtin_gem?(spec)
101
+ if !cached_path(spec)
102
+ cached_built_in_gem(spec) unless spec.remote
103
+ force = true
104
+ else
105
+ spec.loaded_from = loaded_from(spec)
106
+ end
107
+ end
108
+
109
+ if installed?(spec) && !force
110
+ print_using_message "Using #{version_message(spec)}"
111
+ return nil # no post-install message
112
+ end
84
113
 
85
114
  # Download the gem to get the spec, because some specs that are returned
86
115
  # by rubygems.org are broken and wrong.
87
- if spec.source_uri
116
+ if spec.remote
88
117
  # Check for this spec from other sources
89
- uris = [spec.source_uri.without_credentials]
90
- uris += source_uris_for_spec(spec)
118
+ uris = [spec.remote.anonymized_uri]
119
+ uris += remotes_for_spec(spec).map(&:anonymized_uri)
91
120
  uris.uniq!
92
121
  Installer.ambiguous_gems << [spec.name, *uris] if uris.length > 1
93
122
 
@@ -96,54 +125,68 @@ module Bundler
96
125
  end
97
126
 
98
127
  unless Bundler.settings[:no_install]
128
+ message = "Installing #{version_message(spec)}"
129
+ message += " with native extensions" if spec.extensions.any?
130
+ Bundler.ui.confirm message
131
+
99
132
  path = cached_gem(spec)
100
- if Bundler.requires_sudo?
133
+ if requires_sudo?
101
134
  install_path = Bundler.tmp(spec.full_name)
102
135
  bin_path = install_path.join("bin")
103
136
  else
104
- install_path = Bundler.rubygems.gem_dir
137
+ install_path = rubygems_dir
105
138
  bin_path = Bundler.system_bindir
106
139
  end
107
140
 
141
+ Bundler.mkdir_p bin_path, :no_sudo => true unless spec.executables.empty? || Bundler.rubygems.provides?(">= 2.7.5")
142
+
108
143
  installed_spec = nil
109
144
  Bundler.rubygems.preserve_paths do
110
- installed_spec = Bundler::GemInstaller.new(path,
145
+ installed_spec = Bundler::RubyGemsGemInstaller.at(
146
+ path,
111
147
  :install_dir => install_path.to_s,
112
148
  :bin_dir => bin_path.to_s,
113
149
  :ignore_dependencies => true,
114
150
  :wrappers => true,
115
- :env_shebang => true
151
+ :env_shebang => true,
152
+ :build_args => opts[:build_args],
153
+ :bundler_expected_checksum => spec.respond_to?(:checksum) && spec.checksum,
154
+ :bundler_extension_cache_path => extension_cache_path(spec)
116
155
  ).install
117
156
  end
157
+ spec.full_gem_path = installed_spec.full_gem_path
118
158
 
119
159
  # SUDO HAX
120
- if Bundler.requires_sudo?
160
+ if requires_sudo?
121
161
  Bundler.rubygems.repository_subdirectories.each do |name|
122
162
  src = File.join(install_path, name, "*")
123
- dst = File.join(Bundler.rubygems.gem_dir, name)
163
+ dst = File.join(rubygems_dir, name)
124
164
  if name == "extensions" && Dir.glob(src).any?
125
165
  src = File.join(src, "*/*")
126
166
  ext_src = Dir.glob(src).first
127
- ext_src.gsub!(src[0..-6], '')
167
+ ext_src.gsub!(src[0..-6], "")
128
168
  dst = File.dirname(File.join(dst, ext_src))
129
169
  end
130
- Bundler.mkdir_p dst
170
+ SharedHelpers.filesystem_access(dst) do |p|
171
+ Bundler.mkdir_p(p)
172
+ end
131
173
  Bundler.sudo "cp -R #{src} #{dst}" if Dir[src].any?
132
174
  end
133
175
 
134
176
  spec.executables.each do |exe|
135
- Bundler.mkdir_p Bundler.system_bindir
177
+ SharedHelpers.filesystem_access(Bundler.system_bindir) do |p|
178
+ Bundler.mkdir_p(p)
179
+ end
136
180
  Bundler.sudo "cp -R #{install_path}/bin/#{exe} #{Bundler.system_bindir}/"
137
181
  end
138
182
  end
139
183
  installed_spec.loaded_from = loaded_from(spec)
140
184
  end
141
185
  spec.loaded_from = loaded_from(spec)
142
- ["Installing #{version_message(spec)}", spec.post_install_message]
186
+
187
+ spec.post_install_message
143
188
  ensure
144
- if install_path && Bundler.requires_sudo?
145
- FileUtils.remove_entry_secure(install_path)
146
- end
189
+ Bundler.rm_rf(install_path) if requires_sudo?
147
190
  end
148
191
 
149
192
  def cache(spec, custom_path = nil)
@@ -165,7 +208,11 @@ module Bundler
165
208
  cached_path = cached_path(spec)
166
209
  if cached_path.nil?
167
210
  remote_spec = remote_specs.search(spec).first
168
- cached_path = fetch_gem(remote_spec)
211
+ if remote_spec
212
+ cached_path = fetch_gem(remote_spec)
213
+ else
214
+ Bundler.ui.warn "#{spec.full_name} is built in to Ruby, and can't be cached because your Gemfile doesn't have any sources that contain it."
215
+ end
169
216
  end
170
217
  cached_path
171
218
  end
@@ -175,13 +222,21 @@ module Bundler
175
222
  @remotes.unshift(uri) unless @remotes.include?(uri)
176
223
  end
177
224
 
178
- def replace_remotes(other_remotes)
225
+ def equivalent_remotes?(other_remotes)
226
+ other_remotes.map(&method(:remove_auth)) == @remotes.map(&method(:remove_auth))
227
+ end
228
+
229
+ def replace_remotes(other_remotes, allow_equivalent = false)
179
230
  return false if other_remotes == @remotes
180
231
 
232
+ equivalent = allow_equivalent && equivalent_remotes?(other_remotes)
233
+
181
234
  @remotes = []
182
235
  other_remotes.reverse_each do |r|
183
236
  add_remote r.to_s
184
237
  end
238
+
239
+ !equivalent
185
240
  end
186
241
 
187
242
  def unmet_deps
@@ -194,23 +249,61 @@ module Bundler
194
249
 
195
250
  def fetchers
196
251
  @fetchers ||= remotes.map do |uri|
197
- Bundler::Fetcher.new(uri)
252
+ remote = Source::Rubygems::Remote.new(uri)
253
+ Bundler::Fetcher.new(remote)
198
254
  end
199
255
  end
200
256
 
257
+ def double_check_for(unmet_dependency_names)
258
+ return unless @allow_remote
259
+ return unless api_fetchers.any?
260
+
261
+ unmet_dependency_names = unmet_dependency_names.call
262
+ unless unmet_dependency_names.nil?
263
+ if api_fetchers.size <= 1
264
+ # can't do this when there are multiple fetchers because then we might not fetch from _all_
265
+ # of them
266
+ unmet_dependency_names -= remote_specs.spec_names # avoid re-fetching things we've already gotten
267
+ end
268
+ return if unmet_dependency_names.empty?
269
+ end
270
+
271
+ Bundler.ui.debug "Double checking for #{unmet_dependency_names || "all specs (due to the size of the request)"} in #{self}"
272
+
273
+ fetch_names(api_fetchers, unmet_dependency_names, specs, false)
274
+ end
275
+
276
+ def dependency_names_to_double_check
277
+ names = []
278
+ remote_specs.each do |spec|
279
+ case spec
280
+ when EndpointSpecification, Gem::Specification, StubSpecification, LazySpecification
281
+ names.concat(spec.runtime_dependencies)
282
+ when RemoteSpecification # from the full index
283
+ return nil
284
+ else
285
+ raise "unhandled spec type (#{spec.inspect})"
286
+ end
287
+ end
288
+ names.map!(&:name) if names
289
+ names
290
+ end
291
+
201
292
  protected
202
293
 
203
- def source_uris_for_spec(spec)
294
+ def credless_remotes
295
+ remotes.map(&method(:suppress_configured_credentials))
296
+ end
297
+
298
+ def remotes_for_spec(spec)
204
299
  specs.search_all(spec.name).inject([]) do |uris, s|
205
- uris << s.source_uri.without_credentials if s.source_uri
300
+ uris << s.remote if s.remote
206
301
  uris
207
302
  end
208
303
  end
209
304
 
210
- private
211
-
212
305
  def loaded_from(spec)
213
- "#{Bundler.rubygems.gem_dir}/specifications/#{spec.full_name}.gemspec"
306
+ "#{rubygems_dir}/specifications/#{spec.full_name}.gemspec"
214
307
  end
215
308
 
216
309
  def cached_gem(spec)
@@ -222,20 +315,21 @@ module Bundler
222
315
  end
223
316
 
224
317
  def cached_path(spec)
225
- possibilities = @caches.map { |p| "#{p}/#{spec.file_name}" }
226
- possibilities.find { |p| File.exist?(p) }
318
+ possibilities = @caches.map {|p| "#{p}/#{spec.file_name}" }
319
+ possibilities.find {|p| File.exist?(p) }
227
320
  end
228
321
 
229
322
  def normalize_uri(uri)
230
323
  uri = uri.to_s
231
- uri = "#{uri}/" unless uri =~ %r'/$'
324
+ uri = "#{uri}/" unless uri =~ %r{/$}
232
325
  uri = URI(uri)
233
- raise ArgumentError, "The source must be an absolute URI" unless uri.absolute?
326
+ raise ArgumentError, "The source must be an absolute URI. For example:\n" \
327
+ "source 'https://rubygems.org'" if !uri.absolute? || (uri.is_a?(URI::HTTP) && uri.host.nil?)
234
328
  uri
235
329
  end
236
330
 
237
331
  def suppress_configured_credentials(remote)
238
- remote_nouser = remote.dup.tap { |uri| uri.user = uri.password = nil }.to_s
332
+ remote_nouser = remove_auth(remote)
239
333
  if remote.userinfo && remote.userinfo == Bundler.settings[remote_nouser]
240
334
  remote_nouser
241
335
  else
@@ -243,33 +337,25 @@ module Bundler
243
337
  end
244
338
  end
245
339
 
340
+ def remove_auth(remote)
341
+ if remote.user || remote.password
342
+ remote.dup.tap {|uri| uri.user = uri.password = nil }.to_s
343
+ else
344
+ remote.to_s
345
+ end
346
+ end
347
+
246
348
  def installed_specs
247
- @installed_specs ||= begin
248
- idx = Index.new
249
- have_bundler = false
250
- Bundler.rubygems.all_specs.reverse.each do |spec|
251
- next if spec.name == 'bundler' && spec.version.to_s != VERSION
252
- have_bundler = true if spec.name == 'bundler'
349
+ @installed_specs ||= Index.build do |idx|
350
+ Bundler.rubygems.all_specs.reverse_each do |spec|
351
+ next if spec.name == "bundler"
253
352
  spec.source = self
353
+ if Bundler.rubygems.spec_missing_extensions?(spec, false)
354
+ Bundler.ui.debug "Source #{self} is ignoring #{spec} because it is missing extensions"
355
+ next
356
+ end
254
357
  idx << spec
255
358
  end
256
-
257
- # Always have bundler locally
258
- unless have_bundler
259
- # We're running bundler directly from the source
260
- # so, let's create a fake gemspec for it (it's a path)
261
- # gemspec
262
- bundler = Gem::Specification.new do |s|
263
- s.name = 'bundler'
264
- s.version = VERSION
265
- s.platform = Gem::Platform::RUBY
266
- s.source = self
267
- s.authors = ["bundler team"]
268
- s.loaded_from = File.expand_path("..", __FILE__)
269
- end
270
- idx << bundler
271
- end
272
- idx
273
359
  end
274
360
  end
275
361
 
@@ -277,20 +363,23 @@ module Bundler
277
363
  @cached_specs ||= begin
278
364
  idx = installed_specs.dup
279
365
 
280
- path = Bundler.app_cache
281
- Dir["#{path}/*.gem"].each do |gemfile|
366
+ Dir["#{cache_path}/*.gem"].each do |gemfile|
282
367
  next if gemfile =~ /^bundler\-[\d\.]+?\.gem/
283
368
  s ||= Bundler.rubygems.spec_from_gem(gemfile)
284
369
  s.source = self
370
+ if Bundler.rubygems.spec_missing_extensions?(s, false)
371
+ Bundler.ui.debug "Source #{self} is ignoring #{s} because it is missing extensions"
372
+ next
373
+ end
285
374
  idx << s
286
375
  end
287
- end
288
376
 
289
- idx
377
+ idx
378
+ end
290
379
  end
291
380
 
292
381
  def api_fetchers
293
- fetchers.select{|f| f.use_api }
382
+ fetchers.select {|f| f.use_api && f.fetchers.first.api_fetcher? }
294
383
  end
295
384
 
296
385
  def remote_specs
@@ -298,68 +387,55 @@ module Bundler
298
387
  index_fetchers = fetchers - api_fetchers
299
388
 
300
389
  # gather lists from non-api sites
301
- index_fetchers.each do |f|
302
- Bundler.ui.info "Fetching source index from #{f.uri}"
303
- idx.use f.specs(nil, self)
304
- end
390
+ fetch_names(index_fetchers, nil, idx, false)
305
391
 
306
392
  # because ensuring we have all the gems we need involves downloading
307
393
  # the gemspecs of those gems, if the non-api sites contain more than
308
- # about 100 gems, we just treat all sites as non-api for speed.
394
+ # about 500 gems, we treat all sites as non-api for speed.
309
395
  allow_api = idx.size < API_REQUEST_LIMIT && dependency_names.size < API_REQUEST_LIMIT
310
396
  Bundler.ui.debug "Need to query more than #{API_REQUEST_LIMIT} gems." \
311
397
  " Downloading full index instead..." unless allow_api
312
398
 
313
- if allow_api
314
- api_fetchers.each do |f|
315
- Bundler.ui.info "Fetching gem metadata from #{f.uri}", Bundler.ui.debug?
316
- idx.use f.specs(dependency_names, self)
317
- Bundler.ui.info "" if !Bundler.ui.debug? # new line now that the dots are over
318
- end
319
-
320
- # Suppose the gem Foo depends on the gem Bar. Foo exists in Source A. Bar has some versions that exist in both
321
- # sources A and B. At this point, the API request will have found all the versions of Bar in source A,
322
- # but will not have found any versions of Bar from source B, which is a problem if the requested version
323
- # of Foo specifically depends on a version of Bar that is only found in source B. This ensures that for
324
- # each spec we found, we add all possible versions from all sources to the index.
325
- begin
326
- idxcount = idx.size
327
- api_fetchers.each do |f|
328
- Bundler.ui.info "Fetching version metadata from #{f.uri}", Bundler.ui.debug?
329
- idx.use f.specs(idx.dependency_names, self), true
330
- Bundler.ui.info "" if !Bundler.ui.debug? # new line now that the dots are over
331
- end
332
- end until idxcount == idx.size
333
-
334
- if api_fetchers.any? && api_fetchers.all?{|f| f.use_api }
335
- # it's possible that gems from one source depend on gems from some
336
- # other source, so now we download gemspecs and iterate over those
337
- # dependencies, looking for gems we don't have info on yet.
338
- unmet = idx.unmet_dependency_names
339
-
340
- # if there are any cross-site gems we missed, get them now
341
- api_fetchers.each do |f|
342
- Bundler.ui.info "Fetching dependency metadata from #{f.uri}", Bundler.ui.debug?
343
- idx.use f.specs(unmet, self)
344
- Bundler.ui.info "" if !Bundler.ui.debug? # new line now that the dots are over
345
- end if unmet.any?
346
- else
347
- allow_api = false
348
- end
349
- end
399
+ fetch_names(api_fetchers, allow_api && dependency_names, idx, false)
400
+ end
401
+ end
350
402
 
351
- if !allow_api
352
- api_fetchers.each do |f|
353
- Bundler.ui.info "Fetching source index from #{f.uri}"
354
- idx.use f.specs(nil, self)
355
- end
403
+ def fetch_names(fetchers, dependency_names, index, override_dupes)
404
+ fetchers.each do |f|
405
+ if dependency_names
406
+ Bundler.ui.info "Fetching gem metadata from #{f.uri}", Bundler.ui.debug?
407
+ index.use f.specs_with_retry(dependency_names, self), override_dupes
408
+ Bundler.ui.info "" unless Bundler.ui.debug? # new line now that the dots are over
409
+ else
410
+ Bundler.ui.info "Fetching source index from #{f.uri}"
411
+ index.use f.specs_with_retry(nil, self), override_dupes
356
412
  end
357
413
  end
358
414
  end
359
415
 
360
416
  def fetch_gem(spec)
361
- return false unless spec.source_uri
362
- Fetcher.download_gem_from_uri(spec, spec.source_uri.original_uri)
417
+ return false unless spec.remote
418
+
419
+ spec.fetch_platform
420
+
421
+ download_path = requires_sudo? ? Bundler.tmp(spec.full_name) : rubygems_dir
422
+ gem_path = "#{rubygems_dir}/cache/#{spec.full_name}.gem"
423
+
424
+ SharedHelpers.filesystem_access("#{download_path}/cache") do |p|
425
+ FileUtils.mkdir_p(p)
426
+ end
427
+ download_gem(spec, download_path)
428
+
429
+ if requires_sudo?
430
+ SharedHelpers.filesystem_access("#{rubygems_dir}/cache") do |p|
431
+ Bundler.mkdir_p(p)
432
+ end
433
+ Bundler.sudo "mv #{download_path}/cache/#{spec.full_name}.gem #{gem_path}"
434
+ end
435
+
436
+ gem_path
437
+ ensure
438
+ Bundler.rm_rf(download_path) if requires_sudo?
363
439
  end
364
440
 
365
441
  def builtin_gem?(spec)
@@ -370,10 +446,94 @@ module Bundler
370
446
  spec.loaded_from && spec.loaded_from.include?("specifications/default/")
371
447
  end
372
448
 
373
- def remotes_equal?(other_remotes)
374
- remotes.map(&method(:suppress_configured_credentials)) == other_remotes.map(&method(:suppress_configured_credentials))
449
+ def installed?(spec)
450
+ installed_specs[spec].any?
451
+ end
452
+
453
+ def requires_sudo?
454
+ Bundler.requires_sudo?
455
+ end
456
+
457
+ def rubygems_dir
458
+ Bundler.rubygems.gem_dir
459
+ end
460
+
461
+ def cache_path
462
+ Bundler.app_cache
375
463
  end
376
464
 
465
+ private
466
+
467
+ # Checks if the requested spec exists in the global cache. If it does,
468
+ # we copy it to the download path, and if it does not, we download it.
469
+ #
470
+ # @param [Specification] spec
471
+ # the spec we want to download or retrieve from the cache.
472
+ #
473
+ # @param [String] download_path
474
+ # the local directory the .gem will end up in.
475
+ #
476
+ def download_gem(spec, download_path)
477
+ local_path = File.join(download_path, "cache/#{spec.full_name}.gem")
478
+
479
+ if (cache_path = download_cache_path(spec)) && cache_path.file?
480
+ SharedHelpers.filesystem_access(local_path) do
481
+ FileUtils.cp(cache_path, local_path)
482
+ end
483
+ else
484
+ uri = spec.remote.uri
485
+ Bundler.ui.confirm("Fetching #{version_message(spec)}")
486
+ rubygems_local_path = Bundler.rubygems.download_gem(spec, uri, download_path)
487
+ if rubygems_local_path != local_path
488
+ FileUtils.mv(rubygems_local_path, local_path)
489
+ end
490
+ cache_globally(spec, local_path)
491
+ end
492
+ end
493
+
494
+ # Checks if the requested spec exists in the global cache. If it does
495
+ # not, we create the relevant global cache subdirectory if it does not
496
+ # exist and copy the spec from the local cache to the global cache.
497
+ #
498
+ # @param [Specification] spec
499
+ # the spec we want to copy to the global cache.
500
+ #
501
+ # @param [String] local_cache_path
502
+ # the local directory from which we want to copy the .gem.
503
+ #
504
+ def cache_globally(spec, local_cache_path)
505
+ return unless cache_path = download_cache_path(spec)
506
+ return if cache_path.exist?
507
+
508
+ SharedHelpers.filesystem_access(cache_path.dirname, &:mkpath)
509
+ SharedHelpers.filesystem_access(cache_path) do
510
+ FileUtils.cp(local_cache_path, cache_path)
511
+ end
512
+ end
513
+
514
+ # Returns the global cache path of the calling Rubygems::Source object.
515
+ #
516
+ # Note that the Source determines the path's subdirectory. We use this
517
+ # subdirectory in the global cache path so that gems with the same name
518
+ # -- and possibly different versions -- from different sources are saved
519
+ # to their respective subdirectories and do not override one another.
520
+ #
521
+ # @param [Gem::Specification] specification
522
+ #
523
+ # @return [Pathname] The global cache path.
524
+ #
525
+ def download_cache_path(spec)
526
+ return unless Bundler.feature_flag.global_gem_cache?
527
+ return unless remote = spec.remote
528
+ return unless cache_slug = remote.cache_slug
529
+
530
+ Bundler.user_cache.join("gems", cache_slug, spec.file_name)
531
+ end
532
+
533
+ def extension_cache_slug(spec)
534
+ return unless remote = spec.remote
535
+ remote.cache_slug
536
+ end
377
537
  end
378
538
  end
379
539
  end