output_helper.py 2.7 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394
  1. # -*- coding: utf-8 -*-
  2. import os, sys, re
  3. from colorama import Style
  4. from contextlib import contextmanager
  5. # RegExp for stripping color codes
  6. seq = re.compile(r'\x1B\[\d+m')
  7. FNULL = open(os.devnull, 'w')
  8. # To prevent the entire disk from being consumed, refuse to
  9. # append more lines to a log file once it's grown too large.
  10. # Logs that hit this limit are probably repeating the same
  11. # message endlessly anyway.
  12. TOO_MANY_BYTES = 50 * 1024 * 1024
  13. def log(log_text=None, **kwargs):
  14. '''
  15. Logs the given text and optional prefix to stdout (if quiet is False) and
  16. to an optional log file. By default, we strip out newlines in order to
  17. print our lines correctly, but you can override this functionality if you
  18. want to print multi-line output.
  19. '''
  20. # set up some defaults
  21. color = kwargs.get('color', '')
  22. color_reset = Style.RESET_ALL if color else ''
  23. prefix = kwargs.get('prefix', '')
  24. border = kwargs.get('border')
  25. border_bottom = kwargs.get('border_bottom')
  26. file = kwargs.get('file')
  27. quiet = kwargs.get('quiet')
  28. if border is not None:
  29. border = color + (border * 80) + os.linesep + color_reset
  30. border_bottom = border if border_bottom is None else \
  31. color + (border_bottom * 80) + os.linesep + color_reset
  32. elif not log_text:
  33. return
  34. try:
  35. new_log_text = border or ''
  36. for line in log_text.splitlines():
  37. if line.strip() is not '':
  38. if prefix:
  39. new_log_text += Style.DIM + prefix + Style.RESET_ALL
  40. new_log_text += color + line + color_reset + os.linesep
  41. new_log_text += border_bottom or ''
  42. if not quiet:
  43. sys.stdout.write(Style.RESET_ALL + new_log_text)
  44. sys.stdout.flush()
  45. if file is not None and os.fstat(
  46. file.fileno()).st_size < TOO_MANY_BYTES:
  47. file.write(seq.sub('', new_log_text))
  48. file.flush()
  49. except:
  50. pass
  51. class QuietOutputStream:
  52. '''
  53. Provides an output stream which either writes to stdout or nothing
  54. depending on the is_quiet param.
  55. '''
  56. def __init__(self, is_quiet):
  57. self.is_quiet = is_quiet
  58. def fileno(self):
  59. with self.enable():
  60. return sys.stdout.fileno()
  61. def write(self, message):
  62. with self.enable():
  63. sys.stdout.write(message)
  64. @contextmanager
  65. def enable(self):
  66. if self.is_quiet:
  67. old_out = sys.stdout
  68. old_err = sys.stderr
  69. try:
  70. sys.stdout = FNULL
  71. sys.stderr = FNULL
  72. yield
  73. finally:
  74. sys.stdout = old_out
  75. sys.stderr = old_err
  76. else:
  77. yield