rubygems-update 3.4.22 → 3.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (540) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +105 -2
  3. data/Manifest.txt +46 -221
  4. data/README.md +1 -3
  5. data/bundler/CHANGELOG.md +63 -0
  6. data/bundler/bundler.gemspec +4 -2
  7. data/bundler/exe/bundle +1 -10
  8. data/bundler/lib/bundler/build_metadata.rb +3 -3
  9. data/bundler/lib/bundler/capistrano.rb +1 -1
  10. data/bundler/lib/bundler/checksum.rb +254 -0
  11. data/bundler/lib/bundler/ci_detector.rb +75 -0
  12. data/bundler/lib/bundler/cli/add.rb +3 -3
  13. data/bundler/lib/bundler/cli/binstubs.rb +4 -4
  14. data/bundler/lib/bundler/cli/cache.rb +1 -1
  15. data/bundler/lib/bundler/cli/check.rb +1 -1
  16. data/bundler/lib/bundler/cli/common.rb +9 -1
  17. data/bundler/lib/bundler/cli/config.rb +8 -7
  18. data/bundler/lib/bundler/cli/console.rb +3 -2
  19. data/bundler/lib/bundler/cli/doctor.rb +2 -2
  20. data/bundler/lib/bundler/cli/exec.rb +1 -1
  21. data/bundler/lib/bundler/cli/gem.rb +28 -23
  22. data/bundler/lib/bundler/cli/info.rb +2 -13
  23. data/bundler/lib/bundler/cli/install.rb +5 -4
  24. data/bundler/lib/bundler/cli/issue.rb +1 -1
  25. data/bundler/lib/bundler/cli/lock.rb +4 -4
  26. data/bundler/lib/bundler/cli/open.rb +1 -1
  27. data/bundler/lib/bundler/cli/outdated.rb +6 -6
  28. data/bundler/lib/bundler/cli/plugin.rb +7 -14
  29. data/bundler/lib/bundler/cli/pristine.rb +38 -30
  30. data/bundler/lib/bundler/cli/show.rb +2 -2
  31. data/bundler/lib/bundler/cli/update.rb +5 -5
  32. data/bundler/lib/bundler/cli.rb +215 -263
  33. data/bundler/lib/bundler/compact_index_client/cache.rb +29 -9
  34. data/bundler/lib/bundler/compact_index_client/cache_file.rb +153 -0
  35. data/bundler/lib/bundler/compact_index_client/gem_parser.rb +7 -3
  36. data/bundler/lib/bundler/compact_index_client/updater.rb +79 -81
  37. data/bundler/lib/bundler/compact_index_client.rb +14 -7
  38. data/bundler/lib/bundler/constants.rb +1 -1
  39. data/bundler/lib/bundler/current_ruby.rb +5 -21
  40. data/bundler/lib/bundler/definition.rb +42 -15
  41. data/bundler/lib/bundler/dependency.rb +16 -12
  42. data/bundler/lib/bundler/digest.rb +2 -2
  43. data/bundler/lib/bundler/dsl.rb +46 -30
  44. data/bundler/lib/bundler/endpoint_specification.rb +5 -1
  45. data/bundler/lib/bundler/env.rb +1 -3
  46. data/bundler/lib/bundler/errors.rb +43 -0
  47. data/bundler/lib/bundler/fetcher/base.rb +3 -1
  48. data/bundler/lib/bundler/fetcher/compact_index.rb +4 -4
  49. data/bundler/lib/bundler/fetcher/downloader.rb +13 -11
  50. data/bundler/lib/bundler/fetcher/gem_remote_fetcher.rb +16 -0
  51. data/bundler/lib/bundler/fetcher/index.rb +1 -1
  52. data/bundler/lib/bundler/fetcher.rb +28 -25
  53. data/bundler/lib/bundler/friendly_errors.rb +5 -5
  54. data/bundler/lib/bundler/gem_helper.rb +1 -1
  55. data/bundler/lib/bundler/gem_helpers.rb +5 -2
  56. data/bundler/lib/bundler/graph.rb +9 -9
  57. data/bundler/lib/bundler/index.rb +1 -2
  58. data/bundler/lib/bundler/injector.rb +1 -1
  59. data/bundler/lib/bundler/inline.rb +3 -3
  60. data/bundler/lib/bundler/installer/gem_installer.rb +5 -5
  61. data/bundler/lib/bundler/installer/parallel_installer.rb +16 -8
  62. data/bundler/lib/bundler/installer/standalone.rb +2 -3
  63. data/bundler/lib/bundler/installer.rb +9 -9
  64. data/bundler/lib/bundler/lazy_specification.rb +24 -17
  65. data/bundler/lib/bundler/lockfile_generator.rb +9 -0
  66. data/bundler/lib/bundler/lockfile_parser.rb +81 -10
  67. data/bundler/lib/bundler/man/bundle-add.1 +3 -26
  68. data/bundler/lib/bundler/man/bundle-binstubs.1 +4 -16
  69. data/bundler/lib/bundler/man/bundle-cache.1 +3 -24
  70. data/bundler/lib/bundler/man/bundle-check.1 +3 -12
  71. data/bundler/lib/bundler/man/bundle-clean.1 +3 -10
  72. data/bundler/lib/bundler/man/bundle-config.1 +20 -211
  73. data/bundler/lib/bundler/man/bundle-config.1.ronn +6 -0
  74. data/bundler/lib/bundler/man/bundle-console.1 +4 -22
  75. data/bundler/lib/bundler/man/bundle-doctor.1 +4 -18
  76. data/bundler/lib/bundler/man/bundle-exec.1 +12 -73
  77. data/bundler/lib/bundler/man/bundle-gem.1 +13 -49
  78. data/bundler/lib/bundler/man/bundle-help.1 +3 -7
  79. data/bundler/lib/bundler/man/bundle-info.1 +3 -9
  80. data/bundler/lib/bundler/man/bundle-init.1 +3 -12
  81. data/bundler/lib/bundler/man/bundle-inject.1 +6 -19
  82. data/bundler/lib/bundler/man/bundle-install.1 +27 -125
  83. data/bundler/lib/bundler/man/bundle-install.1.ronn +1 -0
  84. data/bundler/lib/bundler/man/bundle-list.1 +4 -19
  85. data/bundler/lib/bundler/man/bundle-lock.1 +5 -29
  86. data/bundler/lib/bundler/man/bundle-open.1 +7 -27
  87. data/bundler/lib/bundler/man/bundle-outdated.1 +3 -55
  88. data/bundler/lib/bundler/man/bundle-outdated.1.ronn +1 -0
  89. data/bundler/lib/bundler/man/bundle-platform.1 +5 -27
  90. data/bundler/lib/bundler/man/bundle-plugin.1 +3 -29
  91. data/bundler/lib/bundler/man/bundle-pristine.1 +5 -16
  92. data/bundler/lib/bundler/man/bundle-remove.1 +4 -14
  93. data/bundler/lib/bundler/man/bundle-show.1 +3 -10
  94. data/bundler/lib/bundler/man/bundle-update.1 +18 -137
  95. data/bundler/lib/bundler/man/bundle-version.1 +3 -16
  96. data/bundler/lib/bundler/man/bundle-viz.1 +4 -16
  97. data/bundler/lib/bundler/man/bundle.1 +5 -44
  98. data/bundler/lib/bundler/man/gemfile.5 +24 -301
  99. data/bundler/lib/bundler/man/gemfile.5.ronn +4 -0
  100. data/bundler/lib/bundler/match_metadata.rb +4 -0
  101. data/bundler/lib/bundler/match_platform.rb +1 -1
  102. data/bundler/lib/bundler/plugin/api/source.rb +3 -2
  103. data/bundler/lib/bundler/plugin/installer.rb +1 -1
  104. data/bundler/lib/bundler/plugin.rb +3 -3
  105. data/bundler/lib/bundler/resolver/base.rb +1 -1
  106. data/bundler/lib/bundler/resolver/incompatibility.rb +1 -1
  107. data/bundler/lib/bundler/resolver/spec_group.rb +1 -4
  108. data/bundler/lib/bundler/resolver.rb +16 -16
  109. data/bundler/lib/bundler/ruby_dsl.rb +20 -12
  110. data/bundler/lib/bundler/ruby_version.rb +1 -1
  111. data/bundler/lib/bundler/rubygems_ext.rb +24 -50
  112. data/bundler/lib/bundler/rubygems_gem_installer.rb +6 -56
  113. data/bundler/lib/bundler/rubygems_integration.rb +25 -94
  114. data/bundler/lib/bundler/runtime.rb +2 -2
  115. data/bundler/lib/bundler/self_manager.rb +23 -7
  116. data/bundler/lib/bundler/settings.rb +27 -7
  117. data/bundler/lib/bundler/setup.rb +4 -1
  118. data/bundler/lib/bundler/shared_helpers.rb +35 -13
  119. data/bundler/lib/bundler/source/git/git_proxy.rb +15 -15
  120. data/bundler/lib/bundler/source/git.rb +4 -3
  121. data/bundler/lib/bundler/source/metadata.rb +15 -15
  122. data/bundler/lib/bundler/source/path.rb +7 -6
  123. data/bundler/lib/bundler/source/rubygems.rb +21 -14
  124. data/bundler/lib/bundler/source.rb +2 -0
  125. data/bundler/lib/bundler/spec_set.rb +38 -10
  126. data/bundler/lib/bundler/stub_specification.rb +1 -0
  127. data/bundler/lib/bundler/templates/Executable.bundler +1 -1
  128. data/bundler/lib/bundler/templates/newgem/README.md.tt +3 -3
  129. data/bundler/lib/bundler/templates/newgem/Rakefile.tt +2 -6
  130. data/bundler/lib/bundler/templates/newgem/ext/newgem/Cargo.toml.tt +1 -1
  131. data/bundler/lib/bundler/templates/newgem/standard.yml.tt +1 -1
  132. data/bundler/lib/bundler/ui/shell.rb +1 -1
  133. data/bundler/lib/bundler/vendor/connection_pool/.document +1 -0
  134. data/bundler/lib/bundler/vendor/connection_pool/lib/connection_pool/version.rb +1 -1
  135. data/bundler/lib/bundler/vendor/connection_pool/lib/connection_pool.rb +53 -6
  136. data/bundler/lib/bundler/vendor/fileutils/.document +1 -0
  137. data/bundler/lib/bundler/vendor/fileutils/lib/fileutils.rb +8 -20
  138. data/bundler/lib/bundler/vendor/net-http-persistent/.document +1 -0
  139. data/bundler/lib/bundler/vendor/net-http-persistent/lib/net/http/persistent/connection.rb +3 -3
  140. data/bundler/lib/bundler/vendor/net-http-persistent/lib/net/http/persistent/pool.rb +2 -2
  141. data/bundler/lib/bundler/vendor/net-http-persistent/lib/net/http/persistent/timed_stack_multi.rb +1 -1
  142. data/bundler/lib/bundler/vendor/net-http-persistent/lib/net/http/persistent.rb +34 -34
  143. data/bundler/lib/bundler/vendor/pub_grub/.document +1 -0
  144. data/bundler/lib/bundler/vendor/thor/.document +1 -0
  145. data/bundler/lib/bundler/vendor/tsort/.document +1 -0
  146. data/bundler/lib/bundler/vendor/tsort/lib/tsort.rb +3 -0
  147. data/bundler/lib/bundler/vendor/uri/.document +1 -0
  148. data/bundler/lib/bundler/vendor/uri/lib/uri/common.rb +256 -132
  149. data/bundler/lib/bundler/vendor/uri/lib/uri/generic.rb +1 -0
  150. data/bundler/lib/bundler/vendor/uri/lib/uri/rfc3986_parser.rb +95 -31
  151. data/bundler/lib/bundler/vendor/uri/lib/uri/version.rb +1 -1
  152. data/bundler/lib/bundler/vendored_net_http.rb +8 -0
  153. data/bundler/lib/bundler/vendored_persistent.rb +0 -4
  154. data/bundler/lib/bundler/vendored_timeout.rb +8 -0
  155. data/bundler/lib/bundler/version.rb +1 -1
  156. data/bundler/lib/bundler/vlad.rb +1 -1
  157. data/bundler/lib/bundler/yaml_serializer.rb +3 -3
  158. data/bundler/lib/bundler.rb +41 -32
  159. data/lib/rubygems/available_set.rb +4 -4
  160. data/lib/rubygems/basic_specification.rb +35 -37
  161. data/lib/rubygems/bundler_version_finder.rb +4 -4
  162. data/lib/rubygems/ci_detector.rb +75 -0
  163. data/lib/rubygems/command.rb +13 -15
  164. data/lib/rubygems/command_manager.rb +5 -4
  165. data/lib/rubygems/commands/build_command.rb +2 -2
  166. data/lib/rubygems/commands/cert_command.rb +1 -2
  167. data/lib/rubygems/commands/check_command.rb +4 -4
  168. data/lib/rubygems/commands/cleanup_command.rb +12 -14
  169. data/lib/rubygems/commands/contents_command.rb +4 -4
  170. data/lib/rubygems/commands/dependency_command.rb +4 -5
  171. data/lib/rubygems/commands/environment_command.rb +1 -3
  172. data/lib/rubygems/commands/exec_command.rb +1 -1
  173. data/lib/rubygems/commands/fetch_command.rb +2 -2
  174. data/lib/rubygems/commands/generate_index_command.rb +39 -74
  175. data/lib/rubygems/commands/help_command.rb +3 -3
  176. data/lib/rubygems/commands/info_command.rb +2 -2
  177. data/lib/rubygems/commands/install_command.rb +8 -16
  178. data/lib/rubygems/commands/list_command.rb +2 -2
  179. data/lib/rubygems/commands/lock_command.rb +1 -1
  180. data/lib/rubygems/commands/open_command.rb +1 -1
  181. data/lib/rubygems/commands/owner_command.rb +1 -1
  182. data/lib/rubygems/commands/pristine_command.rb +13 -15
  183. data/lib/rubygems/commands/push_command.rb +2 -2
  184. data/lib/rubygems/commands/query_command.rb +4 -5
  185. data/lib/rubygems/commands/rdoc_command.rb +2 -2
  186. data/lib/rubygems/commands/search_command.rb +2 -2
  187. data/lib/rubygems/commands/setup_command.rb +31 -34
  188. data/lib/rubygems/commands/sources_command.rb +12 -12
  189. data/lib/rubygems/commands/specification_command.rb +10 -10
  190. data/lib/rubygems/commands/stale_command.rb +1 -1
  191. data/lib/rubygems/commands/uninstall_command.rb +9 -10
  192. data/lib/rubygems/commands/unpack_command.rb +4 -4
  193. data/lib/rubygems/commands/update_command.rb +10 -12
  194. data/lib/rubygems/commands/which_command.rb +1 -1
  195. data/lib/rubygems/commands/yank_command.rb +1 -1
  196. data/lib/rubygems/compatibility.rb +5 -6
  197. data/lib/rubygems/config_file.rb +4 -4
  198. data/lib/rubygems/core_ext/kernel_gem.rb +0 -2
  199. data/lib/rubygems/core_ext/kernel_require.rb +19 -48
  200. data/lib/rubygems/core_ext/kernel_warn.rb +1 -1
  201. data/lib/rubygems/core_ext/tcpsocket_init.rb +1 -1
  202. data/lib/rubygems/defaults.rb +15 -3
  203. data/lib/rubygems/dependency.rb +12 -14
  204. data/lib/rubygems/dependency_installer.rb +29 -30
  205. data/lib/rubygems/dependency_list.rb +1 -1
  206. data/lib/rubygems/deprecate.rb +16 -15
  207. data/lib/rubygems/doctor.rb +5 -5
  208. data/lib/rubygems/errors.rb +2 -6
  209. data/lib/rubygems/exceptions.rb +2 -1
  210. data/lib/rubygems/ext/builder.rb +15 -10
  211. data/lib/rubygems/ext/cargo_builder.rb +5 -5
  212. data/lib/rubygems/ext/ext_conf_builder.rb +1 -3
  213. data/lib/rubygems/gem_runner.rb +4 -4
  214. data/lib/rubygems/gemcutter_utilities/webauthn_listener/response.rb +3 -3
  215. data/lib/rubygems/gemcutter_utilities/webauthn_poller.rb +3 -3
  216. data/lib/rubygems/gemcutter_utilities.rb +18 -19
  217. data/lib/rubygems/install_update_options.rb +18 -19
  218. data/lib/rubygems/installer.rb +59 -33
  219. data/lib/rubygems/installer_uninstaller_utils.rb +0 -2
  220. data/lib/rubygems/local_remote_options.rb +7 -10
  221. data/lib/rubygems/name_tuple.rb +7 -9
  222. data/lib/rubygems/net/http.rb +3 -0
  223. data/lib/rubygems/net-http/.document +1 -0
  224. data/lib/rubygems/net-http/LICENSE.txt +22 -0
  225. data/lib/rubygems/net-http/lib/net/http/backward.rb +40 -0
  226. data/lib/rubygems/net-http/lib/net/http/exceptions.rb +34 -0
  227. data/lib/rubygems/net-http/lib/net/http/generic_request.rb +414 -0
  228. data/lib/rubygems/net-http/lib/net/http/header.rb +981 -0
  229. data/lib/rubygems/net-http/lib/net/http/proxy_delta.rb +17 -0
  230. data/lib/rubygems/net-http/lib/net/http/request.rb +88 -0
  231. data/lib/rubygems/net-http/lib/net/http/requests.rb +425 -0
  232. data/lib/rubygems/net-http/lib/net/http/response.rb +738 -0
  233. data/lib/rubygems/net-http/lib/net/http/responses.rb +1174 -0
  234. data/lib/rubygems/net-http/lib/net/http/status.rb +84 -0
  235. data/lib/rubygems/net-http/lib/net/http.rb +2496 -0
  236. data/lib/rubygems/net-http/lib/net/https.rb +23 -0
  237. data/lib/rubygems/net-protocol/.document +1 -0
  238. data/lib/rubygems/net-protocol/LICENSE.txt +22 -0
  239. data/lib/rubygems/net-protocol/lib/net/protocol.rb +544 -0
  240. data/lib/rubygems/optparse/lib/optparse.rb +39 -17
  241. data/lib/rubygems/package/old.rb +2 -2
  242. data/lib/rubygems/package/tar_header.rb +45 -39
  243. data/lib/rubygems/package/tar_reader/entry.rb +5 -4
  244. data/lib/rubygems/package/tar_reader.rb +5 -3
  245. data/lib/rubygems/package/tar_writer.rb +19 -17
  246. data/lib/rubygems/package.rb +27 -26
  247. data/lib/rubygems/package_task.rb +2 -2
  248. data/lib/rubygems/path_support.rb +9 -10
  249. data/lib/rubygems/platform.rb +60 -45
  250. data/lib/rubygems/query_utils.rb +7 -9
  251. data/lib/rubygems/remote_fetcher.rb +15 -15
  252. data/lib/rubygems/request/connection_pools.rb +3 -3
  253. data/lib/rubygems/request.rb +20 -17
  254. data/lib/rubygems/request_set/gem_dependency_api.rb +119 -122
  255. data/lib/rubygems/request_set/lockfile/parser.rb +9 -9
  256. data/lib/rubygems/request_set/lockfile/tokenizer.rb +20 -12
  257. data/lib/rubygems/request_set/lockfile.rb +6 -11
  258. data/lib/rubygems/request_set.rb +5 -5
  259. data/lib/rubygems/requirement.rb +7 -7
  260. data/lib/rubygems/resolv/.document +1 -0
  261. data/lib/rubygems/resolv/LICENSE.txt +22 -0
  262. data/lib/rubygems/resolv/lib/resolv.rb +3387 -0
  263. data/lib/rubygems/resolver/activation_request.rb +1 -3
  264. data/lib/rubygems/resolver/api_set/gem_parser.rb +7 -3
  265. data/lib/rubygems/resolver/best_set.rb +1 -1
  266. data/lib/rubygems/resolver/composed_set.rb +1 -1
  267. data/lib/rubygems/resolver/conflict.rb +4 -12
  268. data/lib/rubygems/resolver/index_set.rb +4 -4
  269. data/lib/rubygems/resolver/index_specification.rb +2 -2
  270. data/lib/rubygems/resolver/installer_set.rb +5 -6
  271. data/lib/rubygems/resolver/lock_set.rb +1 -1
  272. data/lib/rubygems/resolver/molinillo/.document +1 -0
  273. data/lib/rubygems/resolver.rb +3 -10
  274. data/lib/rubygems/s3_uri_signer.rb +6 -6
  275. data/lib/rubygems/safe_marshal/elements.rb +138 -0
  276. data/lib/rubygems/safe_marshal/reader.rb +306 -0
  277. data/lib/rubygems/safe_marshal/visitors/stream_printer.rb +31 -0
  278. data/lib/rubygems/safe_marshal/visitors/to_ruby.rb +385 -0
  279. data/lib/rubygems/safe_marshal/visitors/visitor.rb +74 -0
  280. data/lib/rubygems/safe_marshal.rb +74 -0
  281. data/lib/rubygems/safe_yaml.rb +5 -28
  282. data/lib/rubygems/security/policies.rb +36 -38
  283. data/lib/rubygems/security/policy.rb +7 -11
  284. data/lib/rubygems/security/signer.rb +1 -1
  285. data/lib/rubygems/security/trust_dir.rb +3 -3
  286. data/lib/rubygems/security.rb +8 -22
  287. data/lib/rubygems/source/git.rb +1 -3
  288. data/lib/rubygems/source/installed.rb +0 -2
  289. data/lib/rubygems/source/local.rb +5 -8
  290. data/lib/rubygems/source/lock.rb +1 -3
  291. data/lib/rubygems/source/specific_file.rb +0 -1
  292. data/lib/rubygems/source/vendor.rb +0 -2
  293. data/lib/rubygems/source.rb +12 -12
  294. data/lib/rubygems/source_list.rb +4 -4
  295. data/lib/rubygems/spec_fetcher.rb +29 -29
  296. data/lib/rubygems/specification.rb +125 -138
  297. data/lib/rubygems/specification_policy.rb +55 -25
  298. data/lib/rubygems/stub_specification.rb +4 -5
  299. data/lib/rubygems/text.rb +1 -2
  300. data/lib/rubygems/timeout/.document +1 -0
  301. data/lib/rubygems/timeout/LICENSE.txt +22 -0
  302. data/lib/rubygems/timeout/lib/timeout.rb +199 -0
  303. data/lib/rubygems/timeout.rb +3 -0
  304. data/lib/rubygems/tsort/lib/tsort.rb +3 -0
  305. data/lib/rubygems/uninstaller.rb +7 -9
  306. data/lib/rubygems/update_suggestion.rb +5 -18
  307. data/lib/rubygems/uri_formatter.rb +1 -1
  308. data/lib/rubygems/user_interaction.rb +15 -21
  309. data/lib/rubygems/util/licenses.rb +65 -35
  310. data/lib/rubygems/util/list.rb +3 -1
  311. data/lib/rubygems/util.rb +2 -4
  312. data/lib/rubygems/validator.rb +5 -3
  313. data/lib/rubygems/version.rb +34 -28
  314. data/lib/rubygems/version_option.rb +2 -5
  315. data/lib/rubygems/yaml_serializer.rb +3 -3
  316. data/lib/rubygems.rb +37 -37
  317. data/rubygems-update.gemspec +4 -4
  318. data/setup.rb +2 -2
  319. metadata +50 -225
  320. data/lib/rubygems/indexer.rb +0 -428
  321. data/lib/rubygems/mock_gem_ui.rb +0 -86
  322. data/test/rubygems/alternate_cert.pem +0 -19
  323. data/test/rubygems/alternate_cert_32.pem +0 -19
  324. data/test/rubygems/alternate_key.pem +0 -27
  325. data/test/rubygems/bad_rake.rb +0 -3
  326. data/test/rubygems/bundler_test_gem.rb +0 -424
  327. data/test/rubygems/ca_cert.pem +0 -77
  328. data/test/rubygems/child_cert.pem +0 -19
  329. data/test/rubygems/child_cert_32.pem +0 -19
  330. data/test/rubygems/child_key.pem +0 -27
  331. data/test/rubygems/client.pem +0 -107
  332. data/test/rubygems/data/excon-0.7.7.gemspec.rz +0 -0
  333. data/test/rubygems/data/gem-private_key.pem +0 -27
  334. data/test/rubygems/data/gem-public_cert.pem +0 -20
  335. data/test/rubygems/data/null-required-ruby-version.gemspec.rz +0 -0
  336. data/test/rubygems/data/null-required-rubygems-version.gemspec.rz +0 -0
  337. data/test/rubygems/data/pry-0.4.7.gemspec.rz +0 -0
  338. data/test/rubygems/encrypted_private_key.pem +0 -30
  339. data/test/rubygems/expired_cert.pem +0 -19
  340. data/test/rubygems/fake_certlib/openssl.rb +0 -9
  341. data/test/rubygems/foo/discover.rb +0 -1
  342. data/test/rubygems/future_cert.pem +0 -19
  343. data/test/rubygems/future_cert_32.pem +0 -19
  344. data/test/rubygems/good_rake.rb +0 -3
  345. data/test/rubygems/grandchild_cert.pem +0 -19
  346. data/test/rubygems/grandchild_cert_32.pem +0 -19
  347. data/test/rubygems/grandchild_key.pem +0 -27
  348. data/test/rubygems/helper.rb +0 -1649
  349. data/test/rubygems/installer_test_case.rb +0 -248
  350. data/test/rubygems/invalid_client.pem +0 -49
  351. data/test/rubygems/invalid_issuer_cert.pem +0 -20
  352. data/test/rubygems/invalid_issuer_cert_32.pem +0 -20
  353. data/test/rubygems/invalid_key.pem +0 -27
  354. data/test/rubygems/invalid_signer_cert.pem +0 -19
  355. data/test/rubygems/invalid_signer_cert_32.pem +0 -19
  356. data/test/rubygems/invalidchild_cert.pem +0 -19
  357. data/test/rubygems/invalidchild_cert_32.pem +0 -19
  358. data/test/rubygems/invalidchild_key.pem +0 -27
  359. data/test/rubygems/multifactor_auth_utilities.rb +0 -111
  360. data/test/rubygems/package/tar_test_case.rb +0 -175
  361. data/test/rubygems/packages/Bluebie-legs-0.6.2.gem +0 -0
  362. data/test/rubygems/packages/ascii_binder-0.1.10.1.gem +0 -0
  363. data/test/rubygems/packages/ill-formatted-platform-1.0.0.10.gem +0 -0
  364. data/test/rubygems/plugin/exception/rubygems_plugin.rb +0 -4
  365. data/test/rubygems/plugin/load/rubygems_plugin.rb +0 -5
  366. data/test/rubygems/plugin/standarderror/rubygems_plugin.rb +0 -4
  367. data/test/rubygems/private3072_key.pem +0 -40
  368. data/test/rubygems/private_ec_key.pem +0 -9
  369. data/test/rubygems/private_key.pem +0 -27
  370. data/test/rubygems/public3072_cert.pem +0 -25
  371. data/test/rubygems/public_cert.pem +0 -20
  372. data/test/rubygems/public_cert_32.pem +0 -19
  373. data/test/rubygems/public_key.pem +0 -9
  374. data/test/rubygems/rubygems/commands/crash_command.rb +0 -5
  375. data/test/rubygems/rubygems_plugin.rb +0 -24
  376. data/test/rubygems/sff/discover.rb +0 -1
  377. data/test/rubygems/simple_gem.rb +0 -68
  378. data/test/rubygems/specifications/bar-0.0.2.gemspec +0 -9
  379. data/test/rubygems/specifications/foo-0.0.1-x86-mswin32.gemspec +0 -0
  380. data/test/rubygems/specifications/rubyforge-0.0.1.gemspec +0 -14
  381. data/test/rubygems/ssl_cert.pem +0 -80
  382. data/test/rubygems/ssl_key.pem +0 -27
  383. data/test/rubygems/test_bundled_ca.rb +0 -61
  384. data/test/rubygems/test_config.rb +0 -28
  385. data/test/rubygems/test_deprecate.rb +0 -158
  386. data/test/rubygems/test_exit.rb +0 -17
  387. data/test/rubygems/test_gem.rb +0 -1799
  388. data/test/rubygems/test_gem_available_set.rb +0 -130
  389. data/test/rubygems/test_gem_bundler_version_finder.rb +0 -127
  390. data/test/rubygems/test_gem_command.rb +0 -403
  391. data/test/rubygems/test_gem_command_manager.rb +0 -400
  392. data/test/rubygems/test_gem_commands_build_command.rb +0 -739
  393. data/test/rubygems/test_gem_commands_cert_command.rb +0 -866
  394. data/test/rubygems/test_gem_commands_check_command.rb +0 -68
  395. data/test/rubygems/test_gem_commands_cleanup_command.rb +0 -292
  396. data/test/rubygems/test_gem_commands_contents_command.rb +0 -271
  397. data/test/rubygems/test_gem_commands_dependency_command.rb +0 -228
  398. data/test/rubygems/test_gem_commands_environment_command.rb +0 -169
  399. data/test/rubygems/test_gem_commands_exec_command.rb +0 -857
  400. data/test/rubygems/test_gem_commands_fetch_command.rb +0 -258
  401. data/test/rubygems/test_gem_commands_generate_index_command.rb +0 -81
  402. data/test/rubygems/test_gem_commands_help_command.rb +0 -94
  403. data/test/rubygems/test_gem_commands_info_command.rb +0 -70
  404. data/test/rubygems/test_gem_commands_install_command.rb +0 -1573
  405. data/test/rubygems/test_gem_commands_list_command.rb +0 -33
  406. data/test/rubygems/test_gem_commands_lock_command.rb +0 -67
  407. data/test/rubygems/test_gem_commands_mirror.rb +0 -20
  408. data/test/rubygems/test_gem_commands_open_command.rb +0 -101
  409. data/test/rubygems/test_gem_commands_outdated_command.rb +0 -50
  410. data/test/rubygems/test_gem_commands_owner_command.rb +0 -503
  411. data/test/rubygems/test_gem_commands_pristine_command.rb +0 -708
  412. data/test/rubygems/test_gem_commands_push_command.rb +0 -603
  413. data/test/rubygems/test_gem_commands_query_command.rb +0 -858
  414. data/test/rubygems/test_gem_commands_search_command.rb +0 -16
  415. data/test/rubygems/test_gem_commands_server_command.rb +0 -20
  416. data/test/rubygems/test_gem_commands_setup_command.rb +0 -474
  417. data/test/rubygems/test_gem_commands_signin_command.rb +0 -259
  418. data/test/rubygems/test_gem_commands_signout_command.rb +0 -30
  419. data/test/rubygems/test_gem_commands_sources_command.rb +0 -534
  420. data/test/rubygems/test_gem_commands_specification_command.rb +0 -277
  421. data/test/rubygems/test_gem_commands_stale_command.rb +0 -43
  422. data/test/rubygems/test_gem_commands_uninstall_command.rb +0 -542
  423. data/test/rubygems/test_gem_commands_unpack_command.rb +0 -224
  424. data/test/rubygems/test_gem_commands_update_command.rb +0 -836
  425. data/test/rubygems/test_gem_commands_which_command.rb +0 -85
  426. data/test/rubygems/test_gem_commands_yank_command.rb +0 -299
  427. data/test/rubygems/test_gem_config_file.rb +0 -551
  428. data/test/rubygems/test_gem_dependency.rb +0 -398
  429. data/test/rubygems/test_gem_dependency_installer.rb +0 -1190
  430. data/test/rubygems/test_gem_dependency_list.rb +0 -265
  431. data/test/rubygems/test_gem_dependency_resolution_error.rb +0 -27
  432. data/test/rubygems/test_gem_doctor.rb +0 -195
  433. data/test/rubygems/test_gem_ext_builder.rb +0 -337
  434. data/test/rubygems/test_gem_ext_cargo_builder/custom_name/.gitignore +0 -1
  435. data/test/rubygems/test_gem_ext_cargo_builder/custom_name/custom_name.gemspec +0 -10
  436. data/test/rubygems/test_gem_ext_cargo_builder/custom_name/ext/custom_name_lib/Cargo.lock +0 -249
  437. data/test/rubygems/test_gem_ext_cargo_builder/custom_name/ext/custom_name_lib/Cargo.toml +0 -10
  438. data/test/rubygems/test_gem_ext_cargo_builder/custom_name/ext/custom_name_lib/src/lib.rs +0 -27
  439. data/test/rubygems/test_gem_ext_cargo_builder/custom_name/lib/custom_name.rb +0 -3
  440. data/test/rubygems/test_gem_ext_cargo_builder/rust_ruby_example/.gitignore +0 -1
  441. data/test/rubygems/test_gem_ext_cargo_builder/rust_ruby_example/Cargo.lock +0 -249
  442. data/test/rubygems/test_gem_ext_cargo_builder/rust_ruby_example/Cargo.toml +0 -10
  443. data/test/rubygems/test_gem_ext_cargo_builder/rust_ruby_example/rust_ruby_example.gemspec +0 -10
  444. data/test/rubygems/test_gem_ext_cargo_builder/rust_ruby_example/src/lib.rs +0 -51
  445. data/test/rubygems/test_gem_ext_cargo_builder.rb +0 -167
  446. data/test/rubygems/test_gem_ext_cargo_builder_link_flag_converter.rb +0 -34
  447. data/test/rubygems/test_gem_ext_cargo_builder_unit.rb +0 -60
  448. data/test/rubygems/test_gem_ext_cmake_builder.rb +0 -84
  449. data/test/rubygems/test_gem_ext_configure_builder.rb +0 -80
  450. data/test/rubygems/test_gem_ext_ext_conf_builder.rb +0 -229
  451. data/test/rubygems/test_gem_ext_rake_builder.rb +0 -113
  452. data/test/rubygems/test_gem_gem_runner.rb +0 -119
  453. data/test/rubygems/test_gem_gemcutter_utilities.rb +0 -361
  454. data/test/rubygems/test_gem_impossible_dependencies_error.rb +0 -60
  455. data/test/rubygems/test_gem_indexer.rb +0 -381
  456. data/test/rubygems/test_gem_install_update_options.rb +0 -208
  457. data/test/rubygems/test_gem_installer.rb +0 -2512
  458. data/test/rubygems/test_gem_local_remote_options.rb +0 -133
  459. data/test/rubygems/test_gem_name_tuple.rb +0 -43
  460. data/test/rubygems/test_gem_package.rb +0 -1306
  461. data/test/rubygems/test_gem_package_old.rb +0 -91
  462. data/test/rubygems/test_gem_package_tar_header.rb +0 -226
  463. data/test/rubygems/test_gem_package_tar_reader.rb +0 -150
  464. data/test/rubygems/test_gem_package_tar_reader_entry.rb +0 -350
  465. data/test/rubygems/test_gem_package_tar_writer.rb +0 -331
  466. data/test/rubygems/test_gem_package_task.rb +0 -118
  467. data/test/rubygems/test_gem_path_support.rb +0 -139
  468. data/test/rubygems/test_gem_platform.rb +0 -497
  469. data/test/rubygems/test_gem_rdoc.rb +0 -137
  470. data/test/rubygems/test_gem_remote_fetcher.rb +0 -1227
  471. data/test/rubygems/test_gem_request.rb +0 -547
  472. data/test/rubygems/test_gem_request_connection_pools.rb +0 -152
  473. data/test/rubygems/test_gem_request_set.rb +0 -672
  474. data/test/rubygems/test_gem_request_set_gem_dependency_api.rb +0 -853
  475. data/test/rubygems/test_gem_request_set_lockfile.rb +0 -469
  476. data/test/rubygems/test_gem_request_set_lockfile_parser.rb +0 -544
  477. data/test/rubygems/test_gem_request_set_lockfile_tokenizer.rb +0 -307
  478. data/test/rubygems/test_gem_requirement.rb +0 -505
  479. data/test/rubygems/test_gem_resolver.rb +0 -859
  480. data/test/rubygems/test_gem_resolver_activation_request.rb +0 -43
  481. data/test/rubygems/test_gem_resolver_api_set.rb +0 -210
  482. data/test/rubygems/test_gem_resolver_api_specification.rb +0 -167
  483. data/test/rubygems/test_gem_resolver_best_set.rb +0 -159
  484. data/test/rubygems/test_gem_resolver_composed_set.rb +0 -44
  485. data/test/rubygems/test_gem_resolver_conflict.rb +0 -82
  486. data/test/rubygems/test_gem_resolver_dependency_request.rb +0 -83
  487. data/test/rubygems/test_gem_resolver_git_set.rb +0 -188
  488. data/test/rubygems/test_gem_resolver_git_specification.rb +0 -114
  489. data/test/rubygems/test_gem_resolver_index_set.rb +0 -88
  490. data/test/rubygems/test_gem_resolver_index_specification.rb +0 -93
  491. data/test/rubygems/test_gem_resolver_installed_specification.rb +0 -47
  492. data/test/rubygems/test_gem_resolver_installer_set.rb +0 -320
  493. data/test/rubygems/test_gem_resolver_local_specification.rb +0 -44
  494. data/test/rubygems/test_gem_resolver_lock_set.rb +0 -62
  495. data/test/rubygems/test_gem_resolver_lock_specification.rb +0 -98
  496. data/test/rubygems/test_gem_resolver_requirement_list.rb +0 -19
  497. data/test/rubygems/test_gem_resolver_specification.rb +0 -63
  498. data/test/rubygems/test_gem_resolver_vendor_set.rb +0 -82
  499. data/test/rubygems/test_gem_resolver_vendor_specification.rb +0 -82
  500. data/test/rubygems/test_gem_security.rb +0 -341
  501. data/test/rubygems/test_gem_security_policy.rb +0 -535
  502. data/test/rubygems/test_gem_security_signer.rb +0 -218
  503. data/test/rubygems/test_gem_security_trust_dir.rb +0 -99
  504. data/test/rubygems/test_gem_silent_ui.rb +0 -123
  505. data/test/rubygems/test_gem_source.rb +0 -254
  506. data/test/rubygems/test_gem_source_fetch_problem.rb +0 -37
  507. data/test/rubygems/test_gem_source_git.rb +0 -310
  508. data/test/rubygems/test_gem_source_installed.rb +0 -35
  509. data/test/rubygems/test_gem_source_list.rb +0 -119
  510. data/test/rubygems/test_gem_source_local.rb +0 -107
  511. data/test/rubygems/test_gem_source_lock.rb +0 -113
  512. data/test/rubygems/test_gem_source_specific_file.rb +0 -76
  513. data/test/rubygems/test_gem_source_subpath_problem.rb +0 -50
  514. data/test/rubygems/test_gem_source_vendor.rb +0 -30
  515. data/test/rubygems/test_gem_spec_fetcher.rb +0 -338
  516. data/test/rubygems/test_gem_specification.rb +0 -3856
  517. data/test/rubygems/test_gem_stream_ui.rb +0 -255
  518. data/test/rubygems/test_gem_stub_specification.rb +0 -278
  519. data/test/rubygems/test_gem_text.rb +0 -103
  520. data/test/rubygems/test_gem_uninstaller.rb +0 -675
  521. data/test/rubygems/test_gem_unsatisfiable_dependency_error.rb +0 -31
  522. data/test/rubygems/test_gem_update_suggestion.rb +0 -209
  523. data/test/rubygems/test_gem_uri.rb +0 -41
  524. data/test/rubygems/test_gem_uri_formatter.rb +0 -27
  525. data/test/rubygems/test_gem_util.rb +0 -91
  526. data/test/rubygems/test_gem_validator.rb +0 -42
  527. data/test/rubygems/test_gem_version.rb +0 -305
  528. data/test/rubygems/test_gem_version_option.rb +0 -165
  529. data/test/rubygems/test_kernel.rb +0 -124
  530. data/test/rubygems/test_project_sanity.rb +0 -49
  531. data/test/rubygems/test_remote_fetch_error.rb +0 -20
  532. data/test/rubygems/test_require.rb +0 -732
  533. data/test/rubygems/test_rubygems.rb +0 -76
  534. data/test/rubygems/test_webauthn_listener.rb +0 -143
  535. data/test/rubygems/test_webauthn_listener_response.rb +0 -93
  536. data/test/rubygems/test_webauthn_poller.rb +0 -124
  537. data/test/rubygems/utilities.rb +0 -436
  538. data/test/rubygems/wrong_key_cert.pem +0 -19
  539. data/test/rubygems/wrong_key_cert_32.pem +0 -19
  540. data/test/test_changelog_generator.rb +0 -17
@@ -9,11 +9,8 @@ module Bundler
9
9
 
10
10
  def initialize(directory)
11
11
  @directory = Pathname.new(directory).expand_path
12
- info_roots.each do |dir|
13
- SharedHelpers.filesystem_access(dir) do
14
- FileUtils.mkdir_p(dir)
15
- end
16
- end
12
+ info_roots.each {|dir| mkdir(dir) }
13
+ mkdir(info_etag_root)
17
14
  end
18
15
 
19
16
  def names
@@ -24,6 +21,10 @@ module Bundler
24
21
  directory.join("names")
25
22
  end
26
23
 
24
+ def names_etag_path
25
+ directory.join("names.etag")
26
+ end
27
+
27
28
  def versions
28
29
  versions_by_name = Hash.new {|hash, key| hash[key] = [] }
29
30
  info_checksums_by_name = {}
@@ -31,12 +32,12 @@ module Bundler
31
32
  lines(versions_path).each do |line|
32
33
  name, versions_string, info_checksum = line.split(" ", 3)
33
34
  info_checksums_by_name[name] = info_checksum || ""
34
- versions_string.split(",").each do |version|
35
- if version.start_with?("-")
36
- version = version[1..-1].split("-", 2).unshift(name)
35
+ versions_string.split(",") do |version|
36
+ delete = version.delete_prefix!("-")
37
+ version = version.split("-", 2).unshift(name)
38
+ if delete
37
39
  versions_by_name[name].delete(version)
38
40
  else
39
- version = version.split("-", 2).unshift(name)
40
41
  versions_by_name[name] << version
41
42
  end
42
43
  end
@@ -49,6 +50,10 @@ module Bundler
49
50
  directory.join("versions")
50
51
  end
51
52
 
53
+ def versions_etag_path
54
+ directory.join("versions.etag")
55
+ end
56
+
52
57
  def checksums
53
58
  checksums = {}
54
59
 
@@ -76,8 +81,19 @@ module Bundler
76
81
  end
77
82
  end
78
83
 
84
+ def info_etag_path(name)
85
+ name = name.to_s
86
+ info_etag_root.join("#{name}-#{SharedHelpers.digest(:MD5).hexdigest(name).downcase}")
87
+ end
88
+
79
89
  private
80
90
 
91
+ def mkdir(dir)
92
+ SharedHelpers.filesystem_access(dir) do
93
+ FileUtils.mkdir_p(dir)
94
+ end
95
+ end
96
+
81
97
  def lines(path)
82
98
  return [] unless path.file?
83
99
  lines = SharedHelpers.filesystem_access(path, :read, &:read).split("\n")
@@ -96,6 +112,10 @@ module Bundler
96
112
  directory.join("info-special-characters"),
97
113
  ]
98
114
  end
115
+
116
+ def info_etag_root
117
+ directory.join("info-etags")
118
+ end
99
119
  end
100
120
  end
101
121
  end
@@ -0,0 +1,153 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../vendored_fileutils"
4
+ require "rubygems/package"
5
+
6
+ module Bundler
7
+ class CompactIndexClient
8
+ # write cache files in a way that is robust to concurrent modifications
9
+ # if digests are given, the checksums will be verified
10
+ class CacheFile
11
+ DEFAULT_FILE_MODE = 0o644
12
+ private_constant :DEFAULT_FILE_MODE
13
+
14
+ class Error < RuntimeError; end
15
+ class ClosedError < Error; end
16
+
17
+ class DigestMismatchError < Error
18
+ def initialize(digests, expected_digests)
19
+ super "Calculated checksums #{digests.inspect} did not match expected #{expected_digests.inspect}."
20
+ end
21
+ end
22
+
23
+ # Initialize with a copy of the original file, then yield the instance.
24
+ def self.copy(path, &block)
25
+ new(path) do |file|
26
+ file.initialize_digests
27
+
28
+ SharedHelpers.filesystem_access(path, :read) do
29
+ path.open("rb") do |s|
30
+ file.open {|f| IO.copy_stream(s, f) }
31
+ end
32
+ end
33
+
34
+ yield file
35
+ end
36
+ end
37
+
38
+ # Write data to a temp file, then replace the original file with it verifying the digests if given.
39
+ def self.write(path, data, digests = nil)
40
+ return unless data
41
+ new(path) do |file|
42
+ file.digests = digests
43
+ file.write(data)
44
+ end
45
+ end
46
+
47
+ attr_reader :original_path, :path
48
+
49
+ def initialize(original_path, &block)
50
+ @original_path = original_path
51
+ @perm = original_path.file? ? original_path.stat.mode : DEFAULT_FILE_MODE
52
+ @path = original_path.sub(/$/, ".#{$$}.tmp")
53
+ return unless block_given?
54
+ begin
55
+ yield self
56
+ ensure
57
+ close
58
+ end
59
+ end
60
+
61
+ def size
62
+ path.size
63
+ end
64
+
65
+ # initialize the digests using CompactIndexClient::SUPPORTED_DIGESTS, or a subset based on keys.
66
+ def initialize_digests(keys = nil)
67
+ @digests = keys ? SUPPORTED_DIGESTS.slice(*keys) : SUPPORTED_DIGESTS.dup
68
+ @digests.transform_values! {|algo_class| SharedHelpers.digest(algo_class).new }
69
+ end
70
+
71
+ # reset the digests so they don't contain any previously read data
72
+ def reset_digests
73
+ @digests&.each_value(&:reset)
74
+ end
75
+
76
+ # set the digests that will be verified at the end
77
+ def digests=(expected_digests)
78
+ @expected_digests = expected_digests
79
+
80
+ if @expected_digests.nil?
81
+ @digests = nil
82
+ elsif @digests
83
+ @digests = @digests.slice(*@expected_digests.keys)
84
+ else
85
+ initialize_digests(@expected_digests.keys)
86
+ end
87
+ end
88
+
89
+ # remove this method when we stop generating md5 digests for legacy etags
90
+ def md5
91
+ @digests && @digests["md5"]
92
+ end
93
+
94
+ def digests?
95
+ @digests&.any?
96
+ end
97
+
98
+ # Open the temp file for writing, reusing original permissions, yielding the IO object.
99
+ def open(write_mode = "wb", perm = @perm, &block)
100
+ raise ClosedError, "Cannot reopen closed file" if @closed
101
+ SharedHelpers.filesystem_access(path, :write) do
102
+ path.open(write_mode, perm) do |f|
103
+ yield digests? ? Gem::Package::DigestIO.new(f, @digests) : f
104
+ end
105
+ end
106
+ end
107
+
108
+ # Returns false without appending when no digests since appending is too error prone to do without digests.
109
+ def append(data)
110
+ return false unless digests?
111
+ open("a") {|f| f.write data }
112
+ verify && commit
113
+ end
114
+
115
+ def write(data)
116
+ reset_digests
117
+ open {|f| f.write data }
118
+ commit!
119
+ end
120
+
121
+ def commit!
122
+ verify || raise(DigestMismatchError.new(@base64digests, @expected_digests))
123
+ commit
124
+ end
125
+
126
+ # Verify the digests, returning true on match, false on mismatch.
127
+ def verify
128
+ return true unless @expected_digests && digests?
129
+ @base64digests = @digests.transform_values!(&:base64digest)
130
+ @digests = nil
131
+ @base64digests.all? {|algo, digest| @expected_digests[algo] == digest }
132
+ end
133
+
134
+ # Replace the original file with the temp file without verifying digests.
135
+ # The file is permanently closed.
136
+ def commit
137
+ raise ClosedError, "Cannot commit closed file" if @closed
138
+ SharedHelpers.filesystem_access(original_path, :write) do
139
+ FileUtils.mv(path, original_path)
140
+ end
141
+ @closed = true
142
+ end
143
+
144
+ # Remove the temp file without replacing the original file.
145
+ # The file is permanently closed.
146
+ def close
147
+ return if @closed
148
+ FileUtils.remove_file(path) if @path&.file?
149
+ @closed = true
150
+ end
151
+ end
152
+ end
153
+ end
@@ -6,12 +6,15 @@ module Bundler
6
6
  GemParser = Gem::Resolver::APISet::GemParser
7
7
  else
8
8
  class GemParser
9
+ EMPTY_ARRAY = [].freeze
10
+ private_constant :EMPTY_ARRAY
11
+
9
12
  def parse(line)
10
13
  version_and_platform, rest = line.split(" ", 2)
11
14
  version, platform = version_and_platform.split("-", 2)
12
- dependencies, requirements = rest.split("|", 2).map {|s| s.split(",") } if rest
13
- dependencies = dependencies ? dependencies.map {|d| parse_dependency(d) } : []
14
- requirements = requirements ? requirements.map {|d| parse_dependency(d) } : []
15
+ dependencies, requirements = rest.split("|", 2).map! {|s| s.split(",") } if rest
16
+ dependencies = dependencies ? dependencies.map! {|d| parse_dependency(d) } : EMPTY_ARRAY
17
+ requirements = requirements ? requirements.map! {|d| parse_dependency(d) } : EMPTY_ARRAY
15
18
  [version, platform, dependencies, requirements]
16
19
  end
17
20
 
@@ -20,6 +23,7 @@ module Bundler
20
23
  def parse_dependency(string)
21
24
  dependency = string.split(":")
22
25
  dependency[-1] = dependency[-1].split("&") if dependency.size > 1
26
+ dependency[0] = -dependency[0]
23
27
  dependency
24
28
  end
25
29
  end
@@ -1,20 +1,11 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative "../vendored_fileutils"
4
-
5
3
  module Bundler
6
4
  class CompactIndexClient
7
5
  class Updater
8
- class MisMatchedChecksumError < Error
9
- def initialize(path, server_checksum, local_checksum)
10
- @path = path
11
- @server_checksum = server_checksum
12
- @local_checksum = local_checksum
13
- end
14
-
15
- def message
16
- "The checksum of /#{@path} does not match the checksum provided by the server! Something is wrong " \
17
- "(local checksum is #{@local_checksum.inspect}, was expecting #{@server_checksum.inspect})."
6
+ class MismatchedChecksumError < Error
7
+ def initialize(path, message)
8
+ super "The checksum of /#{path} does not match the checksum provided by the server! Something is wrong. #{message}"
18
9
  end
19
10
  end
20
11
 
@@ -22,95 +13,102 @@ module Bundler
22
13
  @fetcher = fetcher
23
14
  end
24
15
 
25
- def update(local_path, remote_path, retrying = nil)
26
- headers = {}
27
-
28
- local_temp_path = local_path.sub(/$/, ".#{$$}")
29
- local_temp_path = local_temp_path.sub(/$/, ".retrying") if retrying
30
- local_temp_path = local_temp_path.sub(/$/, ".tmp")
31
-
32
- # first try to fetch any new bytes on the existing file
33
- if retrying.nil? && local_path.file?
34
- copy_file local_path, local_temp_path
16
+ def update(remote_path, local_path, etag_path)
17
+ append(remote_path, local_path, etag_path) || replace(remote_path, local_path, etag_path)
18
+ rescue CacheFile::DigestMismatchError => e
19
+ raise MismatchedChecksumError.new(remote_path, e.message)
20
+ rescue Zlib::GzipFile::Error
21
+ raise Bundler::HTTPError
22
+ end
35
23
 
36
- headers["If-None-Match"] = etag_for(local_temp_path)
37
- headers["Range"] =
38
- if local_temp_path.size.nonzero?
39
- # Subtract a byte to ensure the range won't be empty.
40
- # Avoids 416 (Range Not Satisfiable) responses.
41
- "bytes=#{local_temp_path.size - 1}-"
42
- else
43
- "bytes=#{local_temp_path.size}-"
44
- end
45
- end
24
+ private
46
25
 
47
- response = @fetcher.call(remote_path, headers)
48
- return nil if response.is_a?(Net::HTTPNotModified)
26
+ def append(remote_path, local_path, etag_path)
27
+ return false unless local_path.file? && local_path.size.nonzero?
49
28
 
50
- content = response.body
29
+ CacheFile.copy(local_path) do |file|
30
+ etag = etag_path.read.tap(&:chomp!) if etag_path.file?
31
+ etag ||= generate_etag(etag_path, file) # Remove this after 2.5.0 has been out for a while.
51
32
 
52
- etag = (response["ETag"] || "").gsub(%r{\AW/}, "")
53
- correct_response = SharedHelpers.filesystem_access(local_temp_path) do
54
- if response.is_a?(Net::HTTPPartialContent) && local_temp_path.size.nonzero?
55
- local_temp_path.open("a") {|f| f << slice_body(content, 1..-1) }
33
+ # Subtract a byte to ensure the range won't be empty.
34
+ # Avoids 416 (Range Not Satisfiable) responses.
35
+ response = @fetcher.call(remote_path, request_headers(etag, file.size - 1))
36
+ break true if response.is_a?(Gem::Net::HTTPNotModified)
56
37
 
57
- etag_for(local_temp_path) == etag
38
+ file.digests = parse_digests(response)
39
+ # server may ignore Range and return the full response
40
+ if response.is_a?(Gem::Net::HTTPPartialContent)
41
+ break false unless file.append(response.body.byteslice(1..-1))
58
42
  else
59
- local_temp_path.open("wb") {|f| f << content }
60
-
61
- etag.length.zero? || etag_for(local_temp_path) == etag
43
+ file.write(response.body)
62
44
  end
45
+ CacheFile.write(etag_path, etag(response))
46
+ true
63
47
  end
48
+ end
64
49
 
65
- if correct_response
66
- SharedHelpers.filesystem_access(local_path) do
67
- FileUtils.mv(local_temp_path, local_path)
68
- end
69
- return nil
70
- end
50
+ # request without range header to get the full file or a 304 Not Modified
51
+ def replace(remote_path, local_path, etag_path)
52
+ etag = etag_path.read.tap(&:chomp!) if etag_path.file?
53
+ response = @fetcher.call(remote_path, request_headers(etag))
54
+ return true if response.is_a?(Gem::Net::HTTPNotModified)
55
+ CacheFile.write(local_path, response.body, parse_digests(response))
56
+ CacheFile.write(etag_path, etag(response))
57
+ end
71
58
 
72
- if retrying
73
- raise MisMatchedChecksumError.new(remote_path, etag, etag_for(local_temp_path))
74
- end
59
+ def request_headers(etag, range_start = nil)
60
+ headers = {}
61
+ headers["Range"] = "bytes=#{range_start}-" if range_start
62
+ headers["If-None-Match"] = etag if etag
63
+ headers
64
+ end
75
65
 
76
- update(local_path, remote_path, :retrying)
77
- rescue Zlib::GzipFile::Error
78
- raise Bundler::HTTPError
79
- ensure
80
- FileUtils.remove_file(local_temp_path) if File.exist?(local_temp_path)
66
+ def etag_for_request(etag_path)
67
+ etag_path.read.tap(&:chomp!) if etag_path.file?
81
68
  end
82
69
 
83
- def etag_for(path)
84
- sum = checksum_for_file(path)
85
- sum ? %("#{sum}") : nil
70
+ # When first releasing this opaque etag feature, we want to generate the old MD5 etag
71
+ # based on the content of the file. After that it will always use the saved opaque etag.
72
+ # This transparently saves existing users with good caches from updating a bunch of files.
73
+ # Remove this behavior after 2.5.0 has been out for a while.
74
+ def generate_etag(etag_path, file)
75
+ etag = file.md5.hexdigest
76
+ CacheFile.write(etag_path, etag)
77
+ etag
86
78
  end
87
79
 
88
- def slice_body(body, range)
89
- body.byteslice(range)
80
+ def etag(response)
81
+ return unless response["ETag"]
82
+ etag = response["ETag"].delete_prefix("W/")
83
+ return if etag.delete_prefix!('"') && !etag.delete_suffix!('"')
84
+ etag
90
85
  end
91
86
 
92
- def checksum_for_file(path)
93
- return nil unless path.file?
94
- # This must use File.read instead of Digest.file().hexdigest
95
- # because we need to preserve \n line endings on windows when calculating
96
- # the checksum
97
- SharedHelpers.filesystem_access(path, :read) do
98
- SharedHelpers.digest(:MD5).hexdigest(File.read(path))
87
+ # Unwraps and returns a Hash of digest algorithms and base64 values
88
+ # according to RFC 8941 Structured Field Values for HTTP.
89
+ # https://www.rfc-editor.org/rfc/rfc8941#name-parsing-a-byte-sequence
90
+ # Ignores unsupported algorithms.
91
+ def parse_digests(response)
92
+ return unless header = response["Repr-Digest"] || response["Digest"]
93
+ digests = {}
94
+ header.split(",") do |param|
95
+ algorithm, value = param.split("=", 2)
96
+ algorithm.strip!
97
+ algorithm.downcase!
98
+ next unless SUPPORTED_DIGESTS.key?(algorithm)
99
+ next unless value = byte_sequence(value)
100
+ digests[algorithm] = value
99
101
  end
102
+ digests.empty? ? nil : digests
100
103
  end
101
104
 
102
- private
103
-
104
- def copy_file(source, dest)
105
- SharedHelpers.filesystem_access(source, :read) do
106
- File.open(source, "r") do |s|
107
- SharedHelpers.filesystem_access(dest, :write) do
108
- File.open(dest, "wb", s.stat.mode) do |f|
109
- IO.copy_stream(s, f)
110
- end
111
- end
112
- end
113
- end
105
+ # Unwrap surrounding colons (byte sequence)
106
+ # The wrapping characters must be matched or we return nil.
107
+ # Also handles quotes because right now rubygems.org sends them.
108
+ def byte_sequence(value)
109
+ return if value.delete_prefix!(":") && !value.delete_suffix!(":")
110
+ return if value.delete_prefix!('"') && !value.delete_suffix!('"')
111
+ value
114
112
  end
115
113
  end
116
114
  end
@@ -5,7 +5,13 @@ require "set"
5
5
 
6
6
  module Bundler
7
7
  class CompactIndexClient
8
+ # NOTE: MD5 is here not because we expect a server to respond with it, but
9
+ # because we use it to generate the etag on first request during the upgrade
10
+ # to the compact index client that uses opaque etags saved to files.
11
+ # Remove once 2.5.0 has been out for a while.
12
+ SUPPORTED_DIGESTS = { "sha-256" => :SHA256, "md5" => :MD5 }.freeze
8
13
  DEBUG_MUTEX = Thread::Mutex.new
14
+
9
15
  def self.debug
10
16
  return unless ENV["DEBUG_COMPACT_INDEX"]
11
17
  DEBUG_MUTEX.synchronize { warn("[#{self}] #{yield}") }
@@ -14,6 +20,7 @@ module Bundler
14
20
  class Error < StandardError; end
15
21
 
16
22
  require_relative "compact_index_client/cache"
23
+ require_relative "compact_index_client/cache_file"
17
24
  require_relative "compact_index_client/updater"
18
25
 
19
26
  attr_reader :directory
@@ -54,13 +61,13 @@ module Bundler
54
61
 
55
62
  def names
56
63
  Bundler::CompactIndexClient.debug { "/names" }
57
- update(@cache.names_path, "names")
64
+ update("names", @cache.names_path, @cache.names_etag_path)
58
65
  @cache.names
59
66
  end
60
67
 
61
68
  def versions
62
69
  Bundler::CompactIndexClient.debug { "/versions" }
63
- update(@cache.versions_path, "versions")
70
+ update("versions", @cache.versions_path, @cache.versions_etag_path)
64
71
  versions, @info_checksums_by_name = @cache.versions
65
72
  versions
66
73
  end
@@ -76,36 +83,36 @@ module Bundler
76
83
  def update_and_parse_checksums!
77
84
  Bundler::CompactIndexClient.debug { "update_and_parse_checksums!" }
78
85
  return @info_checksums_by_name if @parsed_checksums
79
- update(@cache.versions_path, "versions")
86
+ update("versions", @cache.versions_path, @cache.versions_etag_path)
80
87
  @info_checksums_by_name = @cache.checksums
81
88
  @parsed_checksums = true
82
89
  end
83
90
 
84
91
  private
85
92
 
86
- def update(local_path, remote_path)
93
+ def update(remote_path, local_path, local_etag_path)
87
94
  Bundler::CompactIndexClient.debug { "update(#{local_path}, #{remote_path})" }
88
95
  unless synchronize { @endpoints.add?(remote_path) }
89
96
  Bundler::CompactIndexClient.debug { "already fetched #{remote_path}" }
90
97
  return
91
98
  end
92
- @updater.update(local_path, url(remote_path))
99
+ @updater.update(url(remote_path), local_path, local_etag_path)
93
100
  end
94
101
 
95
102
  def update_info(name)
96
103
  Bundler::CompactIndexClient.debug { "update_info(#{name})" }
97
104
  path = @cache.info_path(name)
98
- checksum = @updater.checksum_for_file(path)
99
105
  unless existing = @info_checksums_by_name[name]
100
106
  Bundler::CompactIndexClient.debug { "skipping updating info for #{name} since it is missing from versions" }
101
107
  return
102
108
  end
109
+ checksum = SharedHelpers.checksum_for_file(path, :MD5)
103
110
  if checksum == existing
104
111
  Bundler::CompactIndexClient.debug { "skipping updating info for #{name} since the versions checksum matches the local checksum" }
105
112
  return
106
113
  end
107
114
  Bundler::CompactIndexClient.debug { "updating info for #{name} since the versions checksum #{existing} != the local checksum #{checksum}" }
108
- update(path, "info/#{name}")
115
+ update("info/#{name}", path, @cache.info_etag_path(name))
109
116
  end
110
117
 
111
118
  def url(path)
@@ -3,5 +3,5 @@
3
3
  module Bundler
4
4
  WINDOWS = RbConfig::CONFIG["host_os"] =~ /(msdos|mswin|djgpp|mingw)/
5
5
  FREEBSD = RbConfig::CONFIG["host_os"].to_s.include?("bsd")
6
- NULL = WINDOWS ? "NUL" : "/dev/null"
6
+ NULL = File::NULL
7
7
  end
@@ -43,7 +43,7 @@ module Bundler
43
43
  ].freeze
44
44
 
45
45
  def ruby?
46
- return true if Bundler::GemHelpers.generic_local_platform == Gem::Platform::RUBY
46
+ return true if Bundler::GemHelpers.generic_local_platform_is_ruby?
47
47
 
48
48
  !windows? && (RUBY_ENGINE == "ruby" || RUBY_ENGINE == "rbx" || RUBY_ENGINE == "maglev" || RUBY_ENGINE == "truffleruby")
49
49
  end
@@ -71,26 +71,10 @@ module Bundler
71
71
  def windows?
72
72
  Gem.win_platform?
73
73
  end
74
-
75
- def mswin?
76
- # For backwards compatibility
77
- windows?
78
-
79
- # TODO: This should correctly be:
80
- # windows? && Bundler.local_platform != Gem::Platform::RUBY && Bundler.local_platform.os == "mswin32" && Bundler.local_platform.cpu == "x86"
81
- end
82
-
83
- def mswin64?
84
- windows? && Bundler.local_platform != Gem::Platform::RUBY && Bundler.local_platform.os == "mswin64" && Bundler.local_platform.cpu == "x64"
85
- end
86
-
87
- def mingw?
88
- windows? && Bundler.local_platform != Gem::Platform::RUBY && Bundler.local_platform.os == "mingw32" && Bundler.local_platform.cpu != "x64"
89
- end
90
-
91
- def x64_mingw?
92
- Gem.win_platform? && Bundler.local_platform != Gem::Platform::RUBY && Bundler.local_platform.os.start_with?("mingw") && Bundler.local_platform.cpu == "x64"
93
- end
74
+ alias_method :mswin?, :windows?
75
+ alias_method :mswin64?, :windows?
76
+ alias_method :mingw?, :windows?
77
+ alias_method :x64_mingw?, :windows?
94
78
 
95
79
  (KNOWN_MINOR_VERSIONS + KNOWN_MAJOR_VERSIONS).each do |version|
96
80
  trimmed_version = version.tr(".", "")