require 'logger' module EY module Serverside # FileIO class Shell # Compatibility with old LoggedOutput where the module was included into the class. module Helpers def verbose? shell.verbose? end def warning(*a) shell.warning(*a) end def info(*a) shell.info(*a) end def debug(*a) shell.debug(*a) end def logged_system(*a) shell.logged_system(*a) end end class Formatter def initialize(stdout, stderr, start_time, verbose) @stdout, @stderr = stdout, stderr @start = start_time.to_i @verbose = verbose end def call(severity, time, _, message) if %w[WARN ERROR FATAL].include?(severity) msg = prepend("#{timestamp(time)}!> ", "#{severity_name(severity)}#{message}") else msg = prepend(timestamp(time), message) end put_to_io(severity, msg) msg end def prepend(pre, str) str.gsub(/^/, pre).sub(/\n?\z/m,"\n") end def put_to_io(severity, msg) if severity == "DEBUG" && !@verbose # quiet elsif severity == "INFO" @stdout << msg else @stderr << msg end end def timestamp(datetime) diff = datetime.to_i - @start diff = 0 if diff < 0 "+%2dm %02ds " % diff.divmod(60) end def severity_name(severity) if %w[INFO DEBUG ANY].include?(severity) "" elsif severity =='WARN' "WARNING: " else "#{severity}: " end end end class YieldIO def initialize(&block) @block = block end def <<(str) @block.call str end end attr_reader :logger def initialize(options) @start_time = options[:start_time] @verbose = options[:verbose] @log_pathname = Pathname.new(options[:log_path]) @log_pathname.unlink if @log_pathname.exist? # start fresh @stdout = options[:stdout] || $stdout @stderr = options[:stderr] || $stderr @logger = Logger.new(@log_pathname.to_s) @logger.level = Logger::DEBUG # Always log to the file at debug, formatter hides debug for non-verbose @logger.formatter = Formatter.new(@stdout, @stderr, start_time, @verbose) end def start_time @start_time ||= Time.now end # a nice info outputter that prepends spermy operators for some reason. def status(msg) info msg.gsub(/^/, '~> ') end # a debug outputter that displays a command being run def running(cmd) debug ":: running #{cmd}" end def fatal(msg) logger.fatal msg end def error(msg) logger.error msg end def warning(msg) logger.warn msg end def info(msg) logger.info msg end def debug(msg) logger.debug msg end def logged_system(cmd) running(cmd) # :quiet means don't raise an error on nonzero exit status status = Open4.spawn cmd, 0 => '', 1 => out, 2 => err, :quiet => true status.exitstatus == 0 end # Return an IO that outputs to stdout or not according to the verbosity settings # debug is hidden in non-verbose mode def out YieldIO.new { |msg| logger.debug(msg) } end # Return an IO that outputs to stderr # unknown always shows, but without a severity title def err YieldIO.new { |msg| logger.unknown(msg) } end end end end