libzypp  17.35.15
OutNormal.cc
Go to the documentation of this file.
1 /*---------------------------------------------------------------------\
2 | ____ _ __ __ ___ |
3 | |__ / \ / / . \ . \ |
4 | / / \ V /| _/ _/ |
5 | / /__ | | | | | | |
6 | /_____||_| |_| |_| |
7 | |
8 ----------------------------------------------------------------------*/
9 
10 #include <iostream>
11 #include <fstream>
12 #include <sstream>
13 
14 #include <unistd.h>
15 
16 #include <zypp-core/Pathname.h>
17 #include <zypp-core/ByteCount.h> // for download progress reporting
18 #include <zypp-core/base/Logger.h>
19 #include <zypp-core/base/String.h> // for toUpper()
20 #include <zypp-core/base/Gettext.h>
21 
22 #include <zypp-tui/utils/colors.h>
24 
25 #include "OutNormal.h"
26 
27 using std::cout;
28 using std::cerr;
29 using std::endl;
30 
31 namespace ztui {
32 
34 : Out( TYPE_NORMAL, verbosity_r )
35 , _use_colors( false )
36 , _isatty( do_ttyout() )
37 , _newline( true )
38 , _oneup( false )
39 {}
40 
42 {}
43 
44 bool OutNormal::mine( Type type )
45 { return( type & Out::TYPE_NORMAL ); }
46 
47 bool OutNormal::infoWarningFilter( Verbosity verbosity_r, Type mask )
48 {
49  if ( !mine( mask ) )
50  return true;
51  if ( verbosity() < verbosity_r )
52  return true;
53  return false;
54 }
55 
57 {
58  if ( !_newline ) // An active Progress bar is not NL terminated
59  cout << ansi::tty::clearLN; // Wipe it before writing out a normal line to the screen
60  // Alternative : cout << endl; to Keep the progress bar visible.
61 }
62 
63 void OutNormal::info( const std::string & msg_r, Verbosity verbosity_r, Type mask )
64 {
65  if ( infoWarningFilter( verbosity_r, mask ) )
66  return;
67 
69 
71  if ( verbosity_r == Out::QUIET )
73  else if ( verbosity_r == Out::DEBUG )
75 
76  cout << msg << endl;
77  _newline = true;
78 }
79 
80 void OutNormal::infoLine( const TermLine & msg, Verbosity verbosity_r, Type mask )
81 { info( msg.get( termwidth() ), verbosity_r, mask ); }
82 
83 void OutNormal::warning( const std::string & msg, Verbosity verbosity_r, Type mask )
84 {
85  if ( infoWarningFilter( verbosity_r, mask ) )
86  return;
87 
89 
90  cout << ( ColorContext::MSG_WARNING << _("Warning: ") ) << msg << endl;
91  _newline = true;
92 }
93 
94 void OutNormal::error( const std::string & problem_desc, const std::string & hint )
95 {
97 
98  cerr << ( ColorContext::MSG_ERROR << problem_desc );
99  if ( !hint.empty() && verbosity() > Out::QUIET )
100  cerr << endl << hint;
101  cerr << endl;
102  _newline = true;
103 }
104 
105 // ----------------------------------------------------------------------------
106 
107 void OutNormal::error( const zypp::Exception & e, const std::string & problem_desc, const std::string & hint )
108 {
109  fixupProgressNL();
110 
111  // problem and cause
112  cerr << ( ColorContext::MSG_ERROR << problem_desc << endl << zyppExceptionReport(e) ) << endl;
113 
114  // hint
115  if ( !hint.empty() && verbosity() > Out::QUIET )
116  cerr << hint << endl;
117 
118  _newline = true;
119 }
120 
121 // ----------------------------------------------------------------------------
122 inline std::ostream & PROGRESS_FLUSH( std::ostream & str ) {
123  static const bool dbg = getenv("ZYPPER_PBD"); // every progress bar redraw on a single line
124  return (dbg ? str << std::endl : str << std::flush );
125 }
126 
127 void OutNormal::displayProgress ( const std::string & s, int percent )
128 {
129  static AliveCursor cursor;
130 
131  if ( _isatty )
132  {
134  outstr.lhs << s << ' ';
135 
136  // dont display percents if invalid
137  if ( percent >= 0 && percent <= 100 )
138  {
139  outstr.percentHint = percent;
140  }
141  ++cursor;
142  outstr.rhs << '[' << cursor.current() << ']';
143 
144  if ( _oneup )
146  cout << ansi::tty::clearLN;
147 
148  std::string outline( outstr.get( termwidth() ) );
149  cout << outline << PROGRESS_FLUSH;
150  // no _oneup if CRUSHed // _oneup = ( outline.length() > termwidth() );
151  }
152  else
153  cout << '.' << std::flush;
154 }
155 
156 // ----------------------------------------------------------------------------
157 
158 void OutNormal::displayTick( const std::string & s )
159 {
160  static AliveCursor cursor;
161 
162  if ( _isatty )
163  {
165  ++cursor;
166  outstr.lhs << s << ' ';
167  outstr.rhs << '[' << cursor.current() << ']';
168 
169  if( _oneup )
171  cout << ansi::tty::clearLN;
172 
173  std::string outline( outstr.get( termwidth() ) );
174  cout << outline << PROGRESS_FLUSH;
175  // no _oneup if CRUSHed // _oneup = ( outline.length() > termwidth() );
176  }
177  else
178  cout << '.' << std::flush;
179 }
180 
181 // ----------------------------------------------------------------------------
182 void OutNormal::progressStart( const std::string & id, const std::string & label, bool is_tick )
183 {
184  if ( progressFilter() )
185  return;
186 
187  if ( !_isatty )
188  cout << label << " [";
189 
190  if ( is_tick )
191  displayTick( label );
192  else
193  displayProgress( label, 0 );
194 
195  _newline = false;
196 }
197 
198 void OutNormal::progress( const std::string & id, const std::string & label, int value )
199 {
200  if (progressFilter())
201  return;
202 
203  if (value)
204  displayProgress(label, value);
205  else
206  displayTick(label);
207 
208  _newline = false;
209 }
210 
211 void OutNormal::progressEnd( const std::string & id, const std::string & label, const std::string & donetag, bool error )
212 {
213  if ( progressFilter() )
214  return;
215 
216  if ( !error && _use_colors )
217  cout << ColorContext::MSG_STATUS;
218 
220  if ( _isatty )
221  {
222  if ( _oneup )
223  {
225  _oneup = false;
226  }
227  cout << ansi::tty::clearLN;
228 
229  outstr.lhs << label << ' ';
230  outstr.rhs << '[';
231  }
232  // else: just write the donetag
233 
234  outstr.rhs << donetag << ']';
235 
236  std::string outline( outstr.get( termwidth() ) );
237  cout << outline << endl << std::flush;
238  _newline = true;
239 
240  if ( !error && _use_colors )
241  cout << ColorContext::DEFAULT;
242 }
243 
244 // progress with download rate
246 {
247  if ( verbosity() < NORMAL )
248  return;
249 
250  if ( _isatty )
251  cout << ansi::tty::clearLN;
252 
254  outstr.lhs << _("Retrieving:") << ' ';
255  if ( verbosity() == DEBUG )
256  outstr.lhs << uri;
257  else
258  outstr.lhs << zypp::Pathname(uri.getPathName()).basename();
259  outstr.lhs << ' ';
260  if (_isatty)
261  outstr.rhs << '[' << _("starting") << ']';
262  else
263  outstr.rhs << '[' ;
264 
265  std::string outline( outstr.get( termwidth() ) );
266  cout << outline << PROGRESS_FLUSH;
267  // no _oneup if CRUSHed // _oneup = (outline.length() > termwidth());
268 
269  _newline = false;
270 }
271 
272 void OutNormal::dwnldProgress( const zypp::Url & uri, int value, long rate )
273 {
274  if ( verbosity() < NORMAL )
275  return;
276 
277  if ( !_isatty )
278  {
279  cout << '.' << std::flush;
280  return;
281  }
282 
283  if( _oneup )
285  cout << ansi::tty::clearLN;
286 
288  outstr.lhs << _("Retrieving:") << " ";
289  if ( verbosity() == DEBUG )
290  outstr.lhs << uri;
291  else
292  outstr.lhs << zypp::Pathname(uri.getPathName()).basename();
293  outstr.lhs << ' ';
294 
295  // dont display percents if invalid
296  if ( value >= 0 && value <= 100 )
297  outstr.percentHint = value;
298 
299  static AliveCursor cursor;
300  ++cursor;
301  outstr.rhs << '[' << cursor.current();
302  if ( rate > 0 )
303  outstr.rhs << " (" << zypp::ByteCount(rate) << "/s)";
304  outstr.rhs << ']';
305 
306  std::string outline( outstr.get( termwidth() ) );
307  cout << outline << PROGRESS_FLUSH;
308  // no _oneup if CRUSHed // _oneup = (outline.length() > termwidth());
309  _newline = false;
310 }
311 
312 void OutNormal::dwnldProgressEnd( const zypp::Url & uri, long rate, zypp::TriBool error )
313 {
314  if ( verbosity() < NORMAL )
315  return;
316 
317  if ( bool(!error) && _use_colors )
318  cout << ColorContext::MSG_STATUS;
319 
321  if ( _isatty )
322  {
323  if( _oneup )
325  cout << ansi::tty::clearLN;
326  outstr.lhs << _("Retrieving:") << " ";
327  if ( verbosity() == DEBUG )
328  outstr.lhs << uri;
329  else
330  outstr.lhs << zypp::Pathname(uri.getPathName()).basename();
331  outstr.lhs << ' ';
332  outstr.rhs << '[';
333  if ( zypp::indeterminate( error ) )
334  // Translator: download progress bar result: "........[not found]"
335  outstr.rhs << CHANGEString(_("not found") );
336  else if ( error )
337  // Translator: download progress bar result: "............[error]"
338  outstr.rhs << NEGATIVEString(_("error") );
339  else
340  // Translator: download progress bar result: ".............[done]"
341  outstr.rhs << _("done");
342  }
343  else
344  outstr.rhs << ( zypp::indeterminate( error ) ? _("not found") : ( error ? _("error") : _("done") ) );
345 
346  if ( rate > 0 )
347  outstr.rhs << " (" << zypp::ByteCount(rate) << "/s)";
348  outstr.rhs << ']';
349 
350  std::string outline( outstr.get( termwidth() ) );
351  cout << outline << endl << std::flush;
352  _newline = true;
353 
354  if ( bool(!error) && _use_colors )
355  cout << ColorContext::DEFAULT;
356 }
357 
358 void OutNormal::prompt( PromptId id, const std::string & prompt, const PromptOptions & poptions, const std::string & startdesc )
359 {
360  fixupProgressNL();
361 
362  if ( startdesc.empty() )
363  {
364  if ( _isatty )
365  cout << ansi::tty::clearLN;
366  }
367  else
368  cout << startdesc << endl;
369 
370  std::ostringstream pstr;
371  ColorStream cout( pstr, ColorContext::PROMPT ); // scoped color on std::cout
372 
373  cout << prompt;
374  if ( ! poptions.empty() )
375  cout << text::optBlankAfter(prompt) << ColorString( poptions.optionString() );
376  cout << ": ";
377 
378  if ( do_colors() )
379  {
380  // bsc#948566: Terminal is dumb and simply counts the amount of printable
381  // characters. If the number of printable characters within ansi SGR sequences
382  // is not a multiple of 8, tab stops are not computed correctly. We use
383  // superfluous resets ("\033[0m"; 3 printable chars) to fill up.
384  // Better ideas are welcome.
385  size_t invis = 0;
386  bool insgr = false;
387  for ( char ch : pstr.str() )
388  {
389  if ( insgr )
390  {
391  ++invis;
392  if ( ch == 'm' )
393  insgr = false;
394  }
395  else if ( ch == '\033' )
396  insgr = true;
397  }
398  invis %= 8;
399 
400  if ( invis )
401  {
402  // "\033[0m" has 3 printable chars:
403  // ( resets[to fill] * 3 ) % 8 == to fill
404  // 0 1 2 3 4 5 6 7
405  static const size_t resets[] = { 0,3,6,1,4,7,2,5 };
406  for ( size_t i = resets[8-invis]; i; --i )
407  cout << ansi::Color::SGRReset();
408  }
409  }
410 
411  std::cout << pstr.str() << std::flush;
412  // prompt ends with newline (user hits <enter>) unless exited abnormaly
413  _newline = true;
414 }
415 
416 void OutNormal::promptHelp( const PromptOptions & poptions )
417 {
418  cout << endl;
419 
420  if ( poptions.helpEmpty() )
421  cout << _("No help available for this prompt.") << endl;
422 
423  // Nevertheless list all option names and their '#NUM' shortcut
424  unsigned pos = 0; // Userland counter #NUM (starts with #1)
425 
426  zypp::str::Format fopt { "#%-2d: %-10s" };
427  for ( unsigned idx = 0; idx < poptions.options().size(); ++idx )
428  {
429  if ( poptions.isDisabled(idx) )
430  continue;
431 
432  cout << ( fopt % ++pos % poptions.options()[idx] );
433  if ( ! poptions.helpEmpty() )
434  {
435  const std::string & help { poptions.optionHelp(idx) };
436  cout << " - ";
437  if ( help.empty() )
438  cout << ( ColorContext::LOWLIGHT << "(" << _("no help available for this option") << ")" );
439  else
440  cout << help;
441  }
442  cout << endl;
443  }
444 
445  ColorStream cout( std::cout, ColorContext::PROMPT ); // scoped color on std::cout
446  cout << endl << ColorString( poptions.optionString() ) << ": " << std::flush;
447  // prompt ends with newline (user hits <enter>) unless exited abnormaly
448  _newline = true;
449 }
450 
451 unsigned OutNormal::termwidth() const
452 {
453  if ( _isatty )
454  {
455  struct winsize wns;
456  if ( !ioctl( 1, TIOCGWINSZ, &wns ) )
457  return wns.ws_col;
458  }
459  return Out::termwidth(); // unlimited
460 }
461 
462 }
void progressStart(const std::string &id, const std::string &label, bool is_tick) override
Start of an operation with reported progress.
Definition: OutNormal.cc:182
void fixupProgressNL()
Definition: OutNormal.cc:56
virtual std::string zyppExceptionReport(const zypp::Exception &e)
Return a Exception as a string suitable for output.
Definition: Out.cc:128
void prompt(PromptId id, const std::string &prompt, const PromptOptions &poptions, const std::string &startdesc) override
Prompt the user for a decision.
Definition: OutNormal.cc:358
void dwnldProgress(const zypp::Url &uri, int value, long rate) override
Reports download progress.
Definition: OutNormal.cc:272
boost::logic::tribool TriBool
3-state boolean logic (true, false and indeterminate).
Definition: String.h:30
Colored string if do_colors.
Definition: ansi.h:496
#define _(MSG)
Definition: Gettext.h:39
void progress(const std::string &id, const std::string &label, int value) override
Progress report for an on-going operation.
Definition: OutNormal.cc:198
Store and operate with byte count.
Definition: ByteCount.h:31
Base class for producing common (for now) zypper output.
Definition: Out.h:423
bool do_colors()
If output is done in colors (depends on config)
Definition: colors.cc:32
CCString< ColorContext::NEGATIVE > NEGATIVEString
Definition: colors.h:85
~OutNormal() override
Definition: OutNormal.cc:41
bool infoWarningFilter(Verbosity verbosity, Type mask)
Definition: OutNormal.cc:47
void warning(const std::string &msg, Verbosity verbosity, Type mask) override
Show a warning.
Definition: OutNormal.cc:83
char current() const
Definition: AliveCursor.h:29
bool _use_colors
Definition: OutNormal.h:65
String related utilities and Regular expression matching.
void error(const std::string &problem_desc, const std::string &hint) override
Show an error message and an optional hint.
Definition: OutNormal.cc:94
Example: PromptOptions popts; popts.setOptions(_("y/n/p"), 0 / * default reply * /); popts...
Definition: promptoptions.h:38
Verbosity verbosity() const
Get current verbosity.
Definition: Out.h:864
Convenient building of std::string with boost::format.
Definition: String.h:252
void displayProgress(const std::string &s, int percent)
Definition: OutNormal.cc:127
zypp::str::Str lhs
Definition: Out.h:361
const StrVector & options() const
Definition: promptoptions.h:64
CCString< ColorContext::CHANGE > CHANGEString
Definition: colors.h:84
unsigned PromptId
Definition: Out.h:447
bool mine(Type type) override
Determine whether the output is intended for the particular type.
Definition: OutNormal.cc:44
Default output verbosity level.
Definition: Out.h:430
bool do_ttyout()
True unless output is a dumb tty or file.
Definition: colors.cc:27
bool isDisabled(unsigned opt) const
Definition: promptoptions.h:82
virtual unsigned termwidth() const
Width for formatted output [0==unlimited].
Definition: Out.h:919
void dwnldProgressStart(const zypp::Url &uri) override
Reoprt start of a download.
Definition: OutNormal.cc:245
const EscapeSequence cursorUP
Cursor up 1 line.
Colored stream output if do_colors.
Definition: ansi.h:673
zypp::DefaultIntegral< int,-1 > percentHint
Definition: Out.h:359
std::string get() const
Return plain line made of lhs + rhs.
Definition: Out.h:366
plain text output
Definition: Out.h:439
bool helpEmpty() const
Definition: promptoptions.h:78
std::ostream & PROGRESS_FLUSH(std::ostream &str)
Definition: OutNormal.cc:122
zypp::str::Str rhs
Definition: Out.h:362
unsigned termwidth() const override
Width for formatted output [0==unlimited].
Definition: OutNormal.cc:451
virtual bool progressFilter()
Determine whether to show progress.
Definition: Out.cc:123
Only important messages (no progress or status, only the result).
Definition: Out.h:429
Verbosity
Verbosity levels.
Definition: Out.h:427
void dwnldProgressEnd(const zypp::Url &uri, long rate, zypp::TriBool error) override
Reports end of a download.
Definition: OutNormal.cc:312
ColorString optionString() const
Option string (may have embedded color codes)
Base class for Exception.
Definition: Exception.h:146
const std::string & optionHelp(unsigned opt) const
Definition: promptoptions.h:74
bool empty() const
Definition: promptoptions.h:71
std::string getPathName(EEncoding eflag=zypp::url::E_DECODED) const
Returns the path name from the URL.
Definition: Url.cc:622
const char * optBlankAfter(const std::string &str_r)
Definition: Out.h:68
void displayTick(const std::string &s)
Definition: OutNormal.cc:158
void infoLine(const TermLine &msg, Verbosity verbosity, Type mask) override
info taking a TermLine
Definition: OutNormal.cc:80
static const std::string & SGRReset()
ANSI SGR sesquence to reset all attributes.
Definition: ansi.h:291
TypeBit type() const
Return the type of the instance.
Definition: Out.h:895
OutNormal(Verbosity verbosity=NORMAL)
Definition: OutNormal.cc:33
const EscapeSequence clearLN
Clear entire line.
Info info()
Definition: Out.h:678
void progressEnd(const std::string &id, const std::string &label, const std::string &donetag, bool error) override
End of an operation with reported progress.
Definition: OutNormal.cc:211
void promptHelp(const PromptOptions &poptions) override
Print help for prompt, if available.
Definition: OutNormal.cc:416
Url manipulation class.
Definition: Url.h:91