conan-io/conan

View on GitHub
conans/cli/output.py

Summary

Maintainability
D
1 day
Test Coverage
import logging
import sys

import tqdm
from colorama import Fore, Style

from conans.util.env_reader import get_env


class Color(object):
    """ Wrapper around colorama colors that are undefined in importing
    """
    RED = Fore.RED  # @UndefinedVariable
    WHITE = Fore.WHITE  # @UndefinedVariable
    CYAN = Fore.CYAN  # @UndefinedVariable
    GREEN = Fore.GREEN  # @UndefinedVariable
    MAGENTA = Fore.MAGENTA  # @UndefinedVariable
    BLUE = Fore.BLUE  # @UndefinedVariable
    YELLOW = Fore.YELLOW  # @UndefinedVariable
    BLACK = Fore.BLACK  # @UndefinedVariable

    BRIGHT_RED = Style.BRIGHT + Fore.RED  # @UndefinedVariable
    BRIGHT_BLUE = Style.BRIGHT + Fore.BLUE  # @UndefinedVariable
    BRIGHT_YELLOW = Style.BRIGHT + Fore.YELLOW  # @UndefinedVariable
    BRIGHT_GREEN = Style.BRIGHT + Fore.GREEN  # @UndefinedVariable
    BRIGHT_CYAN = Style.BRIGHT + Fore.CYAN  # @UndefinedVariable
    BRIGHT_WHITE = Style.BRIGHT + Fore.WHITE  # @UndefinedVariable
    BRIGHT_MAGENTA = Style.BRIGHT + Fore.MAGENTA  # @UndefinedVariable


if get_env("CONAN_COLOR_DARK", 0):
    Color.WHITE = Fore.BLACK
    Color.CYAN = Fore.BLUE
    Color.YELLOW = Fore.MAGENTA
    Color.BRIGHT_WHITE = Fore.BLACK
    Color.BRIGHT_CYAN = Fore.BLUE
    Color.BRIGHT_YELLOW = Fore.MAGENTA
    Color.BRIGHT_GREEN = Fore.GREEN

try:
    from logging import NullHandler
except ImportError:  # TODO: Remove if Python > 3.1
    class NullHandler(logging.Handler):
        def handle(self, record):
            pass

        def emit(self, record):
            pass

        def createLock(self):
            self.lock = None


class TqdmHandler(logging.StreamHandler):
    def __init__(self, stream=None):
        self._stream = stream
        super(TqdmHandler, self).__init__(stream)

    def emit(self, record):
        try:
            msg = self.format(record)
            tqdm.tqdm.write(msg, file=self._stream)
            self.flush()
        except (KeyboardInterrupt, SystemExit):
            raise
        except:
            self.handleError(record)


class ConanOutput(object):
    def __init__(self, quiet=False):
        self._logger = logging.getLogger("conan_out_logger")
        self._stream_handler = None
        self._quiet = quiet
        self._color = self._init_colors()

        if self._quiet:
            self._logger.addHandler(NullHandler())
        else:
            self._stream = sys.stderr
            self._stream_handler = TqdmHandler(self._stream)
            self._stream_handler.setFormatter(logging.Formatter("%(message)s"))
            self._logger.addHandler(self._stream_handler)
            self._logger.setLevel(logging.INFO)
            self._logger.propagate = False

        self._scope = ""

    @property
    def stream(self):
        return self._stream

    @property
    def color(self):
        return self._color

    @property
    def scope(self):
        return self._scope

    @scope.setter
    def scope(self, out_scope):
        self._scope = out_scope

    @property
    def is_terminal(self):
        return hasattr(self._stream, "isatty") and self._stream.isatty()

    def _write(self, msg, level, fg=None, bg=None):
        if self._scope:
            msg = "{}: {}".format(self.scope, msg)
        if self._color:
            msg = "{}{}{}{}".format(fg or '', bg or '', msg, Style.RESET_ALL)
        self._logger.log(level, msg)

    def debug(self, msg):
        self._write(msg, logging.DEBUG)

    def info(self, msg, fg=None, bg=None):
        self._write(msg, logging.INFO, fg, bg)

    # TODO: remove, just to support the migration system warn message
    def warn(self, msg):
        self._write("WARNING: {}".format(msg), logging.WARNING, Color.YELLOW)

    def warning(self, msg):
        self._write("WARNING: {}".format(msg), logging.WARNING, Color.YELLOW)

    def error(self, msg):
        self._write("ERROR: {}".format(msg), logging.ERROR, Color.RED)

    def critical(self, msg):
        self._write("ERROR: {}".format(msg), logging.CRITICAL, Color.BRIGHT_RED)

    def flush(self):
        if self._stream_handler:
            self._stream_handler.flush()

    @staticmethod
    def _init_colors():
        clicolor = get_env("CLICOLOR")
        clicolor_force = get_env("CLICOLOR_FORCE")
        no_color = get_env("NO_COLOR")
        if no_color or (clicolor and clicolor == "0"):
            import colorama
            colorama.init(strip=True)
            return False
        else:
            import colorama
            if clicolor_force or (clicolor and clicolor != "0"):
                colorama.init(convert=False, strip=False)
            else:
                # TODO: check if colorama checks for stripping colors are enough
                colorama.init()
            return True