diff options
Diffstat (limited to 'vespaclient/src/perl/lib/Yahoo/Vespa/ConsoleOutput.pm')
-rw-r--r-- | vespaclient/src/perl/lib/Yahoo/Vespa/ConsoleOutput.pm | 331 |
1 files changed, 0 insertions, 331 deletions
diff --git a/vespaclient/src/perl/lib/Yahoo/Vespa/ConsoleOutput.pm b/vespaclient/src/perl/lib/Yahoo/Vespa/ConsoleOutput.pm deleted file mode 100644 index 60db964e7f7..00000000000 --- a/vespaclient/src/perl/lib/Yahoo/Vespa/ConsoleOutput.pm +++ /dev/null @@ -1,331 +0,0 @@ -# Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -# -# Output handler -# -# Intentions: -# - Make it easy for unit tests to redirect output. -# - Allow programmers to add all sorts of debug information into tools usable -# for debugging, while hiding it by default for real users. -# - Allow generic functionality that can be reused by all. For instance color -# coding of very important information. -# -# Ideas for improvement: -# - Could possibly detect terminal width and do proper line breaking of long -# lines -# -# A note about colors: -# - This module will detect if terminal supports colors. If not, it will not -# print any. (Color support can be turned off by giving --nocolors argument -# through argument parser, by setting a TERM value that does not support -# colors or programmatically call setUseAnsiColors(0). -# - Currently only red and grey are used in addition to default. These colors -# should work well for both light and dark backgrounds. -# - -package Yahoo::Vespa::ConsoleOutput; - -use strict; -use warnings; -use Yahoo::Vespa::Utils; - -BEGIN { # - Define exports for modul - use base 'Exporter'; - our @EXPORT = qw( - printResult printError printWarning printInfo printDebug printSpam - enableAutomaticLineBreaks - COLOR_RESET COLOR_WARN COLOR_ERR COLOR_ANON - ); - our @EXPORT_OK = qw( - getTerminalWidth getVerbosity usingAnsiColors ansiColorsSupported - setVerbosity - ); -} - -my %TYPES = ( - 'result' => 0, # Output from a tool. Expected when app runs successfully. - 'error' => 1, # Error found, typically aborting the script with a failure. - 'warning' => 2, # An issue that may or may not cause the program to fail. - 'info' => 3, # Useful information to get from the script. - 'debug' => 4, # Debug information useful to debug script or to see - # internals of what is happening. - 'spam' => 5, # Spammy information used when large amounts of details is - # wanted. Typically to debug some failure. -); -my $VERBOSITY; # Current verbosity level -my $ANSI_COLORS_SUPPORTED; # True if terminal supports colors -my $ANSI_COLORS; # True if we want to use colors (and support it) -my %ATTRIBUTE_PREFIX; # Ansi escape prefixes for verbosity levels -my %ATTRIBUTE_POSTFIX; # Ansi escape postfixes for verbosity levels -my %OUTPUT_STREAM; # Where to write different verbosity levels (stdout|stderr) -my $TERMINAL_WIDTH; # With of terminal in columns -my $COLUMN_POSITION; # Current index of cursor in terminal -my $ENABLE_AUTO_LINE_BREAKS; - -use constant COLOR_RESET => "\e[0m"; -use constant COLOR_ERR => "\e[91m"; -use constant COLOR_WARN => "\e[93m"; -use constant COLOR_ANON => "\e[90m"; - -&initialize(*STDOUT, *STDERR); - -return 1; - -########################## Default exported functions ######################## - -sub printResult { # (Output...) - printAtLevel('result', @_); -} -sub printError { # (Output...) - printAtLevel('error', @_); -} -sub printWarning { # (Output...) - printAtLevel('warning', @_); -} -sub printInfo { # (Output...) - printAtLevel('info', @_); -} -sub printDebug { # (Output...) - printAtLevel('debug', @_); -} -sub printSpam { # (Output...) - printAtLevel('spam', @_); -} -sub enableAutomaticLineBreaks { # (Bool) -> (OldValue) - my $oldval = $ENABLE_AUTO_LINE_BREAKS; - $ENABLE_AUTO_LINE_BREAKS = ($_[0] ? 1 : 0); - return $oldval; -} - -######################## Optionally exported functions ####################### - -sub getTerminalWidth { # () -> ColumnCount - # May be undefined if someone prints before initialized - return (defined $TERMINAL_WIDTH ? $TERMINAL_WIDTH : 80); -} -sub getVerbosity { # () -> VerbosityLevel - return $VERBOSITY; -} -sub usingAnsiColors { # () -> Bool - return $ANSI_COLORS; -} -sub ansiColorsSupported { # () -> Bool - return $ANSI_COLORS_SUPPORTED; -} -sub setVerbosity { # (VerbosityLevel) - $VERBOSITY = $_[0]; -} - -################## Functions for unit tests to mock internals ################ - -sub setTerminalWidth { # (ColumnCount) - $TERMINAL_WIDTH = $_[0]; -} -sub setUseAnsiColors { # (Bool) - if ($ANSI_COLORS_SUPPORTED && $_[0]) { - $ANSI_COLORS = 1; - } else { - $ANSI_COLORS = 0; - } -} - -############## Utility functions - Not intended for external use ############# - -sub initialize { # () - my ($stdout, $stderr, $use_colors_by_default) = @_; - if (!defined $VERBOSITY) { - $VERBOSITY = &getDefaultVerbosity(); - } - $COLUMN_POSITION = 0; - $ENABLE_AUTO_LINE_BREAKS = 1; - %ATTRIBUTE_PREFIX = map { $_ => '' } keys %TYPES; - %ATTRIBUTE_POSTFIX = map { $_ => '' } keys %TYPES; - &setAttribute('error', COLOR_ERR, COLOR_RESET); - &setAttribute('warning', COLOR_WARN, COLOR_RESET); - &setAttribute('debug', COLOR_ANON, COLOR_RESET); - &setAttribute('spam', COLOR_ANON, COLOR_RESET); - %OUTPUT_STREAM = map { $_ => $stdout } keys %TYPES; - $OUTPUT_STREAM{'error'} = $stderr; - $OUTPUT_STREAM{'warning'} = $stderr; - if (defined $use_colors_by_default) { - $ANSI_COLORS_SUPPORTED = $use_colors_by_default; - $ANSI_COLORS = $ANSI_COLORS_SUPPORTED; - } else { - &detectTerminalColorSupport(); - } - if (!defined $TERMINAL_WIDTH) { - $TERMINAL_WIDTH = &detectTerminalWidth(); - } -} -sub setAttribute { # (type, prefox, postfix) - my ($type, $prefix, $postfix) = @_; - $ATTRIBUTE_PREFIX{$type} = $prefix; - $ATTRIBUTE_POSTFIX{$type} = $postfix; -} -sub stripAnsiEscapes { # (Line) -> (StrippedLine) - $_[0] =~ s/\e\[[^m]*m//g; - return $_[0]; -} -sub getDefaultVerbosity { # () -> VerbosityLevel - # We can not print at correct verbosity levels before argument parsing has - # completed. We try some simple arg parsing here assuming default options - # used to set verbosity, such that we likely guess correctly, allowing - # correct verbosity from the start. - my $default = 3; - foreach my $arg (@ARGV) { - if ($arg eq '--') { return $default; } - if ($arg =~ /^-([^-]+)/) { - my $optstring = $1; - while ($optstring =~ /^(.)(.*)$/) { - my $char = $1; - $optstring = $2; - if ($char eq 'v') { - ++$default; - } - if ($char eq 's') { - if ($default > 0) { - --$default; - } - } - } - } - } - return $default; -} -sub detectTerminalWidth { #() -> ColumnCount - my $cols = &checkConsoleFeature('cols'); - if (!defined $cols) { - printDebug "Assuming terminal width of 80.\n"; - return 80; - } - if ($cols =~ /^\d+$/ && $cols > 10 && $cols < 500) { - printDebug "Detected terminal width of $cols.\n"; - return $cols; - } else { - printDebug "Unexpected terminal width of '$cols' given. " - . "Assuming size of 80.\n"; - return 80; - } -} -sub detectTerminalColorSupport { # () -> Bool - my $colorcount = &checkConsoleFeature('colors'); - if (!defined $colorcount) { - $ANSI_COLORS_SUPPORTED = 0; - printDebug "Assuming no color support.\n"; - return 0; - } - if ($colorcount =~ /^\d+$/ && $colorcount >= 8) { - $ANSI_COLORS_SUPPORTED = 1; - if (!defined $ANSI_COLORS) { - $ANSI_COLORS = $ANSI_COLORS_SUPPORTED; - } - printDebug "Color support detected.\n"; - return 1; - } -} -sub checkConsoleFeature { # (Feature) -> Bool - my ($feature) = @_; - # Unit tests must mock. Can't depend on TERM being set. - assertNotUnitTest(); - if (!exists $ENV{'TERM'}) { - printDebug "Terminal not set. Unknown.\n"; - return; - } - if (-f '/usr/bin/tput') { - my ($fh, $result); - if (open ($fh, "tput $feature 2>/dev/null |")) { - $result = <$fh>; - close $fh; - } else { - printDebug "Failed to open tput pipe.\n"; - return; - } - if ($? != 0) { - printDebug "Failed tput call to detect feature $feature $!\n"; - return; - } - chomp $result; - #printSpam "Console feature $feature: '$result'\n"; - return $result; - } else { - printDebug "No tput binary. Dont know how to detect feature.\n"; - return; - } -} -sub printAtLevel { # (Level, Output...) - # Prints an array of data that may contain newlines - my $level = shift @_; - exists $TYPES{$level} or confess "Unknown print level '$level'."; - if ($TYPES{$level} > $VERBOSITY) { - return; - } - my $buffer = ''; - my $width = &getTerminalWidth(); - foreach my $printable (@_) { - my @lines = split(/\n/, $printable, -1); - my $current = 0; - for (my $i=0; $i < scalar @lines; ++$i) { - if ($i != 0) { - $buffer .= "\n"; - $COLUMN_POSITION = 0; - } - my $last = ($i + 1 == scalar @lines); - printLineAtLevel($level, $lines[$i], \$buffer, $last); - } - } - my $stream = $OUTPUT_STREAM{$level}; - print $stream $buffer; -} -sub printLineAtLevel { # (Level, Line, Buffer, Last) - # Prints a single line, which might still have to be broken into multiple - # lines - my ($level, $data, $buffer, $last) = @_; - if (!$ANSI_COLORS) { - $data = &stripAnsiEscapes($data); - } - my $width = &getTerminalWidth(); - while (1) { - my $remaining = $width - $COLUMN_POSITION; - if (&prefixLineWithLevel($level)) { - $remaining -= (2 + length $level); - } - if ($ENABLE_AUTO_LINE_BREAKS && $remaining < length $data) { - my $min = int (2 * $width / 3) - $COLUMN_POSITION; - if ($min < 1) { $min = 1; } - if ($data =~ /^(.{$min,$remaining}) (.*?)$/s) { - my ($first, $rest) = ($1, $2); - &printLinePartAtLevel($level, $first, $buffer); - $$buffer .= "\n"; - $data = $rest; - $COLUMN_POSITION = 0; - } else { - last; - } - } else { - last; - } - } - if (!$last || length $data > 0) { - &printLinePartAtLevel($level, $data, $buffer); - } -} -sub printLinePartAtLevel { # ($Level, Line, Buffer) - # Print a single line that should fit on one line - my ($level, $data, $buffer) = @_; - if ($ANSI_COLORS) { - $$buffer .= $ATTRIBUTE_PREFIX{$level}; - } - if (&prefixLineWithLevel($level)) { - $$buffer .= $level . ": "; - $COLUMN_POSITION = (length $level) + 2; - } - $$buffer .= $data; - $COLUMN_POSITION += length $data; - if ($ANSI_COLORS) { - $$buffer .= $ATTRIBUTE_POSTFIX{$level}; - } -} -sub prefixLineWithLevel { # (Level) -> Bool - my ($level) = @_; - return ($TYPES{$level} > 2 && $VERBOSITY >= 4 && $COLUMN_POSITION == 0); -} - |