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
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Bundler
4
+ class Gemdeps
5
+ def initialize(runtime)
6
+ @runtime = runtime
7
+ end
8
+
9
+ def requested_specs
10
+ @runtime.requested_specs
11
+ end
12
+
13
+ def specs
14
+ @runtime.specs
15
+ end
16
+
17
+ def dependencies
18
+ @runtime.dependencies
19
+ end
20
+
21
+ def current_dependencies
22
+ @runtime.current_dependencies
23
+ end
24
+
25
+ def requires
26
+ @runtime.requires
27
+ end
28
+ end
29
+ end
@@ -1,4 +1,6 @@
1
- require 'set'
1
+ # frozen_string_literal: true
2
+
3
+ require "set"
2
4
  module Bundler
3
5
  class Graph
4
6
  GRAPH_NAME = :Gemfile
@@ -12,11 +14,10 @@ module Bundler
12
14
  @without_groups = without.map(&:to_sym)
13
15
 
14
16
  @groups = []
15
- @relations = Hash.new {|h, k| h[k] = Set.new}
17
+ @relations = Hash.new {|h, k| h[k] = Set.new }
16
18
  @node_options = {}
17
19
  @edge_options = {}
18
20
 
19
- _patching_gem_dependency_class
20
21
  _populate_relations
21
22
  end
22
23
 
@@ -26,32 +27,30 @@ module Bundler
26
27
  GraphVizClient.new(self).run
27
28
  end
28
29
 
29
- private
30
+ private
30
31
 
31
32
  def _populate_relations
32
33
  parent_dependencies = _groups.values.to_set.flatten
33
- while true
34
- if parent_dependencies.empty?
35
- break
36
- else
37
- tmp = Set.new
38
- parent_dependencies.each do |dependency|
39
- child_dependencies = dependency.to_spec.runtime_dependencies.to_set
40
- @relations[dependency.name] += child_dependencies.map(&:name).to_set
41
- tmp += child_dependencies
42
-
43
- @node_options[dependency.name] = _make_label(dependency, :node)
44
- child_dependencies.each do |c_dependency|
45
- @edge_options["#{dependency.name}_#{c_dependency.name}"] = _make_label(c_dependency, :edge)
46
- end
34
+ loop do
35
+ break if parent_dependencies.empty?
36
+
37
+ tmp = Set.new
38
+ parent_dependencies.each do |dependency|
39
+ child_dependencies = spec_for_dependency(dependency).runtime_dependencies.to_set
40
+ @relations[dependency.name] += child_dependencies.map(&:name).to_set
41
+ tmp += child_dependencies
42
+
43
+ @node_options[dependency.name] = _make_label(dependency, :node)
44
+ child_dependencies.each do |c_dependency|
45
+ @edge_options["#{dependency.name}_#{c_dependency.name}"] = _make_label(c_dependency, :edge)
47
46
  end
48
- parent_dependencies = tmp
49
47
  end
48
+ parent_dependencies = tmp
50
49
  end
51
50
  end
52
51
 
53
52
  def _groups
54
- relations = Hash.new {|h, k| h[k] = Set.new}
53
+ relations = Hash.new {|h, k| h[k] = Set.new }
55
54
  @env.current_dependencies.each do |dependency|
56
55
  dependency.groups.each do |group|
57
56
  next if @without_groups.include?(group)
@@ -72,7 +71,7 @@ module Bundler
72
71
  when :node
73
72
  if symbol_or_string_or_dependency.is_a?(Gem::Dependency)
74
73
  label = symbol_or_string_or_dependency.name.dup
75
- label << "\n#{symbol_or_string_or_dependency.to_spec.version.to_s}" if @show_version
74
+ label << "\n#{spec_for_dependency(symbol_or_string_or_dependency).version}" if @show_version
76
75
  else
77
76
  label = symbol_or_string_or_dependency.to_s
78
77
  end
@@ -88,25 +87,8 @@ module Bundler
88
87
  label.nil? ? {} : { :label => label }
89
88
  end
90
89
 
91
- def _patching_gem_dependency_class
92
- # method borrow from rubygems/dependency.rb
93
- # redefinition of matching_specs will also redefine to_spec and to_specs
94
- Gem::Dependency.class_eval do
95
- def matching_specs platform_only = false
96
- matches = Bundler.load.specs.select { |spec|
97
- self.name == spec.name and
98
- requirement.satisfied_by? spec.version
99
- }
100
-
101
- if platform_only
102
- matches.reject! { |spec|
103
- not Gem::Platform.match spec.platform
104
- }
105
- end
106
-
107
- matches = matches.sort_by { |s| s.sort_obj } # HACK: shouldn't be needed
108
- end
109
- end
90
+ def spec_for_dependency(dependency)
91
+ @env.requested_specs.find {|s| s.name == dependency.name }
110
92
  end
111
93
 
112
94
  class GraphVizClient
@@ -121,9 +103,9 @@ module Bundler
121
103
  end
122
104
 
123
105
  def g
124
- @g ||= ::GraphViz.digraph(@graph_name, {:concentrate => true, :normalize => true, :nodesep => 0.55}) do |g|
106
+ @g ||= ::GraphViz.digraph(@graph_name, :concentrate => true, :normalize => true, :nodesep => 0.55) do |g|
125
107
  g.edge[:weight] = 2
126
- g.edge[:fontname] = g.node[:fontname] = 'Arial, Helvetica, SansSerif'
108
+ g.edge[:fontname] = g.node[:fontname] = "Arial, Helvetica, SansSerif"
127
109
  g.edge[:fontsize] = 12
128
110
  end
129
111
  end
@@ -131,19 +113,20 @@ module Bundler
131
113
  def run
132
114
  @groups.each do |group|
133
115
  g.add_nodes(
134
- group,
135
- {:style => 'filled',
136
- :fillcolor => '#B9B9D5',
137
- :shape => "box3d",
138
- :fontsize => 16}.merge(@node_options[group])
116
+ group, {
117
+ :style => "filled",
118
+ :fillcolor => "#B9B9D5",
119
+ :shape => "box3d",
120
+ :fontsize => 16
121
+ }.merge(@node_options[group])
139
122
  )
140
123
  end
141
124
 
142
125
  @relations.each do |parent, children|
143
126
  children.each do |child|
144
127
  if @groups.include?(parent)
145
- g.add_nodes(child, {:style => 'filled', :fillcolor => '#B9B9D5'}.merge(@node_options[child]))
146
- g.add_edges(parent, child, {:constraint => false}.merge(@edge_options["#{parent}_#{child}"]))
128
+ g.add_nodes(child, { :style => "filled", :fillcolor => "#B9B9D5" }.merge(@node_options[child]))
129
+ g.add_edges(parent, child, { :constraint => false }.merge(@edge_options["#{parent}_#{child}"]))
147
130
  else
148
131
  g.add_nodes(child, @node_options[child])
149
132
  g.add_edges(parent, child, @edge_options["#{parent}_#{child}"])
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "set"
2
4
 
3
5
  module Bundler
@@ -11,21 +13,23 @@ module Bundler
11
13
  end
12
14
 
13
15
  attr_reader :specs, :all_specs, :sources
14
- protected :specs, :all_specs
16
+ protected :specs, :all_specs
17
+
18
+ RUBY = "ruby".freeze
19
+ NULL = "\0".freeze
15
20
 
16
21
  def initialize
17
22
  @sources = []
18
23
  @cache = {}
19
- @specs = Hash.new { |h,k| h[k] = Hash.new }
20
- @all_specs = Hash.new { |h,k| h[k] = [] }
24
+ @specs = Hash.new {|h, k| h[k] = {} }
25
+ @all_specs = Hash.new {|h, k| h[k] = EMPTY_SEARCH }
21
26
  end
22
27
 
23
28
  def initialize_copy(o)
24
- super
25
- @sources = @sources.dup
29
+ @sources = o.sources.dup
26
30
  @cache = {}
27
- @specs = Hash.new { |h,k| h[k] = Hash.new }
28
- @all_specs = Hash.new { |h,k| h[k] = [] }
31
+ @specs = Hash.new {|h, k| h[k] = {} }
32
+ @all_specs = Hash.new {|h, k| h[k] = EMPTY_SEARCH }
29
33
 
30
34
  o.specs.each do |name, hash|
31
35
  @specs[name] = hash.dup
@@ -36,7 +40,7 @@ module Bundler
36
40
  end
37
41
 
38
42
  def inspect
39
- "#<#{self.class}:0x#{object_id} sources=#{sources.map{|s| s.inspect}} specs.size=#{specs.size}>"
43
+ "#<#{self.class}:0x#{object_id} sources=#{sources.map(&:inspect)} specs.size=#{specs.size}>"
40
44
  end
41
45
 
42
46
  def empty?
@@ -45,7 +49,7 @@ module Bundler
45
49
  end
46
50
 
47
51
  def search_all(name)
48
- all_matches = @all_specs[name] + local_search(name)
52
+ all_matches = local_search(name) + @all_specs[name]
49
53
  @sources.each do |source|
50
54
  all_matches.concat(source.search_all(name))
51
55
  end
@@ -55,20 +59,33 @@ module Bundler
55
59
  # Search this index's specs, and any source indexes that this index knows
56
60
  # about, returning all of the results.
57
61
  def search(query, base = nil)
62
+ sort_specs(unsorted_search(query, base))
63
+ end
64
+
65
+ def unsorted_search(query, base)
58
66
  results = local_search(query, base)
59
- seen = Set.new(results.map { |spec| [spec.name, spec.version, spec.platform] })
67
+
68
+ seen = results.map(&:full_name).to_set unless @sources.empty?
60
69
 
61
70
  @sources.each do |source|
62
- source.search(query, base).each do |spec|
63
- lookup = [spec.name, spec.version, spec.platform]
64
- unless seen.include?(lookup)
65
- results << spec
66
- seen << lookup
67
- end
71
+ source.unsorted_search(query, base).each do |spec|
72
+ results << spec if seen.add?(spec.full_name)
68
73
  end
69
74
  end
70
75
 
71
- results.sort_by {|s| [s.version, s.platform.to_s == 'ruby' ? "\0" : s.platform.to_s] }
76
+ results
77
+ end
78
+ protected :unsorted_search
79
+
80
+ def self.sort_specs(specs)
81
+ specs.sort_by do |s|
82
+ platform_string = s.platform.to_s
83
+ [s.version, platform_string == RUBY ? NULL : platform_string]
84
+ end
85
+ end
86
+
87
+ def sort_specs(specs)
88
+ self.class.sort_specs(specs)
72
89
  end
73
90
 
74
91
  def local_search(query, base = nil)
@@ -76,49 +93,59 @@ module Bundler
76
93
  when Gem::Specification, RemoteSpecification, LazySpecification, EndpointSpecification then search_by_spec(query)
77
94
  when String then specs_by_name(query)
78
95
  when Gem::Dependency then search_by_dependency(query, base)
96
+ when DepProxy then search_by_dependency(query.dep, base)
79
97
  else
80
98
  raise "You can't search for a #{query.inspect}."
81
99
  end
82
100
  end
83
101
 
84
- def source_types
85
- sources.map{|s| s.class }.uniq
86
- end
87
-
88
- alias [] search
102
+ alias_method :[], :search
89
103
 
90
104
  def <<(spec)
91
- @specs[spec.name]["#{spec.version}-#{spec.platform}"] = spec
92
-
105
+ @specs[spec.name][spec.full_name] = spec
93
106
  spec
94
107
  end
95
108
 
96
109
  def each(&blk)
110
+ return enum_for(:each) unless blk
97
111
  specs.values.each do |spec_sets|
98
112
  spec_sets.values.each(&blk)
99
113
  end
114
+ sources.each {|s| s.each(&blk) }
115
+ self
116
+ end
117
+
118
+ def spec_names
119
+ names = specs.keys + sources.map(&:spec_names)
120
+ names.uniq!
121
+ names
100
122
  end
101
123
 
102
124
  # returns a list of the dependencies
103
125
  def unmet_dependency_names
104
- names = dependency_names
105
- names.delete_if{|n| n == "bundler" }
106
- names.select{|n| search(n).empty? }
126
+ dependency_names.select do |name|
127
+ name != "bundler" && search(name).empty?
128
+ end
107
129
  end
108
130
 
109
131
  def dependency_names
110
132
  names = []
111
- each{|s| names.push(*s.dependencies.map{|d| d.name }) }
133
+ each do |spec|
134
+ spec.dependencies.each do |dep|
135
+ next if dep.type == :development
136
+ names << dep.name
137
+ end
138
+ end
112
139
  names.uniq
113
140
  end
114
141
 
115
142
  def use(other, override_dupes = false)
116
143
  return unless other
117
144
  other.each do |s|
118
- if (dupes = search_by_spec(s)) && dupes.any?
119
- @all_specs[s.name] = [s] + dupes
145
+ if (dupes = search_by_spec(s)) && !dupes.empty?
146
+ # safe to << since it's a new array when it has contents
147
+ @all_specs[s.name] = dupes << s
120
148
  next unless override_dupes
121
- self << s
122
149
  end
123
150
  self << s
124
151
  end
@@ -131,20 +158,25 @@ module Bundler
131
158
  end
132
159
  end
133
160
 
134
- def ==(o)
161
+ # Whether all the specs in self are in other
162
+ # TODO: rename to #include?
163
+ def ==(other)
135
164
  all? do |spec|
136
- other_spec = o[spec].first
137
- (spec.dependencies & other_spec.dependencies).empty? && spec.source == other_spec.source
165
+ other_spec = other[spec].first
166
+ other_spec && dependencies_eql?(spec, other_spec) && spec.source == other_spec.source
138
167
  end
139
168
  end
140
169
 
170
+ def dependencies_eql?(spec, other_spec)
171
+ deps = spec.dependencies.select {|d| d.type != :development }
172
+ other_deps = other_spec.dependencies.select {|d| d.type != :development }
173
+ Set.new(deps) == Set.new(other_deps)
174
+ end
175
+
141
176
  def add_source(index)
142
- if index.is_a?(Index)
143
- @sources << index
144
- @sources.uniq! # need to use uniq! here instead of checking for the item before adding
145
- else
146
- raise ArgumentError, "Source must be an index, not #{index.class}"
147
- end
177
+ raise ArgumentError, "Source must be an index, not #{index.class}" unless index.is_a?(Index)
178
+ @sources << index
179
+ @sources.uniq! # need to use uniq! here instead of checking for the item before adding
148
180
  end
149
181
 
150
182
  private
@@ -156,8 +188,10 @@ module Bundler
156
188
  def search_by_dependency(dependency, base = nil)
157
189
  @cache[base || false] ||= {}
158
190
  @cache[base || false][dependency] ||= begin
159
- specs = specs_by_name(dependency.name) + (base || [])
191
+ specs = specs_by_name(dependency.name)
192
+ specs += base if base
160
193
  found = specs.select do |spec|
194
+ next true if spec.source.is_a?(Source::Gemspec)
161
195
  if base # allow all platforms when searching from a lockfile
162
196
  dependency.matches_spec?(spec)
163
197
  else
@@ -165,37 +199,15 @@ module Bundler
165
199
  end
166
200
  end
167
201
 
168
- wants_prerelease = dependency.requirement.prerelease?
169
- only_prerelease = specs.all? {|spec| spec.version.prerelease? }
170
-
171
- unless wants_prerelease || only_prerelease
172
- found.reject! { |spec| spec.version.prerelease? }
173
- end
174
-
175
202
  found
176
203
  end
177
204
  end
178
205
 
179
- def search_by_spec(spec)
180
- spec = @specs[spec.name]["#{spec.version}-#{spec.platform}"]
181
- spec ? [spec] : []
182
- end
183
-
184
- if RUBY_VERSION < '1.9'
185
- def same_version?(a, b)
186
- regex = /^(.*?)(?:\.0)*$/
187
- a.to_s[regex, 1] == b.to_s[regex, 1]
188
- end
189
- else
190
- def same_version?(a, b)
191
- a == b
192
- end
193
- end
206
+ EMPTY_SEARCH = [].freeze
194
207
 
195
- def spec_satisfies_dependency?(spec, dep)
196
- return false unless dep.name == spec.name
197
- dep.requirement.satisfied_by?(spec.version)
208
+ def search_by_spec(spec)
209
+ spec = @specs[spec.name][spec.full_name]
210
+ spec ? [spec] : EMPTY_SEARCH
198
211
  end
199
-
200
212
  end
201
213
  end
@@ -1,64 +1,253 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Bundler
2
4
  class Injector
3
- def self.inject(new_deps)
4
- injector = new(new_deps)
5
+ INJECTED_GEMS = "injected gems".freeze
6
+
7
+ def self.inject(new_deps, options = {})
8
+ injector = new(new_deps, options)
5
9
  injector.inject(Bundler.default_gemfile, Bundler.default_lockfile)
6
10
  end
7
11
 
8
- def initialize(new_deps)
9
- @new_deps = new_deps
12
+ def self.remove(gems, options = {})
13
+ injector = new(gems, options)
14
+ injector.remove(Bundler.default_gemfile, Bundler.default_lockfile)
10
15
  end
11
16
 
17
+ def initialize(deps, options = {})
18
+ @deps = deps
19
+ @options = options
20
+ end
21
+
22
+ # @param [Pathname] gemfile_path The Gemfile in which to inject the new dependency.
23
+ # @param [Pathname] lockfile_path The lockfile in which to inject the new dependency.
24
+ # @return [Array]
12
25
  def inject(gemfile_path, lockfile_path)
13
- if Bundler.settings[:frozen]
26
+ if Bundler.frozen_bundle?
14
27
  # ensure the lock and Gemfile are synced
15
28
  Bundler.definition.ensure_equivalent_gemfile_and_lockfile(true)
16
- # temporarily remove frozen while we inject
17
- frozen = Bundler.settings.delete(:frozen)
18
29
  end
19
30
 
20
- # evaluate the Gemfile we have now
21
- builder = Dsl.new
22
- builder.eval_gemfile(gemfile_path)
31
+ # temporarily unfreeze
32
+ Bundler.settings.temporary(:deployment => false, :frozen => false) do
33
+ # evaluate the Gemfile we have now
34
+ builder = Dsl.new
35
+ builder.eval_gemfile(gemfile_path)
36
+
37
+ # don't inject any gems that are already in the Gemfile
38
+ @deps -= builder.dependencies
23
39
 
24
- # don't inject any gems that are already in the Gemfile
25
- @new_deps -= builder.dependencies
40
+ # add new deps to the end of the in-memory Gemfile
41
+ # Set conservative versioning to false because
42
+ # we want to let the resolver resolve the version first
43
+ builder.eval_gemfile(INJECTED_GEMS, build_gem_lines(false)) if @deps.any?
26
44
 
27
- # add new deps to the end of the in-memory Gemfile
28
- builder.eval_gemfile("injected gems", new_gem_lines) if @new_deps.any?
45
+ # resolve to see if the new deps broke anything
46
+ @definition = builder.to_definition(lockfile_path, {})
47
+ @definition.resolve_remotely!
29
48
 
30
- # resolve to see if the new deps broke anything
31
- definition = builder.to_definition(lockfile_path, {})
32
- definition.resolve_remotely!
49
+ # since nothing broke, we can add those gems to the gemfile
50
+ append_to(gemfile_path, build_gem_lines(@options[:conservative_versioning])) if @deps.any?
33
51
 
34
- # since nothing broke, we can add those gems to the gemfile
35
- append_to(gemfile_path) if @new_deps.any?
52
+ # since we resolved successfully, write out the lockfile
53
+ @definition.lock(Bundler.default_lockfile)
36
54
 
37
- # since we resolved successfully, write out the lockfile
38
- definition.lock(Bundler.default_lockfile)
55
+ # invalidate the cached Bundler.definition
56
+ Bundler.reset_paths!
39
57
 
40
- # return an array of the deps that we added
41
- return @new_deps
42
- ensure
43
- Bundler.settings[:frozen] = '1' if frozen
58
+ # return an array of the deps that we added
59
+ @deps
60
+ end
61
+ end
62
+
63
+ # @param [Pathname] gemfile_path The Gemfile from which to remove dependencies.
64
+ # @param [Pathname] lockfile_path The lockfile from which to remove dependencies.
65
+ # @return [Array]
66
+ def remove(gemfile_path, lockfile_path)
67
+ # remove gems from each gemfiles we have
68
+ Bundler.definition.gemfiles.each do |path|
69
+ deps = remove_deps(path)
70
+
71
+ show_warning("No gems were removed from the gemfile.") if deps.empty?
72
+
73
+ deps.each {|dep| Bundler.ui.confirm "#{SharedHelpers.pretty_dependency(dep, false)} was removed." }
74
+ end
44
75
  end
45
76
 
46
77
  private
47
78
 
48
- def new_gem_lines
49
- @new_deps.map do |d|
50
- %|gem '#{d.name}', '#{d.requirement}'|
79
+ def conservative_version(spec)
80
+ version = spec.version
81
+ return ">= 0" if version.nil?
82
+ segments = version.segments
83
+ seg_end_index = version >= Gem::Version.new("1.0") ? 1 : 2
84
+
85
+ prerelease_suffix = version.to_s.gsub(version.release.to_s, "") if version.prerelease?
86
+ "#{version_prefix}#{segments[0..seg_end_index].join(".")}#{prerelease_suffix}"
87
+ end
88
+
89
+ def version_prefix
90
+ if @options[:strict]
91
+ "= "
92
+ elsif @options[:optimistic]
93
+ ">= "
94
+ else
95
+ "~> "
96
+ end
97
+ end
98
+
99
+ def build_gem_lines(conservative_versioning)
100
+ @deps.map do |d|
101
+ name = d.name.dump
102
+
103
+ requirement = if conservative_versioning
104
+ ", \"#{conservative_version(@definition.specs[d.name][0])}\""
105
+ else
106
+ ", #{d.requirement.as_list.map(&:dump).join(", ")}"
107
+ end
108
+
109
+ if d.groups != Array(:default)
110
+ group = d.groups.size == 1 ? ", :group => #{d.groups.first.inspect}" : ", :groups => #{d.groups.inspect}"
111
+ end
112
+
113
+ source = ", :source => \"#{d.source}\"" unless d.source.nil?
114
+
115
+ %(gem #{name}#{requirement}#{group}#{source})
51
116
  end.join("\n")
52
117
  end
53
118
 
54
- def append_to(gemfile_path)
119
+ def append_to(gemfile_path, new_gem_lines)
55
120
  gemfile_path.open("a") do |f|
56
121
  f.puts
57
- f.puts "# Added at #{Time.now} by #{`whoami`.chomp}:"
58
122
  f.puts new_gem_lines
59
123
  end
60
124
  end
61
125
 
126
+ # evalutes a gemfile to remove the specified gem
127
+ # from it.
128
+ def remove_deps(gemfile_path)
129
+ initial_gemfile = IO.readlines(gemfile_path)
130
+
131
+ Bundler.ui.info "Removing gems from #{gemfile_path}"
132
+
133
+ # evaluate the Gemfile we have
134
+ builder = Dsl.new
135
+ builder.eval_gemfile(gemfile_path)
136
+
137
+ removed_deps = remove_gems_from_dependencies(builder, @deps, gemfile_path)
138
+
139
+ # abort the opertion if no gems were removed
140
+ # no need to operate on gemfile furthur
141
+ return [] if removed_deps.empty?
142
+
143
+ cleaned_gemfile = remove_gems_from_gemfile(@deps, gemfile_path)
144
+
145
+ SharedHelpers.write_to_gemfile(gemfile_path, cleaned_gemfile)
146
+
147
+ # check for errors
148
+ # including extra gems being removed
149
+ # or some gems not being removed
150
+ # and return the actual removed deps
151
+ cross_check_for_errors(gemfile_path, builder.dependencies, removed_deps, initial_gemfile)
152
+ end
153
+
154
+ # @param [Dsl] builder Dsl object of current Gemfile.
155
+ # @param [Array] gems Array of names of gems to be removed.
156
+ # @param [Pathname] path of the Gemfile
157
+ # @return [Array] removed_deps Array of removed dependencies.
158
+ def remove_gems_from_dependencies(builder, gems, gemfile_path)
159
+ removed_deps = []
62
160
 
161
+ gems.each do |gem_name|
162
+ deleted_dep = builder.dependencies.find {|d| d.name == gem_name }
163
+
164
+ if deleted_dep.nil?
165
+ raise GemfileError, "`#{gem_name}` is not specified in #{gemfile_path} so it could not be removed."
166
+ end
167
+
168
+ builder.dependencies.delete(deleted_dep)
169
+
170
+ removed_deps << deleted_dep
171
+ end
172
+
173
+ removed_deps
174
+ end
175
+
176
+ # @param [Array] gems Array of names of gems to be removed.
177
+ # @param [Pathname] gemfile_path The Gemfile from which to remove dependencies.
178
+ def remove_gems_from_gemfile(gems, gemfile_path)
179
+ patterns = /gem\s+(['"])#{Regexp.union(gems)}\1|gem\s*\((['"])#{Regexp.union(gems)}\2\)/
180
+
181
+ # remove lines which match the regex
182
+ new_gemfile = IO.readlines(gemfile_path).reject {|line| line.match(patterns) }
183
+
184
+ # remove lone \n and append them with other strings
185
+ new_gemfile.each_with_index do |_line, index|
186
+ if new_gemfile[index + 1] == "\n"
187
+ new_gemfile[index] += new_gemfile[index + 1]
188
+ new_gemfile.delete_at(index + 1)
189
+ end
190
+ end
191
+
192
+ %w[group source env install_if].each {|block| remove_nested_blocks(new_gemfile, block) }
193
+
194
+ new_gemfile.join.chomp
195
+ end
196
+
197
+ # @param [Array] gemfile Array of gemfile contents.
198
+ # @param [String] block_name Name of block name to look for.
199
+ def remove_nested_blocks(gemfile, block_name)
200
+ nested_blocks = 0
201
+
202
+ # count number of nested blocks
203
+ gemfile.each_with_index {|line, index| nested_blocks += 1 if !gemfile[index + 1].nil? && gemfile[index + 1].include?(block_name) && line.include?(block_name) }
204
+
205
+ while nested_blocks >= 0
206
+ nested_blocks -= 1
207
+
208
+ gemfile.each_with_index do |line, index|
209
+ next unless !line.nil? && line.include?(block_name)
210
+ if gemfile[index + 1] =~ /^\s*end\s*$/
211
+ gemfile[index] = nil
212
+ gemfile[index + 1] = nil
213
+ end
214
+ end
215
+
216
+ gemfile.compact!
217
+ end
218
+ end
219
+
220
+ # @param [Pathname] gemfile_path The Gemfile from which to remove dependencies.
221
+ # @param [Array] original_deps Array of original dependencies.
222
+ # @param [Array] removed_deps Array of removed dependencies.
223
+ # @param [Array] initial_gemfile Contents of original Gemfile before any operation.
224
+ def cross_check_for_errors(gemfile_path, original_deps, removed_deps, initial_gemfile)
225
+ # evalute the new gemfile to look for any failure cases
226
+ builder = Dsl.new
227
+ builder.eval_gemfile(gemfile_path)
228
+
229
+ # record gems which were removed but not requested
230
+ extra_removed_gems = original_deps - builder.dependencies
231
+
232
+ # if some extra gems were removed then raise error
233
+ # and revert Gemfile to original
234
+ unless extra_removed_gems.empty?
235
+ SharedHelpers.write_to_gemfile(gemfile_path, initial_gemfile.join)
236
+
237
+ raise InvalidOption, "Gems could not be removed. #{extra_removed_gems.join(", ")} would also have been removed. Bundler cannot continue."
238
+ end
239
+
240
+ # record gems which could not be removed due to some reasons
241
+ errored_deps = builder.dependencies.select {|d| d.gemfile == gemfile_path } & removed_deps.select {|d| d.gemfile == gemfile_path }
242
+
243
+ show_warning "#{errored_deps.map(&:name).join(", ")} could not be removed." unless errored_deps.empty?
244
+
245
+ # return actual removed dependencies
246
+ removed_deps - errored_deps
247
+ end
248
+
249
+ def show_warning(message)
250
+ Bundler.ui.info Bundler.ui.add_color(message, :yellow)
251
+ end
63
252
  end
64
253
  end