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