19
19
# IN THE SOFTWARE.
20
20
import sys
21
21
22
+ from io import StringIO
22
23
from os import getcwd
23
24
24
25
from humanfriendly .terminal import terminal_supports_colors , ansi_wrap , auto_encode
@@ -43,6 +44,7 @@ def __init__(self):
43
44
self ._prev_cwd = None
44
45
self ._progress_spinner = None
45
46
self ._need_to_erase_spinner = False
47
+ self ._error_once_cache = set ()
46
48
47
49
def init (self , verbose , debug ):
48
50
self ._verbose = verbose
@@ -112,12 +114,15 @@ def output(self, text, *args, **kw):
112
114
auto_encode (sys .stdout , text + '\n ' , * args , ** kw )
113
115
sys .stdout .flush ()
114
116
117
+ def _output_on_stream (self , tmp_stream , out_stream , text , color , * args , ** kw ):
118
+ if terminal_supports_colors (out_stream ):
119
+ text = ansi_wrap (text , color = color )
120
+ auto_encode (tmp_stream , text , ind = _DETAIL_INDENT , * args , ** kw )
121
+
115
122
def _output (self , text , color , * args , ** kw ):
116
123
self ._erase_spinner ()
117
124
118
- if terminal_supports_colors (sys .stdout ):
119
- text = ansi_wrap (text , color = color )
120
- auto_encode (sys .stdout , text , ind = _DETAIL_INDENT , * args , ** kw )
125
+ self ._output_on_stream (sys .stdout , sys .stdout , text , color , * args , ** kw )
121
126
sys .stdout .flush ()
122
127
123
128
def warning (self , text , run_id = None , cmd = None , cwd = None , ** kw ):
@@ -128,6 +133,21 @@ def error(self, text, run_id=None, cmd=None, cwd=None, **kw):
128
133
self ._output_detail_header (run_id , cmd , cwd )
129
134
self ._output (text , 'red' , ** kw )
130
135
136
+ def _is_first_error_with (self , text ):
137
+ if text not in self ._error_once_cache :
138
+ self ._error_once_cache .add (text )
139
+ return True
140
+ return False
141
+
142
+ def error_once (self , text , run_id = None , cmd = None , cwd = None , ** kw ):
143
+ stream = StringIO ("" )
144
+ self ._output_on_stream (stream , sys .stdout , text , 'red' , ** kw )
145
+ stream_str = stream .getvalue ()
146
+
147
+ if self ._is_first_error_with (stream_str ):
148
+ self ._output_detail_header (run_id , cmd , cwd )
149
+ self ._output (text , 'red' , ** kw )
150
+
131
151
def verbose_output_info (self , text , run_id = None , cmd = None , cwd = None , ** kw ):
132
152
if self ._verbose :
133
153
self ._output_detail_header (run_id , cmd , cwd )
@@ -191,6 +211,9 @@ def warning(self, text, run_id=None, cmd=None, cwd=None, **kw):
191
211
def error (self , text , run_id = None , cmd = None , cwd = None , ** kw ):
192
212
pass
193
213
214
+ def error_once (self , text , run_id = None , cmd = None , cwd = None , ** kw ):
215
+ pass
216
+
194
217
def verbose_output_info (self , text , run_id = None , cmd = None , cwd = None , ** kw ):
195
218
pass
196
219
0 commit comments