From c0456228aa67dadc0b1d28712b4b94a7d1f40054 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Mon, 2 Nov 2020 16:57:20 +0100 Subject: Merging upstream version 0.11.9. Signed-off-by: Daniel Baumann --- gita/info.py | 108 +++++++++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 79 insertions(+), 29 deletions(-) (limited to 'gita/info.py') diff --git a/gita/info.py b/gita/info.py index 18d20fd..473127a 100644 --- a/gita/info.py +++ b/gita/info.py @@ -2,14 +2,19 @@ import os import sys import yaml import subprocess +from enum import Enum +from pathlib import Path +from functools import lru_cache from typing import Tuple, List, Callable, Dict + from . import common -class Color: +class Color(str, Enum): """ Terminal color """ + black = '\x1b[30m' red = '\x1b[31m' # local diverges from remote green = '\x1b[32m' # local == remote yellow = '\x1b[33m' # local is behind @@ -18,6 +23,43 @@ class Color: cyan = '\x1b[36m' white = '\x1b[37m' # no remote branch end = '\x1b[0m' + b_black = '\x1b[30;1m' + b_red = '\x1b[31;1m' + b_green = '\x1b[32;1m' + b_yellow = '\x1b[33;1m' + b_blue = '\x1b[34;1m' + b_purple = '\x1b[35;1m' + b_cyan = '\x1b[36;1m' + b_white = '\x1b[37;1m' + + +def show_colors(): # pragma: no cover + """ + + """ + for i, c in enumerate(Color, start=1): + if c != Color.end: + print(f'{c.value}{c.name:<8} ', end='') + if i % 9 == 0: + print() + print(f'{Color.end}') + for situation, c in get_color_encoding().items(): + print(f'{situation:<12}: {c.value}{c.name:<8}{Color.end} ') + + +@lru_cache() +def get_color_encoding(): + """ + + """ + # TODO: add config file + return { + 'no-remote': Color.white, + 'in-sync': Color.green, + 'diverged': Color.red, + 'local-ahead': Color.purple, + 'remote-ahead': Color.yellow, + } def get_info_funcs() -> List[Callable[[str], str]]: @@ -26,35 +68,30 @@ def get_info_funcs() -> List[Callable[[str], str]]: take the repo path as input and return the corresponding information as str. See `get_path`, `get_repo_status`, `get_common_commit` for examples. """ - info_items, to_display = get_info_items() - return [info_items[k] for k in to_display] + to_display = get_info_items() + # This re-definition is to make unit test mocking to work + all_info_items = { + 'branch': get_repo_status, + 'commit_msg': get_commit_msg, + 'path': get_path, + } + return [all_info_items[k] for k in to_display] -def get_info_items() -> Tuple[Dict[str, Callable[[str], str]], List[str]]: +def get_info_items() -> List[str]: """ - Return the available information items for display in the `gita ll` - sub-command, and the ones to be displayed. - It loads custom information functions and configuration if they exist. + Return the information items to be displayed in the `gita ll` command. """ # default settings - info_items = {'branch': get_repo_status, - 'commit_msg': get_commit_msg, - 'path': get_path, } display_items = ['branch', 'commit_msg'] # custom settings - root = common.get_config_dir() - src_fname = os.path.join(root, 'extra_repo_info.py') - yml_fname = os.path.join(root, 'info.yml') - if os.path.isfile(src_fname): - sys.path.append(root) - from extra_repo_info import extra_info_items - info_items.update(extra_info_items) - if os.path.isfile(yml_fname): - with open(yml_fname, 'r') as stream: + yml_config = Path(common.get_config_fname('info.yml')) + if yml_config.is_file(): + with open(yml_config, 'r') as stream: display_items = yaml.load(stream, Loader=yaml.FullLoader) - display_items = [x for x in display_items if x in info_items] - return info_items, display_items + display_items = [x for x in display_items if x in ALL_INFO_ITEMS] + return display_items def get_path(path): @@ -113,13 +150,15 @@ def get_commit_msg(path: str) -> str: return result.stdout.strip() -def get_repo_status(path: str) -> str: +def get_repo_status(path: str, no_colors=False) -> str: head = get_head(path) - dirty, staged, untracked, color = _get_repo_status(path) - return f'{color}{head+" "+dirty+staged+untracked:<10}{Color.end}' + dirty, staged, untracked, color = _get_repo_status(path, no_colors) + if color: + return f'{color}{head+" "+dirty+staged+untracked:<10}{Color.end}' + return f'{head+" "+dirty+staged+untracked:<10}' -def _get_repo_status(path: str) -> Tuple[str]: +def _get_repo_status(path: str, no_colors: bool) -> Tuple[str]: """ Return the status of one repo """ @@ -128,19 +167,30 @@ def _get_repo_status(path: str) -> Tuple[str]: staged = '+' if run_quiet_diff(['--cached']) else '' untracked = '_' if has_untracked() else '' + if no_colors: + return dirty, staged, untracked, '' + + colors = get_color_encoding() diff_returncode = run_quiet_diff(['@{u}', '@{0}']) has_no_remote = diff_returncode == 128 has_no_diff = diff_returncode == 0 if has_no_remote: - color = Color.white + color = colors['no-remote'] elif has_no_diff: - color = Color.green + color = colors['in-sync'] else: common_commit = get_common_commit() outdated = run_quiet_diff(['@{u}', common_commit]) if outdated: diverged = run_quiet_diff(['@{0}', common_commit]) - color = Color.red if diverged else Color.yellow + color = colors['diverged'] if diverged else colors['remote-ahead'] else: # local is ahead of remote - color = Color.purple + color = colors['local-ahead'] return dirty, staged, untracked, color + + +ALL_INFO_ITEMS = { + 'branch': get_repo_status, + 'commit_msg': get_commit_msg, + 'path': get_path, + } -- cgit v1.2.3