Repository: nosarthur/gita

Issue:
A no colour option for when running through either a script or cron.
I am using gita to backup some repositories so need to run `gita ll` (just to see what will change) then do `gita pull`. Because this runs through cron, I get some ugly control characters instead of colours. Would it be possible to add a `--no-colours` option?

Thank you

Discussion:

Patch:
diff --git a/gita/__main__.py b/gita/__main__.py
index e00f20d..13a048e 100644
--- a/gita/__main__.py
+++ b/gita/__main__.py
@@ -57,7 +57,7 @@ def f_ll(args: argparse.Namespace):
     if args.group:  # only display repos in this group
         group_repos = utils.get_groups()[args.group]
         repos = {k: repos[k] for k in group_repos if k in repos}
-    for line in utils.describe(repos):
+    for line in utils.describe(repos, no_colors=args.no_colors):
         print(line)
 
 
@@ -245,6 +245,8 @@ def main(argv=None):
                       nargs='?',
                       choices=utils.get_groups(),
                       help="show repos in the chosen group")
+    p_ll.add_argument('-n', '--no-colors', action='store_true',
+            help='Disable coloring on the branch names.')
     p_ll.set_defaults(func=f_ll)
 
     p_context = subparsers.add_parser('context',
diff --git a/gita/info.py b/gita/info.py
index 18d20fd..2d1d33f 100644
--- a/gita/info.py
+++ b/gita/info.py
@@ -42,6 +42,7 @@ def get_info_items() -> Tuple[Dict[str, Callable[[str], str]], List[str]]:
             'path': get_path, }
     display_items = ['branch', 'commit_msg']
 
+    # FIXME: remove these code
     # custom settings
     root = common.get_config_dir()
     src_fname = os.path.join(root, 'extra_repo_info.py')
@@ -113,13 +114,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,6 +131,9 @@ 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, ''
+
     diff_returncode = run_quiet_diff(['@{u}', '@{0}'])
     has_no_remote = diff_returncode == 128
     has_no_diff = diff_returncode == 0
diff --git a/gita/utils.py b/gita/utils.py
index 900aefa..cc0a354 100644
--- a/gita/utils.py
+++ b/gita/utils.py
@@ -2,7 +2,7 @@ import os
 import yaml
 import asyncio
 import platform
-from functools import lru_cache
+from functools import lru_cache, partial
 from pathlib import Path
 from typing import List, Dict, Coroutine, Union
 
@@ -197,13 +197,19 @@ def exec_async_tasks(tasks: List[Coroutine]) -> List[Union[None, str]]:
     return errors
 
 
-def describe(repos: Dict[str, str]) -> str:
+def describe(repos: Dict[str, str], no_colors: bool=False) -> str:
     """
     Return the status of all repos
     """
     if repos:
         name_width = max(len(n) for n in repos) + 1
     funcs = info.get_info_funcs()
+
+    get_repo_status = info.get_repo_status
+    if get_repo_status in funcs and no_colors:
+        idx = funcs.index(get_repo_status)
+        funcs[idx] = partial(get_repo_status, no_colors=True)
+
     for name in sorted(repos):
         path = repos[name]
         display_items = ' '.join(f(path) for f in funcs)
diff --git a/setup.py b/setup.py
index 0cdd33f..cf4ab90 100644
--- a/setup.py
+++ b/setup.py
@@ -7,7 +7,7 @@ with open('README.md', encoding='utf-8') as f:
 setup(
     name='gita',
     packages=['gita'],
-    version='0.11.6',
+    version='0.11.7',
     license='MIT',
     description='Manage multiple git repos with sanity',
     long_description=long_description,


Test patch:
diff --git a/tests/test_main.py b/tests/test_main.py
index 1b23bee..1d6c9f6 100644
--- a/tests/test_main.py
+++ b/tests/test_main.py
@@ -5,7 +5,7 @@ import argparse
 import shlex
 
 from gita import __main__
-from gita import utils
+from gita import utils, info
 from conftest import (
     PATH_FNAME, PATH_FNAME_EMPTY, PATH_FNAME_CLASH, GROUP_FNAME,
     async_mock, TEST_DIR,
@@ -35,6 +35,14 @@ class TestLsLl:
         out, err = capfd.readouterr()
         assert err == ''
         assert 'gita' in out
+        assert info.Color.end in out
+
+        # no color on branch name
+        __main__.main(['ll', '-n'])
+        out, err = capfd.readouterr()
+        assert err == ''
+        assert 'gita' in out
+        assert info.Color.end not in out
 
         __main__.main(['ls', 'gita'])
         out, err = capfd.readouterr()
diff --git a/tests/test_utils.py b/tests/test_utils.py
index dfabcee..607a33b 100644
--- a/tests/test_utils.py
+++ b/tests/test_utils.py
@@ -9,12 +9,9 @@ from conftest import (
 
 
 @pytest.mark.parametrize('test_input, diff_return, expected', [
-    ({
-        'abc': '/root/repo/'
-    }, True, 'abc \x1b[31mrepo *+_  \x1b[0m msg'),
-    ({
-        'repo': '/root/repo2/'
-    }, False, 'repo \x1b[32mrepo _    \x1b[0m msg'),
+    ([{'abc': '/root/repo/'}, False], True, 'abc \x1b[31mrepo *+_  \x1b[0m msg'),
+    ([{'abc': '/root/repo/'}, True], True, 'abc repo *+_   msg'),
+    ([{'repo': '/root/repo2/'}, False], False, 'repo \x1b[32mrepo _    \x1b[0m msg'),
 ])
 def test_describe(test_input, diff_return, expected, monkeypatch):
     monkeypatch.setattr(info, 'get_head', lambda x: 'repo')
@@ -23,8 +20,8 @@ def test_describe(test_input, diff_return, expected, monkeypatch):
     monkeypatch.setattr(info, 'has_untracked', lambda: True)
     monkeypatch.setattr('os.chdir', lambda x: None)
     print('expected: ', repr(expected))
-    print('got:      ', repr(next(utils.describe(test_input))))
-    assert expected == next(utils.describe(test_input))
+    print('got:      ', repr(next(utils.describe(*test_input))))
+    assert expected == next(utils.describe(*test_input))
 
 
 @pytest.mark.parametrize('path_fname, expected', [