@@ -29,6 +29,7 @@ def initialize
2929 @sources = SourceList . new
3030 @git_sources = { }
3131 @dependencies = [ ]
32+ @plugins = [ ]
3233 @groups = [ ]
3334 @install_conditionals = [ ]
3435 @optional_groups = [ ]
@@ -97,7 +98,7 @@ def gem(name, *args)
9798 options [ "gemfile" ] = @gemfile
9899 version = args || [ ">= 0" ]
99100
100- normalize_options ( name , version , options )
101+ normalize_options ( name , version , true , options )
101102
102103 dep = Dependency . new ( name , version , options )
103104
@@ -228,7 +229,7 @@ def github(repo, options = {})
228229
229230 def to_definition ( lockfile , unlock , lockfile_contents : nil )
230231 check_primary_source_safety
231- Definition . new ( lockfile , @dependencies , @sources , unlock , @ruby_version , @optional_groups , @gemfiles , lockfile_contents )
232+ Definition . new ( lockfile , @dependencies , @sources , unlock , @ruby_version , @optional_groups , @gemfiles , lockfile_contents , @plugins )
232233 end
233234
234235 def group ( *args , &blk )
@@ -270,8 +271,29 @@ def env(name)
270271 @env = old
271272 end
272273
273- def plugin ( *args )
274- # Pass on
274+ def plugin ( name , *args )
275+ options = args . last . is_a? ( Hash ) ? args . pop . dup : { }
276+ options [ "gemfile" ] = @gemfile
277+ version = args || [ ">= 0" ]
278+
279+ # We don't care to add sources for plugins in this pass over the gemfile
280+ # since we're not actually installing plugins here (they should already
281+ # be installed), just keeping track of them so that we can verify they
282+ # are actually installed. This is important because otherwise sources
283+ # unique to the plugin (like a git source) would end up in the lockfile,
284+ # which we don't want.
285+ normalize_options ( name , version , false , options )
286+
287+ dep = Dependency . new ( name , version , options )
288+
289+ # if there's already a dependency with this name we try to prefer one
290+ if current = @plugins . find { |d | d . name == dep . name }
291+ Bundler . ui . warn "Your Gemfile lists the plugin #{ current . name } (#{ current . requirement } ) more than once.\n " \
292+ "You should keep only one of them.\n " \
293+ "Remove any duplicate entries and specify the plugin only once."
294+ end
295+
296+ @plugins << dep
275297 end
276298
277299 def method_missing ( name , *args )
@@ -347,7 +369,7 @@ def valid_keys
347369 @valid_keys ||= VALID_KEYS
348370 end
349371
350- def normalize_options ( name , version , opts )
372+ def normalize_options ( name , version , add_to_sources , opts )
351373 if name . is_a? ( Symbol )
352374 raise GemfileError , %(You need to specify gem names as Strings. Use 'gem "#{ name } "' instead)
353375 end
@@ -382,7 +404,7 @@ def normalize_options(name, version, opts)
382404 end
383405
384406 # Save sources passed in a key
385- if opts . key? ( "source" )
407+ if opts . key? ( "source" ) && add_to_sources
386408 source = normalize_source ( opts [ "source" ] )
387409 opts [ "source" ] = @sources . add_rubygems_source ( "remotes" => source )
388410 end
@@ -403,8 +425,10 @@ def normalize_options(name, version, opts)
403425 else
404426 options = opts . dup
405427 end
406- source = send ( type , param , options ) { }
407- opts [ "source" ] = source
428+ if add_to_sources
429+ source = send ( type , param , options ) { }
430+ opts [ "source" ] = source
431+ end
408432 end
409433
410434 opts [ "source" ] ||= @source
0 commit comments