require 'thor' require_relative '../sbuilder' module Sbuilder class Cli < Thor include Sbuilder::Utils::MyLogger # mix logger PROGNAME = "main" # logger progname VERSION_BANNER = <<-EOS.unindent #{File.basename $0} - #{Sbuilder::version} EOS # ------------------------------------------------------------------ # make two thor tasks share options? # http://stackoverflow.com/questions/14346285/how-to-make-two-thor-tasks-share-options class << self def add_shared_option(name, options = {}) @shared_options = {} if @shared_options.nil? @shared_options[name] = options end def shared_options(*option_names) option_names.each do |option_name| opt = @shared_options[option_name] raise "Tried to access shared option '#{option_name}' but it was not previously defined" if opt.nil? yield option_name, opt if block_given? option option_name, opt end end end # ------------------------------------------------------------------ # constructore def initialize(*args) super @logger = getLogger( PROGNAME, options ) end # ------------------------------------------------------------------ # class options class_option :log, :aliases => "-l", :type =>:string, :default => nil, :enum => [ "DEBUG", "INFO", "WARN", "ERROR" ], :desc => "Set debug level " class_option :logfile, :type =>:string, :default => File.join(Dir.getwd, Sbuilder::Constants::LOGFILE), :desc => "Set file for log output" # ------------------------------------------------------------------ # shared options add_shared_option :verbosity, :aliases => "-v", :type =>:numeric, :default => Sbuilder::Constants::OPT_VERBOSITY, :desc => "Output verbosity range 0-2 (nothing- a lot)" add_shared_option :cnf_dir, :aliases => "-C", :type =>:string, :default => Sbuilder::Constants::CNF_DIR, :desc => "Configuration directory" add_shared_option :src_dir, :aliases => "-S", :type =>:string, :default => Sbuilder::Constants::SRC_DIR, :desc => "Source directory for TLA+ snippets" add_shared_option :gen_dir, :aliases => "-G", :type =>:string, :default => Sbuilder::Constants::GEN_DIR, :desc => "Generation output directory" add_shared_option :cache_dir, :aliases => "-T", :type =>:string, :default => Sbuilder::Constants::CACHE_DIR, :desc => "Cache directory" add_shared_option :templates, :aliases => "-t", :type => :array, :default => [Sbuilder::Constants::SRC_PATH, Sbuilder::Constants::TEMPLATE_PATH], :desc => "Location of TLA+ snippets (accessible in template generation)" add_shared_option :default_templates, :aliases => "-d", :type => :array, :default => [Sbuilder::Constants::TEMPLATE_GEM], :desc => "Location of (default) GEM templates" add_shared_option :cnf_file, :aliases => "-c", :type => :string, :default => Sbuilder::Constants::CNF_FILE, :desc => "Main configuration file (in [--cnf-dir])" # ------------------------------------------------------------------ # require after shared options added, before subcommand require_relative 'cli-example' # ------------------------------------------------------------------ # action 'config' desc "example SUBCOMMAND", "Configuration instructions" shared_options :cnf_dir shared_options :src_dir shared_options :verbosity subcommand "example", Example # # ------------------------------------------------------------------ # # # require_relative 'cli-unmustache' # desc "unmustache", "Preprocess mustache files" # shared_options :src_dir # shared_options :cache_dir # subcommand "unmustache", Unmustache # ------------------------------------------------------------------ # action load # desc :load, "Load configurations" # def load() # ctrl = getController( options ) # ctrl.load # end # make default task to be version default_task :version # ------------------------------------------------------------------ # action init - create directories desc :extend, "Create TLA extension templates under '/extend' directory, and application templates into '' directory" shared_options :src_dir option :benchmark, :aliases => "-b", :type =>:string, :default => nil, :desc => "Include mustache partial call to benchmark directories into TLA template" def extend() Dir.glob( File.join File.dirname( __FILE__), "../../src-extend/extend/extend_*.*" ).each do |extendTemplate| extend_files( "#{options[:src_dir]}/extend", extendTemplate, options[:benchmark] ) end Dir.glob( File.join File.dirname( __FILE__), "../../src-extend/extend_app/*" ).each do |extendTemplate| extend_files( "#{options[:src_dir]}", extendTemplate ) end end # ------------------------------------------------------------------ # action init - create directories desc :version, "Output version" def version() puts VERSION_BANNER end # ------------------------------------------------------------------ # action init - create directories desc :init, "Init configuration directories" shared_options :cnf_dir shared_options :src_dir shared_options :cache_dir shared_options :gen_dir def init() init_dirs( options ) init_files( options ) end # init desc "generate [SETUP]", "Generates specification for [SETUP], defaults all setups" shared_options :templates shared_options :default_templates shared_options :verbosity shared_options :cnf_dir shared_options :cnf_file # shared_options :src_dir shared_options :cache_dir shared_options :gen_dir option :filter_src, :aliases => "-f", :type => :boolean, :default => false, :desc => "Filter files TLA+ specification code, false-> no filter->include all snippets" option :filter_list, :aliases => "-F", :type => :string, :default => nil, :desc => "List of files to include in TLA+ specification code" def generate( setupDirectory=nil) ctrl = getController( options ) ctrl.setup( setupDirectory ) end # ------------------------------------------------------------------ # list desc "list setups", "Lists setup" shared_options :verbosity shared_options :cnf_dir def list( what ) validateWhats( what ) ctrl = getCtrl # puts "#{ctrl.getSetups().map { |setup| setup['setupDirectory']}.join(' ')}" puts "#{getSetupNames(ctrl).join(' ')}" end desc "document [setup]", "Document configuration for all setups or for the given setup" shared_options :verbosity shared_options :cnf_dir def document( what=nil ) controller = getCtrl controller.load validateWhats( what, getSetupNames(controller) ) if what invariants = controller.templateData('invariants')['invariants'] puts "INVARIANTS:" invariants.each do |invariant| puts <<-EOS.unindent - #{invariant[:name]}: #{invariant[:desc]} EOS end puts "SETUPS:" controller.processSetups( what ) do |setupName, setupConf, possibilities| assumptions = controller.getSetupAssumptionList( setupConf ) puts <<-EOS.unindent - #{setupName}: #{setupConf['desc']} - possibilities: #{(setupConf['possibilities'] || [] ).join( ' ' )} - assumptions: #{assumptions.join( ' ' )} - interfaces: #{controller.templateData('steps' )['steps'].map {|step| step[:interface_operation] }.uniq.join( ' ' )} EOS end end # ------------------------------------------------------------------ # common routines no_commands do # ensure that 'what' is correct def validateWhats( what, whats = [ "setups", "setup" ] ) raise <<-EOS unless whats.include?( what ) Unknown target '#{what}' Valid targets: #{whats.join(',')} EOS end # @return [Sbuilder::Controller] contrller, which has loader configurations def getCtrl ctrl = getController( options ) return ctrl end # Copy 'extendFile' file to 'dirPath', append {{>benchmark/basename(extendFile}} # # @param dirPath [String] directory where extension file created # @param extendFile [String] path to file, which copy to 'dirPath' # @param benchmark [String] optional benchmark directory where load partial templates def extend_files( dirPath, extendFile, benchmark=nil ) raise "No such directory /extend (#{dirPath})" unless File.exist?( dirPath ) @logger.info( "#{__method__} extend file=#{File.basename( extendFile )}" ) targetPath = "#{dirPath}/#{File.basename( extendFile )}" msg = "Extension template #{targetPath}" if File.exists?( targetPath) then msg += " already exists - not created" else msg += " does not exist - created" FileUtils.cp( extendFile, targetPath ) if benchmark then partial_call = <<-EOS {{! Benchmark option in extend command defined --> added call to partial in benchmark directory }} {{>#{benchmark}/benchmark-#{File.basename(extendFile)} }} EOS # append mustache partitial call open( targetPath, 'a' ) { |f| f.puts( partial_call ) } end end @logger.info( "#{__method__} #{msg}" ) puts msg end # @param controller [Sbuilder::Controller] controller to read the setups # @return [String:Array] names of setups defined in 'ctrl' def getSetupNames( ctrl ) ctrl.getSetups().map { |setup| setup['setupDirectory'] } end # ------------------------------------------------------------------ def init_files( options ) [ { :file => "#{options[:cnf_dir]}/#{Sbuilder::Constants::CNF_FILE }.example", :content => [ Sbuilder::CliCustomer::SBUILDER_YAML_CUSTOMER] }, { :file => "#{options[:cnf_dir]}/#{Sbuilder::CliCustomer::FILE_RESOLVER_CUSTOMER}.example", :content => [ Sbuilder::CliCustomer::RESOLVER_CUSTOMER] }, { :file => "#{options[:cnf_dir]}/#{Sbuilder::CliCustomer::FILE_EXTENSIONS_CUSTOMER_COMMON}.example", :content => [Sbuilder::CliCustomer::EXTENSIONS_CUSTOMER_COMMON] }, { :file => "#{options[:cnf_dir]}/#{Sbuilder::CliCustomer::FILE_EXTENSIONS_CUSTOMER_IF}.example", :content => [Sbuilder::CliCustomer::EXTENSIONS_CUSTOMER_IF] }, { :file => "#{options[:cnf_dir]}/#{Sbuilder::CliCustomer::FILE_EXTENSIONS_CUSTOMER_RUN1}.example", :content => [Sbuilder::CliCustomer::EXTENSIONS_CUSTOMER_RUN1] }, { :file => "#{options[:cnf_dir]}/#{Sbuilder::CliCustomer::FILE_EXTENSIONS_CUSTOMER_RUN2}.example", :content => [Sbuilder::CliCustomer::EXTENSIONS_CUSTOMER_RUN2] }, { :file => "#{options[:cnf_dir]}/#{Sbuilder::CliCustomer::FILE_INTERFACE_CUSTOMER}.example", :content => [Sbuilder::CliCustomer::INTERFACE_CUSTOMER_SWAGGER] }, ].each do |example| puts "File #{example[:file]} - created" File.open( example[:file] ,'w' ) { |f| example[:content].each { |lines| f.write( lines )} } end end # init files # ------------------------------------------------------------------ # def init_dirs( options ) [ options[:cnf_dir], options[:cache_dir], options[:src_dir], "#{options[:src_dir]}/extend", options[:gen_dir], ].each do |dir| if ! File.exists?( dir ) then puts "Directory #{dir} - created" Dir.mkdir( dir ) else puts "Directory #{dir} - already exists - no need to create" end end end # init dirs # DRY method to get controller def getController( opts ) Sbuilder::Controller.new( getFactory( opts ), opts ) end # DRY method to get factory def getFactory( opts ) Sbuilder::Factory.getFactory( opts ) end end # no_command end # class Cli end # module