https://svn.lrde.epita.fr/svn/lrdetools/trunk
Index: ChangeLog
from Nicolas Pouillard <ertai(a)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