rubygems-update 2.6.7 → 2.6.8

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

Potentially problematic release.


This version of rubygems-update might be problematic. Click here for more details.

Files changed (136) hide show
  1. checksums.yaml +4 -4
  2. data/History.txt +11 -0
  3. data/Manifest.txt +10 -5
  4. data/bundler/CHANGELOG.md +108 -0
  5. data/bundler/DEVELOPMENT.md +6 -4
  6. data/bundler/ISSUES.md +17 -0
  7. data/bundler/README.md +2 -0
  8. data/bundler/exe/bundle +4 -6
  9. data/bundler/exe/bundle_ruby +2 -4
  10. data/bundler/exe/bundler +1 -19
  11. data/bundler/lib/bundler.rb +114 -44
  12. data/bundler/lib/bundler/cli.rb +90 -17
  13. data/bundler/lib/bundler/cli/binstubs.rb +4 -3
  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/clean.rb +1 -1
  17. data/bundler/lib/bundler/cli/common.rb +13 -0
  18. data/bundler/lib/bundler/cli/console.rb +3 -0
  19. data/bundler/lib/bundler/cli/doctor.rb +93 -0
  20. data/bundler/lib/bundler/cli/exec.rb +18 -2
  21. data/bundler/lib/bundler/cli/gem.rb +3 -2
  22. data/bundler/lib/bundler/cli/inject.rb +25 -7
  23. data/bundler/lib/bundler/cli/install.rb +25 -7
  24. data/bundler/lib/bundler/cli/lock.rb +20 -7
  25. data/bundler/lib/bundler/cli/outdated.rb +97 -38
  26. data/bundler/lib/bundler/cli/platform.rb +1 -1
  27. data/bundler/lib/bundler/cli/show.rb +1 -1
  28. data/bundler/lib/bundler/cli/update.rb +9 -6
  29. data/bundler/lib/bundler/compact_index_client.rb +102 -0
  30. data/bundler/lib/bundler/compact_index_client/cache.rb +119 -0
  31. data/bundler/lib/bundler/compact_index_client/updater.rb +88 -0
  32. data/bundler/lib/bundler/current_ruby.rb +3 -3
  33. data/bundler/lib/bundler/definition.rb +210 -46
  34. data/bundler/lib/bundler/dependency.rb +1 -1
  35. data/bundler/lib/bundler/deployment.rb +6 -0
  36. data/bundler/lib/bundler/deprecate.rb +16 -0
  37. data/bundler/lib/bundler/dsl.rb +70 -24
  38. data/bundler/lib/bundler/endpoint_specification.rb +2 -0
  39. data/bundler/lib/bundler/env.rb +5 -1
  40. data/bundler/lib/bundler/environment_preserver.rb +1 -1
  41. data/bundler/lib/bundler/errors.rb +12 -1
  42. data/bundler/lib/bundler/feature_flag.rb +32 -0
  43. data/bundler/lib/bundler/fetcher.rb +3 -2
  44. data/bundler/lib/bundler/fetcher/base.rb +10 -0
  45. data/bundler/lib/bundler/fetcher/compact_index.rb +33 -12
  46. data/bundler/lib/bundler/fetcher/dependency.rb +2 -13
  47. data/bundler/lib/bundler/fetcher/downloader.rb +12 -1
  48. data/bundler/lib/bundler/friendly_errors.rb +9 -2
  49. data/bundler/lib/bundler/gem_helper.rb +3 -3
  50. data/bundler/lib/bundler/gem_helpers.rb +69 -1
  51. data/bundler/lib/bundler/gem_version_promoter.rb +175 -0
  52. data/bundler/lib/bundler/gemdeps.rb +28 -0
  53. data/bundler/lib/bundler/graph.rb +4 -25
  54. data/bundler/lib/bundler/index.rb +11 -2
  55. data/bundler/lib/bundler/injector.rb +12 -5
  56. data/bundler/lib/bundler/inline.rb +4 -4
  57. data/bundler/lib/bundler/installer.rb +25 -9
  58. data/bundler/lib/bundler/installer/gem_installer.rb +13 -15
  59. data/bundler/lib/bundler/installer/parallel_installer.rb +121 -99
  60. data/bundler/lib/bundler/lazy_specification.rb +28 -3
  61. data/bundler/lib/bundler/lockfile_parser.rb +27 -17
  62. data/bundler/lib/bundler/match_platform.rb +2 -1
  63. data/bundler/lib/bundler/mirror.rb +2 -2
  64. data/bundler/lib/bundler/plugin.rb +156 -32
  65. data/bundler/lib/bundler/plugin/api.rb +29 -5
  66. data/bundler/lib/bundler/plugin/api/source.rb +293 -0
  67. data/bundler/lib/bundler/plugin/dsl.rb +25 -1
  68. data/bundler/lib/bundler/plugin/index.rb +80 -13
  69. data/bundler/lib/bundler/plugin/installer.rb +6 -10
  70. data/bundler/lib/bundler/plugin/source_list.rb +4 -0
  71. data/bundler/lib/bundler/postit_trampoline.rb +56 -40
  72. data/bundler/lib/bundler/remote_specification.rb +5 -0
  73. data/bundler/lib/bundler/resolver.rb +64 -47
  74. data/bundler/lib/bundler/retry.rb +2 -1
  75. data/bundler/lib/bundler/ruby_version.rb +11 -4
  76. data/bundler/lib/bundler/rubygems_ext.rb +25 -3
  77. data/bundler/lib/bundler/rubygems_gem_installer.rb +54 -0
  78. data/bundler/lib/bundler/rubygems_integration.rb +148 -70
  79. data/bundler/lib/bundler/runtime.rb +27 -3
  80. data/bundler/lib/bundler/settings.rb +80 -17
  81. data/bundler/lib/bundler/setup.rb +7 -4
  82. data/bundler/lib/bundler/shared_helpers.rb +45 -8
  83. data/bundler/lib/bundler/source.rb +2 -1
  84. data/bundler/lib/bundler/source/gemspec.rb +4 -0
  85. data/bundler/lib/bundler/source/git.rb +9 -6
  86. data/bundler/lib/bundler/source/git/git_proxy.rb +37 -4
  87. data/bundler/lib/bundler/source/path.rb +10 -27
  88. data/bundler/lib/bundler/source/path/installer.rb +39 -11
  89. data/bundler/lib/bundler/source/rubygems.rb +3 -2
  90. data/bundler/lib/bundler/source_list.rb +28 -8
  91. data/bundler/lib/bundler/spec_set.rb +30 -15
  92. data/bundler/lib/bundler/templates/Executable.standalone +4 -2
  93. data/bundler/lib/bundler/templates/Gemfile +0 -1
  94. data/bundler/lib/bundler/templates/newgem/README.md.tt +1 -1
  95. data/bundler/lib/bundler/templates/newgem/bin/console.tt +1 -1
  96. data/bundler/lib/bundler/ui/shell.rb +25 -9
  97. data/bundler/lib/bundler/ui/silent.rb +10 -0
  98. data/bundler/lib/bundler/vendor/molinillo/lib/molinillo/gem_metadata.rb +1 -1
  99. data/bundler/lib/bundler/vendor/molinillo/lib/molinillo/resolution.rb +8 -2
  100. data/bundler/lib/bundler/vendor/postit/lib/postit.rb +5 -5
  101. data/bundler/lib/bundler/vendor/postit/lib/postit/environment.rb +3 -3
  102. data/bundler/lib/bundler/vendor/postit/lib/postit/installer.rb +1 -1
  103. data/bundler/lib/bundler/vendor/postit/lib/postit/parser.rb +1 -1
  104. data/bundler/lib/bundler/vendor/postit/lib/postit/setup.rb +4 -4
  105. data/bundler/lib/bundler/vendor/postit/lib/postit/version.rb +2 -2
  106. data/bundler/lib/bundler/version.rb +1 -1
  107. data/bundler/lib/bundler/yaml_serializer.rb +34 -11
  108. data/bundler/man/bundle-binstubs.ronn +29 -0
  109. data/bundler/man/bundle-config.ronn +33 -1
  110. data/bundler/man/bundle-exec.ronn +9 -0
  111. data/bundler/man/bundle-install.ronn +6 -41
  112. data/bundler/man/bundle-package.ronn +1 -1
  113. data/bundler/man/bundle.ronn +9 -8
  114. data/bundler/man/gemfile.5.ronn +1 -1
  115. data/lib/rubygems.rb +1 -1
  116. data/lib/rubygems/dependency.rb +7 -4
  117. data/lib/rubygems/request.rb +46 -0
  118. data/lib/rubygems/resolver/molinillo/lib/molinillo/dependency_graph.rb +7 -0
  119. data/lib/rubygems/resolver/molinillo/lib/molinillo/dependency_graph/action.rb +1 -1
  120. data/lib/rubygems/resolver/molinillo/lib/molinillo/dependency_graph/add_edge_no_circular.rb +2 -2
  121. data/lib/rubygems/resolver/molinillo/lib/molinillo/dependency_graph/add_vertex.rb +2 -2
  122. data/lib/rubygems/resolver/molinillo/lib/molinillo/dependency_graph/delete_edge.rb +62 -0
  123. data/lib/rubygems/resolver/molinillo/lib/molinillo/dependency_graph/detach_vertex_named.rb +1 -1
  124. data/lib/rubygems/resolver/molinillo/lib/molinillo/dependency_graph/log.rb +12 -1
  125. data/lib/rubygems/resolver/molinillo/lib/molinillo/dependency_graph/set_payload.rb +2 -2
  126. data/lib/rubygems/resolver/molinillo/lib/molinillo/dependency_graph/tag.rb +2 -2
  127. data/lib/rubygems/resolver/molinillo/lib/molinillo/gem_metadata.rb +1 -1
  128. data/lib/rubygems/resolver/molinillo/lib/molinillo/resolution.rb +11 -3
  129. data/test/rubygems/test_gem_request.rb +132 -0
  130. data/test/rubygems/test_gem_specification.rb +7 -0
  131. metadata +34 -29
  132. data/bundler/lib/bundler/environment.rb +0 -42
  133. data/bundler/lib/bundler/vendor/compact_index_client/lib/compact_index_client.rb +0 -79
  134. data/bundler/lib/bundler/vendor/compact_index_client/lib/compact_index_client/cache.rb +0 -98
  135. data/bundler/lib/bundler/vendor/compact_index_client/lib/compact_index_client/updater.rb +0 -80
  136. data/bundler/lib/bundler/vendor/compact_index_client/lib/compact_index_client/version.rb +0 -4
@@ -5,6 +5,22 @@ require "bundler/match_platform"
5
5
 
6
6
  module Bundler
7
7
  class LazySpecification
8
+ Identifier = Struct.new(:name, :version, :source, :platform, :dependencies)
9
+ class Identifier
10
+ include Comparable
11
+ def <=>(other)
12
+ return unless other.is_a?(Identifier)
13
+ [name, version, platform_string] <=> [other.name, other.version, other.platform_string]
14
+ end
15
+
16
+ protected
17
+
18
+ def platform_string
19
+ platform_string = platform.to_s
20
+ platform_string == Index::RUBY ? Index::NULL : platform_string
21
+ end
22
+ end
23
+
8
24
  include MatchPlatform
9
25
 
10
26
  attr_reader :name, :version, :dependencies, :platform
@@ -53,7 +69,12 @@ module Bundler
53
69
  end
54
70
 
55
71
  def __materialize__
56
- @specification = source.specs.search(Gem::Dependency.new(name, version)).last
72
+ search_object = Bundler.settings[:specific_platform] || Bundler.settings[:force_ruby_platform] ? self : Dependency.new(name, version)
73
+ @specification = if source.is_a?(Source::Gemspec) && source.gemspec.name == name
74
+ source.gemspec.tap {|s| s.source = source }
75
+ else
76
+ source.specs.search(search_object).last
77
+ end
57
78
  end
58
79
 
59
80
  def respond_to?(*args)
@@ -61,11 +82,15 @@ module Bundler
61
82
  end
62
83
 
63
84
  def to_s
64
- @__to_s ||= "#{name} (#{version})"
85
+ @__to_s ||= if platform == Gem::Platform::RUBY || platform.nil?
86
+ "#{name} (#{version})"
87
+ else
88
+ "#{name} (#{version}-#{platform})"
89
+ end
65
90
  end
66
91
 
67
92
  def identifier
68
- @__identifier ||= [name, version, source, platform, dependencies].hash
93
+ @__identifier ||= Identifier.new(name, version, source, platform, dependencies)
69
94
  end
70
95
 
71
96
  private
@@ -22,14 +22,18 @@ module Bundler
22
22
  GIT = "GIT".freeze
23
23
  GEM = "GEM".freeze
24
24
  PATH = "PATH".freeze
25
+ PLUGIN = "PLUGIN SOURCE".freeze
25
26
  SPECS = " specs:".freeze
26
27
  OPTIONS = /^ ([a-z]+): (.*)$/i
27
- SOURCE = [GIT, GEM, PATH].freeze
28
+ SOURCE = [GIT, GEM, PATH, PLUGIN].freeze
28
29
 
29
30
  SECTIONS_BY_VERSION_INTRODUCED = {
30
- Gem::Version.create("1.0") => [DEPENDENCIES, PLATFORMS, GIT, GEM, PATH].freeze,
31
- Gem::Version.create("1.10") => [BUNDLED].freeze,
32
- Gem::Version.create("1.12") => [RUBY].freeze,
31
+ # The strings have to be dup'ed for old RG on Ruby 2.3+
32
+ # TODO: remove dup in Bundler 2.0
33
+ Gem::Version.create("1.0".dup) => [DEPENDENCIES, PLATFORMS, GIT, GEM, PATH].freeze,
34
+ Gem::Version.create("1.10".dup) => [BUNDLED].freeze,
35
+ Gem::Version.create("1.12".dup) => [RUBY].freeze,
36
+ Gem::Version.create("1.13".dup) => [PLUGIN].freeze,
33
37
  }.freeze
34
38
 
35
39
  KNOWN_SECTIONS = SECTIONS_BY_VERSION_INTRODUCED.values.flatten.freeze
@@ -46,7 +50,7 @@ module Bundler
46
50
 
47
51
  def self.sections_to_ignore(base_version = nil)
48
52
  base_version &&= base_version.release
49
- base_version ||= Gem::Version.create("1.0")
53
+ base_version ||= Gem::Version.create("1.0".dup)
50
54
  attributes = []
51
55
  SECTIONS_BY_VERSION_INTRODUCED.each do |version, introduced|
52
56
  next if version <= base_version
@@ -88,7 +92,7 @@ module Bundler
88
92
  end
89
93
  end
90
94
  @sources << @rubygems_aggregate
91
- @specs = @specs.values
95
+ @specs = @specs.values.sort_by(&:identifier)
92
96
  warn_for_outdated_bundler_version
93
97
  rescue ArgumentError => e
94
98
  Bundler.ui.debug(e)
@@ -105,8 +109,8 @@ module Bundler
105
109
  raise LockfileError, "You must use Bundler #{bundler_version.segments.first} or greater with this lockfile."
106
110
  when 0
107
111
  if current_version < bundler_version
108
- Bundler.ui.warn "Warning: the running version of Bundler is older " \
109
- "than the version that created the lockfile. We suggest you " \
112
+ Bundler.ui.warn "Warning: the running version of Bundler (#{current_version}) is older " \
113
+ "than the version that created the lockfile (#{bundler_version}). We suggest you " \
110
114
  "upgrade to the latest version of Bundler by running `gem " \
111
115
  "install bundler#{prerelease_text}`.\n"
112
116
  end
@@ -116,17 +120,14 @@ module Bundler
116
120
  private
117
121
 
118
122
  TYPES = {
119
- GIT => Bundler::Source::Git,
120
- GEM => Bundler::Source::Rubygems,
121
- PATH => Bundler::Source::Path,
123
+ GIT => Bundler::Source::Git,
124
+ GEM => Bundler::Source::Rubygems,
125
+ PATH => Bundler::Source::Path,
126
+ PLUGIN => Bundler::Plugin,
122
127
  }.freeze
123
128
 
124
129
  def parse_source(line)
125
130
  case line
126
- when GIT, GEM, PATH
127
- @current_source = nil
128
- @opts = {}
129
- @type = line
130
131
  when SPECS
131
132
  case @type
132
133
  when PATH
@@ -145,6 +146,9 @@ module Bundler
145
146
  @rubygems_aggregate.add_remote(url)
146
147
  end
147
148
  @current_source = @rubygems_aggregate
149
+ when PLUGIN
150
+ @current_source = Plugin.source_from_lock(@opts)
151
+ @sources << @current_source
148
152
  end
149
153
  when OPTIONS
150
154
  value = $2
@@ -159,6 +163,10 @@ module Bundler
159
163
  else
160
164
  @opts[key] = value
161
165
  end
166
+ when *SOURCE
167
+ @current_source = nil
168
+ @opts = {}
169
+ @type = line
162
170
  else
163
171
  parse_spec(line)
164
172
  end
@@ -199,8 +207,10 @@ module Bundler
199
207
  def parse_spec(line)
200
208
  if line =~ NAME_VERSION_4
201
209
  name = $1
202
- version = Gem::Version.new($2)
203
- platform = $3 ? Gem::Platform.new($3) : Gem::Platform::RUBY
210
+ version = $2
211
+ platform = $3
212
+ version = Gem::Version.new(version)
213
+ platform = platform ? Gem::Platform.new(platform) : Gem::Platform::RUBY
204
214
  @current_spec = LazySpecification.new(name, version, platform)
205
215
  @current_spec.source = @current_source
206
216
 
@@ -8,7 +8,8 @@ module Bundler
8
8
  def match_platform(p)
9
9
  Gem::Platform::RUBY == platform ||
10
10
  platform.nil? || p == platform ||
11
- generic(Gem::Platform.new(platform)) === p
11
+ generic(Gem::Platform.new(platform)) === p ||
12
+ Gem::Platform.new(platform) === p
12
13
  end
13
14
  end
14
15
  end
@@ -43,7 +43,7 @@ module Bundler
43
43
  private
44
44
 
45
45
  def fetch_valid_mirror_for(uri)
46
- mirror = (@mirrors[URI(uri.to_s.downcase)] || Mirror.new(uri)).validate!(@prober)
46
+ mirror = (@mirrors[URI(uri.to_s.downcase)] || @mirrors[URI(uri.to_s).host] || Mirror.new(uri)).validate!(@prober)
47
47
  mirror = Mirror.new(uri) unless mirror.valid?
48
48
  mirror
49
49
  end
@@ -121,7 +121,7 @@ module Bundler
121
121
  if uri == "all"
122
122
  @all = true
123
123
  else
124
- @uri = Settings.normalize_uri(uri)
124
+ @uri = URI(uri).absolute? ? Settings.normalize_uri(uri) : uri
125
125
  end
126
126
  @value = value
127
127
  end
@@ -1,8 +1,8 @@
1
1
  # frozen_string_literal: true
2
+ require "bundler/plugin/api"
2
3
 
3
4
  module Bundler
4
5
  module Plugin
5
- autoload :API, "bundler/plugin/api"
6
6
  autoload :DSL, "bundler/plugin/dsl"
7
7
  autoload :Index, "bundler/plugin/index"
8
8
  autoload :Installer, "bundler/plugin/installer"
@@ -10,45 +10,62 @@ module Bundler
10
10
 
11
11
  class MalformattedPlugin < PluginError; end
12
12
  class UndefinedCommandError < PluginError; end
13
+ class UnknownSourceError < PluginError; end
13
14
 
14
15
  PLUGIN_FILE_NAME = "plugins.rb".freeze
15
16
 
16
17
  module_function
17
18
 
18
- @commands = {}
19
+ def reset!
20
+ instance_variables.each {|i| remove_instance_variable(i) }
21
+
22
+ @sources = {}
23
+ @commands = {}
24
+ @hooks_by_event = Hash.new {|h, k| h[k] = [] }
25
+ @loaded_plugin_names = []
26
+ end
27
+
28
+ reset!
19
29
 
20
30
  # Installs a new plugin by the given name
21
31
  #
22
32
  # @param [Array<String>] names the name of plugin to be installed
23
- # @param [Hash] options various parameters as described in description
24
- # @option options [String] :source rubygems source to fetch the plugin gem from
25
- # @option options [String] :version (optional) the version of the plugin to install
33
+ # @param [Hash] options various parameters as described in description.
34
+ # Refer to cli/plugin for available options
26
35
  def install(names, options)
27
- paths = Installer.new.install(names, options)
36
+ specs = Installer.new.install(names, options)
28
37
 
29
- save_plugins paths
38
+ save_plugins names, specs
30
39
  rescue PluginError => e
31
- paths.values.map {|path| Bundler.rm_rf(path) } if paths
32
- Bundler.ui.error "Failed to install plugin #{name}: #{e.message}\n #{e.backtrace.join("\n ")}"
40
+ specs.values.map {|spec| Bundler.rm_rf(spec.full_gem_path) } if specs
41
+ Bundler.ui.error "Failed to install plugin #{name}: #{e.message}\n #{e.backtrace.join("\n ")}"
33
42
  end
34
43
 
35
44
  # Evaluates the Gemfile with a limited DSL and installs the plugins
36
45
  # specified by plugin method
37
46
  #
38
47
  # @param [Pathname] gemfile path
48
+ # @param [Proc] block that can be evaluated for (inline) Gemfile
39
49
  def gemfile_install(gemfile = nil, &inline)
50
+ builder = DSL.new
40
51
  if block_given?
41
- builder = DSL.new
42
52
  builder.instance_eval(&inline)
43
- definition = builder.to_definition(nil, true)
44
53
  else
45
- definition = DSL.evaluate(gemfile, nil, {})
54
+ builder.eval_gemfile(gemfile)
46
55
  end
47
- return unless definition.dependencies.any?
56
+ definition = builder.to_definition(nil, true)
57
+
58
+ return if definition.dependencies.empty?
48
59
 
49
- plugins = Installer.new.install_definition(definition)
60
+ plugins = definition.dependencies.map(&:name).reject {|p| index.installed? p }
61
+ installed_specs = Installer.new.install_definition(definition)
50
62
 
51
- save_plugins plugins
63
+ save_plugins plugins, installed_specs, builder.inferred_plugins
64
+ rescue => e
65
+ unless e.is_a?(GemfileError)
66
+ Bundler.ui.error "Failed to install plugin: #{e.message}\n #{e.backtrace[0]}"
67
+ end
68
+ raise
52
69
  end
53
70
 
54
71
  # The index object used to store the details about the plugin
@@ -56,9 +73,25 @@ module Bundler
56
73
  @index ||= Index.new
57
74
  end
58
75
 
59
- # The directory root to all plugin related data
76
+ # The directory root for all plugin related data
77
+ #
78
+ # Points to root in app_config_path if ran in an app else points to the one
79
+ # in user_bundle_path
60
80
  def root
61
- @root ||= Bundler.user_bundle_path.join("plugin")
81
+ @root ||= if SharedHelpers.in_bundle?
82
+ local_root
83
+ else
84
+ global_root
85
+ end
86
+ end
87
+
88
+ def local_root
89
+ Bundler.app_config_path.join("plugin")
90
+ end
91
+
92
+ # The global directory root for all plugin related data
93
+ def global_root
94
+ Bundler.user_bundle_path.join("plugin")
62
95
  end
63
96
 
64
97
  # The cache directory for plugin stuffs
@@ -71,7 +104,7 @@ module Bundler
71
104
  @commands[command] = cls
72
105
  end
73
106
 
74
- # Checks if any plugins handles the command
107
+ # Checks if any plugin handles the command
75
108
  def command?(command)
76
109
  !index.command_plugin(command).nil?
77
110
  end
@@ -79,13 +112,64 @@ module Bundler
79
112
  # To be called from Cli class to pass the command and argument to
80
113
  # approriate plugin class
81
114
  def exec_command(command, args)
82
- raise UndefinedCommandError, "Command #{command} not found" unless command? command
115
+ raise UndefinedCommandError, "Command `#{command}` not found" unless command? command
83
116
 
84
117
  load_plugin index.command_plugin(command) unless @commands.key? command
85
118
 
86
119
  @commands[command].new.exec(command, args)
87
120
  end
88
121
 
122
+ # To be called via the API to register to handle a source plugin
123
+ def add_source(source, cls)
124
+ @sources[source] = cls
125
+ end
126
+
127
+ # Checks if any plugin declares the source
128
+ def source?(name)
129
+ !index.source_plugin(name.to_s).nil?
130
+ end
131
+
132
+ # @return [Class] that handles the source. The calss includes API::Source
133
+ def source(name)
134
+ raise UnknownSourceError, "Source #{name} not found" unless source? name
135
+
136
+ load_plugin(index.source_plugin(name)) unless @sources.key? name
137
+
138
+ @sources[name]
139
+ end
140
+
141
+ # @param [Hash] The options that are present in the lock file
142
+ # @return [API::Source] the instance of the class that handles the source
143
+ # type passed in locked_opts
144
+ def source_from_lock(locked_opts)
145
+ src = source(locked_opts["type"])
146
+
147
+ src.new(locked_opts.merge("uri" => locked_opts["remote"]))
148
+ end
149
+
150
+ # To be called via the API to register a hooks and corresponding block that
151
+ # will be called to handle the hook
152
+ def add_hook(event, &block)
153
+ @hooks_by_event[event.to_s] << block
154
+ end
155
+
156
+ # Runs all the hooks that are registered for the passed event
157
+ #
158
+ # It passes the passed arguments and block to the block registered with
159
+ # the api.
160
+ #
161
+ # @param [String] event
162
+ def hook(event, *args, &arg_blk)
163
+ return unless Bundler.feature_flag.plugins?
164
+
165
+ plugins = index.hook_plugins(event)
166
+ return unless plugins.any?
167
+
168
+ (plugins - @loaded_plugin_names).each {|name| load_plugin(name) }
169
+
170
+ @hooks_by_event[event].each {|blk| blk.call(*args, &arg_blk) }
171
+ end
172
+
89
173
  # currently only intended for specs
90
174
  #
91
175
  # @return [String, nil] installed path
@@ -95,13 +179,16 @@ module Bundler
95
179
 
96
180
  # Post installation processing and registering with index
97
181
  #
98
- # @param [Hash] plugins mapped to their installtion path
99
- def save_plugins(plugins)
100
- plugins.each do |name, path|
101
- path = Pathname.new path
102
- validate_plugin! path
103
- register_plugin name, path
104
- Bundler.ui.info "Installed plugin #{name}"
182
+ # @param [Array<String>] plugins list to be installed
183
+ # @param [Hash] specs of plugins mapped to installation path (currently they
184
+ # contain all the installed specs, including plugins)
185
+ # @param [Array<String>] names of inferred source plugins that can be ignored
186
+ def save_plugins(plugins, specs, optional_plugins = [])
187
+ plugins.each do |name|
188
+ spec = specs[name]
189
+ validate_plugin! Pathname.new(spec.full_gem_path)
190
+ installed = register_plugin(name, spec, optional_plugins.include?(name))
191
+ Bundler.ui.info "Installed plugin #{name}" if installed
105
192
  end
106
193
  end
107
194
 
@@ -110,21 +197,33 @@ module Bundler
110
197
  # At present it only checks whether it contains plugins.rb file
111
198
  #
112
199
  # @param [Pathname] plugin_path the path plugin is installed at
113
- # @raise [Error] if plugins.rb file is not found
200
+ # @raise [MalformattedPlugin] if plugins.rb file is not found
114
201
  def validate_plugin!(plugin_path)
115
202
  plugin_file = plugin_path.join(PLUGIN_FILE_NAME)
116
- raise MalformattedPlugin, "#{PLUGIN_FILE_NAME} was not found in the plugin!" unless plugin_file.file?
203
+ raise MalformattedPlugin, "#{PLUGIN_FILE_NAME} was not found in the plugin." unless plugin_file.file?
117
204
  end
118
205
 
119
206
  # Runs the plugins.rb file in an isolated namespace, records the plugin
120
207
  # actions it registers for and then passes the data to index to be stored.
121
208
  #
122
209
  # @param [String] name the name of the plugin
123
- # @param [Pathname] path the path where the plugin is installed at
124
- def register_plugin(name, path)
210
+ # @param [Specification] spec of installed plugin
211
+ # @param [Boolean] optional_plugin, removed if there is conflict with any
212
+ # other plugin (used for default source plugins)
213
+ #
214
+ # @raise [MalformattedPlugin] if plugins.rb raises any error
215
+ def register_plugin(name, spec, optional_plugin = false)
125
216
  commands = @commands
217
+ sources = @sources
218
+ hooks = @hooks_by_event
126
219
 
127
220
  @commands = {}
221
+ @sources = {}
222
+ @hooks_by_event = Hash.new {|h, k| h[k] = [] }
223
+
224
+ load_paths = spec.load_paths
225
+ add_to_load_path(load_paths)
226
+ path = Pathname.new spec.full_gem_path
128
227
 
129
228
  begin
130
229
  load path.join(PLUGIN_FILE_NAME), true
@@ -132,9 +231,18 @@ module Bundler
132
231
  raise MalformattedPlugin, "#{e.class}: #{e.message}"
133
232
  end
134
233
 
135
- index.register_plugin name, path.to_s, @commands.keys
234
+ if optional_plugin && @sources.keys.any? {|s| source? s }
235
+ Bundler.rm_rf(path)
236
+ false
237
+ else
238
+ index.register_plugin(name, path.to_s, load_paths, @commands.keys,
239
+ @sources.keys, @hooks_by_event.keys)
240
+ true
241
+ end
136
242
  ensure
137
243
  @commands = commands
244
+ @sources = sources
245
+ @hooks_by_event = hooks
138
246
  end
139
247
 
140
248
  # Executes the plugins.rb file
@@ -146,11 +254,27 @@ module Bundler
146
254
  # done to avoid conflicts
147
255
  path = index.plugin_path(name)
148
256
 
257
+ add_to_load_path(index.load_paths(name))
258
+
149
259
  load path.join(PLUGIN_FILE_NAME)
260
+
261
+ @loaded_plugin_names << name
262
+ rescue => e
263
+ Bundler.ui.error "Failed loading plugin #{name}: #{e.message}"
264
+ raise
265
+ end
266
+
267
+ def add_to_load_path(load_paths)
268
+ if insert_index = Bundler.rubygems.load_path_insert_index
269
+ $LOAD_PATH.insert(insert_index, *load_paths)
270
+ else
271
+ $LOAD_PATH.unshift(*load_paths)
272
+ end
150
273
  end
151
274
 
152
275
  class << self
153
- private :load_plugin, :register_plugin, :save_plugins, :validate_plugin!
276
+ private :load_plugin, :register_plugin, :save_plugins, :validate_plugin!,
277
+ :add_to_load_path
154
278
  end
155
279
  end
156
280
  end