diff options
author | Bundlerbot <bot@bundler.io> | 2019-03-26 00:37:48 +0000 |
---|---|---|
committer | Bundlerbot <bot@bundler.io> | 2019-03-26 00:37:48 +0000 |
commit | 6f39ea5b15d61e5bdf7915bc94d66c31b1242d15 (patch) | |
tree | 9fe72e6e4588331a3e5e8e8381aafc837089b94b | |
parent | aaa0b0ce6a447aa0f01301799f3163832da6566d (diff) | |
parent | 16223dcfbc0176ba6a1e855890fa36172ec8b9de (diff) | |
download | bundler-6f39ea5b15d61e5bdf7915bc94d66c31b1242d15.tar.gz |
Merge #7067
7067: Tweaking vendoring r=hsbt a=deivid-rodriguez
### What was the end-user problem that led to this PR?
The problem was that we were not using the latest versions of some of our vendored dependencies.
### What was your diagnosis of the problem?
My diagnosis was that we should upgrade them.
### What is your fix for the problem, implemented in this PR?
My fix is to upgrade them using `automatiek`, and add a few tweaks to our vendoring setup.
### Why did you choose this fix out of the possible options?
I chose this fix because.... I didn't really considered other options.
Co-authored-by: David RodrÃguez <deivid.rodriguez@riseup.net>
-rw-r--r-- | Rakefile | 41 | ||||
-rw-r--r-- | lib/bundler/vendor/fileutils/lib/fileutils.rb | 149 | ||||
-rw-r--r-- | lib/bundler/vendor/thor/lib/thor/actions.rb | 18 | ||||
-rw-r--r-- | lib/bundler/vendor/thor/lib/thor/actions/file_manipulation.rb | 13 | ||||
-rw-r--r-- | lib/bundler/vendor/thor/lib/thor/base.rb | 7 | ||||
-rw-r--r-- | lib/bundler/vendor/thor/lib/thor/error.rb | 82 | ||||
-rw-r--r-- | lib/bundler/vendor/thor/lib/thor/group.rb | 4 | ||||
-rw-r--r-- | lib/bundler/vendor/thor/lib/thor/parser/options.rb | 9 | ||||
-rw-r--r-- | lib/bundler/vendor/thor/lib/thor/runner.rb | 4 | ||||
-rw-r--r-- | lib/bundler/vendor/thor/lib/thor/shell.rb | 2 | ||||
-rw-r--r-- | lib/bundler/vendor/thor/lib/thor/shell/basic.rb | 59 | ||||
-rw-r--r-- | lib/bundler/vendor/thor/lib/thor/version.rb | 2 |
12 files changed, 328 insertions, 62 deletions
@@ -10,8 +10,8 @@ else File.expand_path("tmp/rubygems") end -def bundler_spec - @bundler_spec ||= Gem::Specification.load("bundler.gemspec") +def development_dependencies + @development_dependencies ||= Gem::Specification.load("bundler.gemspec").development_dependencies end # Benchmark task execution @@ -43,7 +43,7 @@ namespace :spec do desc "Ensure spec dependencies are installed" task :deps do - deps = Hash[bundler_spec.development_dependencies.map do |d| + deps = Hash[development_dependencies.map do |d| [d.name, d.requirement.to_s] end] @@ -228,7 +228,7 @@ task :rubocop do end namespace :man do - ronn_dep = bundler_spec.development_dependencies.find do |dep| + ronn_dep = development_dependencies.find do |dep| dep.name == "ronn" end @@ -297,9 +297,32 @@ namespace :man do end end +automatiek_dep = development_dependencies.find do |dep| + dep.name == "automatiek" +end + +automatiek_requirement = automatiek_dep.requirement.to_s + begin + gem "automatiek", automatiek_requirement + require "automatiek" +rescue LoadError + namespace :vendor do + desc "Vendor a specific version of molinillo" + task(:molinillo) { abort "We couldn't activate automatiek (#{automatiek_requirement}). Try `gem install automatiek:'#{automatiek_requirement}'` to be able to vendor gems" } + + desc "Vendor a specific version of fileutils" + task(:fileutils) { abort "We couldn't activate automatiek (#{automatiek_requirement}). Try `gem install automatiek:'#{automatiek_requirement}'` to be able to vendor gems" } + desc "Vendor a specific version of thor" + task(:thor) { abort "We couldn't activate automatiek (#{automatiek_requirement}). Try `gem install automatiek:'#{automatiek_requirement}'` to be able to vendor gems" } + + desc "Vendor a specific version of net-http-persistent" + task(:"net-http-persistent") { abort "We couldn't activate automatiek (#{automatiek_requirement}). Try `gem install automatiek:'#{automatiek_requirement}'` to be able to vendor gems" } + end +else + desc "Vendor a specific version of molinillo" Automatiek::RakeTask.new("molinillo") do |lib| lib.download = { :github => "https://github.com/CocoaPods/Molinillo" } lib.namespace = "Molinillo" @@ -307,6 +330,7 @@ begin lib.vendor_lib = "lib/bundler/vendor/molinillo" end + desc "Vendor a specific version of thor" Automatiek::RakeTask.new("thor") do |lib| lib.download = { :github => "https://github.com/erikhuda/thor" } lib.namespace = "Thor" @@ -314,6 +338,7 @@ begin lib.vendor_lib = "lib/bundler/vendor/thor" end + desc "Vendor a specific version of fileutils" Automatiek::RakeTask.new("fileutils") do |lib| lib.download = { :github => "https://github.com/ruby/fileutils" } lib.namespace = "FileUtils" @@ -321,6 +346,7 @@ begin lib.vendor_lib = "lib/bundler/vendor/fileutils" end + desc "Vendor a specific version of net-http-persistent" Automatiek::RakeTask.new("net-http-persistent") do |lib| lib.download = { :github => "https://github.com/drbrain/net-http-persistent" } lib.namespace = "Net::HTTP::Persistent" @@ -337,13 +363,6 @@ begin end lib.send(:extend, mixin) end -rescue LoadError - namespace :vendor do - task(:fileutils) { abort "Install the automatiek gem to be able to vendor gems." } - task(:molinillo) { abort "Install the automatiek gem to be able to vendor gems." } - task(:thor) { abort "Install the automatiek gem to be able to vendor gems." } - task("net-http-persistent") { abort "Install the automatiek gem to be able to vendor gems." } - end end task :override_version do diff --git a/lib/bundler/vendor/fileutils/lib/fileutils.rb b/lib/bundler/vendor/fileutils/lib/fileutils.rb index cc69740845..77b3bade52 100644 --- a/lib/bundler/vendor/fileutils/lib/fileutils.rb +++ b/lib/bundler/vendor/fileutils/lib/fileutils.rb @@ -85,8 +85,12 @@ # <tt>:verbose</tt> flags to methods in Bundler::FileUtils. # +require 'rbconfig' + module Bundler::FileUtils + VERSION = "1.1.0" + def self.private_module_function(name) #:nodoc: module_function name private_class_method name @@ -117,8 +121,9 @@ module Bundler::FileUtils # def cd(dir, verbose: nil, &block) # :yield: dir fu_output_message "cd #{dir}" if verbose - Dir.chdir(dir, &block) + result = Dir.chdir(dir, &block) fu_output_message 'cd -' if verbose and block + result end module_function :cd @@ -245,15 +250,15 @@ module Bundler::FileUtils fu_output_message "rmdir #{parents ? '-p ' : ''}#{list.join ' '}" if verbose return if noop list.each do |dir| - begin - Dir.rmdir(dir = remove_trailing_slash(dir)) - if parents + Dir.rmdir(dir = remove_trailing_slash(dir)) + if parents + begin until (parent = File.dirname(dir)) == '.' or parent == dir dir = parent Dir.rmdir(dir) end + rescue Errno::ENOTEMPTY, Errno::EEXIST, Errno::ENOENT end - rescue Errno::ENOTEMPTY, Errno::EEXIST, Errno::ENOENT end end end @@ -295,6 +300,39 @@ module Bundler::FileUtils # # :call-seq: + # Bundler::FileUtils.cp_lr(src, dest, noop: nil, verbose: nil, dereference_root: true, remove_destination: false) + # + # Hard link +src+ to +dest+. If +src+ is a directory, this method links + # all its contents recursively. If +dest+ is a directory, links + # +src+ to +dest/src+. + # + # +src+ can be a list of files. + # + # # Installing the library "mylib" under the site_ruby directory. + # Bundler::FileUtils.rm_r site_ruby + '/mylib', :force => true + # Bundler::FileUtils.cp_lr 'lib/', site_ruby + '/mylib' + # + # # Examples of linking several files to target directory. + # Bundler::FileUtils.cp_lr %w(mail.rb field.rb debug/), site_ruby + '/tmail' + # Bundler::FileUtils.cp_lr Dir.glob('*.rb'), '/home/aamine/lib/ruby', :noop => true, :verbose => true + # + # # If you want to link all contents of a directory instead of the + # # directory itself, c.f. src/x -> dest/x, src/y -> dest/y, + # # use the following code. + # Bundler::FileUtils.cp_lr 'src/.', 'dest' # cp_lr('src', 'dest') makes dest/src, but this doesn't. + # + def cp_lr(src, dest, noop: nil, verbose: nil, + dereference_root: true, remove_destination: false) + fu_output_message "cp -lr#{remove_destination ? ' --remove-destination' : ''} #{[src,dest].flatten.join ' '}" if verbose + return if noop + fu_each_src_dest(src, dest) do |s, d| + link_entry s, d, dereference_root, remove_destination + end + end + module_function :cp_lr + + # + # :call-seq: # Bundler::FileUtils.ln_s(target, link, force: nil, noop: nil, verbose: nil) # Bundler::FileUtils.ln_s(target, dir, force: nil, noop: nil, verbose: nil) # Bundler::FileUtils.ln_s(targets, dir, force: nil, noop: nil, verbose: nil) @@ -340,6 +378,26 @@ module Bundler::FileUtils module_function :ln_sf # + # Hard links a file system entry +src+ to +dest+. + # If +src+ is a directory, this method links its contents recursively. + # + # Both of +src+ and +dest+ must be a path name. + # +src+ must exist, +dest+ must not exist. + # + # If +dereference_root+ is true, this method dereferences the tree root. + # + # If +remove_destination+ is true, this method removes each destination file before copy. + # + def link_entry(src, dest, dereference_root = false, remove_destination = false) + Entry_.new(src, nil, dereference_root).traverse do |ent| + destent = Entry_.new(dest, ent.rel, false) + File.unlink destent.path if remove_destination && File.file?(destent.path) + ent.link destent.path + end + end + module_function :link_entry + + # # Copies a file content +src+ to +dest+. If +dest+ is a directory, # copies +src+ to +dest/src+. # @@ -412,7 +470,7 @@ module Bundler::FileUtils def copy_entry(src, dest, preserve = false, dereference_root = false, remove_destination = false) Entry_.new(src, nil, dereference_root).wrap_traverse(proc do |ent| destent = Entry_.new(dest, ent.rel, false) - File.unlink destent.path if remove_destination && File.file?(destent.path) + File.unlink destent.path if remove_destination && (File.file?(destent.path) || File.symlink?(destent.path)) ent.copy destent.path end, proc do |ent| destent = Entry_.new(dest, ent.rel, false) @@ -486,7 +544,7 @@ module Bundler::FileUtils module_function :move def rename_cannot_overwrite_file? #:nodoc: - /emx/ =~ RUBY_PLATFORM + /emx/ =~ RbConfig::CONFIG['host_os'] end private_module_function :rename_cannot_overwrite_file? @@ -601,8 +659,8 @@ module Bundler::FileUtils # # For details of this security vulnerability, see Perl's case: # - # * http://www.cve.mitre.org/cgi-bin/cvename.cgi?name=CAN-2005-0448 - # * http://www.cve.mitre.org/cgi-bin/cvename.cgi?name=CAN-2004-0452 + # * https://cve.mitre.org/cgi-bin/cvename.cgi?name=CAN-2005-0448 + # * https://cve.mitre.org/cgi-bin/cvename.cgi?name=CAN-2004-0452 # # For fileutils.rb, this vulnerability is reported in [ruby-dev:26100]. # @@ -626,22 +684,38 @@ module Bundler::FileUtils unless parent_st.sticky? raise ArgumentError, "parent directory is world writable, Bundler::FileUtils#remove_entry_secure does not work; abort: #{path.inspect} (parent directory mode #{'%o' % parent_st.mode})" end + # freeze tree root euid = Process.euid - File.open(fullpath + '/.') {|f| - unless fu_stat_identical_entry?(st, f.stat) - # symlink (TOC-to-TOU attack?) - File.unlink fullpath - return - end - f.chown euid, -1 - f.chmod 0700 - unless fu_stat_identical_entry?(st, File.lstat(fullpath)) - # TOC-to-TOU attack? - File.unlink fullpath - return - end - } + dot_file = fullpath + "/." + begin + File.open(dot_file) {|f| + unless fu_stat_identical_entry?(st, f.stat) + # symlink (TOC-to-TOU attack?) + File.unlink fullpath + return + end + f.chown euid, -1 + f.chmod 0700 + } + rescue EISDIR # JRuby in non-native mode can't open files as dirs + File.lstat(dot_file).tap {|fstat| + unless fu_stat_identical_entry?(st, fstat) + # symlink (TOC-to-TOU attack?) + File.unlink fullpath + return + end + File.chown euid, -1, dot_file + File.chmod 0700, dot_file + } + end + + unless fu_stat_identical_entry?(st, File.lstat(fullpath)) + # TOC-to-TOU attack? + File.unlink fullpath + return + end + # ---- tree root is frozen ---- root = Entry_.new(path) root.preorder_traverse do |ent| @@ -742,8 +816,15 @@ module Bundler::FileUtils # def compare_stream(a, b) bsize = fu_stream_blksize(a, b) - sa = String.new(capacity: bsize) - sb = String.new(capacity: bsize) + + if RUBY_VERSION > "2.4" + sa = String.new(capacity: bsize) + sb = String.new(capacity: bsize) + else + sa = String.new + sb = String.new + end + begin a.read(bsize, sa) b.read(bsize, sb) @@ -1068,7 +1149,7 @@ module Bundler::FileUtils private def fu_windows? - /mswin|mingw|bccwin|emx/ =~ RUBY_PLATFORM + /mswin|mingw|bccwin|emx/ =~ RbConfig::CONFIG['host_os'] end def fu_copy_stream0(src, dest, blksize = nil) #:nodoc: @@ -1250,6 +1331,22 @@ module Bundler::FileUtils end end + def link(dest) + case + when directory? + if !File.exist?(dest) and descendant_directory?(dest, path) + raise ArgumentError, "cannot link directory %s to itself %s" % [path, dest] + end + begin + Dir.mkdir dest + rescue + raise unless File.directory?(dest) + end + else + File.link path(), dest + end + end + def copy(dest) lstat case diff --git a/lib/bundler/vendor/thor/lib/thor/actions.rb b/lib/bundler/vendor/thor/lib/thor/actions.rb index e6698572a9..b06feac2a0 100644 --- a/lib/bundler/vendor/thor/lib/thor/actions.rb +++ b/lib/bundler/vendor/thor/lib/thor/actions.rb @@ -113,8 +113,10 @@ class Bundler::Thor # the script started). # def relative_to_original_destination_root(path, remove_dot = true) - path = path.dup - if path.gsub!(@destination_stack[0], ".") + root = @destination_stack[0] + if path.start_with?(root) && [File::SEPARATOR, File::ALT_SEPARATOR, nil, ''].include?(path[root.size..root.size]) + path = path.dup + path[0...root.size] = '.' remove_dot ? (path[2..-1] || "") : path else path @@ -217,6 +219,7 @@ class Bundler::Thor shell.padding += 1 if verbose contents = if is_uri + require "open-uri" open(path, "Accept" => "application/x-thor-template", &:read) else open(path, &:read) @@ -252,9 +255,16 @@ class Bundler::Thor say_status :run, desc, config.fetch(:verbose, true) - unless options[:pretend] - config[:capture] ? `#{command}` : system(command.to_s) + return if options[:pretend] + + result = config[:capture] ? `#{command}` : system(command.to_s) + + if config[:abort_on_failure] + success = config[:capture] ? $?.success? : result + abort unless success end + + result end # Executes a ruby script (taking into account WIN32 platform quirks). diff --git a/lib/bundler/vendor/thor/lib/thor/actions/file_manipulation.rb b/lib/bundler/vendor/thor/lib/thor/actions/file_manipulation.rb index 4c83bebc86..cc29db05a8 100644 --- a/lib/bundler/vendor/thor/lib/thor/actions/file_manipulation.rb +++ b/lib/bundler/vendor/thor/lib/thor/actions/file_manipulation.rb @@ -60,6 +60,9 @@ class Bundler::Thor # destination. If a block is given instead of destination, the content of # the url is yielded and used as location. # + # +get+ relies on open-uri, so passing application user input would provide + # a command injection attack vector. + # # ==== Parameters # source<String>:: the address of the given content. # destination<String>:: the relative path to the destination root. @@ -117,7 +120,13 @@ class Bundler::Thor context = config.delete(:context) || instance_eval("binding") create_file destination, nil, config do - content = CapturableERB.new(::File.binread(source), nil, "-", "@output_buffer").tap do |erb| + match = ERB.version.match(/(\d+\.\d+\.\d+)/) + capturable_erb = if match && match[1] >= "2.2.0" # Ruby 2.6+ + CapturableERB.new(::File.binread(source), :trim_mode => "-", :eoutvar => "@output_buffer") + else + CapturableERB.new(::File.binread(source), nil, "-", "@output_buffer") + end + content = capturable_erb.tap do |erb| erb.filename = source end.result(context) content = yield(content) if block @@ -301,7 +310,7 @@ class Bundler::Thor def comment_lines(path, flag, *args) flag = flag.respond_to?(:source) ? flag.source : flag - gsub_file(path, /^(\s*)([^#|\n]*#{flag})/, '\1# \2', *args) + gsub_file(path, /^(\s*)([^#\n]*#{flag})/, '\1# \2', *args) end # Removes a file at the given location. diff --git a/lib/bundler/vendor/thor/lib/thor/base.rb b/lib/bundler/vendor/thor/lib/thor/base.rb index 7e41dc226b..e79d03d087 100644 --- a/lib/bundler/vendor/thor/lib/thor/base.rb +++ b/lib/bundler/vendor/thor/lib/thor/base.rb @@ -466,13 +466,13 @@ class Bundler::Thor dispatch(nil, given_args.dup, nil, config) rescue Bundler::Thor::Error => e config[:debug] || ENV["THOR_DEBUG"] == "1" ? (raise e) : config[:shell].error(e.message) - exit(1) if exit_on_failure? + exit(false) if exit_on_failure? rescue Errno::EPIPE # This happens if a thor command is piped to something like `head`, # which closes the pipe when it's done reading. This will also # mean that if the pipe is closed, further unnecessary # computation will not occur. - exit(0) + exit(true) end # Allows to use private methods from parent in child classes as commands. @@ -493,8 +493,7 @@ class Bundler::Thor alias_method :public_task, :public_command def handle_no_command_error(command, has_namespace = $thor_runner) #:nodoc: - raise UndefinedCommandError, "Could not find command #{command.inspect} in #{namespace.inspect} namespace." if has_namespace - raise UndefinedCommandError, "Could not find command #{command.inspect}." + raise UndefinedCommandError.new(command, all_commands.keys, (namespace if has_namespace)) end alias_method :handle_no_task_error, :handle_no_command_error diff --git a/lib/bundler/vendor/thor/lib/thor/error.rb b/lib/bundler/vendor/thor/lib/thor/error.rb index 2f816081f3..16c68294e4 100644 --- a/lib/bundler/vendor/thor/lib/thor/error.rb +++ b/lib/bundler/vendor/thor/lib/thor/error.rb @@ -1,4 +1,23 @@ class Bundler::Thor + Correctable = + begin + require 'did_you_mean' + + # In order to support versions of Ruby that don't have keyword + # arguments, we need our own spell checker class that doesn't take key + # words. Even though this code wouldn't be hit because of the check + # above, it's still necessary because the interpreter would otherwise be + # unable to parse the file. + class NoKwargSpellChecker < DidYouMean::SpellChecker # :nodoc: + def initialize(dictionary) + @dictionary = dictionary + end + end + + DidYouMean::Correctable + rescue LoadError, NameError + end + # Bundler::Thor::Error is raised when it's caused by wrong usage of thor classes. Those # errors have their backtrace suppressed and are nicely shown to the user. # @@ -10,6 +29,35 @@ class Bundler::Thor # Raised when a command was not found. class UndefinedCommandError < Error + class SpellChecker + attr_reader :error + + def initialize(error) + @error = error + end + + def corrections + @corrections ||= spell_checker.correct(error.command).map(&:inspect) + end + + def spell_checker + NoKwargSpellChecker.new(error.all_commands) + end + end + + attr_reader :command, :all_commands + + def initialize(command, all_commands, namespace) + @command = command + @all_commands = all_commands + + message = "Could not find command #{command.inspect}" + message = namespace ? "#{message} in #{namespace.inspect} namespace." : "#{message}." + + super(message) + end + + prepend Correctable if Correctable end UndefinedTaskError = UndefinedCommandError @@ -22,6 +70,33 @@ class Bundler::Thor end class UnknownArgumentError < Error + class SpellChecker + attr_reader :error + + def initialize(error) + @error = error + end + + def corrections + @corrections ||= + error.unknown.flat_map { |unknown| spell_checker.correct(unknown) }.uniq.map(&:inspect) + end + + def spell_checker + @spell_checker ||= NoKwargSpellChecker.new(error.switches) + end + end + + attr_reader :switches, :unknown + + def initialize(switches, unknown) + @switches = switches + @unknown = unknown + + super("Unknown switches #{unknown.map(&:inspect).join(', ')}") + end + + prepend Correctable if Correctable end class RequiredArgumentMissingError < InvocationError @@ -29,4 +104,11 @@ class Bundler::Thor class MalformattedArgumentError < InvocationError end + + if Correctable + DidYouMean::SPELL_CHECKERS.merge!( + 'Bundler::Thor::UndefinedCommandError' => UndefinedCommandError::SpellChecker, + 'Bundler::Thor::UnknownArgumentError' => UnknownArgumentError::SpellChecker + ) + end end diff --git a/lib/bundler/vendor/thor/lib/thor/group.rb b/lib/bundler/vendor/thor/lib/thor/group.rb index 05ddc10cd3..30db46529e 100644 --- a/lib/bundler/vendor/thor/lib/thor/group.rb +++ b/lib/bundler/vendor/thor/lib/thor/group.rb @@ -61,7 +61,7 @@ class Bundler::Thor::Group invocations[name] = false invocation_blocks[name] = block if block_given? - class_eval <<-METHOD, __FILE__, __LINE__ + class_eval <<-METHOD, __FILE__, __LINE__ + 1 def _invoke_#{name.to_s.gsub(/\W/, '_')} klass, command = self.class.prepare_for_invocation(nil, #{name.inspect}) @@ -120,7 +120,7 @@ class Bundler::Thor::Group invocations[name] = true invocation_blocks[name] = block if block_given? - class_eval <<-METHOD, __FILE__, __LINE__ + class_eval <<-METHOD, __FILE__, __LINE__ + 1 def _invoke_from_option_#{name.to_s.gsub(/\W/, '_')} return unless options[#{name.inspect}] diff --git a/lib/bundler/vendor/thor/lib/thor/parser/options.rb b/lib/bundler/vendor/thor/lib/thor/parser/options.rb index 70f6366842..179f4fa015 100644 --- a/lib/bundler/vendor/thor/lib/thor/parser/options.rb +++ b/lib/bundler/vendor/thor/lib/thor/parser/options.rb @@ -44,6 +44,7 @@ class Bundler::Thor @shorts = {} @switches = {} @extra = [] + @stopped_parsing_after_extra_index = nil options.each do |option| @switches[option.switch_name] = option @@ -66,6 +67,7 @@ class Bundler::Thor if result == OPTS_END shift @parsing_options = false + @stopped_parsing_after_extra_index ||= @extra.size super else result @@ -99,6 +101,7 @@ class Bundler::Thor elsif @stop_on_unknown @parsing_options = false @extra << shifted + @stopped_parsing_after_extra_index ||= @extra.size @extra << shift while peek break elsif match @@ -120,9 +123,11 @@ class Bundler::Thor end def check_unknown! + to_check = @stopped_parsing_after_extra_index ? @extra[0...@stopped_parsing_after_extra_index] : @extra + # an unknown option starts with - or -- and has no more --'s afterward. - unknown = @extra.select { |str| str =~ /^--?(?:(?!--).)*$/ } - raise UnknownArgumentError, "Unknown switches '#{unknown.join(', ')}'" unless unknown.empty? + unknown = to_check.select { |str| str =~ /^--?(?:(?!--).)*$/ } + raise UnknownArgumentError.new(@switches.keys, unknown) unless unknown.empty? end protected diff --git a/lib/bundler/vendor/thor/lib/thor/runner.rb b/lib/bundler/vendor/thor/lib/thor/runner.rb index b110b8d478..65ae422d7f 100644 --- a/lib/bundler/vendor/thor/lib/thor/runner.rb +++ b/lib/bundler/vendor/thor/lib/thor/runner.rb @@ -3,7 +3,7 @@ require "bundler/vendor/thor/lib/thor/group" require "bundler/vendor/thor/lib/thor/core_ext/io_binary_read" require "yaml" -require "digest" +require "digest/md5" require "pathname" class Bundler::Thor::Runner < Bundler::Thor #:nodoc: # rubocop:disable ClassLength @@ -90,7 +90,7 @@ class Bundler::Thor::Runner < Bundler::Thor #:nodoc: # rubocop:disable ClassLeng end thor_yaml[as] = { - :filename => Digest(:MD5).hexdigest(name + as), + :filename => Digest::MD5.hexdigest(name + as), :location => location, :namespaces => Bundler::Thor::Util.namespaces_in_content(contents, base) } diff --git a/lib/bundler/vendor/thor/lib/thor/shell.rb b/lib/bundler/vendor/thor/lib/thor/shell.rb index e945549324..a68cdf8a98 100644 --- a/lib/bundler/vendor/thor/lib/thor/shell.rb +++ b/lib/bundler/vendor/thor/lib/thor/shell.rb @@ -55,7 +55,7 @@ class Bundler::Thor # Common methods that are delegated to the shell. SHELL_DELEGATED_METHODS.each do |method| - module_eval <<-METHOD, __FILE__, __LINE__ + module_eval <<-METHOD, __FILE__, __LINE__ + 1 def #{method}(*args,&block) shell.#{method}(*args,&block) end diff --git a/lib/bundler/vendor/thor/lib/thor/shell/basic.rb b/lib/bundler/vendor/thor/lib/thor/shell/basic.rb index 5162390efd..52648fee8f 100644 --- a/lib/bundler/vendor/thor/lib/thor/shell/basic.rb +++ b/lib/bundler/vendor/thor/lib/thor/shell/basic.rb @@ -1,6 +1,8 @@ class Bundler::Thor module Shell class Basic + DEFAULT_TERMINAL_WIDTH = 80 + attr_accessor :base attr_reader :padding @@ -45,6 +47,10 @@ class Bundler::Thor # Asks something to the user and receives a response. # + # If a default value is specified it will be presented to the user + # and allows them to select that value with an empty response. This + # option is ignored when limited answers are supplied. + # # If asked to limit the correct responses, you can pass in an # array of acceptable answers. If one of those is not supplied, # they will be shown a message stating that one of those answers @@ -61,6 +67,8 @@ class Bundler::Thor # ==== Example # ask("What is your name?") # + # ask("What is the planet furthest from the sun?", :default => "Pluto") + # # ask("What is your favorite Neopolitan flavor?", :limited_to => ["strawberry", "chocolate", "vanilla"]) # # ask("What is your password?", :echo => false) @@ -222,8 +230,20 @@ class Bundler::Thor paras = message.split("\n\n") paras.map! do |unwrapped| - unwrapped.strip.tr("\n", " ").squeeze(" ").gsub(/.{1,#{width}}(?:\s|\Z)/) { ($& + 5.chr).gsub(/\n\005/, "\n").gsub(/\005/, "\n") } - end + counter = 0 + unwrapped.split(" ").inject do |memo, word| + word = word.gsub(/\n\005/, "\n").gsub(/\005/, "\n") + counter = 0 if word.include? "\n" + if (counter + word.length + 1) < width + memo = "#{memo} #{word}" + counter += (word.length + 1) + else + memo = "#{memo}\n#{word}" + counter = word.length + end + memo + end + end.compact! paras.each do |para| para.split("\n").each do |line| @@ -239,11 +259,11 @@ class Bundler::Thor # # ==== Parameters # destination<String>:: the destination file to solve conflicts - # block<Proc>:: an optional block that returns the value to be used in diff + # block<Proc>:: an optional block that returns the value to be used in diff and merge # def file_collision(destination) return true if @always_force - options = block_given? ? "[Ynaqdh]" : "[Ynaqh]" + options = block_given? ? "[Ynaqdhm]" : "[Ynaqh]" loop do answer = ask( @@ -267,6 +287,13 @@ class Bundler::Thor when is?(:diff) show_diff(destination, yield) if block_given? say "Retrying..." + when is?(:merge) + if block_given? && !merge_tool.empty? + merge(destination, yield) + return nil + end + + say "Please specify merge tool to `THOR_MERGE` env." else say file_collision_help end @@ -279,11 +306,11 @@ class Bundler::Thor result = if ENV["THOR_COLUMNS"] ENV["THOR_COLUMNS"].to_i else - unix? ? dynamic_width : 80 + unix? ? dynamic_width : DEFAULT_TERMINAL_WIDTH end - result < 10 ? 80 : result + result < 10 ? DEFAULT_TERMINAL_WIDTH : result rescue - 80 + DEFAULT_TERMINAL_WIDTH end # Called if something goes wrong during the execution. This is used by Bundler::Thor @@ -344,6 +371,7 @@ class Bundler::Thor q - quit, abort d - diff, show the differences between the old and the new h - help, show this help + m - merge, run merge tool HELP end @@ -432,6 +460,23 @@ class Bundler::Thor end correct_answer end + + def merge(destination, content) #:nodoc: + require "tempfile" + Tempfile.open([File.basename(destination), File.extname(destination)], File.dirname(destination)) do |temp| + temp.write content + temp.rewind + system %(#{merge_tool} "#{temp.path}" "#{destination}") + end + end + + def merge_tool #:nodoc: + @merge_tool ||= ENV["THOR_MERGE"] || git_merge_tool + end + + def git_merge_tool #:nodoc: + `git config merge.tool`.rstrip rescue "" + end end end end diff --git a/lib/bundler/vendor/thor/lib/thor/version.rb b/lib/bundler/vendor/thor/lib/thor/version.rb index df8f18821a..98f2b79081 100644 --- a/lib/bundler/vendor/thor/lib/thor/version.rb +++ b/lib/bundler/vendor/thor/lib/thor/version.rb @@ -1,3 +1,3 @@ class Bundler::Thor - VERSION = "0.20.0" + VERSION = "0.20.3" end |