Integrate colorama for coloured output #164

Merged
witten merged 5 commits from :feature/coloured-output-first-step into master 2019-05-13 19:50:37 +00:00
14 changed files with 112 additions and 17 deletions
Showing only changes of commit 1f524d6c87 - Show all commits

View File

@ -3,13 +3,14 @@ import os
import subprocess
from borgmatic.borg import extract
from borgmatic.logger import get_logger
DEFAULT_CHECKS = ('repository', 'archives')
DEFAULT_PREFIX = '{hostname}-'
logger = logging.getLogger(__name__)
logger = get_logger(__name__)
def _parse_checks(consistency_config):

View File

@ -5,9 +5,10 @@ import os
import tempfile
from borgmatic.borg.execute import execute_command
from borgmatic.logger import get_logger
logger = logging.getLogger(__name__)
logger = get_logger(__name__)
def _expand_directory(directory):

View File

@ -1,8 +1,9 @@
import logging
import subprocess
from borgmatic.logger import get_logger
logger = logging.getLogger(__name__)
logger = get_logger(__name__)
def execute_command(full_command, capture_output=False):

View File

@ -2,8 +2,10 @@ import logging
import sys
import subprocess
from borgmatic.logger import get_logger
logger = logging.getLogger(__name__)
logger = get_logger(__name__)
def extract_last_archive_dry_run(repository, lock_wait=None, local_path='borg', remote_path=None):

View File

@ -1,9 +1,10 @@
import logging
from borgmatic.borg.execute import execute_command
from borgmatic.logger import get_logger
logger = logging.getLogger(__name__)
logger = get_logger(__name__)
def display_archives_info(

View File

@ -1,8 +1,9 @@
import logging
import subprocess
from borgmatic.logger import get_logger
logger = logging.getLogger(__name__)
logger = get_logger(__name__)
def initialize_repository(

View File

@ -1,9 +1,10 @@
import logging
from borgmatic.borg.execute import execute_command
from borgmatic.logger import get_logger
logger = logging.getLogger(__name__)
logger = get_logger(__name__)
def list_archives(

View File

@ -1,8 +1,10 @@
import logging
import subprocess
from borgmatic.logger import get_logger
logger = logging.getLogger(__name__)
logger = get_logger(__name__)
def _make_prune_flags(retention_config):

View File

@ -1,5 +1,6 @@
from argparse import ArgumentParser
import collections
import colorama
import json
import logging
import os
@ -20,12 +21,12 @@ from borgmatic.borg import (
)
from borgmatic.commands import hook
from borgmatic.config import checks, collect, convert, validate
from borgmatic.logger import should_do_markup, get_logger
from borgmatic.signals import configure_signals
from borgmatic.verbosity import verbosity_to_log_level

Super minor: I tend to alpha order imports within each group, just to make visual scanning easier. E.g., from borgmatic.logger would go on the line after from borgmatic.config.

Super minor: I tend to alpha order imports within each group, just to make visual scanning easier. E.g., `from borgmatic.logger` would go on the line after `from borgmatic.config`.

I'll fix. I'd recommend integrating https://isort.readthedocs.io/en/latest/ so that the tooling mandates and saves you time checking it yourself. Here's a configuration I use myself that plays well with Black: https://git.coop/decentral1se/pypkgtemplate/blob/master/%7B%7Bcookiecutter.package%7D%7D/setup.cfg#L7.

I'll fix. I'd recommend integrating https://isort.readthedocs.io/en/latest/ so that the tooling mandates and saves you time checking it yourself. Here's a configuration I use myself that plays well with Black: https://git.coop/decentral1se/pypkgtemplate/blob/master/%7B%7Bcookiecutter.package%7D%7D/setup.cfg#L7.

Point taken. I filed witten/borgmatic#169 for that.

Point taken. I filed https://projects.torsion.org/witten/borgmatic/issues/169 for that.
logger = logging.getLogger(__name__)
logger = get_logger(__name__)
LEGACY_CONFIG_PATH = '/etc/borgmatic/config'
@ -169,6 +170,9 @@ def parse_arguments(*arguments):
action='store_true',
help='Go through the motions, but do not actually write to any repositories',
)
common_group.add_argument(
'-nc', '--no-color', dest='no_color', action='store_true', help='Disable colored output'

May seem silly, but I think I'd prefer American spelling for this. I don't have any good reason except perhaps it's just more common among users: https://en.wikipedia.org/wiki/Comparison_of_American_and_British_English#Demographics

But if you like, you can include flags for both (e.g. --no-color and --no-colour) to be more inclusive!

May seem silly, but I think I'd prefer American spelling for this. I don't have any good reason except perhaps it's just more common among users: https://en.wikipedia.org/wiki/Comparison_of_American_and_British_English#Demographics But if you like, you can include flags for both (e.g. `--no-color` and `--no-colour`) to be more inclusive!
)
common_group.add_argument(
'-v',
'--verbosity',
@ -472,6 +476,8 @@ def main(): # pragma: no cover
logger.critical(error)
exit_with_help_link()
colorama.init(autoreset=True, strip=not should_do_markup(args.no_color))
logging.basicConfig(level=verbosity_to_log_level(args.verbosity), format='%(message)s')
if args.version:

View File

@ -1,8 +1,9 @@
import logging
import subprocess
from borgmatic.logger import get_logger
logger = logging.getLogger(__name__)
logger = get_logger(__name__)
def execute_hook(commands, config_filename, description, dry_run):

View File

@ -3,8 +3,9 @@ import sys
import logging
from borgmatic.config import collect, validate
from borgmatic.logger import get_logger
logger = logging.getLogger(__name__)
logger = get_logger(__name__)
def parse_arguments(*arguments):

View File

@ -1,10 +1,11 @@
import os
import logging
import ruamel.yaml
from borgmatic.logger import get_logger
logger = logging.getLogger(__name__)
logger = get_logger(__name__)
def load_configuration(filename):

View File

@ -6,9 +6,10 @@ import pykwalify.errors
import ruamel.yaml
from borgmatic.config import load
from borgmatic.logger import get_logger
logger = logging.getLogger(__name__)
logger = get_logger(__name__)
def schema_filename():

75
borgmatic/logger.py Normal file
View File

@ -0,0 +1,75 @@
import logging
import os
import sys
import colorama
def to_bool(arg):
'''
Return a boolean value based on `arg`.
'''
if arg is None or isinstance(arg, bool):
return arg
if isinstance(arg, str):
arg = arg.lower()
if arg in ('yes', 'on', '1', 'true', 1):
return True
return False

It'd be good to have a simple automated test or three for this function, given that it's pure logic.

It'd be good to have a simple automated test or three for this function, given that it's pure logic.

Makes sense! Also, to note, I took this implementation from the Ansible utility, so it is well battle tested for this use case.

Makes sense! Also, to note, I took this implementation from the Ansible utility, so it is well battle tested for this use case.
def should_do_markup(no_colour):
'''
Determine if we should enable colorama marking up.
'''
if no_colour:
return False
py_colors = os.environ.get('PY_COLORS', None)
if py_colors is not None:
return to_bool(py_colors)
return sys.stdout.isatty() and os.environ.get('TERM') != 'dumb'

Nice to have the auto-detection here!

Nice to have the auto-detection here!
class BorgmaticLogger(logging.Logger):
def warn(self, msg, *args, **kwargs):
return super(BorgmaticLogger, self).warn(
color_text(colorama.Fore.YELLOW, msg), *args, **kwargs
)
def info(self, msg, *args, **kwargs):
return super(BorgmaticLogger, self).info(
color_text(colorama.Fore.GREEN, msg), *args, **kwargs
)
def debug(self, msg, *args, **kwargs):
return super(BorgmaticLogger, self).debug(
color_text(colorama.Fore.CYAN, msg), *args, **kwargs
)
def critical(self, msg, *args, **kwargs):
return super(BorgmaticLogger, self).critical(
color_text(colorama.Fore.RED, msg), *args, **kwargs
)
def get_logger(name=None):
'''
Build a logger with the given name.
'''
logging.setLoggerClass(BorgmaticLogger)
logger = logging.getLogger(name)
logger.propagate = False

Given that these *_text() functions are only used in one place, I might be inclined to just inline them there. Do not feel strongly though.

Given that these `*_text()` functions are only used in one place, I might be inclined to just inline them there. Do not feel strongly though.
return logger
def color_text(color, msg):
'''
Give colored text.
'''
return '{}{}{}'.format(color, msg, colorama.Style.RESET_ALL)