bundler 1.13.0.rc.1 → 1.13.0.rc.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 (90) hide show
  1. checksums.yaml +4 -4
  2. data/.codeclimate.yml +1 -0
  3. data/.rubocop.yml +8 -0
  4. data/.rubocop_todo.yml +21 -21
  5. data/.travis.yml +5 -1
  6. data/CHANGELOG.md +33 -1
  7. data/DEVELOPMENT.md +1 -1
  8. data/Rakefile +21 -12
  9. data/bin/rake +1 -1
  10. data/bin/rspec +1 -1
  11. data/bin/rubocop +2 -2
  12. data/bundler.gemspec +2 -2
  13. data/exe/bundler +1 -19
  14. data/lib/bundler.rb +43 -34
  15. data/lib/bundler/cli.rb +54 -5
  16. data/lib/bundler/cli/binstubs.rb +3 -2
  17. data/lib/bundler/cli/console.rb +3 -0
  18. data/lib/bundler/cli/doctor.rb +95 -0
  19. data/lib/bundler/cli/exec.rb +18 -2
  20. data/lib/bundler/cli/gem.rb +1 -1
  21. data/lib/bundler/cli/inject.rb +25 -7
  22. data/lib/bundler/cli/install.rb +23 -2
  23. data/lib/bundler/cli/lock.rb +14 -2
  24. data/lib/bundler/cli/update.rb +9 -0
  25. data/lib/bundler/definition.rb +86 -17
  26. data/lib/bundler/deployment.rb +6 -0
  27. data/lib/bundler/dsl.rb +67 -22
  28. data/lib/bundler/env.rb +1 -1
  29. data/lib/bundler/environment_preserver.rb +1 -1
  30. data/lib/bundler/errors.rb +11 -1
  31. data/lib/bundler/fetcher.rb +3 -2
  32. data/lib/bundler/fetcher/base.rb +10 -0
  33. data/lib/bundler/fetcher/compact_index.rb +27 -9
  34. data/lib/bundler/fetcher/dependency.rb +1 -12
  35. data/lib/bundler/fetcher/downloader.rb +1 -1
  36. data/lib/bundler/friendly_errors.rb +4 -2
  37. data/lib/bundler/gem_helper.rb +2 -2
  38. data/lib/bundler/gem_version_promoter.rb +175 -0
  39. data/lib/bundler/graph.rb +4 -25
  40. data/lib/bundler/index.rb +9 -1
  41. data/lib/bundler/injector.rb +12 -5
  42. data/lib/bundler/inline.rb +2 -2
  43. data/lib/bundler/installer.rb +23 -8
  44. data/lib/bundler/installer/gem_installer.rb +13 -15
  45. data/lib/bundler/installer/parallel_installer.rb +121 -99
  46. data/lib/bundler/lazy_specification.rb +8 -2
  47. data/lib/bundler/lockfile_parser.rb +20 -12
  48. data/lib/bundler/mirror.rb +2 -2
  49. data/lib/bundler/plugin.rb +153 -31
  50. data/lib/bundler/plugin/api.rb +29 -5
  51. data/lib/bundler/plugin/api/source.rb +293 -0
  52. data/lib/bundler/plugin/dsl.rb +25 -1
  53. data/lib/bundler/plugin/index.rb +80 -13
  54. data/lib/bundler/plugin/installer.rb +6 -10
  55. data/lib/bundler/plugin/source_list.rb +4 -0
  56. data/lib/bundler/postit_trampoline.rb +57 -40
  57. data/lib/bundler/resolver.rb +24 -12
  58. data/lib/bundler/retry.rb +2 -1
  59. data/lib/bundler/ruby_version.rb +4 -2
  60. data/lib/bundler/rubygems_ext.rb +10 -3
  61. data/lib/bundler/rubygems_gem_installer.rb +6 -0
  62. data/lib/bundler/rubygems_integration.rb +101 -66
  63. data/lib/bundler/runtime.rb +25 -2
  64. data/lib/bundler/settings.rb +30 -11
  65. data/lib/bundler/setup.rb +6 -3
  66. data/lib/bundler/shared_helpers.rb +11 -5
  67. data/lib/bundler/source/gemspec.rb +4 -0
  68. data/lib/bundler/source/git.rb +9 -6
  69. data/lib/bundler/source/git/git_proxy.rb +27 -3
  70. data/lib/bundler/source/path.rb +4 -26
  71. data/lib/bundler/source/path/installer.rb +39 -11
  72. data/lib/bundler/source/rubygems.rb +1 -1
  73. data/lib/bundler/source_list.rb +28 -8
  74. data/lib/bundler/spec_set.rb +1 -1
  75. data/lib/bundler/templates/Executable.standalone +4 -2
  76. data/lib/bundler/templates/Gemfile +0 -1
  77. data/lib/bundler/ui/shell.rb +11 -3
  78. data/lib/bundler/ui/silent.rb +1 -3
  79. data/lib/bundler/vendor/compact_index_client/lib/compact_index_client.rb +1 -2
  80. data/lib/bundler/vendor/compact_index_client/lib/compact_index_client/cache.rb +16 -2
  81. data/lib/bundler/version.rb +1 -1
  82. data/lib/bundler/yaml_serializer.rb +34 -11
  83. data/man/bundle-binstubs.ronn +29 -0
  84. data/man/bundle-config.ronn +32 -0
  85. data/man/bundle-install.ronn +6 -41
  86. data/man/bundle-package.ronn +1 -1
  87. data/man/bundle.ronn +4 -3
  88. data/man/gemfile.5.ronn +1 -1
  89. metadata +13 -9
  90. data/lib/bundler/environment.rb +0 -42
@@ -60,8 +60,8 @@ def gemfile(install = false, options = {}, &gemfile)
60
60
 
61
61
  Bundler.ui = ui if install
62
62
  if install || missing_specs.call
63
- Bundler::Installer.install(Bundler.root, definition, :system => true)
64
- Bundler::Installer.post_install_messages.each do |name, message|
63
+ installer = Bundler::Installer.install(Bundler.root, definition, :system => true)
64
+ installer.post_install_messages.each do |name, message|
65
65
  Bundler.ui.info "Post-install message from #{name}:\n#{message}"
66
66
  end
67
67
  end
@@ -7,22 +7,30 @@ require "bundler/installer/standalone"
7
7
  require "bundler/installer/gem_installer"
8
8
 
9
9
  module Bundler
10
- class Installer < Environment
10
+ class Installer
11
11
  class << self
12
- attr_accessor :post_install_messages, :ambiguous_gems
12
+ attr_accessor :ambiguous_gems
13
13
 
14
- Installer.post_install_messages = {}
15
14
  Installer.ambiguous_gems = []
16
15
  end
17
16
 
17
+ attr_reader :post_install_messages
18
+
18
19
  # Begins the installation process for Bundler.
19
20
  # For more information see the #run method on this class.
20
21
  def self.install(root, definition, options = {})
21
22
  installer = new(root, definition)
23
+ Plugin.hook("before-install-all", definition.dependencies)
22
24
  installer.run(options)
23
25
  installer
24
26
  end
25
27
 
28
+ def initialize(root, definition)
29
+ @root = root
30
+ @definition = definition
31
+ @post_install_messages = {}
32
+ end
33
+
26
34
  # Runs the install procedures for a specific Gemfile.
27
35
  #
28
36
  # Firstly, this method will check to see if Bundler.bundle_path exists
@@ -61,7 +69,7 @@ module Bundler
61
69
  @definition.ensure_equivalent_gemfile_and_lockfile(options[:deployment])
62
70
  end
63
71
 
64
- if dependencies.empty?
72
+ if @definition.dependencies.empty?
65
73
  Bundler.ui.warn "The Gemfile specifies no dependencies"
66
74
  lock
67
75
  return
@@ -108,7 +116,7 @@ module Bundler
108
116
  next
109
117
  end
110
118
 
111
- File.open(binstub_path, "w", 0777 & ~File.umask) do |f|
119
+ File.open(binstub_path, "w", 0o777 & ~File.umask) do |f|
112
120
  f.puts ERB.new(template, nil, "-").result(binding)
113
121
  end
114
122
  end
@@ -138,7 +146,7 @@ module Bundler
138
146
  spec.executables.each do |executable|
139
147
  next if executable == "bundle"
140
148
  executable_path = executable_path = Pathname(spec.full_gem_path).join(spec.bindir, executable).relative_path_from(bin_path)
141
- File.open "#{bin_path}/#{executable}", "w", 0755 do |f|
149
+ File.open "#{bin_path}/#{executable}", "w", 0o755 do |f|
142
150
  f.puts ERB.new(template, nil, "-").result(binding)
143
151
  end
144
152
  end
@@ -160,7 +168,7 @@ module Bundler
160
168
  def ensure_specs_are_compatible!
161
169
  system_ruby = Bundler::RubyVersion.system
162
170
  rubygems_version = Gem::Version.create(Gem::VERSION)
163
- specs.each do |spec|
171
+ @definition.specs.each do |spec|
164
172
  if required_ruby_version = spec.required_ruby_version
165
173
  unless required_ruby_version.satisfied_by?(system_ruby.gem_version)
166
174
  raise InstallError, "#{spec.full_name} requires ruby version #{required_ruby_version}, " \
@@ -187,7 +195,10 @@ module Bundler
187
195
  end
188
196
 
189
197
  def install_in_parallel(size, standalone, force = false)
190
- ParallelInstaller.call(self, specs, size, standalone, force)
198
+ spec_installations = ParallelInstaller.call(self, @definition.specs, size, standalone, force)
199
+ spec_installations.each do |installation|
200
+ post_install_messages[installation.name] = installation.post_install_message if installation.has_post_install_message?
201
+ end
191
202
  end
192
203
 
193
204
  def create_bundle_path
@@ -213,5 +224,9 @@ module Bundler
213
224
  return if local
214
225
  options["local"] ? @definition.resolve_with_cache! : @definition.resolve_remotely!
215
226
  end
227
+
228
+ def lock(opts = {})
229
+ @definition.lock(Bundler.default_lockfile, opts[:preserve_unknown_sections])
230
+ end
216
231
  end
217
232
  end
@@ -15,16 +15,24 @@ module Bundler
15
15
  post_install_message = spec_settings ? install_with_settings : install
16
16
  Bundler.ui.debug "#{worker}: #{spec.name} (#{spec.version}) from #{spec.loaded_from}"
17
17
  generate_executable_stubs
18
- post_install_message
19
-
18
+ return true, post_install_message
19
+ rescue Bundler::InstallHookError, Bundler::SecurityError
20
+ raise
20
21
  rescue Errno::ENOSPC
21
- raise Bundler::InstallError, out_of_space_message
22
+ return false, out_of_space_message
22
23
  rescue => e
23
- handle_exception(e)
24
+ return false, specific_failure_message(e)
24
25
  end
25
26
 
26
27
  private
27
28
 
29
+ def specific_failure_message(e)
30
+ message = "#{e.class}: #{e.message}\n"
31
+ message += " " + e.backtrace.join("\n ") + "\n\n" if Bundler.ui.debug?
32
+ message = message.lines.first + Bundler.ui.add_color(message.lines.drop(1).join, :clear)
33
+ message + Bundler.ui.add_color(failure_message, :red)
34
+ end
35
+
28
36
  def failure_message
29
37
  return install_error_message if spec.source.options["git"]
30
38
  "#{install_error_message}\n#{gem_install_message}"
@@ -38,16 +46,6 @@ module Bundler
38
46
  "Make sure that `gem install #{spec.name} -v '#{spec.version}'` succeeds before bundling."
39
47
  end
40
48
 
41
- def handle_exception(e)
42
- # Die if install hook failed or gem signature is bad.
43
- raise e if e.is_a?(Bundler::InstallHookError) || e.is_a?(Bundler::SecurityError)
44
- # other failure, likely a native extension build failure
45
- Bundler.ui.info ""
46
- Bundler.ui.warn "#{e.class}: #{e.message}"
47
- Bundler.ui.debug e.backtrace.join("\n")
48
- raise Bundler::InstallError, failure_message
49
- end
50
-
51
49
  def spec_settings
52
50
  # Fetch the build settings, if there are any
53
51
  Bundler.settings["build.#{spec.name}"]
@@ -63,7 +61,7 @@ module Bundler
63
61
  end
64
62
 
65
63
  def out_of_space_message
66
- "Your disk is out of space. Free some space to be able to install your bundle."
64
+ "#{install_error_message}\nYour disk is out of space. Free some space to be able to install your bundle."
67
65
  end
68
66
 
69
67
  def generate_executable_stubs
@@ -2,124 +2,146 @@
2
2
  require "bundler/worker"
3
3
  require "bundler/installer/gem_installer"
4
4
 
5
- class ParallelInstaller
6
- class SpecInstallation
7
- attr_accessor :spec, :name, :post_install_message, :state
8
- def initialize(spec)
9
- @spec = spec
10
- @name = spec.name
11
- @state = :none
12
- @post_install_message = ""
13
- end
5
+ module Bundler
6
+ class ParallelInstaller
7
+ class SpecInstallation
8
+ attr_accessor :spec, :name, :post_install_message, :state, :error
9
+ def initialize(spec)
10
+ @spec = spec
11
+ @name = spec.name
12
+ @state = :none
13
+ @post_install_message = ""
14
+ @error = nil
15
+ end
14
16
 
15
- def installed?
16
- state == :installed
17
- end
17
+ def installed?
18
+ state == :installed
19
+ end
18
20
 
19
- def enqueued?
20
- state == :enqueued
21
- end
21
+ def enqueued?
22
+ state == :enqueued
23
+ end
22
24
 
23
- # Only true when spec in neither installed nor already enqueued
24
- def ready_to_enqueue?
25
- !installed? && !enqueued?
26
- end
25
+ def failed?
26
+ state == :failed
27
+ end
27
28
 
28
- def has_post_install_message?
29
- !post_install_message.empty?
30
- end
29
+ def installation_attempted?
30
+ installed? || failed?
31
+ end
31
32
 
32
- def ignorable_dependency?(dep)
33
- dep.type == :development || dep.name == @name
34
- end
33
+ # Only true when spec in neither installed nor already enqueued
34
+ def ready_to_enqueue?
35
+ !enqueued? && !installation_attempted?
36
+ end
35
37
 
36
- # Checks installed dependencies against spec's dependencies to make
37
- # sure needed dependencies have been installed.
38
- def dependencies_installed?(all_specs)
39
- installed_specs = all_specs.select(&:installed?).map(&:name)
40
- dependencies(all_specs.map(&:name)).all? {|d| installed_specs.include? d.name }
41
- end
38
+ def has_post_install_message?
39
+ !post_install_message.empty?
40
+ end
42
41
 
43
- # Represents only the non-development dependencies, the ones that are
44
- # itself and are in the total list.
45
- def dependencies(all_spec_names)
46
- @dependencies ||= begin
47
- deps = all_dependencies.reject {|dep| ignorable_dependency? dep }
48
- missing = deps.reject {|dep| all_spec_names.include? dep.name }
49
- unless missing.empty?
50
- raise Bundler::LockfileError, "Your Gemfile.lock is corrupt. The following #{missing.size > 1 ? "gems are" : "gem is"} missing " \
51
- "from the DEPENDENCIES section: '#{missing.map(&:name).join('\' \'')}'"
42
+ def ignorable_dependency?(dep)
43
+ dep.type == :development || dep.name == @name
44
+ end
45
+
46
+ # Checks installed dependencies against spec's dependencies to make
47
+ # sure needed dependencies have been installed.
48
+ def dependencies_installed?(all_specs)
49
+ installed_specs = all_specs.select(&:installed?).map(&:name)
50
+ dependencies(all_specs.map(&:name)).all? {|d| installed_specs.include? d.name }
51
+ end
52
+
53
+ # Represents only the non-development dependencies, the ones that are
54
+ # itself and are in the total list.
55
+ def dependencies(all_spec_names)
56
+ @dependencies ||= begin
57
+ deps = all_dependencies.reject {|dep| ignorable_dependency? dep }
58
+ missing = deps.reject {|dep| all_spec_names.include? dep.name }
59
+ unless missing.empty?
60
+ raise Bundler::LockfileError, "Your Gemfile.lock is corrupt. The following #{missing.size > 1 ? "gems are" : "gem is"} missing " \
61
+ "from the DEPENDENCIES section: '#{missing.map(&:name).join('\' \'')}'"
62
+ end
63
+ deps
52
64
  end
53
- deps
54
65
  end
55
- end
56
66
 
57
- # Represents all dependencies
58
- def all_dependencies
59
- @spec.dependencies
67
+ # Represents all dependencies
68
+ def all_dependencies
69
+ @spec.dependencies
70
+ end
60
71
  end
61
- end
62
72
 
63
- def self.call(*args)
64
- new(*args).call
65
- end
73
+ def self.call(*args)
74
+ new(*args).call
75
+ end
66
76
 
67
- # Returns max number of threads machine can handle with a min of 1
68
- def self.max_threads
69
- [Bundler.settings[:jobs].to_i - 1, 1].max
70
- end
77
+ # Returns max number of threads machine can handle with a min of 1
78
+ def self.max_threads
79
+ [Bundler.settings[:jobs].to_i - 1, 1].max
80
+ end
71
81
 
72
- def initialize(installer, all_specs, size, standalone, force)
73
- @installer = installer
74
- @size = size
75
- @standalone = standalone
76
- @force = force
77
- @specs = all_specs.map {|s| SpecInstallation.new(s) }
78
- end
82
+ def initialize(installer, all_specs, size, standalone, force)
83
+ @installer = installer
84
+ @size = size
85
+ @standalone = standalone
86
+ @force = force
87
+ @specs = all_specs.map {|s| SpecInstallation.new(s) }
88
+ end
79
89
 
80
- def call
81
- enqueue_specs
82
- process_specs until @specs.all?(&:installed?)
83
- ensure
84
- worker_pool && worker_pool.stop
85
- end
90
+ def call
91
+ enqueue_specs
92
+ process_specs until @specs.all?(&:installed?) || @specs.any?(&:failed?)
93
+ handle_error if @specs.any?(&:failed?)
94
+ @specs
95
+ ensure
96
+ worker_pool && worker_pool.stop
97
+ end
86
98
 
87
- def worker_pool
88
- @worker_pool ||= Bundler::Worker.new @size, "Parallel Installer", lambda { |spec_install, worker_num|
89
- message = Bundler::GemInstaller.new(
90
- spec_install.spec, @installer, @standalone, worker_num, @force
91
- ).install_from_spec
92
- spec_install.post_install_message = message unless message.nil?
93
- spec_install
94
- }
95
- end
99
+ def worker_pool
100
+ @worker_pool ||= Bundler::Worker.new @size, "Parallel Installer", lambda { |spec_install, worker_num|
101
+ gem_installer = Bundler::GemInstaller.new(
102
+ spec_install.spec, @installer, @standalone, worker_num, @force
103
+ )
104
+ success, message = gem_installer.install_from_spec
105
+ if success && !message.nil?
106
+ spec_install.post_install_message = message
107
+ elsif !success
108
+ spec_install.state = :failed
109
+ spec_install.error = message
110
+ end
111
+ spec_install
112
+ }
113
+ end
96
114
 
97
- # Dequeue a spec and save its post-install message and then enqueue the
98
- # remaining specs.
99
- # Some specs might've had to wait til this spec was installed to be
100
- # processed so the call to `enqueue_specs` is important after every
101
- # dequeue.
102
- def process_specs
103
- spec = worker_pool.deq
104
- spec.state = :installed
105
- collect_post_install_message spec if spec.has_post_install_message?
106
- enqueue_specs
107
- end
115
+ # Dequeue a spec and save its post-install message and then enqueue the
116
+ # remaining specs.
117
+ # Some specs might've had to wait til this spec was installed to be
118
+ # processed so the call to `enqueue_specs` is important after every
119
+ # dequeue.
120
+ def process_specs
121
+ spec = worker_pool.deq
122
+ spec.state = :installed unless spec.failed?
123
+ enqueue_specs
124
+ end
108
125
 
109
- def collect_post_install_message(spec)
110
- Bundler::Installer.post_install_messages[spec.name] = spec.post_install_message
111
- end
126
+ def handle_error
127
+ errors = @specs.select(&:failed?).map(&:error)
128
+ if exception = errors.find {|e| e.is_a?(Bundler::BundlerError) }
129
+ raise exception
130
+ end
131
+ raise Bundler::InstallError, errors.map(&:to_s).join("\n\n")
132
+ end
112
133
 
113
- # Keys in the remains hash represent uninstalled gems specs.
114
- # We enqueue all gem specs that do not have any dependencies.
115
- # Later we call this lambda again to install specs that depended on
116
- # previously installed specifications. We continue until all specs
117
- # are installed.
118
- def enqueue_specs
119
- @specs.select(&:ready_to_enqueue?).each do |spec|
120
- if spec.dependencies_installed? @specs
121
- worker_pool.enq spec
122
- spec.state = :enqueued
134
+ # Keys in the remains hash represent uninstalled gems specs.
135
+ # We enqueue all gem specs that do not have any dependencies.
136
+ # Later we call this lambda again to install specs that depended on
137
+ # previously installed specifications. We continue until all specs
138
+ # are installed.
139
+ def enqueue_specs
140
+ @specs.select(&:ready_to_enqueue?).each do |spec|
141
+ if spec.dependencies_installed? @specs
142
+ spec.state = :enqueued
143
+ worker_pool.enq spec
144
+ end
123
145
  end
124
146
  end
125
147
  end
@@ -5,6 +5,8 @@ require "bundler/match_platform"
5
5
 
6
6
  module Bundler
7
7
  class LazySpecification
8
+ Identifier = Struct.new(:name, :version, :source, :platform, :dependencies)
9
+
8
10
  include MatchPlatform
9
11
 
10
12
  attr_reader :name, :version, :dependencies, :platform
@@ -61,11 +63,15 @@ module Bundler
61
63
  end
62
64
 
63
65
  def to_s
64
- @__to_s ||= "#{name} (#{version})"
66
+ @__to_s ||= if platform == Gem::Platform::RUBY || platform.nil?
67
+ "#{name} (#{version})"
68
+ else
69
+ "#{name} (#{version}-#{platform})"
70
+ end
65
71
  end
66
72
 
67
73
  def identifier
68
- @__identifier ||= [name, version, source, platform, dependencies].hash
74
+ @__identifier ||= Identifier.new(name, version, source, platform, dependencies)
69
75
  end
70
76
 
71
77
  private
@@ -22,9 +22,10 @@ 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
31
  # The strings have to be dup'ed for old RG on Ruby 2.3+
@@ -32,6 +33,7 @@ module Bundler
32
33
  Gem::Version.create("1.0".dup) => [DEPENDENCIES, PLATFORMS, GIT, GEM, PATH].freeze,
33
34
  Gem::Version.create("1.10".dup) => [BUNDLED].freeze,
34
35
  Gem::Version.create("1.12".dup) => [RUBY].freeze,
36
+ Gem::Version.create("1.13".dup) => [PLUGIN].freeze,
35
37
  }.freeze
36
38
 
37
39
  KNOWN_SECTIONS = SECTIONS_BY_VERSION_INTRODUCED.values.flatten.freeze
@@ -107,8 +109,8 @@ module Bundler
107
109
  raise LockfileError, "You must use Bundler #{bundler_version.segments.first} or greater with this lockfile."
108
110
  when 0
109
111
  if current_version < bundler_version
110
- Bundler.ui.warn "Warning: the running version of Bundler is older " \
111
- "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 " \
112
114
  "upgrade to the latest version of Bundler by running `gem " \
113
115
  "install bundler#{prerelease_text}`.\n"
114
116
  end
@@ -118,17 +120,14 @@ module Bundler
118
120
  private
119
121
 
120
122
  TYPES = {
121
- GIT => Bundler::Source::Git,
122
- GEM => Bundler::Source::Rubygems,
123
- PATH => Bundler::Source::Path,
123
+ GIT => Bundler::Source::Git,
124
+ GEM => Bundler::Source::Rubygems,
125
+ PATH => Bundler::Source::Path,
126
+ PLUGIN => Bundler::Plugin,
124
127
  }.freeze
125
128
 
126
129
  def parse_source(line)
127
130
  case line
128
- when GIT, GEM, PATH
129
- @current_source = nil
130
- @opts = {}
131
- @type = line
132
131
  when SPECS
133
132
  case @type
134
133
  when PATH
@@ -147,6 +146,9 @@ module Bundler
147
146
  @rubygems_aggregate.add_remote(url)
148
147
  end
149
148
  @current_source = @rubygems_aggregate
149
+ when PLUGIN
150
+ @current_source = Plugin.source_from_lock(@opts)
151
+ @sources << @current_source
150
152
  end
151
153
  when OPTIONS
152
154
  value = $2
@@ -161,6 +163,10 @@ module Bundler
161
163
  else
162
164
  @opts[key] = value
163
165
  end
166
+ when *SOURCE
167
+ @current_source = nil
168
+ @opts = {}
169
+ @type = line
164
170
  else
165
171
  parse_spec(line)
166
172
  end
@@ -201,8 +207,10 @@ module Bundler
201
207
  def parse_spec(line)
202
208
  if line =~ NAME_VERSION_4
203
209
  name = $1
204
- version = Gem::Version.new($2)
205
- 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
206
214
  @current_spec = LazySpecification.new(name, version, platform)
207
215
  @current_spec.source = @current_source
208
216