require 'ansi' require 'logging' require 'fileutils' module BuildTool class Progressbar < Logging::Appender def initialize( title, &block ) super( 'Progressbar', :level => :DEBUG ) @pbar = nil @oldlogger = nil if Logging.appenders['stdout'].level >= ::Logging::level_num(:INFO) # We only do the progressbar thing if there is no verbose output active. begin # Remove the old stdout logger. @oldlogger = Logging.appenders[ 'stdout' ] Logging.logger[ 'root' ].remove_appenders( 'stdout' ) Logging.logger[ 'root' ].add_appenders( self ) # Add the progressbar logger @pbar = ANSI::Progressbar.new( title, 100 ) yield ensure @pbar.finish # Reset the logger Logging.logger[ 'root' ].remove_appenders( 'Progressbar' ) Logging.logger[ 'root' ].add_appenders( @oldlogger ) end else # If there is verbose output just print the text logger.info( title ) yield end end def write( event ) message = event.data return if message.empty? case event.level when ::Logging::level_num( :ERROR ) when ::Logging::level_num( :WARN ) # This should never happen. In case of errors an exception is thrown which should # be catched in the initialize() method above. And this logger is removed there. raise NotImplementedError else match = /^\[ *(\d+)%\]/.match( message ) if match # puts match[ 1 ] @pbar.set( match[ 1 ].to_i ) end end self end end # class ProgressLayout module ModuleActions class Base def initialize( command, prio, type, mod ) @command = command @level = nil @logdir = command.log_directory.join( mod.name ) @type = type @prio = prio @filename = "#{prio.to_s}_#{type.to_s}" @logfile = @logdir.join( @filename ) @module = mod end def do # Make sure the directory for this module exists FileUtils.mkdir_p( @logdir ) if ! $noop oldlevel = Logging.appenders['stdout'].level if @level Logging.appenders['stdout'].level = @level end # Open the logfile and then execute the command begin while_logging do execute end ensure Logging.appenders['stdout'].level = oldlevel end end ######### protected ######### def while_logging( level = :trace, &block ) # Only create a logfile if we do real work if !$noop Logging.logger['root'].add_appenders( Logging.appenders.file( @filename, :filename => @logfile, :layout => Logging::Layouts::Pattern.new( :pattern => '%m\n' ), :level => level )) end begin # If there is an associated command_history entry, add a module_event entry logentry = nil state = History::ModuleLog::FINISHED_SUCCESSFUL if @command.cmd logentry = History::ModuleLog.new( :module => @module.name, :event => @type, :logfile => @logfile) @command.cmd.add_module_log(logentry) logentry.started end logger.debug "Opening logfile #{@logfile}" yield rescue Interrupt => e state = History::ModuleLog::CANCELED_BY_USER logger.error "User Interrupt!" raise e rescue Exception => e state = History::ModuleLog::FINISHED_WITH_ERRORS logger.error "#{e.class}:#{e.message}" got_exception = true raise e ensure if logentry logentry.finished( state ) end Logging.logger['root'].remove_appenders( @filename ) logger.debug "Closing logfile #{@logfile}" logger.info("More information in #{@logfile}") if got_exception end end end class Clean < Base def initialize( command, mod, remove_build_directory ) super( command, 10, :clean, mod ) @remove_build_directory = remove_build_directory end def execute() logger.info "Cleaning" @module.clean( @remove_build_directory ) end end class Clone < Base def initialize( command, mod ) super( command, 20, :fetch, mod ) end def execute() logger.info "Fetching" @module.clone end end class Fetch < Base def initialize( command, mod ) super( command, 20, :fetch, mod ) if !mod.vcs_required.fetching_supported? logger.info "Fetching/Rebase not supported by vcs #{mod.vcs.name}. Doing it in one step." end end def execute() logger.info "Fetching remote changes." @module.fetch end end class Rebase < Base def initialize( command, mod ) super( command, 20, :rebase, mod ) if !mod.vcs_required.fetching_supported? logger.info "Fetching not supported by vcs #{mod.vcs.name}. Doing nothing." return end end def execute() logger.info "Rebasing" @module.rebase end end class Configure < Base def initialize( command, mod ) super( command, 40, :configure, mod ) end def execute() logger.info "Configuring" if !$noop and !@module.vcs_required.checkedout? raise ConfigurationError, "Module is not checked out. Enable updating." end @module.configure end end class Reconfigure < Base def initialize( command, mod ) super( command, 40, :reconfigure, mod ) end def execute() logger.info "Reconfiguring" if !$noop and !@module.vcs_required.checkedout? raise ConfigurationError, "Module is not checked out. Enable updating." end @module.build_system_required.reconfigure end end class Make < Base def initialize( command, mod, target = nil ) super( command, 50, :compile, mod ) @target = target end def execute() pb = Progressbar.new( "Make #{@target}" ) do @module.build_system_required.make( @target ) end end end class Install < Base def initialize( command, mod, fast = false ) super( command, 60, :install, mod ) @fast = fast end def execute() pb = Progressbar.new( "Install #{@fast ? 'fast' : '' }" ) do @module.build_system_required.install( @fast ) end end end end # module ModuleAction end # module BuildTool