bundler 2.0.1 → 2.0.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 (94) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +26 -0
  3. data/README.md +1 -1
  4. data/bundler.gemspec +6 -5
  5. data/lib/bundler/build_metadata.rb +2 -2
  6. data/lib/bundler/cli.rb +3 -1
  7. data/lib/bundler/cli/common.rb +1 -1
  8. data/lib/bundler/cli/install.rb +9 -8
  9. data/lib/bundler/cli/issue.rb +2 -2
  10. data/lib/bundler/compatibility_guard.rb +0 -1
  11. data/lib/bundler/definition.rb +3 -1
  12. data/lib/bundler/dsl.rb +1 -1
  13. data/lib/bundler/env.rb +2 -8
  14. data/lib/bundler/feature_flag.rb +1 -1
  15. data/lib/bundler/fetcher/downloader.rb +1 -1
  16. data/lib/bundler/gem_helper.rb +37 -22
  17. data/lib/bundler/injector.rb +7 -7
  18. data/lib/bundler/installer/parallel_installer.rb +0 -4
  19. data/lib/bundler/plugin.rb +13 -11
  20. data/lib/bundler/plugin/index.rb +4 -1
  21. data/lib/bundler/rubygems_ext.rb +0 -1
  22. data/lib/bundler/rubygems_integration.rb +19 -2
  23. data/lib/bundler/shared_helpers.rb +7 -5
  24. data/lib/bundler/templates/Executable.bundler +1 -1
  25. data/lib/bundler/templates/newgem/newgem.gemspec.tt +7 -12
  26. data/lib/bundler/templates/newgem/test/test_helper.rb.tt +4 -0
  27. data/lib/bundler/vendor/fileutils/lib/fileutils.rb +151 -48
  28. data/lib/bundler/vendor/fileutils/lib/fileutils/version.rb +5 -0
  29. data/lib/bundler/vendor/thor/lib/thor/actions.rb +14 -4
  30. data/lib/bundler/vendor/thor/lib/thor/actions/file_manipulation.rb +11 -2
  31. data/lib/bundler/vendor/thor/lib/thor/base.rb +3 -4
  32. data/lib/bundler/vendor/thor/lib/thor/error.rb +82 -0
  33. data/lib/bundler/vendor/thor/lib/thor/group.rb +2 -2
  34. data/lib/bundler/vendor/thor/lib/thor/parser/options.rb +7 -2
  35. data/lib/bundler/vendor/thor/lib/thor/runner.rb +2 -2
  36. data/lib/bundler/vendor/thor/lib/thor/shell.rb +1 -1
  37. data/lib/bundler/vendor/thor/lib/thor/shell/basic.rb +52 -7
  38. data/lib/bundler/vendor/thor/lib/thor/version.rb +1 -1
  39. data/lib/bundler/version.rb +1 -1
  40. data/man/bundle-add.1 +1 -1
  41. data/man/bundle-add.1.txt +1 -1
  42. data/man/bundle-binstubs.1 +1 -1
  43. data/man/bundle-binstubs.1.txt +1 -1
  44. data/man/bundle-check.1 +1 -1
  45. data/man/bundle-check.1.txt +1 -1
  46. data/man/bundle-clean.1 +1 -1
  47. data/man/bundle-clean.1.txt +1 -1
  48. data/man/bundle-config.1 +2 -2
  49. data/man/bundle-config.1.txt +3 -3
  50. data/man/bundle-config.ronn +1 -1
  51. data/man/bundle-doctor.1 +1 -1
  52. data/man/bundle-doctor.1.txt +1 -1
  53. data/man/bundle-exec.1 +1 -1
  54. data/man/bundle-exec.1.txt +1 -1
  55. data/man/bundle-gem.1 +1 -1
  56. data/man/bundle-gem.1.txt +1 -1
  57. data/man/bundle-info.1 +1 -1
  58. data/man/bundle-info.1.txt +1 -1
  59. data/man/bundle-init.1 +2 -2
  60. data/man/bundle-init.1.txt +2 -2
  61. data/man/bundle-init.ronn +1 -1
  62. data/man/bundle-inject.1 +1 -1
  63. data/man/bundle-inject.1.txt +1 -1
  64. data/man/bundle-install.1 +1 -1
  65. data/man/bundle-install.1.txt +1 -1
  66. data/man/bundle-list.1 +1 -1
  67. data/man/bundle-list.1.txt +1 -1
  68. data/man/bundle-lock.1 +1 -1
  69. data/man/bundle-lock.1.txt +1 -1
  70. data/man/bundle-open.1 +1 -1
  71. data/man/bundle-open.1.txt +1 -1
  72. data/man/bundle-outdated.1 +1 -1
  73. data/man/bundle-outdated.1.txt +1 -1
  74. data/man/bundle-package.1 +1 -1
  75. data/man/bundle-package.1.txt +1 -1
  76. data/man/bundle-platform.1 +1 -1
  77. data/man/bundle-platform.1.txt +1 -1
  78. data/man/bundle-pristine.1 +1 -1
  79. data/man/bundle-pristine.1.txt +1 -1
  80. data/man/bundle-remove.1 +1 -1
  81. data/man/bundle-remove.1.txt +1 -1
  82. data/man/bundle-show.1 +1 -1
  83. data/man/bundle-show.1.txt +1 -1
  84. data/man/bundle-update.1 +1 -1
  85. data/man/bundle-update.1.txt +1 -1
  86. data/man/bundle-viz.1 +1 -1
  87. data/man/bundle-viz.1.txt +1 -1
  88. data/man/bundle.1 +2 -2
  89. data/man/bundle.1.txt +2 -2
  90. data/man/bundle.ronn +1 -1
  91. data/man/gemfile.5 +2 -2
  92. data/man/gemfile.5.ronn +1 -1
  93. data/man/gemfile.5.txt +2 -2
  94. metadata +23 -8
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Bundler::FileUtils
4
+ VERSION = "1.2.0"
5
+ end
@@ -113,8 +113,10 @@ class Bundler::Thor
113
113
  # the script started).
114
114
  #
115
115
  def relative_to_original_destination_root(path, remove_dot = true)
116
- path = path.dup
117
- if path.gsub!(@destination_stack[0], ".")
116
+ root = @destination_stack[0]
117
+ if path.start_with?(root) && [File::SEPARATOR, File::ALT_SEPARATOR, nil, ''].include?(path[root.size..root.size])
118
+ path = path.dup
119
+ path[0...root.size] = '.'
118
120
  remove_dot ? (path[2..-1] || "") : path
119
121
  else
120
122
  path
@@ -217,6 +219,7 @@ class Bundler::Thor
217
219
  shell.padding += 1 if verbose
218
220
 
219
221
  contents = if is_uri
222
+ require "open-uri"
220
223
  open(path, "Accept" => "application/x-thor-template", &:read)
221
224
  else
222
225
  open(path, &:read)
@@ -252,9 +255,16 @@ class Bundler::Thor
252
255
 
253
256
  say_status :run, desc, config.fetch(:verbose, true)
254
257
 
255
- unless options[:pretend]
256
- config[:capture] ? `#{command}` : system(command.to_s)
258
+ return if options[:pretend]
259
+
260
+ result = config[:capture] ? `#{command}` : system(command.to_s)
261
+
262
+ if config[:abort_on_failure]
263
+ success = config[:capture] ? $?.success? : result
264
+ abort unless success
257
265
  end
266
+
267
+ result
258
268
  end
259
269
 
260
270
  # Executes a ruby script (taking into account WIN32 platform quirks).
@@ -60,6 +60,9 @@ class Bundler::Thor
60
60
  # destination. If a block is given instead of destination, the content of
61
61
  # the url is yielded and used as location.
62
62
  #
63
+ # +get+ relies on open-uri, so passing application user input would provide
64
+ # a command injection attack vector.
65
+ #
63
66
  # ==== Parameters
64
67
  # source<String>:: the address of the given content.
65
68
  # destination<String>:: the relative path to the destination root.
@@ -117,7 +120,13 @@ class Bundler::Thor
117
120
  context = config.delete(:context) || instance_eval("binding")
118
121
 
119
122
  create_file destination, nil, config do
120
- content = CapturableERB.new(::File.binread(source), nil, "-", "@output_buffer").tap do |erb|
123
+ match = ERB.version.match(/(\d+\.\d+\.\d+)/)
124
+ capturable_erb = if match && match[1] >= "2.2.0" # Ruby 2.6+
125
+ CapturableERB.new(::File.binread(source), :trim_mode => "-", :eoutvar => "@output_buffer")
126
+ else
127
+ CapturableERB.new(::File.binread(source), nil, "-", "@output_buffer")
128
+ end
129
+ content = capturable_erb.tap do |erb|
121
130
  erb.filename = source
122
131
  end.result(context)
123
132
  content = yield(content) if block
@@ -301,7 +310,7 @@ class Bundler::Thor
301
310
  def comment_lines(path, flag, *args)
302
311
  flag = flag.respond_to?(:source) ? flag.source : flag
303
312
 
304
- gsub_file(path, /^(\s*)([^#|\n]*#{flag})/, '\1# \2', *args)
313
+ gsub_file(path, /^(\s*)([^#\n]*#{flag})/, '\1# \2', *args)
305
314
  end
306
315
 
307
316
  # Removes a file at the given location.
@@ -466,13 +466,13 @@ class Bundler::Thor
466
466
  dispatch(nil, given_args.dup, nil, config)
467
467
  rescue Bundler::Thor::Error => e
468
468
  config[:debug] || ENV["THOR_DEBUG"] == "1" ? (raise e) : config[:shell].error(e.message)
469
- exit(1) if exit_on_failure?
469
+ exit(false) if exit_on_failure?
470
470
  rescue Errno::EPIPE
471
471
  # This happens if a thor command is piped to something like `head`,
472
472
  # which closes the pipe when it's done reading. This will also
473
473
  # mean that if the pipe is closed, further unnecessary
474
474
  # computation will not occur.
475
- exit(0)
475
+ exit(true)
476
476
  end
477
477
 
478
478
  # Allows to use private methods from parent in child classes as commands.
@@ -493,8 +493,7 @@ class Bundler::Thor
493
493
  alias_method :public_task, :public_command
494
494
 
495
495
  def handle_no_command_error(command, has_namespace = $thor_runner) #:nodoc:
496
- raise UndefinedCommandError, "Could not find command #{command.inspect} in #{namespace.inspect} namespace." if has_namespace
497
- raise UndefinedCommandError, "Could not find command #{command.inspect}."
496
+ raise UndefinedCommandError.new(command, all_commands.keys, (namespace if has_namespace))
498
497
  end
499
498
  alias_method :handle_no_task_error, :handle_no_command_error
500
499
 
@@ -1,4 +1,23 @@
1
1
  class Bundler::Thor
2
+ Correctable =
3
+ begin
4
+ require 'did_you_mean'
5
+
6
+ # In order to support versions of Ruby that don't have keyword
7
+ # arguments, we need our own spell checker class that doesn't take key
8
+ # words. Even though this code wouldn't be hit because of the check
9
+ # above, it's still necessary because the interpreter would otherwise be
10
+ # unable to parse the file.
11
+ class NoKwargSpellChecker < DidYouMean::SpellChecker # :nodoc:
12
+ def initialize(dictionary)
13
+ @dictionary = dictionary
14
+ end
15
+ end
16
+
17
+ DidYouMean::Correctable
18
+ rescue LoadError, NameError
19
+ end
20
+
2
21
  # Bundler::Thor::Error is raised when it's caused by wrong usage of thor classes. Those
3
22
  # errors have their backtrace suppressed and are nicely shown to the user.
4
23
  #
@@ -10,6 +29,35 @@ class Bundler::Thor
10
29
 
11
30
  # Raised when a command was not found.
12
31
  class UndefinedCommandError < Error
32
+ class SpellChecker
33
+ attr_reader :error
34
+
35
+ def initialize(error)
36
+ @error = error
37
+ end
38
+
39
+ def corrections
40
+ @corrections ||= spell_checker.correct(error.command).map(&:inspect)
41
+ end
42
+
43
+ def spell_checker
44
+ NoKwargSpellChecker.new(error.all_commands)
45
+ end
46
+ end
47
+
48
+ attr_reader :command, :all_commands
49
+
50
+ def initialize(command, all_commands, namespace)
51
+ @command = command
52
+ @all_commands = all_commands
53
+
54
+ message = "Could not find command #{command.inspect}"
55
+ message = namespace ? "#{message} in #{namespace.inspect} namespace." : "#{message}."
56
+
57
+ super(message)
58
+ end
59
+
60
+ prepend Correctable if Correctable
13
61
  end
14
62
  UndefinedTaskError = UndefinedCommandError
15
63
 
@@ -22,6 +70,33 @@ class Bundler::Thor
22
70
  end
23
71
 
24
72
  class UnknownArgumentError < Error
73
+ class SpellChecker
74
+ attr_reader :error
75
+
76
+ def initialize(error)
77
+ @error = error
78
+ end
79
+
80
+ def corrections
81
+ @corrections ||=
82
+ error.unknown.flat_map { |unknown| spell_checker.correct(unknown) }.uniq.map(&:inspect)
83
+ end
84
+
85
+ def spell_checker
86
+ @spell_checker ||= NoKwargSpellChecker.new(error.switches)
87
+ end
88
+ end
89
+
90
+ attr_reader :switches, :unknown
91
+
92
+ def initialize(switches, unknown)
93
+ @switches = switches
94
+ @unknown = unknown
95
+
96
+ super("Unknown switches #{unknown.map(&:inspect).join(', ')}")
97
+ end
98
+
99
+ prepend Correctable if Correctable
25
100
  end
26
101
 
27
102
  class RequiredArgumentMissingError < InvocationError
@@ -29,4 +104,11 @@ class Bundler::Thor
29
104
 
30
105
  class MalformattedArgumentError < InvocationError
31
106
  end
107
+
108
+ if Correctable
109
+ DidYouMean::SPELL_CHECKERS.merge!(
110
+ 'Bundler::Thor::UndefinedCommandError' => UndefinedCommandError::SpellChecker,
111
+ 'Bundler::Thor::UnknownArgumentError' => UnknownArgumentError::SpellChecker
112
+ )
113
+ end
32
114
  end
@@ -61,7 +61,7 @@ class Bundler::Thor::Group
61
61
  invocations[name] = false
62
62
  invocation_blocks[name] = block if block_given?
63
63
 
64
- class_eval <<-METHOD, __FILE__, __LINE__
64
+ class_eval <<-METHOD, __FILE__, __LINE__ + 1
65
65
  def _invoke_#{name.to_s.gsub(/\W/, '_')}
66
66
  klass, command = self.class.prepare_for_invocation(nil, #{name.inspect})
67
67
 
@@ -120,7 +120,7 @@ class Bundler::Thor::Group
120
120
  invocations[name] = true
121
121
  invocation_blocks[name] = block if block_given?
122
122
 
123
- class_eval <<-METHOD, __FILE__, __LINE__
123
+ class_eval <<-METHOD, __FILE__, __LINE__ + 1
124
124
  def _invoke_from_option_#{name.to_s.gsub(/\W/, '_')}
125
125
  return unless options[#{name.inspect}]
126
126
 
@@ -44,6 +44,7 @@ class Bundler::Thor
44
44
  @shorts = {}
45
45
  @switches = {}
46
46
  @extra = []
47
+ @stopped_parsing_after_extra_index = nil
47
48
 
48
49
  options.each do |option|
49
50
  @switches[option.switch_name] = option
@@ -66,6 +67,7 @@ class Bundler::Thor
66
67
  if result == OPTS_END
67
68
  shift
68
69
  @parsing_options = false
70
+ @stopped_parsing_after_extra_index ||= @extra.size
69
71
  super
70
72
  else
71
73
  result
@@ -99,6 +101,7 @@ class Bundler::Thor
99
101
  elsif @stop_on_unknown
100
102
  @parsing_options = false
101
103
  @extra << shifted
104
+ @stopped_parsing_after_extra_index ||= @extra.size
102
105
  @extra << shift while peek
103
106
  break
104
107
  elsif match
@@ -120,9 +123,11 @@ class Bundler::Thor
120
123
  end
121
124
 
122
125
  def check_unknown!
126
+ to_check = @stopped_parsing_after_extra_index ? @extra[0...@stopped_parsing_after_extra_index] : @extra
127
+
123
128
  # an unknown option starts with - or -- and has no more --'s afterward.
124
- unknown = @extra.select { |str| str =~ /^--?(?:(?!--).)*$/ }
125
- raise UnknownArgumentError, "Unknown switches '#{unknown.join(', ')}'" unless unknown.empty?
129
+ unknown = to_check.select { |str| str =~ /^--?(?:(?!--).)*$/ }
130
+ raise UnknownArgumentError.new(@switches.keys, unknown) unless unknown.empty?
126
131
  end
127
132
 
128
133
  protected
@@ -3,7 +3,7 @@ require "bundler/vendor/thor/lib/thor/group"
3
3
  require "bundler/vendor/thor/lib/thor/core_ext/io_binary_read"
4
4
 
5
5
  require "yaml"
6
- require "digest"
6
+ require "digest/md5"
7
7
  require "pathname"
8
8
 
9
9
  class Bundler::Thor::Runner < Bundler::Thor #:nodoc: # rubocop:disable ClassLength
@@ -90,7 +90,7 @@ class Bundler::Thor::Runner < Bundler::Thor #:nodoc: # rubocop:disable ClassLeng
90
90
  end
91
91
 
92
92
  thor_yaml[as] = {
93
- :filename => Digest(:MD5).hexdigest(name + as),
93
+ :filename => Digest::MD5.hexdigest(name + as),
94
94
  :location => location,
95
95
  :namespaces => Bundler::Thor::Util.namespaces_in_content(contents, base)
96
96
  }
@@ -55,7 +55,7 @@ class Bundler::Thor
55
55
 
56
56
  # Common methods that are delegated to the shell.
57
57
  SHELL_DELEGATED_METHODS.each do |method|
58
- module_eval <<-METHOD, __FILE__, __LINE__
58
+ module_eval <<-METHOD, __FILE__, __LINE__ + 1
59
59
  def #{method}(*args,&block)
60
60
  shell.#{method}(*args,&block)
61
61
  end
@@ -1,6 +1,8 @@
1
1
  class Bundler::Thor
2
2
  module Shell
3
3
  class Basic
4
+ DEFAULT_TERMINAL_WIDTH = 80
5
+
4
6
  attr_accessor :base
5
7
  attr_reader :padding
6
8
 
@@ -45,6 +47,10 @@ class Bundler::Thor
45
47
 
46
48
  # Asks something to the user and receives a response.
47
49
  #
50
+ # If a default value is specified it will be presented to the user
51
+ # and allows them to select that value with an empty response. This
52
+ # option is ignored when limited answers are supplied.
53
+ #
48
54
  # If asked to limit the correct responses, you can pass in an
49
55
  # array of acceptable answers. If one of those is not supplied,
50
56
  # they will be shown a message stating that one of those answers
@@ -61,6 +67,8 @@ class Bundler::Thor
61
67
  # ==== Example
62
68
  # ask("What is your name?")
63
69
  #
70
+ # ask("What is the planet furthest from the sun?", :default => "Pluto")
71
+ #
64
72
  # ask("What is your favorite Neopolitan flavor?", :limited_to => ["strawberry", "chocolate", "vanilla"])
65
73
  #
66
74
  # ask("What is your password?", :echo => false)
@@ -222,8 +230,20 @@ class Bundler::Thor
222
230
  paras = message.split("\n\n")
223
231
 
224
232
  paras.map! do |unwrapped|
225
- unwrapped.strip.tr("\n", " ").squeeze(" ").gsub(/.{1,#{width}}(?:\s|\Z)/) { ($& + 5.chr).gsub(/\n\005/, "\n").gsub(/\005/, "\n") }
226
- end
233
+ counter = 0
234
+ unwrapped.split(" ").inject do |memo, word|
235
+ word = word.gsub(/\n\005/, "\n").gsub(/\005/, "\n")
236
+ counter = 0 if word.include? "\n"
237
+ if (counter + word.length + 1) < width
238
+ memo = "#{memo} #{word}"
239
+ counter += (word.length + 1)
240
+ else
241
+ memo = "#{memo}\n#{word}"
242
+ counter = word.length
243
+ end
244
+ memo
245
+ end
246
+ end.compact!
227
247
 
228
248
  paras.each do |para|
229
249
  para.split("\n").each do |line|
@@ -239,11 +259,11 @@ class Bundler::Thor
239
259
  #
240
260
  # ==== Parameters
241
261
  # destination<String>:: the destination file to solve conflicts
242
- # block<Proc>:: an optional block that returns the value to be used in diff
262
+ # block<Proc>:: an optional block that returns the value to be used in diff and merge
243
263
  #
244
264
  def file_collision(destination)
245
265
  return true if @always_force
246
- options = block_given? ? "[Ynaqdh]" : "[Ynaqh]"
266
+ options = block_given? ? "[Ynaqdhm]" : "[Ynaqh]"
247
267
 
248
268
  loop do
249
269
  answer = ask(
@@ -267,6 +287,13 @@ class Bundler::Thor
267
287
  when is?(:diff)
268
288
  show_diff(destination, yield) if block_given?
269
289
  say "Retrying..."
290
+ when is?(:merge)
291
+ if block_given? && !merge_tool.empty?
292
+ merge(destination, yield)
293
+ return nil
294
+ end
295
+
296
+ say "Please specify merge tool to `THOR_MERGE` env."
270
297
  else
271
298
  say file_collision_help
272
299
  end
@@ -279,11 +306,11 @@ class Bundler::Thor
279
306
  result = if ENV["THOR_COLUMNS"]
280
307
  ENV["THOR_COLUMNS"].to_i
281
308
  else
282
- unix? ? dynamic_width : 80
309
+ unix? ? dynamic_width : DEFAULT_TERMINAL_WIDTH
283
310
  end
284
- result < 10 ? 80 : result
311
+ result < 10 ? DEFAULT_TERMINAL_WIDTH : result
285
312
  rescue
286
- 80
313
+ DEFAULT_TERMINAL_WIDTH
287
314
  end
288
315
 
289
316
  # Called if something goes wrong during the execution. This is used by Bundler::Thor
@@ -344,6 +371,7 @@ class Bundler::Thor
344
371
  q - quit, abort
345
372
  d - diff, show the differences between the old and the new
346
373
  h - help, show this help
374
+ m - merge, run merge tool
347
375
  HELP
348
376
  end
349
377
 
@@ -432,6 +460,23 @@ class Bundler::Thor
432
460
  end
433
461
  correct_answer
434
462
  end
463
+
464
+ def merge(destination, content) #:nodoc:
465
+ require "tempfile"
466
+ Tempfile.open([File.basename(destination), File.extname(destination)], File.dirname(destination)) do |temp|
467
+ temp.write content
468
+ temp.rewind
469
+ system %(#{merge_tool} "#{temp.path}" "#{destination}")
470
+ end
471
+ end
472
+
473
+ def merge_tool #:nodoc:
474
+ @merge_tool ||= ENV["THOR_MERGE"] || git_merge_tool
475
+ end
476
+
477
+ def git_merge_tool #:nodoc:
478
+ `git config merge.tool`.rstrip rescue ""
479
+ end
435
480
  end
436
481
  end
437
482
  end
@@ -1,3 +1,3 @@
1
1
  class Bundler::Thor
2
- VERSION = "0.20.0"
2
+ VERSION = "0.20.3"
3
3
  end
@@ -7,7 +7,7 @@ module Bundler
7
7
  # We're doing this because we might write tests that deal
8
8
  # with other versions of bundler and we are unsure how to
9
9
  # handle this better.
10
- VERSION = "2.0.1" unless defined?(::Bundler::VERSION)
10
+ VERSION = "2.0.2" unless defined?(::Bundler::VERSION)
11
11
 
12
12
  def self.overwrite_loaded_gem_version
13
13
  begin
@@ -1,7 +1,7 @@
1
1
  .\" generated with Ronn/v0.7.3
2
2
  .\" http://github.com/rtomayko/ronn/tree/0.7.3
3
3
  .
4
- .TH "BUNDLE\-ADD" "1" "December 2018" "" ""
4
+ .TH "BUNDLE\-ADD" "1" "June 2019" "" ""
5
5
  .
6
6
  .SH "NAME"
7
7
  \fBbundle\-add\fR \- Add gem to the Gemfile and run bundle install
@@ -49,4 +49,4 @@ OPTIONS
49
49
 
50
50
 
51
51
 
52
- December 2018 BUNDLE-ADD(1)
52
+ June 2019 BUNDLE-ADD(1)