1# SPDX-License-Identifier: GPL-2.0+
2# Copyright (c) 2016 Google, Inc
3#
4# Terminal output logging.
5#
6
7import sys
8
9from patman import terminal
10
11# Output verbosity levels that we support
12ERROR, WARNING, NOTICE, INFO, DETAIL, DEBUG = range(6)
13
14in_progress = False
15
16"""
17This class handles output of progress and other useful information
18to the user. It provides for simple verbosity level control and can
19output nothing but errors at verbosity zero.
20
21The idea is that modules set up an Output object early in their years and pass
22it around to other modules that need it. This keeps the output under control
23of a single class.
24
25Public properties:
26    verbose: Verbosity level: 0=silent, 1=progress, 3=full, 4=debug
27"""
28def __enter__():
29    return
30
31def __exit__(unused1, unused2, unused3):
32    """Clean up and remove any progress message."""
33    ClearProgress()
34    return False
35
36def UserIsPresent():
37    """This returns True if it is likely that a user is present.
38
39    Sometimes we want to prompt the user, but if no one is there then this
40    is a waste of time, and may lock a script which should otherwise fail.
41
42    Returns:
43        True if it thinks the user is there, and False otherwise
44    """
45    return stdout_is_tty and verbose > 0
46
47def ClearProgress():
48    """Clear any active progress message on the terminal."""
49    global in_progress
50    if verbose > 0 and stdout_is_tty and in_progress:
51        _stdout.write('\r%s\r' % (" " * len (_progress)))
52        _stdout.flush()
53        in_progress = False
54
55def Progress(msg, warning=False, trailer='...'):
56    """Display progress information.
57
58    Args:
59        msg: Message to display.
60        warning: True if this is a warning."""
61    global in_progress
62    ClearProgress()
63    if verbose > 0:
64        _progress = msg + trailer
65        if stdout_is_tty:
66            col = _color.YELLOW if warning else _color.GREEN
67            _stdout.write('\r' + _color.Color(col, _progress))
68            _stdout.flush()
69            in_progress = True
70        else:
71            _stdout.write(_progress + '\n')
72
73def _Output(level, msg, color=None):
74    """Output a message to the terminal.
75
76    Args:
77        level: Verbosity level for this message. It will only be displayed if
78                this as high as the currently selected level.
79        msg; Message to display.
80        error: True if this is an error message, else False.
81    """
82    if verbose >= level:
83        ClearProgress()
84        if color:
85            msg = _color.Color(color, msg)
86        if level < NOTICE:
87            print(msg, file=sys.stderr)
88        else:
89            print(msg)
90
91def DoOutput(level, msg):
92    """Output a message to the terminal.
93
94    Args:
95        level: Verbosity level for this message. It will only be displayed if
96                this as high as the currently selected level.
97        msg; Message to display.
98    """
99    _Output(level, msg)
100
101def Error(msg):
102    """Display an error message
103
104    Args:
105        msg; Message to display.
106    """
107    _Output(ERROR, msg, _color.RED)
108
109def Warning(msg):
110    """Display a warning message
111
112    Args:
113        msg; Message to display.
114    """
115    _Output(WARNING, msg, _color.YELLOW)
116
117def Notice(msg):
118    """Display an important infomation message
119
120    Args:
121        msg; Message to display.
122    """
123    _Output(NOTICE, msg)
124
125def Info(msg):
126    """Display an infomation message
127
128    Args:
129        msg; Message to display.
130    """
131    _Output(INFO, msg)
132
133def Detail(msg):
134    """Display a detailed message
135
136    Args:
137        msg; Message to display.
138    """
139    _Output(DETAIL, msg)
140
141def Debug(msg):
142    """Display a debug message
143
144    Args:
145        msg; Message to display.
146    """
147    _Output(DEBUG, msg)
148
149def UserOutput(msg):
150    """Display a message regardless of the current output level.
151
152    This is used when the output was specifically requested by the user.
153    Args:
154        msg; Message to display.
155    """
156    _Output(0, msg)
157
158def Init(_verbose=WARNING, stdout=sys.stdout):
159    """Initialize a new output object.
160
161    Args:
162        verbose: Verbosity level (0-4).
163        stdout: File to use for stdout.
164    """
165    global verbose, _progress, _color, _stdout, stdout_is_tty
166
167    verbose = _verbose
168    _progress = ''                    # Our last progress message
169    _color = terminal.Color()
170    _stdout = stdout
171
172    # TODO(sjg): Move this into Chromite libraries when we have them
173    stdout_is_tty = hasattr(sys.stdout, 'isatty') and sys.stdout.isatty()
174    stderr_is_tty = hasattr(sys.stderr, 'isatty') and sys.stderr.isatty()
175
176def Uninit():
177    ClearProgress()
178
179Init()
180