# Author:: The TTK Team. # Copyright:: Copyright (c) 2004 TTK team. All rights reserved. # License:: LGPL # $Id: ttk.rb 575 2005-04-14 10:22:30Z polrop $ require 'optparse' require 'module/hierarchy' require 'pp_hierarchy' module TTK module Getopts class TTK DEFAULT_OPTIONS = { :current_input => nil, :current_output => STDOUT, :current_loader => Loaders::Yaml, :current_dumper => Dumpers::Yaml, :no_default_observer => false, :observers => [], :wclass => Weights::Default, :attributes => {}, :symbols => {}, :log_severity => Logger::Severity::INFO, :log_verbosity => 0, :log_section => [], :tester_uris => [], :profile_on => false, :force_fetch => false, :dump_status => false, :cache_proc => DumpableProc.new('|test, status| status.pass? or status.is_a? TTK::SkipStatus' ) } def self.parse(argv) opts = DEFAULT_OPTIONS.dup optparser = OptionParser.new do |optparser| optparser.banner = "Usage: #{ME} [options] [files...]" optparser.summary_indent = ' ' optparser.summary_width = 25 ### IO options optparser.separator '' optparser.separator 'IO options:' optparser.on('-i', '--input FILE', 'Set input file (only a Result)') do |aFile| if aFile == '-' opts[:current_input] = STDIN else opts[:current_input] = File.new(aFile, 'r') end end optparser.on('-o', '--output FILE', 'Set output file') do |aFile| if aFile == '-' opts[:current_output] = STDOUT else opts[:current_output] = File.new(aFile, 'w') end end ### Strategy options optparser.separator '' optparser.separator 'Strategy options:' optparser.on('-I', '--include PATH', 'Set PATH for test strategy classes') do |aPath| Strategies.module_eval do aPath.split(':').each do |aPath| autoload_tree(aPath, false) do |p| ::TTK.pathname_to_class(p) end end end end optparser.on('--strategy-list', 'List all test strategy classes') do pp_class_hierarchy('Strategies::Strategy') exit end ### Loader options optparser.separator '' optparser.separator 'Loader options:' all_loaders = sub_modules(Loaders) optparser.on('-L', '--loader [TYPE]', all_loaders, 'Select a loader (no argument for the list)') do |aLoader| if aLoader.nil? pp_class_hierarchy('Loaders::Loader') exit else opts[:current_loader] = Loaders.const_get(aLoader) end end ### Dumper options optparser.separator '' optparser.separator 'Dumper options:' all_dumpers = sub_modules(Dumpers) optparser.on('-P', '--dumper [TYPE]', all_dumpers, 'Select a dumper (no argument for the list)') do |aDumper| if aDumper.nil? pp_class_hierarchy('Dumpers::Dumper') exit else opts[:current_dumper] = Dumpers.const_get(aDumper) end end ### Filter options optparser.separator '' optparser.separator 'Filter options:' all_filters = sub_modules(Filters) #FIXME: the result here is overwritten in ttk driver optparser.on('-F', '--filter [TYPE]', all_filters, 'Select a filter ' + '(no argument for the list)') do |aFilter| if aFilter.nil? pp_class_hierarchy('Filters::Filter') exit else dumper = opts[:current_dumper].new(opts[:current_output]) result = Logger.new(dumper) opts[:observers] << Filters.const_get(aFilter).new(result) end end optparser.on('--filter-seq x,y,z', Array, 'Select a filter sequence') do |anArray| dumper = opts[:current_dumper].new(opts[:current_output]) result = Logger.new(dumper) opts[:observers] << anArray.reverse_fold(result) do |aFilter,acc| Filters.const_get(aFilter).new(acc) end end ### Weight options optparser.separator '' optparser.separator 'Weight options:' optparser.on('-W', '--wclass [TYPE]', 'Select the weight class ' + '(no argument for the list)') do |aString| if aString.nil? pp_class_hierarchy('Weights::Weight') exit else opts[:wclass] = Weights.const_get(aString) end end ### Tester options optparser.separator '' optparser.separator 'Server options:' optparser.on('-t', '--tester URI', 'Remote tester uri') do |uri| opts[:tester_uris] << URI.parse(uri) end ### Logger options optparser.separator '' optparser.separator 'Logger options:' optparser.on('-l', '--log FILE', 'Set the log file') do |aFile| io = (aFile == '-') ? STDERR : File.open(aFile, 'w') opts[:observers] << opts[:current_dumper].new(io) end optparser.on('-d', '--severity [NAME]', 'Log severity level ' + '(no argument for the list)') do |level| if level.nil? puts 'Log severity level list:' Logger::Severity.labels.each { |l| puts " - #{l}" } exit else begin raise NameError if level.nil? opts[:log_severity] = Logger::Severity.const_get(level.to_s.upcase) rescue NameError raise(OptionParser::InvalidArgument, level) end end end higher_level = Logger::Verbosity.higher_level optparser.on('-v', '--verbosity NUM', "Log verbosity level [0-#{higher_level}]") do |level| ilevel = level.to_i if ilevel.to_s != level raise(OptionParser::InvalidArgument, level) end if 0 <= ilevel and ilevel <= higher_level opts[:log_verbosity] = ilevel else raise(OptionParser::InvalidArgument, level) end end optparser.on('-s', '--log-section [NAME]', 'Active a log section ' + '(no argument for the list)') do |name| if name.nil? #FIXME: print the section tree exit else #FIXME: check the validity of the section opts[:log_section] << name.to_s end end ### Miscellaneous options optparser.separator '' optparser.separator 'Miscellaneous options:' optparser.on('-S', '--symbols symbols', 'Add a hash of symbols to the root test suite') do |str| opts[:symbols] = opts[:current_loader].new.load_doc(str) end optparser.on('-A', '--attributes attributes', 'Add a hash of attributes to ' + 'the root test suite') do |aString| opts[:attributes] = opts[:current_loader].new.load_doc(aString) end optparser.on('-D', '--define VAR=VALUE', 'Set a global variable') do |aString| if aString =~ /(\w+)=(.*)$/ eval "$#$1 = $2" else STDERR.puts optparser exit end end optparser.on('-C', '--[no-]cache', 'Keep the test in cache') do |c| opts[:cache] = c end optparser.on('--cache-dir DIR', 'Use the cache in DIR') do |dir| dir = Pathname.new(dir) help unless dir.directory? opts[:cache_dir] = dir end optparser.on('-r', '--cache-proc RUBY_CODE', 'Use this block to skip tests in cache mode ' + '(ex: "|test, status| status.pass?")') do |code| help unless code =~ /^\s*|[^,]+,[^,]+|\s*\S+/ opts[:cache_proc] = DumpableProc.new(code) end optparser.on('--profile', 'Switch on profile informations') do opts[:profile_on] = true end optparser.on('--force-fetch', 'Force to fetch file even on the same host') do opts[:force_fetch] = true end optparser.on('--dump-status', 'Dump the global status at the end (STDOUT)') do opts[:dump_status] = true end optparser.on('--gen-strategies-hierarchy', 'Generate the strategies hierarchy description') do hsh = Strategies.sub_classes_tree(Strategies::Strategy, true, true) puts "# TTK's strategies hierarchy generated on #{Time.now}" YAML.dump(hierarchy_to_s(hsh), STDOUT) exit end optparser.on('--no-default-observer', 'Do not add a default observer') do opts[:no_default_observer] = true end optparser.on_tail('-h', '--help [strategy]', 'Show this message') do |aStrategy| if aStrategy.nil? STDERR.puts optparser puts <<-eof For bug reporting instructions, please see: http://www.feydakins.org/projects/ttk/tracker/base_view eof else Strategies.const_get(aStrategy).help end exit end optparser.on_tail('--version', 'Show version') do rev = 0 begin File.open('REVISION') { |io| rev = io.gets.gsub!(/\D/, '').to_i } rescue Errno::ENOENT end date = '' begin File.open('DATE') do |io| date = io.gets.sub!(/^.*?\((.*?)\).*?$/) { $1 } end rescue Errno::ENOENT end date.chomp! require 'erb' res = ERB.new(File.read('VERSION'), nil, '<%>').result(binding) puts res exit end end optparser.parse!(argv) argv << '-' if argv.empty? argv.map! { |x| x == '-' ? STDIN : Pathname.new(x) } opts end protected def self.sub_modules(mod) mod.constants.sort!.map! { |c| c.to_sym } end protected def self.pp_class_hierarchy(name) if name =~ /^(\w+)::(\w+)$/ mod = ::TTK.const_get($1) klass = mod.const_get($2) puts "#{mod} classes hierarchy:" hsh = mod.sub_classes_tree(klass, true, true) hsh.pp_hierarchy(Regexp.new("^#{mod}::"), true) end end protected def self.hierarchy_to_s(hsh) r = {} hsh.each { |k, v| r[k.to_s] = hierarchy_to_s(v) } r end end # class TTK end # module Getopts end # module TTK