<commit_before>require 'io/console'
require 'term/ansicolor'

module SSHKit
  module Formatter
    class Abbreviated < SSHKit::Formatter::Abstract

      class NoColor
        def method_missing(color, string)
          return string
        end
      end

      def initialize(io)
        super

        @log_file = fetch(:fiftyfive_log_file) || "capistrano.log"
        @log_file_formatter = SSHKit::Formatter::Pretty.new(
          ::Logger.new("log/capistrano.log", 1, 20971520)
        )
      end

      def write(obj)
        unless log_started?
          original_output << "Using abbreviated format. " +
                             "Full cap output is being written to " +
                             c.blue(@log_file) + ".\n"
        end

        @log_file_formatter << obj

        case obj
        when SSHKit::Command    then write_command(obj)
        when SSHKit::LogMessage then write_log_message(obj)
        else
          original_output << "Output formatter doesn't know how to handle #{obj.class}\n"
        end
      end
      alias :<< :write

      private

      def write_command(command)
        return unless command.verbosity > SSHKit::Logger::DEBUG

        if new_command?(command) && ! command.started?
          original_output << command_description(command) + "\n"
        elsif command.finished?
          original_output << command_status_message(command) + "\n"
        end
      end

      def write_log_message(log_message)
        return unless log_message.verbosity > SSHKit::Logger::INFO
        original_output << log_message
      end

      def command_description(command)
        rows, columns = if original_output.tty?
          IO.console.winsize
        else
          [20, 80]
        end

        width = columns - 6

        desc = command.to_s.sub(%r(^/usr/bin/env ), "")
        if desc.length > width
          desc = desc[0...(width-1)] + "…"
        end

        clock + c.yellow(desc)
      end

      def command_status_message(command)
        prefix = "     "
        host = c.blue(command.host.to_s)
        elapsed = c.faint(sprintf("%5.3fs", command.runtime))

        status = if command.failure?
          c.red("✘ (see #{@log_file} for details)")
        else
          c.green("✔")
        end

        [prefix, status, host, elapsed].join(" ")
      end

      def clock
        @start_at ||= Time.now
        duration = Time.now - @start_at

        minutes = (duration / 60).to_i
        seconds = (duration - minutes * 60).to_i

        "%02d:%02d " % [minutes, seconds]
      end

      def c
        @c ||= if original_output.tty?
          Term::ANSIColor
        else
          NoColor.new
        end
      end

      def new_command?(command)
        if @last_commmand_s == command.to_s
          false
        else
          @last_commmand_s = command.to_s
          true
        end
      end

      def log_started?
        if @log_started
          true
        else
          @log_started = true
          false
        end
      end
    end
  end
end<commit_msg>Add rake task to output and refactor<commit_after>require 'io/console'
require 'term/ansicolor'

module SSHKit
  module Formatter
    class Abbreviated < SSHKit::Formatter::Abstract

      class NoColor
        def method_missing(color, string)
          return string
        end
      end

      class << self
        attr_accessor :current_task

        def monkey_patch_rake_task!
          return if @rake_patched

          eval(<<-EVAL)
            class ::Rake::Task
              alias :_original_execute_cap55 :execute
              def execute(args=nil)
                SSHKit::Formatter::Abbreviated.current_task = name
                _original_execute_cap55(args)
              end
            end
          EVAL

          @rake_patched = true
        end
      end

      def initialize(io)
        super

        self.class.monkey_patch_rake_task!

        @log_file = fetch(:fiftyfive_log_file) || "capistrano.log"
        @log_file_formatter = SSHKit::Formatter::Pretty.new(
          ::Logger.new("log/capistrano.log", 1, 20971520)
        )

        original_output << "Using abbreviated format. " +
                           "Full cap output is being written to " +
                           c.blue(@log_file) + ".\n"
      end

      def write(obj)
        @log_file_formatter << obj

        case obj
        when SSHKit::Command    then write_command(obj)
        when SSHKit::LogMessage then write_log_message(obj)
        else
          original_output << "Output formatter doesn't know how to handle #{obj.class}\n"
        end
      end
      alias :<< :write

      private

      def write_command(command)
        return unless command.verbosity > SSHKit::Logger::DEBUG

        write_clock_and_current_task_once
        write_command_once(command)

        if command.finished?
          write_command_finished(command)
        end
      end

      def write_clock_and_current_task_once
        task = self.class.current_task
        return if @last_written_task == task
        @last_written_task = task

        original_output << clock + c.blue(task) + "\n"
      end

      def write_command_once(cmd, prefix="      ")
        cmd_str = prefix + cmd.to_s.sub(%r(^/usr/bin/env ), "")
        return if @last_commmand_s == cmd_str
        @last_commmand_s = cmd_str

        cmd_str = truncate_to_console(cmd_str)
        original_output << c.yellow(cmd_str) + "\n"
      end

      def write_command_finished(command, prefix="      ")
        host = command.host.to_s
        elapsed = c.faint(sprintf(" %5.3fs", command.runtime))

        status = if command.failure?
          c.red("✘ #{host} (see #{@log_file} for details)")
        else
          c.green("✔ #{host}")
        end

        original_output << prefix + status + elapsed + "\n"
      end

      def write_log_message(log_message)
        return unless log_message.verbosity > SSHKit::Logger::INFO
        original_output << log_message + "\n"
      end

      def truncate_to_console(str)
        rows, columns = if original_output.tty?
          IO.console.winsize
        else
          [20, 80]
        end

        str.length <= columns ? str : str[0...(columns-1)] + "…"
      end

      def clock
        @start_at ||= Time.now
        duration = Time.now - @start_at

        minutes = (duration / 60).to_i
        seconds = (duration - minutes * 60).to_i

        "%02d:%02d " % [minutes, seconds]
      end

      def c
        @c ||= if original_output.tty?
          Term::ANSIColor
        else
          NoColor.new
        end
      end
    end
  end
end
{'fraction_non_alphanumeric': 0.09435386473429952, 'fraction_numerical': 0.008303140096618358, 'mean_word_length': 1.7444076222038112, 'pattern_counts': {'":': 0, '<': 40, '<?xml version=': 0, '>': 8, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6183259', 'n_tokens_mistral': 2041, 'n_tokens_neox': 1920, 'n_words': 448}