[LrdeTools] 243: Properly handle switches.

https://svn.lrde.epita.fr/svn/lrdetools/trunk Index: ChangeLog from Nicolas Pouillard <ertai@lrde.epita.fr> Properly handle switches. * vcs/lib/vcs/vcs.rb: Add `run_argv', and to classes for options `Switch' and `OptionController'. * vcs/lib/vcs/app.rb: Simplify using `run_argv'. * vcs/lib/vcs/svn.rb: Add a specification of the Svn switches list. app.rb | 10 ----- svn.rb | 45 +++++++++++++++++++++++++ vcs.rb | 114 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 160 insertions(+), 9 deletions(-) Index: vcs/lib/vcs/app.rb --- vcs/lib/vcs/app.rb (revision 242) +++ vcs/lib/vcs/app.rb (working copy) @@ -106,15 +106,7 @@ ".head_cut! exit end - vcs = @@all_vcs[Vcs.default.to_s.downcase.to_sym].new - - if ARGV.empty? - meth = :help! - else - meth = ARGV.shift.sub(/([^!])$/, '\1!') - end - - vcs.send(meth, *ARGV) + vcs = @@all_vcs[Vcs.default.to_s.downcase.to_sym].new.run_argv(ARGV) rescue SystemExit => ex raise ex Index: vcs/lib/vcs/svn.rb --- vcs/lib/vcs/svn.rb (revision 242) +++ vcs/lib/vcs/svn.rb (working copy) @@ -17,4 +17,49 @@ add_basic_method(m) end + self.option_controller = OptionController.new Svn, %q[ + --auto-props + --config-dir DIR + --diff-cmd CMD + --diff3-cmd CMD + --dry-run + --editor-cmd CMD + --encoding ENC + --extensions (-x) ARGS + --file (-F) FILENAME + --force + --force-log + --help (-h or -?) + --ignore-ancestry + --ignore-externals + --incremental + --limit NUM {Integer} + --message (-m) MESSAGE + --new ARG + --no-auth-cache + --no-auto-props + --no-diff-added + --no-diff-deleted + --no-ignore + --no-unlock + --non-interactive + --non-recursive (-N) + --notice-ancestry + --old ARG + --password PASS + --quiet (-q) + --recursive (-R) + --relocate FROM TO [PATH...] + --revision (-r) REV {Integer} + --revprop + --show-updates (-u) + --stop-on-copy + --strict + --targets FILENAME + --username NAME + --verbose (-v) + --version + --xml + ] + end # class Svn Index: vcs/lib/vcs/vcs.rb --- vcs/lib/vcs/vcs.rb (revision 242) +++ vcs/lib/vcs/vcs.rb (working copy) @@ -45,6 +45,7 @@ cattr_accessor :user_conf cattr_accessor :output_io_methods cattr_accessor :logger + class_inheritable_accessor :option_controller class Logger < ::Logger @@ -121,6 +122,98 @@ end # class VcsCmdDataFactory + + + class Switch + cattr_reader :shortcuts + attr_reader :name, :shortcuts, :argument + + @@re ||= + /^ + \s* + --([\w-]+) # The option (--foo) + \s* + (?: \( + (-\w) # A shortcut (-f) + (?:\sor\s(-(?:\?|\w)))? # Another one (-f or -o) + \) + )? + (.*?) # An argument (--foo NUM) + \s* + (?:\{(.*)\})? # A type (--foo NUM {Integer}) + $/x + + def initialize ( aString ) + match = @@re.match(aString) + raise "Cannot parse switch: `#{aString}'" if match.nil? + @name, @argument, @type = match[1], match[4], match[5] + @type = eval(@type) unless @type.nil? + @shortcuts = match[2..3].compact + end + + def to_s + '--' + @name + end + + def to_a_for_option_parser + @shortcuts + ["--#@name#@argument", @type].compact + end + + def to_sym + @name.gsub('-', '_').to_sym + end + + end # class Switch + + + + class OptionController + + attr_reader :switches, :shortcuts, :vcs_name, :option_parser, :options + protected :options + + def initialize ( aVcsClass, aString ) + Vcs.logger.debug { "Creating an option_controller for #{aVcsClass}..." } + @switches = [] + @shortcuts = {} + aString.each_line do |line| + next if line.blank? + switch = Switch.new(line) + @switches << switch + switch.shortcuts.each do |shortcut| + @shortcuts[shortcut] = switch.name + end + end + @option_parser = OptionParser.new do |o| + o.banner = "Type '#{$0} help' for usage." + o.separator '' + @switches.each do |switch| + o.on(*switch.to_a_for_option_parser) do |a, *b| + raise unless b.empty? + options[switch.to_sym] = a + end + end + end + Vcs.logger.debug { @option_parser.to_s } + end + + def parse ( argv ) + @options = {} + [@options, @option_parser.parse(argv)] + end + + def short_to_long ( short_option ) + @shortcuts[short_option] + end + + def to_strings ( name, value ) + option = '--' + name.gsub('_', '-') + [option, value.to_s] + end + + end # class OptionController + + def initialize ( aCmd ) @cmd = aCmd.to_cmd @handlers = Set.new @@ -210,6 +303,16 @@ def run! ( *args ) flush + cmd_args = [] + args.flatten.map do |arg| + if arg.is_a? Hash + arg.each do |k, v| + cmd_args += option_controller.to_strings(k, v) + end + else + cmd_args << arg + end + end (@cmd + args).run(@runner) end @@ -254,6 +357,17 @@ end end + def run_argv ( argv ) + options, new_argv = option_controller.parse(argv) + logger.debug { "options: #{options.inspect}, argv: #{new_argv}" } + if new_argv.empty? + meth = :help! + else + meth = new_argv.shift.sub(/([^!])$/, '\1!') + end + send(meth, *new_argv) + end + %w[ checkout delete diff status log add update commit ].each do |m| add_basic_method(m) end
participants (1)
-
Nicolas Pouillard