lib/gdk/output.rb (134 lines of code) (raw):

# frozen_string_literal: true module GDK module Output COLOR_CODE_RED = '31' COLOR_CODE_GREEN = '32' COLOR_CODE_YELLOW = '33' COLOR_CODE_BLUE = '34' COLOR_CODE_BRIGHT_BLACK = '90' COLORS = { red: COLOR_CODE_RED, green: COLOR_CODE_GREEN, yellow: COLOR_CODE_YELLOW, blue: COLOR_CODE_BLUE, magenta: '35', cyan: '36', bright_red: '31;1', bright_green: '32;1', bright_yellow: '33;1', bright_blue: '34;1', bright_magenta: '35;1', bright_cyan: '36;1' }.freeze ICONS = { info: "\u2139\ufe0f ", # requires an extra space success: "\u2705\ufe0f", warning: "\u26A0\ufe0f ", # requires an extra space error: "\u274C\ufe0f", debug: "\u26CF\ufe0f " # requires an extra space }.freeze def self.included(klass) klass.extend(ClassMethods) end module ClassMethods def ensure_utf8(str) return '' if str.nil? return str unless str.is_a?(String) str = force_encode_utf8(str) return str if str.valid_encoding? str.encode('UTF-8', invalid: :replace, undef: :replace) end # Borrowed from https://gitlab.com/gitlab-org/gitlab/-/blob/0a06e1dcb2474f866e2f335cee2d0cb3c6886db3/lib/gitlab/encoding_helper.rb#L165-172 def force_encode_utf8(message) return message if message.encoding == Encoding::UTF_8 && message.valid_encoding? message = message.dup if message.respond_to?(:frozen?) && message.frozen? message.force_encoding('UTF-8') end def color(index) COLORS.values[index % COLORS.size] end def ansi(code) "\e[#{code}m" end def reset_color ansi(0) end def wrap_in_color(message, color_code) return message unless colorize? "#{ansi(color_code)}#{ensure_utf8(message)}#{reset_color}" end def format_log(log_level, color_code, message) message = ensure_utf8(message) "#{icon(log_level)}#{wrap_in_color(log_level.upcase, color_code)}: #{message}" end def stdout_handle return Support::Rake::TaskLogger.current.file if Support::Rake::TaskLogger.current $stdout.tap { |handle| handle.sync = true } end def stderr_handle return Support::Rake::TaskLogger.current.file if Support::Rake::TaskLogger.current $stderr.tap { |handle| handle.sync = true } end def print(message = nil, stderr: false) output = stderr ? stderr_handle : stdout_handle output.print(ensure_utf8(message)) rescue IOError end def puts(message = nil, stderr: false) output = stderr ? stderr_handle : stdout_handle output.puts(ensure_utf8(message)) end def divider(symbol: '-', length: 80, stderr: false) puts(symbol * length, stderr: stderr) end def notice(message) puts(notice_format(message)) end def notice_format(message) "=> #{message}" end def info(message) puts(icon(:info) + message) end def warn(message) puts(format_log(:warning, COLOR_CODE_YELLOW, message), stderr: true) end def debug(message) return unless GDK.config.gdk.__debug? puts(format_log(:debug, COLOR_CODE_BLUE, message), stderr: true) end def format_error(message) format_log(:error, COLOR_CODE_RED, message) end def error(message, exception = nil, report_error: true) Telemetry.capture_exception(exception || message) if report_error puts(format_error(message), stderr: true) end def abort(message, exception = nil, report_error: true) Telemetry.capture_exception(exception || message) if report_error Kernel.abort(format_error(message)) end def success(message) puts(icon(:success) + message) end def icon(code) return '' unless colorize? "#{ICONS[code]} " end def interactive? $stdin.isatty end def colorize? interactive? && ENV.fetch('NO_COLOR', '').empty? end def prompt(message) Kernel.print("#{message}: ") $stdout.flush raise 'Interactive terminal not available, aborting.' unless interactive? $stdin.gets.to_s.chomp rescue Interrupt '' end end extend ClassMethods include ClassMethods end end