bundler 1.14.6 → 1.15.0.pre.1

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 (131) hide show
  1. checksums.yaml +5 -5
  2. data/.rubocop.yml +1 -1
  3. data/.rubocop_todo.yml +131 -43
  4. data/.travis.yml +5 -5
  5. data/CHANGELOG.md +52 -8
  6. data/CONTRIBUTING.md +10 -29
  7. data/README.md +13 -6
  8. data/Rakefile +4 -2
  9. data/bin/rubocop +1 -1
  10. data/doc/README.md +30 -0
  11. data/doc/TROUBLESHOOTING.md +64 -0
  12. data/doc/contributing/BUG_TRIAGE.md +36 -0
  13. data/doc/contributing/COMMUNITY.md +13 -0
  14. data/doc/contributing/GETTING_HELP.md +11 -0
  15. data/doc/contributing/HOW_YOU_CAN_HELP.md +27 -0
  16. data/doc/contributing/ISSUES.md +51 -0
  17. data/doc/contributing/README.md +38 -0
  18. data/doc/development/NEW_FEATURES.md +10 -0
  19. data/doc/development/PULL_REQUESTS.md +40 -0
  20. data/doc/development/README.md +19 -0
  21. data/doc/development/RELEASING.md +9 -0
  22. data/doc/development/SETUP.md +29 -0
  23. data/doc/documentation/README.md +29 -0
  24. data/doc/documentation/VISION.md +26 -0
  25. data/doc/documentation/WRITING.md +54 -0
  26. data/exe/bundle +4 -1
  27. data/lib/bundler.rb +20 -13
  28. data/lib/bundler/cli.rb +67 -3
  29. data/lib/bundler/cli/add.rb +26 -0
  30. data/lib/bundler/cli/config.rb +24 -6
  31. data/lib/bundler/cli/gem.rb +13 -8
  32. data/lib/bundler/cli/info.rb +51 -0
  33. data/lib/bundler/cli/inject.rb +8 -2
  34. data/lib/bundler/cli/install.rb +1 -1
  35. data/lib/bundler/cli/issue.rb +40 -0
  36. data/lib/bundler/cli/outdated.rb +16 -18
  37. data/lib/bundler/cli/pristine.rb +33 -0
  38. data/lib/bundler/cli/viz.rb +1 -1
  39. data/lib/bundler/definition.rb +64 -48
  40. data/lib/bundler/dsl.rb +6 -0
  41. data/lib/bundler/endpoint_specification.rb +3 -9
  42. data/lib/bundler/env.rb +3 -3
  43. data/lib/bundler/errors.rb +1 -1
  44. data/lib/bundler/fetcher/downloader.rb +3 -2
  45. data/lib/bundler/gem_helper.rb +5 -0
  46. data/lib/bundler/index.rb +9 -3
  47. data/lib/bundler/injector.rb +32 -11
  48. data/lib/bundler/installer.rb +1 -1
  49. data/lib/bundler/installer/parallel_installer.rb +15 -1
  50. data/lib/bundler/lazy_specification.rb +6 -0
  51. data/lib/bundler/lockfile_parser.rb +42 -34
  52. data/lib/bundler/mirror.rb +2 -0
  53. data/lib/bundler/plugin.rb +5 -1
  54. data/lib/bundler/plugin/api/source.rb +1 -1
  55. data/lib/bundler/plugin/index.rb +2 -0
  56. data/lib/bundler/remote_specification.rb +16 -7
  57. data/lib/bundler/resolver.rb +13 -3
  58. data/lib/bundler/rubygems_ext.rb +8 -3
  59. data/lib/bundler/rubygems_integration.rb +85 -36
  60. data/lib/bundler/runtime.rb +4 -1
  61. data/lib/bundler/settings.rb +2 -1
  62. data/lib/bundler/setup.rb +1 -1
  63. data/lib/bundler/shared_helpers.rb +26 -1
  64. data/lib/bundler/source.rb +17 -1
  65. data/lib/bundler/source/git.rb +16 -0
  66. data/lib/bundler/source/path.rb +13 -3
  67. data/lib/bundler/source/path/installer.rb +2 -2
  68. data/lib/bundler/source/rubygems.rb +5 -2
  69. data/lib/bundler/spec_set.rb +22 -13
  70. data/lib/bundler/stub_specification.rb +64 -2
  71. data/lib/bundler/templates/Executable +1 -1
  72. data/lib/bundler/templates/Executable.standalone +5 -5
  73. data/lib/bundler/templates/newgem/Gemfile.tt +2 -2
  74. data/lib/bundler/templates/newgem/LICENSE.txt.tt +1 -1
  75. data/lib/bundler/templates/newgem/README.md.tt +12 -6
  76. data/lib/bundler/templates/newgem/Rakefile.tt +5 -5
  77. data/lib/bundler/templates/newgem/ext/newgem/newgem.c.tt +4 -4
  78. data/lib/bundler/templates/newgem/ext/newgem/newgem.h.tt +3 -3
  79. data/lib/bundler/templates/newgem/lib/newgem.rb.tt +6 -6
  80. data/lib/bundler/templates/newgem/lib/newgem/version.rb.tt +4 -4
  81. data/lib/bundler/templates/newgem/newgem.gemspec.tt +9 -9
  82. data/lib/bundler/templates/newgem/spec/spec_helper.rb.tt +3 -0
  83. data/lib/bundler/templates/newgem/test/newgem_test.rb.tt +1 -1
  84. data/lib/bundler/templates/newgem/test/test_helper.rb.tt +3 -3
  85. data/lib/bundler/ui/shell.rb +9 -6
  86. data/lib/bundler/vendor/thor/lib/thor.rb +31 -23
  87. data/lib/bundler/vendor/thor/lib/thor/actions.rb +21 -22
  88. data/lib/bundler/vendor/thor/lib/thor/actions/create_file.rb +1 -1
  89. data/lib/bundler/vendor/thor/lib/thor/actions/create_link.rb +1 -1
  90. data/lib/bundler/vendor/thor/lib/thor/actions/directory.rb +2 -2
  91. data/lib/bundler/vendor/thor/lib/thor/actions/empty_directory.rb +8 -8
  92. data/lib/bundler/vendor/thor/lib/thor/actions/file_manipulation.rb +23 -12
  93. data/lib/bundler/vendor/thor/lib/thor/actions/inject_into_file.rb +10 -14
  94. data/lib/bundler/vendor/thor/lib/thor/base.rb +30 -30
  95. data/lib/bundler/vendor/thor/lib/thor/command.rb +9 -9
  96. data/lib/bundler/vendor/thor/lib/thor/core_ext/hash_with_indifferent_access.rb +9 -1
  97. data/lib/bundler/vendor/thor/lib/thor/core_ext/io_binary_read.rb +7 -5
  98. data/lib/bundler/vendor/thor/lib/thor/core_ext/ordered_hash.rb +94 -63
  99. data/lib/bundler/vendor/thor/lib/thor/error.rb +3 -3
  100. data/lib/bundler/vendor/thor/lib/thor/group.rb +12 -12
  101. data/lib/bundler/vendor/thor/lib/thor/invocation.rb +4 -5
  102. data/lib/bundler/vendor/thor/lib/thor/parser/argument.rb +4 -7
  103. data/lib/bundler/vendor/thor/lib/thor/parser/arguments.rb +16 -16
  104. data/lib/bundler/vendor/thor/lib/thor/parser/option.rb +40 -19
  105. data/lib/bundler/vendor/thor/lib/thor/parser/options.rb +7 -5
  106. data/lib/bundler/vendor/thor/lib/thor/runner.rb +25 -25
  107. data/lib/bundler/vendor/thor/lib/thor/shell.rb +1 -1
  108. data/lib/bundler/vendor/thor/lib/thor/shell/basic.rb +41 -26
  109. data/lib/bundler/vendor/thor/lib/thor/shell/color.rb +1 -1
  110. data/lib/bundler/vendor/thor/lib/thor/shell/html.rb +4 -4
  111. data/lib/bundler/vendor/thor/lib/thor/util.rb +8 -7
  112. data/lib/bundler/vendor/thor/lib/thor/version.rb +1 -1
  113. data/lib/bundler/version.rb +14 -1
  114. data/lib/bundler/version_ranges.rb +75 -0
  115. data/lib/bundler/worker.rb +2 -1
  116. data/man/bundle-check.ronn +26 -0
  117. data/man/bundle-clean.ronn +18 -0
  118. data/man/bundle-config.ronn +4 -1
  119. data/man/bundle-info.ronn +17 -0
  120. data/man/bundle-init.ronn +18 -0
  121. data/man/bundle-inject.ronn +22 -0
  122. data/man/bundle-open.ronn +19 -0
  123. data/man/bundle-show.ronn +20 -0
  124. data/man/bundle-update.ronn +5 -2
  125. data/man/bundle-viz.ronn +30 -0
  126. data/man/bundle.ronn +3 -0
  127. data/man/gemfile.5.ronn +24 -64
  128. data/task/release.rake +115 -0
  129. metadata +49 -5
  130. data/DEVELOPMENT.md +0 -150
  131. data/ISSUES.md +0 -117
@@ -384,6 +384,12 @@ module Bundler
384
384
 
385
385
  def validate_keys(command, opts, valid_keys)
386
386
  invalid_keys = opts.keys - valid_keys
387
+
388
+ git_source = opts.keys & @git_sources.keys.map(&:to_s)
389
+ if opts["branch"] && !(opts["git"] || opts["github"] || git_source.any?)
390
+ raise GemfileError, %(The `branch` option for `#{command}` is not allowed. Only gems with a git source can specify a branch)
391
+ end
392
+
387
393
  if invalid_keys.any?
388
394
  message = String.new
389
395
  message << "You passed #{invalid_keys.map {|k| ":" + k }.join(", ")} "
@@ -5,8 +5,8 @@ module Bundler
5
5
  ILLFORMED_MESSAGE = 'Ill-formed requirement ["#<YAML::Syck::DefaultKey'.freeze
6
6
  include MatchPlatform
7
7
 
8
- attr_reader :name, :version, :platform, :dependencies, :required_rubygems_version, :required_ruby_version, :checksum
9
- attr_accessor :source, :remote
8
+ attr_reader :name, :version, :platform, :required_rubygems_version, :required_ruby_version, :checksum
9
+ attr_accessor :source, :remote, :dependencies
10
10
 
11
11
  def initialize(name, version, platform, dependencies, metadata = nil)
12
12
  @name = name
@@ -91,13 +91,7 @@ module Bundler
91
91
  end
92
92
 
93
93
  def __swap__(spec)
94
- without_type = proc {|d| Gem::Dependency.new(d.name, d.requirements_list.sort) }
95
- if (extra_deps = spec.runtime_dependencies.map(&without_type).-(dependencies.map(&without_type))) && extra_deps.any?
96
- Bundler.ui.debug "#{full_name} from #{remote} has corrupted API dependencies (API returned #{dependencies}, real spec has (#{spec.runtime_dependencies}))"
97
- raise APIResponseMismatchError,
98
- "Downloading #{full_name} revealed dependencies not in the API (#{extra_deps.map(&:to_s).join(", ")})." \
99
- "\nInstalling with `--full-index` should fix the problem."
100
- end
94
+ SharedHelpers.ensure_same_dependencies(self, dependencies, spec.dependencies)
101
95
  @remote_specification = spec
102
96
  end
103
97
 
@@ -5,12 +5,12 @@ require "bundler/source/git/git_proxy"
5
5
  module Bundler
6
6
  class Env
7
7
  def write(io)
8
- io.write report(:print_gemfile => true, :print_gemspecs => true)
8
+ io.write report
9
9
  end
10
10
 
11
11
  def report(options = {})
12
- print_gemfile = options.delete(:print_gemfile)
13
- print_gemspecs = options.delete(:print_gemspecs)
12
+ print_gemfile = options.delete(:print_gemfile) { true }
13
+ print_gemspecs = options.delete(:print_gemspecs) { true }
14
14
 
15
15
  out = String.new("## Environment\n\n```\n")
16
16
  out << "Bundler #{Bundler::VERSION}\n"
@@ -138,7 +138,7 @@ module Bundler
138
138
  class NoSpaceOnDeviceError < PermissionError
139
139
  def message
140
140
  "There was an error while trying to #{action} `#{@path}`. " \
141
- "There was insufficent space remaining on the device."
141
+ "There was insufficient space remaining on the device."
142
142
  end
143
143
 
144
144
  status_code(31)
@@ -58,9 +58,10 @@ module Bundler
58
58
  case e.message
59
59
  when /host down:/, /getaddrinfo: nodename nor servname provided/
60
60
  raise NetworkDownError, "Could not reach host #{uri.host}. Check your network " \
61
- "connection and try again."
61
+ "connection and try again."
62
62
  else
63
- raise HTTPError, "Network error while fetching #{URICredentialsFilter.credential_filtered_uri(uri)}"
63
+ raise HTTPError, "Network error while fetching #{URICredentialsFilter.credential_filtered_uri(uri)}" \
64
+ " (#{e})"
64
65
  end
65
66
  end
66
67
 
@@ -94,6 +94,7 @@ module Bundler
94
94
  def rubygem_push(path)
95
95
  allowed_push_host = nil
96
96
  gem_command = "gem push '#{path}'"
97
+ gem_command += " --key #{gem_key}" if gem_key
97
98
  if @gemspec.respond_to?(:metadata)
98
99
  allowed_push_host = @gemspec.metadata["allowed_push_host"]
99
100
  gem_command += " --host #{allowed_push_host}" if allowed_push_host
@@ -181,6 +182,10 @@ module Bundler
181
182
  end
182
183
  end
183
184
 
185
+ def gem_key
186
+ Bundler.settings["gem.push_key"].to_s.downcase if Bundler.settings["gem.push_key"]
187
+ end
188
+
184
189
  def gem_push?
185
190
  !%w(n no nil false off 0).include?(ENV["gem_push"].to_s.downcase)
186
191
  end
@@ -58,17 +58,23 @@ module Bundler
58
58
  # Search this index's specs, and any source indexes that this index knows
59
59
  # about, returning all of the results.
60
60
  def search(query, base = nil)
61
+ sort_specs(unsorted_search(query, base))
62
+ end
63
+
64
+ def unsorted_search(query, base)
61
65
  results = local_search(query, base)
62
- seen = results.map(&:full_name).to_set
66
+
67
+ seen = results.map(&:full_name).to_set unless @sources.empty?
63
68
 
64
69
  @sources.each do |source|
65
- source.search(query, base).each do |spec|
70
+ source.unsorted_search(query, base).each do |spec|
66
71
  results << spec if seen.add?(spec.full_name)
67
72
  end
68
73
  end
69
74
 
70
- sort_specs(results)
75
+ results
71
76
  end
77
+ protected :unsorted_search
72
78
 
73
79
  def self.sort_specs(specs)
74
80
  specs.sort_by do |s|
@@ -27,17 +27,18 @@ module Bundler
27
27
  @new_deps -= builder.dependencies
28
28
 
29
29
  # add new deps to the end of the in-memory Gemfile
30
- builder.eval_gemfile("injected gems", new_gem_lines) if @new_deps.any?
30
+ # Set conservative versioining to false because we want to let the resolver resolve the version first
31
+ builder.eval_gemfile("injected gems", build_gem_lines(false)) if @new_deps.any?
31
32
 
32
33
  # resolve to see if the new deps broke anything
33
- definition = builder.to_definition(lockfile_path, {})
34
- definition.resolve_remotely!
34
+ @definition = builder.to_definition(lockfile_path, {})
35
+ @definition.resolve_remotely!
35
36
 
36
37
  # since nothing broke, we can add those gems to the gemfile
37
- append_to(gemfile_path) if @new_deps.any?
38
+ append_to(gemfile_path, build_gem_lines(@options[:conservative_versioning])) if @new_deps.any?
38
39
 
39
40
  # since we resolved successfully, write out the lockfile
40
- definition.lock(Bundler.default_lockfile)
41
+ @definition.lock(Bundler.default_lockfile)
41
42
 
42
43
  # return an array of the deps that we added
43
44
  return @new_deps
@@ -47,17 +48,37 @@ module Bundler
47
48
 
48
49
  private
49
50
 
50
- def new_gem_lines
51
+ def conservative_version(spec)
52
+ version = spec.version
53
+ return ">= 0" if version.nil?
54
+ segments = version.segments
55
+ seg_end_index = version >= Gem::Version.new("1.0") ? 1 : 2
56
+
57
+ prerelease_suffix = version.to_s.gsub(version.release.to_s, "") if version.prerelease?
58
+ "~> #{segments[0..seg_end_index].join(".")}#{prerelease_suffix}"
59
+ end
60
+
61
+ def build_gem_lines(conservative_versioning)
51
62
  @new_deps.map do |d|
52
- name = "'#{d.name}'"
53
- requirement = ", '#{d.requirement}'"
54
- group = ", :group => #{d.groups.inspect}" if d.groups != Array(:default)
55
- source = ", :source => '#{d.source}'" unless d.source.nil?
63
+ name = d.name.dump
64
+
65
+ requirement = if conservative_versioning
66
+ ", \"#{conservative_version(@definition.specs[d.name][0])}\""
67
+ else
68
+ ", #{d.requirement.as_list.map(&:dump).join(", ")}"
69
+ end
70
+
71
+ if d.groups != Array(:default)
72
+ group = d.groups.size == 1 ? ", :group => #{d.groups.inspect}" : ", :groups => #{d.groups.inspect}"
73
+ end
74
+
75
+ source = ", :source => \"#{d.source}\"" unless d.source.nil?
76
+
56
77
  %(gem #{name}#{requirement}#{group}#{source})
57
78
  end.join("\n")
58
79
  end
59
80
 
60
- def append_to(gemfile_path)
81
+ def append_to(gemfile_path, new_gem_lines)
61
82
  gemfile_path.open("a") do |f|
62
83
  f.puts
63
84
  if @options["timestamp"] || @options["timestamp"].nil?
@@ -49,7 +49,7 @@ module Bundler
49
49
  # Bundler returns a warning message stating so and this method returns.
50
50
  #
51
51
  # Fourthly, Bundler checks if the default lockfile (Gemfile.lock) exists, and if so
52
- # then proceeds to set up a defintion based on the default gemfile (Gemfile) and the
52
+ # then proceeds to set up a definition based on the default gemfile (Gemfile) and the
53
53
  # default lock file (Gemfile.lock). However, this is not the case if the platform is different
54
54
  # to that which is specified in Gemfile.lock, or if there are any missing specs for the gems.
55
55
  #
@@ -90,6 +90,7 @@ module Bundler
90
90
  @standalone = standalone
91
91
  @force = force
92
92
  @specs = all_specs.map {|s| SpecInstallation.new(s) }
93
+ @spec_set = all_specs
93
94
  end
94
95
 
95
96
  def call
@@ -116,7 +117,7 @@ module Bundler
116
117
  spec_install.post_install_message = message
117
118
  elsif !success
118
119
  spec_install.state = :failed
119
- spec_install.error = message
120
+ spec_install.error = "#{message}\n\n#{require_tree_for_spec(spec_install.spec)}"
120
121
  end
121
122
  spec_install
122
123
  }
@@ -166,6 +167,19 @@ module Bundler
166
167
  Bundler.ui.warn(warning.join("\n"))
167
168
  end
168
169
 
170
+ def require_tree_for_spec(spec)
171
+ tree = @spec_set.what_required(spec)
172
+ t = String.new("In #{File.basename(SharedHelpers.default_gemfile)}:\n")
173
+ tree.each_with_index do |s, depth|
174
+ t << " " * depth.succ << s.name
175
+ unless tree.last == s
176
+ t << %( was resolved to #{s.version}, which depends on)
177
+ end
178
+ t << %(\n)
179
+ end
180
+ t
181
+ end
182
+
169
183
  # Keys in the remains hash represent uninstalled gems specs.
170
184
  # We enqueue all gem specs that do not have any dependencies.
171
185
  # Later we call this lambda again to install specs that depended on
@@ -79,6 +79,7 @@ module Bundler
79
79
  "To use the platform-specific version of the gem, run `bundle config specific_platform true` and install again."
80
80
  search = source.specs.search(self).last
81
81
  end
82
+ search.dependencies = dependencies if search.is_a?(RemoteSpecification) || search.is_a?(EndpointSpecification)
82
83
  search
83
84
  end
84
85
  end
@@ -99,6 +100,11 @@ module Bundler
99
100
  @__identifier ||= Identifier.new(name, version, source, platform, dependencies)
100
101
  end
101
102
 
103
+ def git_version
104
+ return unless source.is_a?(Bundler::Source::Git)
105
+ " #{source.revision[0..6]}"
106
+ end
107
+
102
108
  private
103
109
 
104
110
  def to_ary
@@ -61,7 +61,7 @@ module Bundler
61
61
  def initialize(lockfile)
62
62
  @platforms = []
63
63
  @sources = []
64
- @dependencies = []
64
+ @dependencies = {}
65
65
  @state = nil
66
66
  @specs = {}
67
67
 
@@ -171,43 +171,53 @@ module Bundler
171
171
  end
172
172
  end
173
173
 
174
- NAME_VERSION = '(?! )(.*?)(?: \(([^-]*)(?:-(.*))?\))?'.freeze
175
- NAME_VERSION_2 = /^ {2}#{NAME_VERSION}(!)?$/
176
- NAME_VERSION_4 = /^ {4}#{NAME_VERSION}$/
177
- NAME_VERSION_6 = /^ {6}#{NAME_VERSION}$/
174
+ space = / /
175
+ NAME_VERSION = /
176
+ ^(#{space}{2}|#{space}{4}|#{space}{6})(?!#{space}) # Exactly 2, 4, or 6 spaces at the start of the line
177
+ (.*?) # Name
178
+ (?:#{space}\(([^-]*) # Space, followed by version
179
+ (?:-(.*))?\))? # Optional platform
180
+ (!)? # Optional pinned marker
181
+ $ # Line end
182
+ /xo
178
183
 
179
184
  def parse_dependency(line)
180
- if line =~ NAME_VERSION_2
181
- name = $1
182
- version = $2
183
- pinned = $4
184
- version = version.split(",").map(&:strip) if version
185
-
186
- dep = Bundler::Dependency.new(name, version)
187
-
188
- if pinned && dep.name != "bundler"
189
- spec = @specs.find {|_, v| v.name == dep.name }
190
- dep.source = spec.last.source if spec
191
-
192
- # Path sources need to know what the default name / version
193
- # to use in the case that there are no gemspecs present. A fake
194
- # gemspec is created based on the version set on the dependency
195
- # TODO: Use the version from the spec instead of from the dependency
196
- if version && version.size == 1 && version.first =~ /^\s*= (.+)\s*$/ && dep.source.is_a?(Bundler::Source::Path)
197
- dep.source.name = name
198
- dep.source.version = $1
199
- end
185
+ return unless line =~ NAME_VERSION
186
+ spaces = $1
187
+ return unless spaces.size == 2
188
+ name = $2
189
+ version = $3
190
+ pinned = $5
191
+
192
+ version = version.split(",").map(&:strip) if version
193
+
194
+ dep = Bundler::Dependency.new(name, version)
195
+
196
+ if pinned && dep.name != "bundler"
197
+ spec = @specs.find {|_, v| v.name == dep.name }
198
+ dep.source = spec.last.source if spec
199
+
200
+ # Path sources need to know what the default name / version
201
+ # to use in the case that there are no gemspecs present. A fake
202
+ # gemspec is created based on the version set on the dependency
203
+ # TODO: Use the version from the spec instead of from the dependency
204
+ if version && version.size == 1 && version.first =~ /^\s*= (.+)\s*$/ && dep.source.is_a?(Bundler::Source::Path)
205
+ dep.source.name = name
206
+ dep.source.version = $1
200
207
  end
201
-
202
- @dependencies << dep
203
208
  end
209
+
210
+ @dependencies[dep.name] = dep
204
211
  end
205
212
 
206
213
  def parse_spec(line)
207
- if line =~ NAME_VERSION_4
208
- name = $1
209
- version = $2
210
- platform = $3
214
+ return unless line =~ NAME_VERSION
215
+ spaces = $1
216
+ name = $2
217
+ version = $3
218
+ platform = $4
219
+
220
+ if spaces.size == 4
211
221
  version = Gem::Version.new(version)
212
222
  platform = platform ? Gem::Platform.new(platform) : Gem::Platform::RUBY
213
223
  @current_spec = LazySpecification.new(name, version, platform)
@@ -216,9 +226,7 @@ module Bundler
216
226
  # Avoid introducing multiple copies of the same spec (caused by
217
227
  # duplicate GIT sections)
218
228
  @specs[@current_spec.identifier] ||= @current_spec
219
- elsif line =~ NAME_VERSION_6
220
- name = $1
221
- version = $2
229
+ elsif spaces.size == 6
222
230
  version = version.split(",").map(&:strip) if version
223
231
  dep = Gem::Dependency.new(name, version)
224
232
  @current_spec.dependencies << dep
@@ -1,4 +1,6 @@
1
1
  # frozen_string_literal: true
2
+ require "socket"
3
+
2
4
  module Bundler
3
5
  class Settings
4
6
  # Class used to build the mirror set and then find a mirror for a given URI
@@ -37,7 +37,11 @@ module Bundler
37
37
 
38
38
  save_plugins names, specs
39
39
  rescue PluginError => e
40
- specs.values.map {|spec| Bundler.rm_rf(spec.full_gem_path) } if specs
40
+ if specs
41
+ specs_to_delete = Hash[specs.select {|k, _v| names.include?(k) && !index.commands.values.include?(k) }]
42
+ specs_to_delete.values.each {|spec| Bundler.rm_rf(spec.full_gem_path) }
43
+ end
44
+
41
45
  Bundler.ui.error "Failed to install plugin #{name}: #{e.message}\n #{e.backtrace.join("\n ")}"
42
46
  end
43
47
 
@@ -6,7 +6,7 @@ module Bundler
6
6
  module Plugin
7
7
  class API
8
8
  # This class provides the base to build source plugins
9
- # All the method here are require to build a source plugin (except
9
+ # All the method here are required to build a source plugin (except
10
10
  # `uri_hash`, `gem_install_dir`; they are helpers).
11
11
  #
12
12
  # Defaults for methods, where ever possible are provided which is
@@ -20,6 +20,8 @@ module Bundler
20
20
  end
21
21
  end
22
22
 
23
+ attr_reader :commands
24
+
23
25
  def initialize
24
26
  @plugin_paths = {}
25
27
  @commands = {}
@@ -11,6 +11,7 @@ module Bundler
11
11
  include Comparable
12
12
 
13
13
  attr_reader :name, :version, :platform
14
+ attr_writer :dependencies
14
15
  attr_accessor :source, :remote
15
16
 
16
17
  def initialize(name, version, platform, spec_fetcher)
@@ -18,6 +19,7 @@ module Bundler
18
19
  @version = Gem::Version.create version
19
20
  @platform = platform
20
21
  @spec_fetcher = spec_fetcher
22
+ @dependencies = nil
21
23
  end
22
24
 
23
25
  # Needed before installs, since the arch matters then and quick
@@ -49,13 +51,7 @@ module Bundler
49
51
  # once the remote gem is downloaded, the backend specification will
50
52
  # be swapped out.
51
53
  def __swap__(spec)
52
- without_type = proc {|d| Gem::Dependency.new(d.name, d.requirements_list) }
53
- if (extra_deps = spec.runtime_dependencies.map(&without_type).-(dependencies.map(&without_type))) && extra_deps.any?
54
- Bundler.ui.debug "#{full_name} from #{remote} has corrupted API dependencies (API returned #{dependencies}, real spec has (#{spec.runtime_dependencies}))"
55
- raise APIResponseMismatchError,
56
- "Downloading #{full_name} revealed dependencies not in the API (#{extra_deps.map(&without_type).map(&:to_s).join(", ")})." \
57
- "\nInstalling with `--full-index` should fix the problem."
58
- end
54
+ SharedHelpers.ensure_same_dependencies(self, dependencies, spec.dependencies)
59
55
  @_remote_specification = spec
60
56
  end
61
57
 
@@ -76,8 +72,21 @@ module Bundler
76
72
  "#<#{self.class} name=#{name} version=#{version} platform=#{platform}>"
77
73
  end
78
74
 
75
+ def dependencies
76
+ @dependencies || method_missing(:dependencies)
77
+ end
78
+
79
+ def git_version
80
+ return unless loaded_from && source.is_a?(Bundler::Source::Git)
81
+ " #{source.revision[0..6]}"
82
+ end
83
+
79
84
  private
80
85
 
86
+ def to_ary
87
+ nil
88
+ end
89
+
81
90
  def _remote_specification
82
91
  @_remote_specification ||= @spec_fetcher.fetch_spec([@name, @version, @platform])
83
92
  @_remote_specification || raise(GemspecError, "Gemspec data for #{full_name} was" \