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
@@ -23,7 +23,7 @@ module Bundler
23
23
  def default_gemfile
24
24
  gemfile = find_gemfile
25
25
  raise GemfileNotFound, "Could not locate Gemfile" unless gemfile
26
- Pathname.new(gemfile)
26
+ Pathname.new(gemfile).untaint
27
27
  end
28
28
 
29
29
  def default_lockfile
@@ -32,7 +32,7 @@ module Bundler
32
32
  case gemfile.basename.to_s
33
33
  when "gems.rb" then Pathname.new(gemfile.sub(/.rb$/, ".locked"))
34
34
  else Pathname.new("#{gemfile}.lock")
35
- end
35
+ end.untaint
36
36
  end
37
37
 
38
38
  def default_bundle_dir
@@ -102,7 +102,7 @@ module Bundler
102
102
  #
103
103
  # @see {Bundler::PermissionError}
104
104
  def filesystem_access(path, action = :write)
105
- yield path
105
+ yield path.dup.untaint
106
106
  rescue Errno::EACCES
107
107
  raise PermissionError.new(path, action)
108
108
  rescue Errno::EAGAIN
@@ -128,6 +128,7 @@ module Bundler
128
128
  end
129
129
 
130
130
  def print_major_deprecations!
131
+ deprecate_gemfile(find_gemfile) if find_gemfile == find_file("Gemfile")
131
132
  if RUBY_VERSION < "2"
132
133
  major_deprecation("Bundler will only support ruby >= 2.0, you are running #{RUBY_VERSION}")
133
134
  end
@@ -140,7 +141,6 @@ module Bundler
140
141
  def find_gemfile
141
142
  given = ENV["BUNDLE_GEMFILE"]
142
143
  return given if given && !given.empty?
143
-
144
144
  find_file("Gemfile", "gems.rb")
145
145
  end
146
146
 
@@ -158,7 +158,7 @@ module Bundler
158
158
 
159
159
  def search_up(*names)
160
160
  previous = nil
161
- current = File.expand_path(SharedHelpers.pwd)
161
+ current = File.expand_path(SharedHelpers.pwd).untaint
162
162
 
163
163
  until !File.directory?(current) || current == previous
164
164
  if ENV["BUNDLE_SPEC_RUN"]
@@ -230,6 +230,12 @@ module Bundler
230
230
  true
231
231
  end
232
232
 
233
+ def deprecate_gemfile(gemfile)
234
+ return unless gemfile && File.basename(gemfile) == "Gemfile"
235
+ Bundler::SharedHelpers.major_deprecation \
236
+ "gems.rb and gems.locked will be prefered to Gemfile and Gemfile.lock."
237
+ end
238
+
233
239
  extend self
234
240
  end
235
241
  end
@@ -8,6 +8,10 @@ module Bundler
8
8
  super
9
9
  @gemspec = options["gemspec"]
10
10
  end
11
+
12
+ def as_path_source
13
+ Path.new(options)
14
+ end
11
15
  end
12
16
  end
13
17
  end
@@ -152,7 +152,7 @@ module Bundler
152
152
  set_local!(app_cache_path) if has_app_cache? && !local?
153
153
 
154
154
  if requires_checkout? && !@copied
155
- git_proxy.checkout
155
+ fetch
156
156
  git_proxy.copy_to(install_path, submodules)
157
157
  serialize_gemspecs_in(install_path)
158
158
  @copied = true
@@ -170,7 +170,7 @@ module Bundler
170
170
  serialize_gemspecs_in(install_path)
171
171
  @copied = true
172
172
  end
173
- generate_bin(spec)
173
+ generate_bin(spec, !Bundler.rubygems.spec_missing_extensions?(spec))
174
174
 
175
175
  requires_checkout? ? spec.post_install_message : nil
176
176
  end
@@ -223,10 +223,6 @@ module Bundler
223
223
 
224
224
  private
225
225
 
226
- def build_extensions(installer)
227
- super if Bundler.rubygems.spec_missing_extensions?(installer.spec)
228
- end
229
-
230
226
  def serialize_gemspecs_in(destination)
231
227
  destination = destination.expand_path(Bundler.root) if destination.relative?
232
228
  Dir["#{destination}/#{@glob}"].each do |spec_path|
@@ -292,6 +288,13 @@ module Bundler
292
288
  def git_proxy
293
289
  @git_proxy ||= GitProxy.new(cache_path, uri, ref, cached_revision, self)
294
290
  end
291
+
292
+ def fetch
293
+ git_proxy.checkout
294
+ rescue GitError
295
+ raise unless Bundler.settings[:allow_offline_install]
296
+ Bundler.ui.warn "Using cached git data because of network errors"
297
+ end
295
298
  end
296
299
  end
297
300
  end
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+ require "tempfile"
2
3
  module Bundler
3
4
  class Source
4
5
  class Git < Path
@@ -80,6 +81,10 @@ module Bundler
80
81
  end
81
82
 
82
83
  def version
84
+ git("--version").match(/(git version\s*)?((\.?\d+)+).*/)[2]
85
+ end
86
+
87
+ def full_version
83
88
  git("--version").sub("git version", "").strip
84
89
  end
85
90
 
@@ -110,7 +115,7 @@ module Bundler
110
115
  FileUtils.rm_rf(p)
111
116
  end
112
117
  git_retry %(clone --no-checkout --quiet "#{path}" "#{destination}")
113
- File.chmod(((File.stat(destination).mode | 0777) & ~File.umask), destination)
118
+ File.chmod(((File.stat(destination).mode | 0o777) & ~File.umask), destination)
114
119
  rescue Errno::EEXIST => e
115
120
  file_path = e.message[%r{.*?(/.*)}, 1]
116
121
  raise GitError, "Bundler could not install a gem because it needs to " \
@@ -143,7 +148,7 @@ module Bundler
143
148
  end
144
149
 
145
150
  def git_retry(command)
146
- Bundler::Retry.new("git #{command}", GitNotAllowedError).attempts do
151
+ Bundler::Retry.new("`git #{command}`", GitNotAllowedError).attempts do
147
152
  git(command)
148
153
  end
149
154
  end
@@ -152,7 +157,9 @@ module Bundler
152
157
  command_with_no_credentials = URICredentialsFilter.credential_filtered_string(command, uri)
153
158
  raise GitNotAllowedError.new(command_with_no_credentials) unless allow?
154
159
 
155
- out = SharedHelpers.with_clean_git_env { `git #{command}` }
160
+ out = SharedHelpers.with_clean_git_env do
161
+ capture_and_filter_stderr(uri) { `git #{command}` }
162
+ end
156
163
 
157
164
  stdout_with_no_credentials = URICredentialsFilter.credential_filtered_string(out, uri)
158
165
  raise GitCommandError.new(command_with_no_credentials, path, error_msg) if check_errors && !$?.success?
@@ -216,6 +223,23 @@ module Bundler
216
223
  return in_path { yield } if allow?
217
224
  raise GitError, "The git source #{uri} is not yet checked out. Please run `bundle install` before trying to start your application"
218
225
  end
226
+
227
+ def capture_and_filter_stderr(uri)
228
+ return_value, captured_err = ""
229
+ backup_stderr = STDERR.dup
230
+ begin
231
+ Tempfile.open("captured_stderr") do |f|
232
+ STDERR.reopen(f)
233
+ return_value = yield
234
+ f.rewind
235
+ captured_err = f.read
236
+ end
237
+ ensure
238
+ STDERR.reopen backup_stderr
239
+ end
240
+ $stderr.puts URICredentialsFilter.credential_filtered_string(captured_err, uri) if uri && !captured_err.empty?
241
+ return_value
242
+ end
219
243
  end
220
244
  end
221
245
  end
@@ -11,7 +11,7 @@ module Bundler
11
11
  DEFAULT_GLOB = "{,*,*/*}.gemspec".freeze
12
12
 
13
13
  def initialize(options)
14
- @options = options
14
+ @options = options.dup
15
15
  @glob = options["glob"] || DEFAULT_GLOB
16
16
 
17
17
  @allow_cached = false
@@ -60,7 +60,7 @@ module Bundler
60
60
  end
61
61
 
62
62
  def eql?(other)
63
- return unless other.class == Path || other.class == Gemspec
63
+ return unless other.class == self.class
64
64
  expanded_path == expand(other.path) &&
65
65
  version == other.version
66
66
  end
@@ -203,13 +203,8 @@ module Bundler
203
203
  end
204
204
  end.compact
205
205
 
206
- SharedHelpers.chdir(gem_dir) do
207
- installer = Path::Installer.new(spec, :env_shebang => false)
208
- run_hooks(:pre_install, installer)
209
- build_extensions(installer) unless disable_extensions
210
- installer.generate_bin
211
- run_hooks(:post_install, installer)
212
- end
206
+ installer = Path::Installer.new(spec, :env_shebang => false, :disable_extensions => disable_extensions)
207
+ installer.post_install
213
208
  rescue Gem::InvalidSpecificationException => e
214
209
  Bundler.ui.warn "\n#{spec.name} at #{spec.full_gem_path} did not have a valid gemspec.\n" \
215
210
  "This prevents bundler from installing bins or native extensions, but " \
@@ -223,23 +218,6 @@ module Bundler
223
218
 
224
219
  Bundler.ui.warn "The validation message from Rubygems was:\n #{e.message}"
225
220
  end
226
-
227
- def build_extensions(installer)
228
- installer.build_extensions
229
- run_hooks(:post_build, installer)
230
- end
231
-
232
- def run_hooks(type, installer)
233
- hooks_meth = "#{type}_hooks"
234
- return unless Gem.respond_to?(hooks_meth)
235
- Gem.send(hooks_meth).each do |hook|
236
- result = hook.call(installer)
237
- next unless result == false
238
- location = " at #{$1}" if hook.inspect =~ /@(.*:\d+)/
239
- message = "#{type} hook#{location} failed for #{installer.spec.full_name}"
240
- raise InstallHookError, message
241
- end
242
- end
243
221
  end
244
222
  end
245
223
  end
@@ -6,13 +6,14 @@ module Bundler
6
6
  attr_reader :spec
7
7
 
8
8
  def initialize(spec, options = {})
9
- @spec = spec
10
- @gem_dir = Bundler.rubygems.path(spec.full_gem_path)
11
- @wrappers = true
12
- @env_shebang = true
13
- @format_executable = options[:format_executable] || false
14
- @build_args = options[:build_args] || Bundler.rubygems.build_args
15
- @gem_bin_dir = "#{Bundler.rubygems.gem_dir}/bin"
9
+ @spec = spec
10
+ @gem_dir = Bundler.rubygems.path(spec.full_gem_path)
11
+ @wrappers = true
12
+ @env_shebang = true
13
+ @format_executable = options[:format_executable] || false
14
+ @build_args = options[:build_args] || Bundler.rubygems.build_args
15
+ @gem_bin_dir = "#{Bundler.rubygems.gem_dir}/bin"
16
+ @disable_extentions = options[:disable_extensions]
16
17
 
17
18
  if Bundler.requires_sudo?
18
19
  @tmp_dir = Bundler.tmp(spec.full_name).to_s
@@ -22,9 +23,26 @@ module Bundler
22
23
  end
23
24
  end
24
25
 
25
- def generate_bin
26
- return if spec.executables.nil? || spec.executables.empty?
26
+ def post_install
27
+ SharedHelpers.chdir(@gem_dir) do
28
+ run_hooks(:pre_install)
29
+
30
+ unless @disable_extentions
31
+ build_extensions
32
+ run_hooks(:post_build)
33
+ end
34
+
35
+ generate_bin unless spec.executables.nil? || spec.executables.empty?
36
+
37
+ run_hooks(:post_install)
38
+ end
39
+ ensure
40
+ Bundler.rm_rf(@tmp_dir) if Bundler.requires_sudo?
41
+ end
42
+
43
+ private
27
44
 
45
+ def generate_bin
28
46
  super
29
47
 
30
48
  if Bundler.requires_sudo?
@@ -35,8 +53,18 @@ module Bundler
35
53
  Bundler.sudo "cp -R #{@bin_dir}/#{exe} #{@gem_bin_dir}"
36
54
  end
37
55
  end
38
- ensure
39
- Bundler.rm_rf(@tmp_dir) if Bundler.requires_sudo?
56
+ end
57
+
58
+ def run_hooks(type)
59
+ hooks_meth = "#{type}_hooks"
60
+ return unless Gem.respond_to?(hooks_meth)
61
+ Gem.send(hooks_meth).each do |hook|
62
+ result = hook.call(self)
63
+ next unless result == false
64
+ location = " at #{$1}" if hook.inspect =~ /@(.*:\d+)/
65
+ message = "#{type} hook#{location} failed for #{spec.full_name}"
66
+ raise InstallHookError, message
67
+ end
40
68
  end
41
69
  end
42
70
  end
@@ -134,7 +134,7 @@ module Bundler
134
134
 
135
135
  installed_spec = nil
136
136
  Bundler.rubygems.preserve_paths do
137
- installed_spec = Bundler::RubyGemsGemInstaller.new(
137
+ installed_spec = Bundler::RubyGemsGemInstaller.at(
138
138
  path,
139
139
  :install_dir => install_path.to_s,
140
140
  :bin_dir => bin_path.to_s,
@@ -2,11 +2,13 @@
2
2
  module Bundler
3
3
  class SourceList
4
4
  attr_reader :path_sources,
5
- :git_sources
5
+ :git_sources,
6
+ :plugin_sources
6
7
 
7
8
  def initialize
8
9
  @path_sources = []
9
10
  @git_sources = []
11
+ @plugin_sources = []
10
12
  @rubygems_aggregate = Source::Rubygems.new
11
13
  @rubygems_sources = []
12
14
  end
@@ -20,13 +22,19 @@ module Bundler
20
22
  end
21
23
 
22
24
  def add_git_source(options = {})
23
- add_source_to_list Source::Git.new(options), git_sources
25
+ add_source_to_list(Source::Git.new(options), git_sources).tap do |source|
26
+ warn_on_git_protocol(source)
27
+ end
24
28
  end
25
29
 
26
30
  def add_rubygems_source(options = {})
27
31
  add_source_to_list Source::Rubygems.new(options), @rubygems_sources
28
32
  end
29
33
 
34
+ def add_plugin_source(source, options = {})
35
+ add_source_to_list Plugin.source(source).new(options), @plugin_sources
36
+ end
37
+
30
38
  def add_rubygems_remote(uri)
31
39
  @rubygems_aggregate.add_remote(uri)
32
40
  @rubygems_aggregate
@@ -41,7 +49,7 @@ module Bundler
41
49
  end
42
50
 
43
51
  def all_sources
44
- path_sources + git_sources + rubygems_sources
52
+ path_sources + git_sources + plugin_sources + rubygems_sources
45
53
  end
46
54
 
47
55
  def get(source)
@@ -49,14 +57,14 @@ module Bundler
49
57
  end
50
58
 
51
59
  def lock_sources
52
- lock_sources = (path_sources + git_sources).sort_by(&:to_s)
60
+ lock_sources = (path_sources + git_sources + plugin_sources).sort_by(&:to_s)
53
61
  lock_sources << combine_rubygems_sources
54
62
  end
55
63
 
56
64
  def replace_sources!(replacement_sources)
57
65
  return true if replacement_sources.empty?
58
66
 
59
- [path_sources, git_sources].each do |source_list|
67
+ [path_sources, git_sources, plugin_sources].each do |source_list|
60
68
  source_list.map! do |source|
61
69
  replacement_sources.find {|s| s == source } || source
62
70
  end
@@ -92,9 +100,10 @@ module Bundler
92
100
 
93
101
  def source_list_for(source)
94
102
  case source
95
- when Source::Git then git_sources
96
- when Source::Path then path_sources
97
- when Source::Rubygems then rubygems_sources
103
+ when Source::Git then git_sources
104
+ when Source::Path then path_sources
105
+ when Source::Rubygems then rubygems_sources
106
+ when Plugin::API::Source then plugin_sources
98
107
  else raise ArgumentError, "Invalid source: #{source.inspect}"
99
108
  end
100
109
  end
@@ -102,5 +111,16 @@ module Bundler
102
111
  def combine_rubygems_sources
103
112
  Source::Rubygems.new("remotes" => rubygems_remotes)
104
113
  end
114
+
115
+ def warn_on_git_protocol(source)
116
+ return if Bundler.settings["git.allow_insecure"]
117
+
118
+ if source.uri =~ /^git\:/
119
+ Bundler.ui.warn "The git source `#{source.uri}` uses the `git` protocol, " \
120
+ "which transmits data without encryption. Disable this warning with " \
121
+ "`bundle config git.allow_insecure true`, or switch to the `https` " \
122
+ "protocol to keep your data secure."
123
+ end
124
+ end
105
125
  end
106
126
  end
@@ -7,7 +7,7 @@ module Bundler
7
7
  extend Forwardable
8
8
  include TSort, Enumerable
9
9
 
10
- def_delegators :@specs, :<<, :length, :add, :remove, :size
10
+ def_delegators :@specs, :<<, :length, :add, :remove, :size, :empty?
11
11
  def_delegators :sorted, :each
12
12
 
13
13
  def initialize(specs)
@@ -6,7 +6,9 @@
6
6
  # this file is here to facilitate running it.
7
7
  #
8
8
 
9
- $:.unshift File.expand_path '../<%= standalone_path %>', __FILE__
9
+ require 'pathname'
10
+ path = Pathname.new(__FILE__)
11
+ $:.unshift File.expand_path '../<%= standalone_path %>', path.realpath
10
12
 
11
13
  require 'bundler/setup'
12
- load File.expand_path '../<%= executable_path %>', __FILE__
14
+ load File.expand_path '../<%= executable_path %>', path.realpath
@@ -1,5 +1,4 @@
1
1
  # frozen_string_literal: true
2
- # A sample Gemfile
3
2
  source "https://rubygems.org"
4
3
 
5
4
  # gem "rails"
@@ -17,8 +17,8 @@ module Bundler
17
17
  @warning_history = []
18
18
  end
19
19
 
20
- def add_color(string, color)
21
- @shell.set_color(string, color)
20
+ def add_color(string, *color)
21
+ @shell.set_color(string, *color)
22
22
  end
23
23
 
24
24
  def info(msg, newline = nil)
@@ -45,7 +45,7 @@ module Bundler
45
45
 
46
46
  def debug?
47
47
  # needs to be false instead of nil to be newline param to other methods
48
- level("debug")
48
+ level("debug") ? true : false
49
49
  end
50
50
 
51
51
  def quiet?
@@ -95,6 +95,14 @@ module Bundler
95
95
  end
96
96
  end
97
97
 
98
+ def tell_err(message, color = nil, newline = nil)
99
+ buffer = @shell.send(:prepare_message, message, *color)
100
+ buffer << "\n" if newline && !message.to_s.end_with?("\n")
101
+
102
+ @shell.send(:stderr).print(buffer)
103
+ @shell.send(:stderr).flush
104
+ end
105
+
98
106
  def strip_leading_spaces(text)
99
107
  spaces = text[/\A\s+/, 0]
100
108
  spaces ? text.gsub(/#{spaces}/, "") : text