bundler 2.0.2

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

Potentially problematic release.


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

Files changed (303) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +3111 -0
  3. data/LICENSE.md +23 -0
  4. data/README.md +63 -0
  5. data/bundler.gemspec +65 -0
  6. data/exe/bundle +31 -0
  7. data/exe/bundle_ruby +60 -0
  8. data/exe/bundler +4 -0
  9. data/lib/bundler.rb +567 -0
  10. data/lib/bundler/build_metadata.rb +53 -0
  11. data/lib/bundler/capistrano.rb +22 -0
  12. data/lib/bundler/cli.rb +792 -0
  13. data/lib/bundler/cli/add.rb +35 -0
  14. data/lib/bundler/cli/binstubs.rb +49 -0
  15. data/lib/bundler/cli/cache.rb +36 -0
  16. data/lib/bundler/cli/check.rb +38 -0
  17. data/lib/bundler/cli/clean.rb +25 -0
  18. data/lib/bundler/cli/common.rb +102 -0
  19. data/lib/bundler/cli/config.rb +119 -0
  20. data/lib/bundler/cli/console.rb +43 -0
  21. data/lib/bundler/cli/doctor.rb +140 -0
  22. data/lib/bundler/cli/exec.rb +105 -0
  23. data/lib/bundler/cli/gem.rb +252 -0
  24. data/lib/bundler/cli/info.rb +50 -0
  25. data/lib/bundler/cli/init.rb +47 -0
  26. data/lib/bundler/cli/inject.rb +60 -0
  27. data/lib/bundler/cli/install.rb +218 -0
  28. data/lib/bundler/cli/issue.rb +40 -0
  29. data/lib/bundler/cli/list.rb +58 -0
  30. data/lib/bundler/cli/lock.rb +63 -0
  31. data/lib/bundler/cli/open.rb +26 -0
  32. data/lib/bundler/cli/outdated.rb +266 -0
  33. data/lib/bundler/cli/package.rb +49 -0
  34. data/lib/bundler/cli/platform.rb +46 -0
  35. data/lib/bundler/cli/plugin.rb +24 -0
  36. data/lib/bundler/cli/pristine.rb +47 -0
  37. data/lib/bundler/cli/remove.rb +18 -0
  38. data/lib/bundler/cli/show.rb +75 -0
  39. data/lib/bundler/cli/update.rb +91 -0
  40. data/lib/bundler/cli/viz.rb +31 -0
  41. data/lib/bundler/compact_index_client.rb +109 -0
  42. data/lib/bundler/compact_index_client/cache.rb +118 -0
  43. data/lib/bundler/compact_index_client/updater.rb +116 -0
  44. data/lib/bundler/compatibility_guard.rb +13 -0
  45. data/lib/bundler/constants.rb +7 -0
  46. data/lib/bundler/current_ruby.rb +94 -0
  47. data/lib/bundler/definition.rb +995 -0
  48. data/lib/bundler/dep_proxy.rb +48 -0
  49. data/lib/bundler/dependency.rb +139 -0
  50. data/lib/bundler/deployment.rb +69 -0
  51. data/lib/bundler/deprecate.rb +44 -0
  52. data/lib/bundler/dsl.rb +615 -0
  53. data/lib/bundler/endpoint_specification.rb +141 -0
  54. data/lib/bundler/env.rb +149 -0
  55. data/lib/bundler/environment_preserver.rb +59 -0
  56. data/lib/bundler/errors.rb +158 -0
  57. data/lib/bundler/feature_flag.rb +75 -0
  58. data/lib/bundler/fetcher.rb +312 -0
  59. data/lib/bundler/fetcher/base.rb +52 -0
  60. data/lib/bundler/fetcher/compact_index.rb +126 -0
  61. data/lib/bundler/fetcher/dependency.rb +82 -0
  62. data/lib/bundler/fetcher/downloader.rb +84 -0
  63. data/lib/bundler/fetcher/index.rb +52 -0
  64. data/lib/bundler/friendly_errors.rb +131 -0
  65. data/lib/bundler/gem_helper.rb +217 -0
  66. data/lib/bundler/gem_helpers.rb +101 -0
  67. data/lib/bundler/gem_remote_fetcher.rb +43 -0
  68. data/lib/bundler/gem_tasks.rb +7 -0
  69. data/lib/bundler/gem_version_promoter.rb +190 -0
  70. data/lib/bundler/gemdeps.rb +29 -0
  71. data/lib/bundler/graph.rb +152 -0
  72. data/lib/bundler/index.rb +213 -0
  73. data/lib/bundler/injector.rb +253 -0
  74. data/lib/bundler/inline.rb +74 -0
  75. data/lib/bundler/installer.rb +318 -0
  76. data/lib/bundler/installer/gem_installer.rb +85 -0
  77. data/lib/bundler/installer/parallel_installer.rb +229 -0
  78. data/lib/bundler/installer/standalone.rb +53 -0
  79. data/lib/bundler/lazy_specification.rb +123 -0
  80. data/lib/bundler/lockfile_generator.rb +95 -0
  81. data/lib/bundler/lockfile_parser.rb +256 -0
  82. data/lib/bundler/match_platform.rb +24 -0
  83. data/lib/bundler/mirror.rb +223 -0
  84. data/lib/bundler/plugin.rb +294 -0
  85. data/lib/bundler/plugin/api.rb +81 -0
  86. data/lib/bundler/plugin/api/source.rb +306 -0
  87. data/lib/bundler/plugin/dsl.rb +53 -0
  88. data/lib/bundler/plugin/events.rb +61 -0
  89. data/lib/bundler/plugin/index.rb +165 -0
  90. data/lib/bundler/plugin/installer.rb +96 -0
  91. data/lib/bundler/plugin/installer/git.rb +38 -0
  92. data/lib/bundler/plugin/installer/rubygems.rb +27 -0
  93. data/lib/bundler/plugin/source_list.rb +27 -0
  94. data/lib/bundler/process_lock.rb +24 -0
  95. data/lib/bundler/psyched_yaml.rb +37 -0
  96. data/lib/bundler/remote_specification.rb +114 -0
  97. data/lib/bundler/resolver.rb +373 -0
  98. data/lib/bundler/resolver/spec_group.rb +106 -0
  99. data/lib/bundler/retry.rb +66 -0
  100. data/lib/bundler/ruby_dsl.rb +18 -0
  101. data/lib/bundler/ruby_version.rb +152 -0
  102. data/lib/bundler/rubygems_ext.rb +209 -0
  103. data/lib/bundler/rubygems_gem_installer.rb +99 -0
  104. data/lib/bundler/rubygems_integration.rb +915 -0
  105. data/lib/bundler/runtime.rb +322 -0
  106. data/lib/bundler/settings.rb +464 -0
  107. data/lib/bundler/settings/validator.rb +102 -0
  108. data/lib/bundler/setup.rb +28 -0
  109. data/lib/bundler/shared_helpers.rb +386 -0
  110. data/lib/bundler/similarity_detector.rb +63 -0
  111. data/lib/bundler/source.rb +94 -0
  112. data/lib/bundler/source/gemspec.rb +18 -0
  113. data/lib/bundler/source/git.rb +329 -0
  114. data/lib/bundler/source/git/git_proxy.rb +262 -0
  115. data/lib/bundler/source/metadata.rb +62 -0
  116. data/lib/bundler/source/path.rb +249 -0
  117. data/lib/bundler/source/path/installer.rb +74 -0
  118. data/lib/bundler/source/rubygems.rb +539 -0
  119. data/lib/bundler/source/rubygems/remote.rb +69 -0
  120. data/lib/bundler/source_list.rb +186 -0
  121. data/lib/bundler/spec_set.rb +208 -0
  122. data/lib/bundler/ssl_certs/.document +1 -0
  123. data/lib/bundler/ssl_certs/certificate_manager.rb +66 -0
  124. data/lib/bundler/ssl_certs/index.rubygems.org/GlobalSignRootCA.pem +21 -0
  125. data/lib/bundler/ssl_certs/rubygems.global.ssl.fastly.net/DigiCertHighAssuranceEVRootCA.pem +23 -0
  126. data/lib/bundler/ssl_certs/rubygems.org/AddTrustExternalCARoot.pem +25 -0
  127. data/lib/bundler/stub_specification.rb +108 -0
  128. data/lib/bundler/templates/.document +1 -0
  129. data/lib/bundler/templates/Executable +29 -0
  130. data/lib/bundler/templates/Executable.bundler +105 -0
  131. data/lib/bundler/templates/Executable.standalone +14 -0
  132. data/lib/bundler/templates/Gemfile +7 -0
  133. data/lib/bundler/templates/gems.rb +8 -0
  134. data/lib/bundler/templates/newgem/CODE_OF_CONDUCT.md.tt +74 -0
  135. data/lib/bundler/templates/newgem/Gemfile.tt +4 -0
  136. data/lib/bundler/templates/newgem/LICENSE.txt.tt +21 -0
  137. data/lib/bundler/templates/newgem/README.md.tt +47 -0
  138. data/lib/bundler/templates/newgem/Rakefile.tt +29 -0
  139. data/lib/bundler/templates/newgem/bin/console.tt +14 -0
  140. data/lib/bundler/templates/newgem/bin/setup.tt +8 -0
  141. data/lib/bundler/templates/newgem/exe/newgem.tt +3 -0
  142. data/lib/bundler/templates/newgem/ext/newgem/extconf.rb.tt +3 -0
  143. data/lib/bundler/templates/newgem/ext/newgem/newgem.c.tt +9 -0
  144. data/lib/bundler/templates/newgem/ext/newgem/newgem.h.tt +6 -0
  145. data/lib/bundler/templates/newgem/gitignore.tt +20 -0
  146. data/lib/bundler/templates/newgem/lib/newgem.rb.tt +13 -0
  147. data/lib/bundler/templates/newgem/lib/newgem/version.rb.tt +7 -0
  148. data/lib/bundler/templates/newgem/newgem.gemspec.tt +50 -0
  149. data/lib/bundler/templates/newgem/rspec.tt +3 -0
  150. data/lib/bundler/templates/newgem/spec/newgem_spec.rb.tt +9 -0
  151. data/lib/bundler/templates/newgem/spec/spec_helper.rb.tt +14 -0
  152. data/lib/bundler/templates/newgem/test/newgem_test.rb.tt +11 -0
  153. data/lib/bundler/templates/newgem/test/test_helper.rb.tt +8 -0
  154. data/lib/bundler/templates/newgem/travis.yml.tt +7 -0
  155. data/lib/bundler/ui.rb +9 -0
  156. data/lib/bundler/ui/rg_proxy.rb +19 -0
  157. data/lib/bundler/ui/shell.rb +146 -0
  158. data/lib/bundler/ui/silent.rb +69 -0
  159. data/lib/bundler/uri_credentials_filter.rb +37 -0
  160. data/lib/bundler/vendor/fileutils/lib/fileutils.rb +1741 -0
  161. data/lib/bundler/vendor/fileutils/lib/fileutils/version.rb +5 -0
  162. data/lib/bundler/vendor/molinillo/lib/molinillo.rb +12 -0
  163. data/lib/bundler/vendor/molinillo/lib/molinillo/compatibility.rb +26 -0
  164. data/lib/bundler/vendor/molinillo/lib/molinillo/delegates/resolution_state.rb +57 -0
  165. data/lib/bundler/vendor/molinillo/lib/molinillo/delegates/specification_provider.rb +81 -0
  166. data/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph.rb +223 -0
  167. data/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/action.rb +36 -0
  168. data/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/add_edge_no_circular.rb +66 -0
  169. data/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/add_vertex.rb +62 -0
  170. data/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/delete_edge.rb +63 -0
  171. data/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/detach_vertex_named.rb +61 -0
  172. data/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/log.rb +126 -0
  173. data/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/set_payload.rb +46 -0
  174. data/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/tag.rb +36 -0
  175. data/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/vertex.rb +136 -0
  176. data/lib/bundler/vendor/molinillo/lib/molinillo/errors.rb +143 -0
  177. data/lib/bundler/vendor/molinillo/lib/molinillo/gem_metadata.rb +6 -0
  178. data/lib/bundler/vendor/molinillo/lib/molinillo/modules/specification_provider.rb +101 -0
  179. data/lib/bundler/vendor/molinillo/lib/molinillo/modules/ui.rb +67 -0
  180. data/lib/bundler/vendor/molinillo/lib/molinillo/resolution.rb +837 -0
  181. data/lib/bundler/vendor/molinillo/lib/molinillo/resolver.rb +46 -0
  182. data/lib/bundler/vendor/molinillo/lib/molinillo/state.rb +58 -0
  183. data/lib/bundler/vendor/net-http-persistent/lib/net/http/faster.rb +27 -0
  184. data/lib/bundler/vendor/net-http-persistent/lib/net/http/persistent.rb +1233 -0
  185. data/lib/bundler/vendor/net-http-persistent/lib/net/http/persistent/ssl_reuse.rb +129 -0
  186. data/lib/bundler/vendor/thor/lib/thor.rb +509 -0
  187. data/lib/bundler/vendor/thor/lib/thor/actions.rb +331 -0
  188. data/lib/bundler/vendor/thor/lib/thor/actions/create_file.rb +104 -0
  189. data/lib/bundler/vendor/thor/lib/thor/actions/create_link.rb +60 -0
  190. data/lib/bundler/vendor/thor/lib/thor/actions/directory.rb +118 -0
  191. data/lib/bundler/vendor/thor/lib/thor/actions/empty_directory.rb +143 -0
  192. data/lib/bundler/vendor/thor/lib/thor/actions/file_manipulation.rb +373 -0
  193. data/lib/bundler/vendor/thor/lib/thor/actions/inject_into_file.rb +109 -0
  194. data/lib/bundler/vendor/thor/lib/thor/base.rb +678 -0
  195. data/lib/bundler/vendor/thor/lib/thor/command.rb +135 -0
  196. data/lib/bundler/vendor/thor/lib/thor/core_ext/hash_with_indifferent_access.rb +97 -0
  197. data/lib/bundler/vendor/thor/lib/thor/core_ext/io_binary_read.rb +12 -0
  198. data/lib/bundler/vendor/thor/lib/thor/core_ext/ordered_hash.rb +129 -0
  199. data/lib/bundler/vendor/thor/lib/thor/error.rb +114 -0
  200. data/lib/bundler/vendor/thor/lib/thor/group.rb +281 -0
  201. data/lib/bundler/vendor/thor/lib/thor/invocation.rb +177 -0
  202. data/lib/bundler/vendor/thor/lib/thor/line_editor.rb +17 -0
  203. data/lib/bundler/vendor/thor/lib/thor/line_editor/basic.rb +37 -0
  204. data/lib/bundler/vendor/thor/lib/thor/line_editor/readline.rb +88 -0
  205. data/lib/bundler/vendor/thor/lib/thor/parser.rb +4 -0
  206. data/lib/bundler/vendor/thor/lib/thor/parser/argument.rb +70 -0
  207. data/lib/bundler/vendor/thor/lib/thor/parser/arguments.rb +175 -0
  208. data/lib/bundler/vendor/thor/lib/thor/parser/option.rb +146 -0
  209. data/lib/bundler/vendor/thor/lib/thor/parser/options.rb +226 -0
  210. data/lib/bundler/vendor/thor/lib/thor/rake_compat.rb +71 -0
  211. data/lib/bundler/vendor/thor/lib/thor/runner.rb +324 -0
  212. data/lib/bundler/vendor/thor/lib/thor/shell.rb +81 -0
  213. data/lib/bundler/vendor/thor/lib/thor/shell/basic.rb +482 -0
  214. data/lib/bundler/vendor/thor/lib/thor/shell/color.rb +149 -0
  215. data/lib/bundler/vendor/thor/lib/thor/shell/html.rb +126 -0
  216. data/lib/bundler/vendor/thor/lib/thor/util.rb +268 -0
  217. data/lib/bundler/vendor/thor/lib/thor/version.rb +3 -0
  218. data/lib/bundler/vendored_fileutils.rb +9 -0
  219. data/lib/bundler/vendored_molinillo.rb +4 -0
  220. data/lib/bundler/vendored_persistent.rb +52 -0
  221. data/lib/bundler/vendored_thor.rb +8 -0
  222. data/lib/bundler/version.rb +28 -0
  223. data/lib/bundler/version_ranges.rb +76 -0
  224. data/lib/bundler/vlad.rb +17 -0
  225. data/lib/bundler/worker.rb +106 -0
  226. data/lib/bundler/yaml_serializer.rb +90 -0
  227. data/man/bundle-add.1 +58 -0
  228. data/man/bundle-add.1.txt +52 -0
  229. data/man/bundle-add.ronn +40 -0
  230. data/man/bundle-binstubs.1 +40 -0
  231. data/man/bundle-binstubs.1.txt +48 -0
  232. data/man/bundle-binstubs.ronn +43 -0
  233. data/man/bundle-check.1 +31 -0
  234. data/man/bundle-check.1.txt +33 -0
  235. data/man/bundle-check.ronn +26 -0
  236. data/man/bundle-clean.1 +24 -0
  237. data/man/bundle-clean.1.txt +26 -0
  238. data/man/bundle-clean.ronn +18 -0
  239. data/man/bundle-config.1 +497 -0
  240. data/man/bundle-config.1.txt +529 -0
  241. data/man/bundle-config.ronn +397 -0
  242. data/man/bundle-doctor.1 +44 -0
  243. data/man/bundle-doctor.1.txt +44 -0
  244. data/man/bundle-doctor.ronn +33 -0
  245. data/man/bundle-exec.1 +165 -0
  246. data/man/bundle-exec.1.txt +178 -0
  247. data/man/bundle-exec.ronn +152 -0
  248. data/man/bundle-gem.1 +80 -0
  249. data/man/bundle-gem.1.txt +91 -0
  250. data/man/bundle-gem.ronn +78 -0
  251. data/man/bundle-info.1 +20 -0
  252. data/man/bundle-info.1.txt +21 -0
  253. data/man/bundle-info.ronn +17 -0
  254. data/man/bundle-init.1 +25 -0
  255. data/man/bundle-init.1.txt +34 -0
  256. data/man/bundle-init.ronn +29 -0
  257. data/man/bundle-inject.1 +33 -0
  258. data/man/bundle-inject.1.txt +32 -0
  259. data/man/bundle-inject.ronn +22 -0
  260. data/man/bundle-install.1 +308 -0
  261. data/man/bundle-install.1.txt +396 -0
  262. data/man/bundle-install.ronn +378 -0
  263. data/man/bundle-list.1 +50 -0
  264. data/man/bundle-list.1.txt +43 -0
  265. data/man/bundle-list.ronn +33 -0
  266. data/man/bundle-lock.1 +84 -0
  267. data/man/bundle-lock.1.txt +93 -0
  268. data/man/bundle-lock.ronn +94 -0
  269. data/man/bundle-open.1 +32 -0
  270. data/man/bundle-open.1.txt +29 -0
  271. data/man/bundle-open.ronn +19 -0
  272. data/man/bundle-outdated.1 +155 -0
  273. data/man/bundle-outdated.1.txt +131 -0
  274. data/man/bundle-outdated.ronn +111 -0
  275. data/man/bundle-package.1 +55 -0
  276. data/man/bundle-package.1.txt +79 -0
  277. data/man/bundle-package.ronn +72 -0
  278. data/man/bundle-platform.1 +61 -0
  279. data/man/bundle-platform.1.txt +57 -0
  280. data/man/bundle-platform.ronn +42 -0
  281. data/man/bundle-pristine.1 +34 -0
  282. data/man/bundle-pristine.1.txt +44 -0
  283. data/man/bundle-pristine.ronn +34 -0
  284. data/man/bundle-remove.1 +31 -0
  285. data/man/bundle-remove.1.txt +34 -0
  286. data/man/bundle-remove.ronn +23 -0
  287. data/man/bundle-show.1 +23 -0
  288. data/man/bundle-show.1.txt +27 -0
  289. data/man/bundle-show.ronn +21 -0
  290. data/man/bundle-update.1 +394 -0
  291. data/man/bundle-update.1.txt +391 -0
  292. data/man/bundle-update.ronn +350 -0
  293. data/man/bundle-viz.1 +39 -0
  294. data/man/bundle-viz.1.txt +39 -0
  295. data/man/bundle-viz.ronn +30 -0
  296. data/man/bundle.1 +136 -0
  297. data/man/bundle.1.txt +116 -0
  298. data/man/bundle.ronn +111 -0
  299. data/man/gemfile.5 +689 -0
  300. data/man/gemfile.5.ronn +521 -0
  301. data/man/gemfile.5.txt +653 -0
  302. data/man/index.txt +25 -0
  303. metadata +463 -0
@@ -0,0 +1,294 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "bundler/plugin/api"
4
+
5
+ module Bundler
6
+ module Plugin
7
+ autoload :DSL, "bundler/plugin/dsl"
8
+ autoload :Events, "bundler/plugin/events"
9
+ autoload :Index, "bundler/plugin/index"
10
+ autoload :Installer, "bundler/plugin/installer"
11
+ autoload :SourceList, "bundler/plugin/source_list"
12
+
13
+ class MalformattedPlugin < PluginError; end
14
+ class UndefinedCommandError < PluginError; end
15
+ class UnknownSourceError < PluginError; end
16
+
17
+ PLUGIN_FILE_NAME = "plugins.rb".freeze
18
+
19
+ module_function
20
+
21
+ def reset!
22
+ instance_variables.each {|i| remove_instance_variable(i) }
23
+
24
+ @sources = {}
25
+ @commands = {}
26
+ @hooks_by_event = Hash.new {|h, k| h[k] = [] }
27
+ @loaded_plugin_names = []
28
+ end
29
+
30
+ reset!
31
+
32
+ # Installs a new plugin by the given name
33
+ #
34
+ # @param [Array<String>] names the name of plugin to be installed
35
+ # @param [Hash] options various parameters as described in description.
36
+ # Refer to cli/plugin for available options
37
+ def install(names, options)
38
+ specs = Installer.new.install(names, options)
39
+
40
+ save_plugins names, specs
41
+ rescue PluginError => e
42
+ if specs
43
+ specs_to_delete = Hash[specs.select {|k, _v| names.include?(k) && !index.commands.values.include?(k) }]
44
+ specs_to_delete.values.each {|spec| Bundler.rm_rf(spec.full_gem_path) }
45
+ end
46
+
47
+ Bundler.ui.error "Failed to install plugin #{name}: #{e.message}\n #{e.backtrace.join("\n ")}"
48
+ end
49
+
50
+ # Evaluates the Gemfile with a limited DSL and installs the plugins
51
+ # specified by plugin method
52
+ #
53
+ # @param [Pathname] gemfile path
54
+ # @param [Proc] block that can be evaluated for (inline) Gemfile
55
+ def gemfile_install(gemfile = nil, &inline)
56
+ Bundler.settings.temporary(:frozen => false, :deployment => false) do
57
+ builder = DSL.new
58
+ if block_given?
59
+ builder.instance_eval(&inline)
60
+ else
61
+ builder.eval_gemfile(gemfile)
62
+ end
63
+ definition = builder.to_definition(nil, true)
64
+
65
+ return if definition.dependencies.empty?
66
+
67
+ plugins = definition.dependencies.map(&:name).reject {|p| index.installed? p }
68
+ installed_specs = Installer.new.install_definition(definition)
69
+
70
+ save_plugins plugins, installed_specs, builder.inferred_plugins
71
+ end
72
+ rescue RuntimeError => e
73
+ unless e.is_a?(GemfileError)
74
+ Bundler.ui.error "Failed to install plugin: #{e.message}\n #{e.backtrace[0]}"
75
+ end
76
+ raise
77
+ end
78
+
79
+ # The index object used to store the details about the plugin
80
+ def index
81
+ @index ||= Index.new
82
+ end
83
+
84
+ # The directory root for all plugin related data
85
+ #
86
+ # If run in an app, points to local root, in app_config_path
87
+ # Otherwise, points to global root, in Bundler.user_bundle_path("plugin")
88
+ def root
89
+ @root ||= if SharedHelpers.in_bundle?
90
+ local_root
91
+ else
92
+ global_root
93
+ end
94
+ end
95
+
96
+ def local_root
97
+ Bundler.app_config_path.join("plugin")
98
+ end
99
+
100
+ # The global directory root for all plugin related data
101
+ def global_root
102
+ Bundler.user_bundle_path("plugin")
103
+ end
104
+
105
+ # The cache directory for plugin stuffs
106
+ def cache
107
+ @cache ||= root.join("cache")
108
+ end
109
+
110
+ # To be called via the API to register to handle a command
111
+ def add_command(command, cls)
112
+ @commands[command] = cls
113
+ end
114
+
115
+ # Checks if any plugin handles the command
116
+ def command?(command)
117
+ !index.command_plugin(command).nil?
118
+ end
119
+
120
+ # To be called from Cli class to pass the command and argument to
121
+ # approriate plugin class
122
+ def exec_command(command, args)
123
+ raise UndefinedCommandError, "Command `#{command}` not found" unless command? command
124
+
125
+ load_plugin index.command_plugin(command) unless @commands.key? command
126
+
127
+ @commands[command].new.exec(command, args)
128
+ end
129
+
130
+ # To be called via the API to register to handle a source plugin
131
+ def add_source(source, cls)
132
+ @sources[source] = cls
133
+ end
134
+
135
+ # Checks if any plugin declares the source
136
+ def source?(name)
137
+ !index.source_plugin(name.to_s).nil?
138
+ end
139
+
140
+ # @return [Class] that handles the source. The calss includes API::Source
141
+ def source(name)
142
+ raise UnknownSourceError, "Source #{name} not found" unless source? name
143
+
144
+ load_plugin(index.source_plugin(name)) unless @sources.key? name
145
+
146
+ @sources[name]
147
+ end
148
+
149
+ # @param [Hash] The options that are present in the lock file
150
+ # @return [API::Source] the instance of the class that handles the source
151
+ # type passed in locked_opts
152
+ def source_from_lock(locked_opts)
153
+ src = source(locked_opts["type"])
154
+
155
+ src.new(locked_opts.merge("uri" => locked_opts["remote"]))
156
+ end
157
+
158
+ # To be called via the API to register a hooks and corresponding block that
159
+ # will be called to handle the hook
160
+ def add_hook(event, &block)
161
+ unless Events.defined_event?(event)
162
+ raise ArgumentError, "Event '#{event}' not defined in Bundler::Plugin::Events"
163
+ end
164
+ @hooks_by_event[event.to_s] << block
165
+ end
166
+
167
+ # Runs all the hooks that are registered for the passed event
168
+ #
169
+ # It passes the passed arguments and block to the block registered with
170
+ # the api.
171
+ #
172
+ # @param [String] event
173
+ def hook(event, *args, &arg_blk)
174
+ return unless Bundler.feature_flag.plugins?
175
+ unless Events.defined_event?(event)
176
+ raise ArgumentError, "Event '#{event}' not defined in Bundler::Plugin::Events"
177
+ end
178
+
179
+ plugins = index.hook_plugins(event)
180
+ return unless plugins.any?
181
+
182
+ (plugins - @loaded_plugin_names).each {|name| load_plugin(name) }
183
+
184
+ @hooks_by_event[event].each {|blk| blk.call(*args, &arg_blk) }
185
+ end
186
+
187
+ # currently only intended for specs
188
+ #
189
+ # @return [String, nil] installed path
190
+ def installed?(plugin)
191
+ Index.new.installed?(plugin)
192
+ end
193
+
194
+ # Post installation processing and registering with index
195
+ #
196
+ # @param [Array<String>] plugins list to be installed
197
+ # @param [Hash] specs of plugins mapped to installation path (currently they
198
+ # contain all the installed specs, including plugins)
199
+ # @param [Array<String>] names of inferred source plugins that can be ignored
200
+ def save_plugins(plugins, specs, optional_plugins = [])
201
+ plugins.each do |name|
202
+ spec = specs[name]
203
+ validate_plugin! Pathname.new(spec.full_gem_path)
204
+ installed = register_plugin(name, spec, optional_plugins.include?(name))
205
+ Bundler.ui.info "Installed plugin #{name}" if installed
206
+ end
207
+ end
208
+
209
+ # Checks if the gem is good to be a plugin
210
+ #
211
+ # At present it only checks whether it contains plugins.rb file
212
+ #
213
+ # @param [Pathname] plugin_path the path plugin is installed at
214
+ # @raise [MalformattedPlugin] if plugins.rb file is not found
215
+ def validate_plugin!(plugin_path)
216
+ plugin_file = plugin_path.join(PLUGIN_FILE_NAME)
217
+ raise MalformattedPlugin, "#{PLUGIN_FILE_NAME} was not found in the plugin." unless plugin_file.file?
218
+ end
219
+
220
+ # Runs the plugins.rb file in an isolated namespace, records the plugin
221
+ # actions it registers for and then passes the data to index to be stored.
222
+ #
223
+ # @param [String] name the name of the plugin
224
+ # @param [Specification] spec of installed plugin
225
+ # @param [Boolean] optional_plugin, removed if there is conflict with any
226
+ # other plugin (used for default source plugins)
227
+ #
228
+ # @raise [MalformattedPlugin] if plugins.rb raises any error
229
+ def register_plugin(name, spec, optional_plugin = false)
230
+ commands = @commands
231
+ sources = @sources
232
+ hooks = @hooks_by_event
233
+
234
+ @commands = {}
235
+ @sources = {}
236
+ @hooks_by_event = Hash.new {|h, k| h[k] = [] }
237
+
238
+ load_paths = spec.load_paths
239
+ add_to_load_path(load_paths)
240
+ path = Pathname.new spec.full_gem_path
241
+
242
+ begin
243
+ load path.join(PLUGIN_FILE_NAME), true
244
+ rescue StandardError => e
245
+ raise MalformattedPlugin, "#{e.class}: #{e.message}"
246
+ end
247
+
248
+ if optional_plugin && @sources.keys.any? {|s| source? s }
249
+ Bundler.rm_rf(path)
250
+ false
251
+ else
252
+ index.register_plugin(name, path.to_s, load_paths, @commands.keys,
253
+ @sources.keys, @hooks_by_event.keys)
254
+ true
255
+ end
256
+ ensure
257
+ @commands = commands
258
+ @sources = sources
259
+ @hooks_by_event = hooks
260
+ end
261
+
262
+ # Executes the plugins.rb file
263
+ #
264
+ # @param [String] name of the plugin
265
+ def load_plugin(name)
266
+ # Need to ensure before this that plugin root where the rest of gems
267
+ # are installed to be on load path to support plugin deps. Currently not
268
+ # done to avoid conflicts
269
+ path = index.plugin_path(name)
270
+
271
+ add_to_load_path(index.load_paths(name))
272
+
273
+ load path.join(PLUGIN_FILE_NAME)
274
+
275
+ @loaded_plugin_names << name
276
+ rescue RuntimeError => e
277
+ Bundler.ui.error "Failed loading plugin #{name}: #{e.message}"
278
+ raise
279
+ end
280
+
281
+ def add_to_load_path(load_paths)
282
+ if insert_index = Bundler.rubygems.load_path_insert_index
283
+ $LOAD_PATH.insert(insert_index, *load_paths)
284
+ else
285
+ $LOAD_PATH.unshift(*load_paths)
286
+ end
287
+ end
288
+
289
+ class << self
290
+ private :load_plugin, :register_plugin, :save_plugins, :validate_plugin!,
291
+ :add_to_load_path
292
+ end
293
+ end
294
+ end
@@ -0,0 +1,81 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Bundler
4
+ # This is the interfacing class represents the API that we intend to provide
5
+ # the plugins to use.
6
+ #
7
+ # For plugins to be independent of the Bundler internals they shall limit their
8
+ # interactions to methods of this class only. This will save them from breaking
9
+ # when some internal change.
10
+ #
11
+ # Currently we are delegating the methods defined in Bundler class to
12
+ # itself. So, this class acts as a buffer.
13
+ #
14
+ # If there is some change in the Bundler class that is incompatible to its
15
+ # previous behavior or if otherwise desired, we can reimplement(or implement)
16
+ # the method to preserve compatibility.
17
+ #
18
+ # To use this, either the class can inherit this class or use it directly.
19
+ # For example of both types of use, refer the file `spec/plugins/command.rb`
20
+ #
21
+ # To use it without inheriting, you will have to create an object of this
22
+ # to use the functions (except for declaration functions like command, source,
23
+ # and hooks).
24
+ module Plugin
25
+ class API
26
+ autoload :Source, "bundler/plugin/api/source"
27
+
28
+ # The plugins should declare that they handle a command through this helper.
29
+ #
30
+ # @param [String] command being handled by them
31
+ # @param [Class] (optional) class that handles the command. If not
32
+ # provided, the `self` class will be used.
33
+ def self.command(command, cls = self)
34
+ Plugin.add_command command, cls
35
+ end
36
+
37
+ # The plugins should declare that they provide a installation source
38
+ # through this helper.
39
+ #
40
+ # @param [String] the source type they provide
41
+ # @param [Class] (optional) class that handles the source. If not
42
+ # provided, the `self` class will be used.
43
+ def self.source(source, cls = self)
44
+ cls.send :include, Bundler::Plugin::API::Source
45
+ Plugin.add_source source, cls
46
+ end
47
+
48
+ def self.hook(event, &block)
49
+ Plugin.add_hook(event, &block)
50
+ end
51
+
52
+ # The cache dir to be used by the plugins for storage
53
+ #
54
+ # @return [Pathname] path of the cache dir
55
+ def cache_dir
56
+ Plugin.cache.join("plugins")
57
+ end
58
+
59
+ # A tmp dir to be used by plugins
60
+ # Accepts names that get concatenated as suffix
61
+ #
62
+ # @return [Pathname] object for the new directory created
63
+ def tmp(*names)
64
+ Bundler.tmp(["plugin", *names].join("-"))
65
+ end
66
+
67
+ def method_missing(name, *args, &blk)
68
+ return Bundler.send(name, *args, &blk) if Bundler.respond_to?(name)
69
+
70
+ return SharedHelpers.send(name, *args, &blk) if SharedHelpers.respond_to?(name)
71
+
72
+ super
73
+ end
74
+
75
+ def respond_to_missing?(name, include_private = false)
76
+ SharedHelpers.respond_to?(name, include_private) ||
77
+ Bundler.respond_to?(name, include_private) || super
78
+ end
79
+ end
80
+ end
81
+ end
@@ -0,0 +1,306 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "uri"
4
+
5
+ module Bundler
6
+ module Plugin
7
+ class API
8
+ # This class provides the base to build source plugins
9
+ # All the method here are required to build a source plugin (except
10
+ # `uri_hash`, `gem_install_dir`; they are helpers).
11
+ #
12
+ # Defaults for methods, where ever possible are provided which is
13
+ # expected to work. But, all source plugins have to override
14
+ # `fetch_gemspec_files` and `install`. Defaults are also not provided for
15
+ # `remote!`, `cache!` and `unlock!`.
16
+ #
17
+ # The defaults shall work for most situations but nevertheless they can
18
+ # be (preferably should be) overridden as per the plugins' needs safely
19
+ # (as long as they behave as expected).
20
+ # On overriding `initialize` you should call super first.
21
+ #
22
+ # If required plugin should override `hash`, `==` and `eql?` methods to be
23
+ # able to match objects representing same sources, but may be created in
24
+ # different situation (like form gemfile and lockfile). The default ones
25
+ # checks only for class and uri, but elaborate source plugins may need
26
+ # more comparisons (e.g. git checking on branch or tag).
27
+ #
28
+ # @!attribute [r] uri
29
+ # @return [String] the remote specified with `source` block in Gemfile
30
+ #
31
+ # @!attribute [r] options
32
+ # @return [String] options passed during initialization (either from
33
+ # lockfile or Gemfile)
34
+ #
35
+ # @!attribute [r] name
36
+ # @return [String] name that can be used to uniquely identify a source
37
+ #
38
+ # @!attribute [rw] dependency_names
39
+ # @return [Array<String>] Names of dependencies that the source should
40
+ # try to resolve. It is not necessary to use this list intenally. This
41
+ # is present to be compatible with `Definition` and is used by
42
+ # rubygems source.
43
+ module Source
44
+ attr_reader :uri, :options, :name
45
+ attr_accessor :dependency_names
46
+
47
+ def initialize(opts)
48
+ @options = opts
49
+ @dependency_names = []
50
+ @uri = opts["uri"]
51
+ @type = opts["type"]
52
+ @name = opts["name"] || "#{@type} at #{@uri}"
53
+ end
54
+
55
+ # This is used by the default `spec` method to constructs the
56
+ # Specification objects for the gems and versions that can be installed
57
+ # by this source plugin.
58
+ #
59
+ # Note: If the spec method is overridden, this function is not necessary
60
+ #
61
+ # @return [Array<String>] paths of the gemspec files for gems that can
62
+ # be installed
63
+ def fetch_gemspec_files
64
+ []
65
+ end
66
+
67
+ # Options to be saved in the lockfile so that the source plugin is able
68
+ # to check out same version of gem later.
69
+ #
70
+ # There options are passed when the source plugin is created from the
71
+ # lock file.
72
+ #
73
+ # @return [Hash]
74
+ def options_to_lock
75
+ {}
76
+ end
77
+
78
+ # Install the gem specified by the spec at appropriate path.
79
+ # `install_path` provides a sufficient default, if the source can only
80
+ # satisfy one gem, but is not binding.
81
+ #
82
+ # @return [String] post installation message (if any)
83
+ def install(spec, opts)
84
+ raise MalformattedPlugin, "Source plugins need to override the install method."
85
+ end
86
+
87
+ # It builds extensions, generates bins and installs them for the spec
88
+ # provided.
89
+ #
90
+ # It depends on `spec.loaded_from` to get full_gem_path. The source
91
+ # plugins should set that.
92
+ #
93
+ # It should be called in `install` after the plugin is done placing the
94
+ # gem at correct install location.
95
+ #
96
+ # It also runs Gem hooks `pre_install`, `post_build` and `post_install`
97
+ #
98
+ # Note: Do not override if you don't know what you are doing.
99
+ def post_install(spec, disable_exts = false)
100
+ opts = { :env_shebang => false, :disable_extensions => disable_exts }
101
+ installer = Bundler::Source::Path::Installer.new(spec, opts)
102
+ installer.post_install
103
+ end
104
+
105
+ # A default installation path to install a single gem. If the source
106
+ # servers multiple gems, it's not of much use and the source should one
107
+ # of its own.
108
+ def install_path
109
+ @install_path ||=
110
+ begin
111
+ base_name = File.basename(URI.parse(uri).normalize.path)
112
+
113
+ gem_install_dir.join("#{base_name}-#{uri_hash[0..11]}")
114
+ end
115
+ end
116
+
117
+ # Parses the gemspec files to find the specs for the gems that can be
118
+ # satisfied by the source.
119
+ #
120
+ # Few important points to keep in mind:
121
+ # - If the gems are not installed then it shall return specs for all
122
+ # the gems it can satisfy
123
+ # - If gem is installed (that is to be detected by the plugin itself)
124
+ # then it shall return at least the specs that are installed.
125
+ # - The `loaded_from` for each of the specs shall be correct (it is
126
+ # used to find the load path)
127
+ #
128
+ # @return [Bundler::Index] index containing the specs
129
+ def specs
130
+ files = fetch_gemspec_files
131
+
132
+ Bundler::Index.build do |index|
133
+ files.each do |file|
134
+ next unless spec = Bundler.load_gemspec(file)
135
+ Bundler.rubygems.set_installed_by_version(spec)
136
+
137
+ spec.source = self
138
+ Bundler.rubygems.validate(spec)
139
+
140
+ index << spec
141
+ end
142
+ end
143
+ end
144
+
145
+ # Set internal representation to fetch the gems/specs from remote.
146
+ #
147
+ # When this is called, the source should try to fetch the specs and
148
+ # install from remote path.
149
+ def remote!
150
+ end
151
+
152
+ # Set internal representation to fetch the gems/specs from app cache.
153
+ #
154
+ # When this is called, the source should try to fetch the specs and
155
+ # install from the path provided by `app_cache_path`.
156
+ def cached!
157
+ end
158
+
159
+ # This is called to update the spec and installation.
160
+ #
161
+ # If the source plugin is loaded from lockfile or otherwise, it shall
162
+ # refresh the cache/specs (e.g. git sources can make a fresh clone).
163
+ def unlock!
164
+ end
165
+
166
+ # Name of directory where plugin the is expected to cache the gems when
167
+ # #cache is called.
168
+ #
169
+ # Also this name is matched against the directories in cache for pruning
170
+ #
171
+ # This is used by `app_cache_path`
172
+ def app_cache_dirname
173
+ base_name = File.basename(URI.parse(uri).normalize.path)
174
+ "#{base_name}-#{uri_hash}"
175
+ end
176
+
177
+ # This method is called while caching to save copy of the gems that the
178
+ # source can resolve to path provided by `app_cache_app`so that they can
179
+ # be reinstalled from the cache without querying the remote (i.e. an
180
+ # alternative to remote)
181
+ #
182
+ # This is stored with the app and source plugins should try to provide
183
+ # specs and install only from this cache when `cached!` is called.
184
+ #
185
+ # This cache is different from the internal caching that can be done
186
+ # at sub paths of `cache_path` (from API). This can be though as caching
187
+ # by bundler.
188
+ def cache(spec, custom_path = nil)
189
+ new_cache_path = app_cache_path(custom_path)
190
+
191
+ FileUtils.rm_rf(new_cache_path)
192
+ FileUtils.cp_r(install_path, new_cache_path)
193
+ FileUtils.touch(app_cache_path.join(".bundlecache"))
194
+ end
195
+
196
+ # This shall check if two source object represent the same source.
197
+ #
198
+ # The comparison shall take place only on the attribute that can be
199
+ # inferred from the options passed from Gemfile and not on attibutes
200
+ # that are used to pin down the gem to specific version (e.g. Git
201
+ # sources should compare on branch and tag but not on commit hash)
202
+ #
203
+ # The sources objects are constructed from Gemfile as well as from
204
+ # lockfile. To converge the sources, it is necessary that they match.
205
+ #
206
+ # The same applies for `eql?` and `hash`
207
+ def ==(other)
208
+ other.is_a?(self.class) && uri == other.uri
209
+ end
210
+
211
+ # When overriding `eql?` please preserve the behaviour as mentioned in
212
+ # docstring for `==` method.
213
+ alias_method :eql?, :==
214
+
215
+ # When overriding `hash` please preserve the behaviour as mentioned in
216
+ # docstring for `==` method, i.e. two methods equal by above comparison
217
+ # should have same hash.
218
+ def hash
219
+ [self.class, uri].hash
220
+ end
221
+
222
+ # A helper method, not necessary if not used internally.
223
+ def installed?
224
+ File.directory?(install_path)
225
+ end
226
+
227
+ # The full path where the plugin should cache the gem so that it can be
228
+ # installed latter.
229
+ #
230
+ # Note: Do not override if you don't know what you are doing.
231
+ def app_cache_path(custom_path = nil)
232
+ @app_cache_path ||= Bundler.app_cache(custom_path).join(app_cache_dirname)
233
+ end
234
+
235
+ # Used by definition.
236
+ #
237
+ # Note: Do not override if you don't know what you are doing.
238
+ def unmet_deps
239
+ specs.unmet_dependency_names
240
+ end
241
+
242
+ # Note: Do not override if you don't know what you are doing.
243
+ def can_lock?(spec)
244
+ spec.source == self
245
+ end
246
+
247
+ # Generates the content to be entered into the lockfile.
248
+ # Saves type and remote and also calls to `options_to_lock`.
249
+ #
250
+ # Plugin should use `options_to_lock` to save information in lockfile
251
+ # and not override this.
252
+ #
253
+ # Note: Do not override if you don't know what you are doing.
254
+ def to_lock
255
+ out = String.new("#{LockfileParser::PLUGIN}\n")
256
+ out << " remote: #{@uri}\n"
257
+ out << " type: #{@type}\n"
258
+ options_to_lock.each do |opt, value|
259
+ out << " #{opt}: #{value}\n"
260
+ end
261
+ out << " specs:\n"
262
+ end
263
+
264
+ def to_s
265
+ "plugin source for #{options[:type]} with uri #{uri}"
266
+ end
267
+
268
+ # Note: Do not override if you don't know what you are doing.
269
+ def include?(other)
270
+ other == self
271
+ end
272
+
273
+ def uri_hash
274
+ SharedHelpers.digest(:SHA1).hexdigest(uri)
275
+ end
276
+
277
+ # Note: Do not override if you don't know what you are doing.
278
+ def gem_install_dir
279
+ Bundler.install_path
280
+ end
281
+
282
+ # It is used to obtain the full_gem_path.
283
+ #
284
+ # spec's loaded_from path is expanded against this to get full_gem_path
285
+ #
286
+ # Note: Do not override if you don't know what you are doing.
287
+ def root
288
+ Bundler.root
289
+ end
290
+
291
+ # @private
292
+ # Returns true
293
+ def bundler_plugin_api_source?
294
+ true
295
+ end
296
+
297
+ # @private
298
+ # This API on source might not be stable, and for now we expect plugins
299
+ # to download all specs in `#specs`, so we implement the method for
300
+ # compatibility purposes and leave it undocumented (and don't support)
301
+ # overriding it)
302
+ def double_check_for(*); end
303
+ end
304
+ end
305
+ end
306
+ end