Hello community, here is the log from the commit of package rubygem-thor for openSUSE:Factory checked in at 2018-11-20 22:43:25 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/rubygem-thor (Old) and /work/SRC/openSUSE:Factory/.rubygem-thor.new.19453 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "rubygem-thor" Tue Nov 20 22:43:25 2018 rev:20 rq:650335 version:0.20.3 Changes: -------- --- /work/SRC/openSUSE:Factory/rubygem-thor/rubygem-thor.changes 2017-08-22 11:09:33.712938794 +0200 +++ /work/SRC/openSUSE:Factory/.rubygem-thor.new.19453/rubygem-thor.changes 2018-11-20 22:43:38.798255821 +0100 @@ -1,0 +2,15 @@ +Mon Nov 12 17:49:13 UTC 2018 - mschnit...@suse.com + +- updated to version 0.20.3 + + * Support old versions of `did_you_mean`. + + # from version 0.20.2 + * Fix `did_you_mean` support. + + # from version 0.20.1 + * Support new versions fo ERB. + * Fix `check_unknown_options!` to not check the content that was not parsed, i.e. after a `--` or after the first unknown with `stop_on_unknown_option!` + * Add `did_you_mean` support. + +------------------------------------------------------------------- Old: ---- thor-0.20.0.gem New: ---- thor-0.20.3.gem ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ rubygem-thor.spec ++++++ --- /var/tmp/diff_new_pack.yNC0me/_old 2018-11-20 22:43:39.882255410 +0100 +++ /var/tmp/diff_new_pack.yNC0me/_new 2018-11-20 22:43:39.886255409 +0100 @@ -1,7 +1,7 @@ # # spec file for package rubygem-thor # -# Copyright (c) 2017 SUSE LINUX GmbH, Nuernberg, Germany. +# Copyright (c) 2018 SUSE LINUX GmbH, Nuernberg, Germany. # # All modifications and additions to the file contributed by third parties # remain the property of their copyright owners, unless otherwise agreed @@ -24,7 +24,7 @@ # Name: rubygem-thor -Version: 0.20.0 +Version: 0.20.3 Release: 0 %define mod_name thor %define mod_full_name %{mod_name}-%{version} ++++++ thor-0.20.0.gem -> thor-0.20.3.gem ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/CHANGELOG.md new/CHANGELOG.md --- old/CHANGELOG.md 2017-08-16 19:50:22.000000000 +0200 +++ new/CHANGELOG.md 2018-11-10 04:00:18.000000000 +0100 @@ -1,3 +1,14 @@ +# 0.20.3 +* Support old versions of `did_you_mean`. + +# 0.20.2 +* Fix `did_you_mean` support. + +# 0.20.1 +* Support new versions fo ERB. +* Fix `check_unknown_options!` to not check the content that was not parsed, i.e. after a `--` or after the first unknown with `stop_on_unknown_option!` +* Add `did_you_mean` support. + ## 0.20.0 * Add `check_default_type!` to check if the default value of an option matches the defined type. It removes the warning on usage and gives the command authors the possibility to check for programming errors. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/README.md new/README.md --- old/README.md 2017-08-16 19:50:22.000000000 +0200 +++ new/README.md 2018-11-10 04:00:18.000000000 +0100 @@ -3,13 +3,11 @@ [![Gem Version](http://img.shields.io/gem/v/thor.svg)][gem] [![Build Status](http://img.shields.io/travis/erikhuda/thor.svg)][travis] -[![Dependency Status](http://img.shields.io/gemnasium/erikhuda/thor.svg)][gemnasium] [![Code Climate](http://img.shields.io/codeclimate/github/erikhuda/thor.svg)][codeclimate] [![Coverage Status](http://img.shields.io/coveralls/erikhuda/thor.svg)][coveralls] [gem]: https://rubygems.org/gems/thor [travis]: http://travis-ci.org/erikhuda/thor -[gemnasium]: https://gemnasium.com/erikhuda/thor [codeclimate]: https://codeclimate.com/github/erikhuda/thor [coveralls]: https://coveralls.io/r/erikhuda/thor @@ -21,7 +19,13 @@ build tool. The syntax is Rake-like, so it should be familiar to most Rake users. +Please note: Thor, by design, is a system tool created to allow seamless file and url +access, which should not receive application user input. It relies on [open-uri][open-uri], +which combined with application user input would provide a command injection attack +vector. + [rake]: https://github.com/ruby/rake +[open-uri]: https://ruby-doc.org/stdlib-2.5.1/libdoc/open-uri/rdoc/index.html Installation ------------ Binary files old/checksums.yaml.gz and new/checksums.yaml.gz differ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lib/thor/actions/file_manipulation.rb new/lib/thor/actions/file_manipulation.rb --- old/lib/thor/actions/file_manipulation.rb 2017-08-16 19:50:22.000000000 +0200 +++ new/lib/thor/actions/file_manipulation.rb 2018-11-10 04:00:18.000000000 +0100 @@ -60,6 +60,9 @@ # 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 @@ 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 @@ 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 -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lib/thor/actions.rb new/lib/thor/actions.rb --- old/lib/thor/actions.rb 2017-08-16 19:50:22.000000000 +0200 +++ new/lib/thor/actions.rb 2018-11-10 04:00:18.000000000 +0100 @@ -113,8 +113,10 @@ # 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 @@ 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 @@ 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 -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lib/thor/base.rb new/lib/thor/base.rb --- old/lib/thor/base.rb 2017-08-16 19:50:22.000000000 +0200 +++ new/lib/thor/base.rb 2018-11-10 04:00:18.000000000 +0100 @@ -113,7 +113,7 @@ end # Whenever a class inherits from Thor or Thor::Group, we should track the - # class and the file on Thor::Base. This is the method responsable for it. + # class and the file on Thor::Base. This is the method responsible for it. # def register_klass_file(klass) #:nodoc: file = caller[1].match(/(.*):\d+/)[1] @@ -466,13 +466,13 @@ dispatch(nil, given_args.dup, nil, config) rescue 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 @@ 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 -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lib/thor/error.rb new/lib/thor/error.rb --- old/lib/thor/error.rb 2017-08-16 19:50:22.000000000 +0200 +++ new/lib/thor/error.rb 2018-11-10 04:00:18.000000000 +0100 @@ -1,4 +1,23 @@ class 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 + # 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 @@ # 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 @@ 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 MalformattedArgumentError < InvocationError end + + if Correctable + DidYouMean::SPELL_CHECKERS.merge!( + 'Thor::UndefinedCommandError' => UndefinedCommandError::SpellChecker, + 'Thor::UnknownArgumentError' => UnknownArgumentError::SpellChecker + ) + end end diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lib/thor/group.rb new/lib/thor/group.rb --- old/lib/thor/group.rb 2017-08-16 19:50:22.000000000 +0200 +++ new/lib/thor/group.rb 2018-11-10 04:00:18.000000000 +0100 @@ -61,7 +61,7 @@ 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 @@ 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 -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lib/thor/parser/options.rb new/lib/thor/parser/options.rb --- old/lib/thor/parser/options.rb 2017-08-16 19:50:22.000000000 +0200 +++ new/lib/thor/parser/options.rb 2018-11-10 04:00:18.000000000 +0100 @@ -44,6 +44,7 @@ @shorts = {} @switches = {} @extra = [] + @stopped_parsing_after_extra_index = nil options.each do |option| @switches[option.switch_name] = option @@ -66,6 +67,7 @@ if result == OPTS_END shift @parsing_options = false + @stopped_parsing_after_extra_index ||= @extra.size super else result @@ -99,6 +101,7 @@ 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 @@ 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 -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lib/thor/shell/basic.rb new/lib/thor/shell/basic.rb --- old/lib/thor/shell/basic.rb 2017-08-16 19:50:22.000000000 +0200 +++ new/lib/thor/shell/basic.rb 2018-11-10 04:00:18.000000000 +0100 @@ -1,6 +1,8 @@ class Thor module Shell class Basic + DEFAULT_TERMINAL_WIDTH = 80 + attr_accessor :base attr_reader :padding @@ -45,6 +47,10 @@ # 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 @@ # ==== 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 @@ 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 @@ # # ==== 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 @@ 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 @@ 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 Thor @@ -344,6 +371,7 @@ 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 @@ 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 -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lib/thor/shell.rb new/lib/thor/shell.rb --- old/lib/thor/shell.rb 2017-08-16 19:50:22.000000000 +0200 +++ new/lib/thor/shell.rb 2018-11-10 04:00:18.000000000 +0100 @@ -55,7 +55,7 @@ # 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 -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lib/thor/util.rb new/lib/thor/util.rb --- old/lib/thor/util.rb 2017-08-16 19:50:22.000000000 +0200 +++ new/lib/thor/util.rb 2018-11-10 04:00:18.000000000 +0100 @@ -27,7 +27,7 @@ end # Receives a constant and converts it to a Thor namespace. Since Thor - # commands can be added to a sandbox, this method is also responsable for + # commands can be added to a sandbox, this method is also responsible for # removing the sandbox namespace. # # This method should not be used in general because it's used to deal with diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lib/thor/version.rb new/lib/thor/version.rb --- old/lib/thor/version.rb 2017-08-16 19:50:22.000000000 +0200 +++ new/lib/thor/version.rb 2018-11-10 04:00:18.000000000 +0100 @@ -1,3 +1,3 @@ class Thor - VERSION = "0.20.0" + VERSION = "0.20.3" end diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/metadata new/metadata --- old/metadata 2017-08-16 19:50:22.000000000 +0200 +++ new/metadata 2018-11-10 04:00:18.000000000 +0100 @@ -1,7 +1,7 @@ --- !ruby/object:Gem::Specification name: thor version: !ruby/object:Gem::Version - version: 0.20.0 + version: 0.20.3 platform: ruby authors: - Yehuda Katz @@ -9,7 +9,7 @@ autorequire: bindir: bin cert_chain: [] -date: 2017-08-16 00:00:00.000000000 Z +date: 2018-11-10 00:00:00.000000000 Z dependencies: - !ruby/object:Gem::Dependency name: bundler @@ -91,7 +91,7 @@ version: 1.3.5 requirements: [] rubyforge_project: -rubygems_version: 2.6.12 +rubygems_version: 2.7.6 signing_key: specification_version: 4 summary: Thor is a toolkit for building powerful command-line interfaces.