diff options
-rw-r--r-- | README.md | 12 | ||||
-rw-r--r-- | gita/__main__.py | 24 | ||||
-rw-r--r-- | gita/info.py | 82 | ||||
-rw-r--r-- | setup.py | 2 | ||||
-rw-r--r-- | tests/test_main.py | 19 | ||||
-rw-r--r-- | tests/test_utils.py | 6 |
6 files changed, 98 insertions, 47 deletions
@@ -333,8 +333,18 @@ For example, the default setting corresponds to branch,commit_msg,commit_time ``` -Here `branch` includes both branch name and status. To get the branch name alone, use `branch_name`. +Here `branch` includes both branch name and status. +The status symbols are similar to the ones used in [spaceship-prompt](https://spaceship-prompt.sh/sections/git/#Git-status-git_status). +To customize these symbols, add a file in `$XDG_CONFIG_HOME/gita/symbols.csv`. +The default settings corresponds to + +```csv +dirty,staged,untracked,local_ahead,remote_ahead,diverged,in_sync,no_remote +*,+,?,↑,↓,⇕,,∅ +``` +Only the symbols to be overridden need to be defined. +You can search unicode symbols [here](https://www.compart.com/en/unicode/). ### customize git command flags diff --git a/gita/__main__.py b/gita/__main__.py index 3d091c6..b2bc32b 100644 --- a/gita/__main__.py +++ b/gita/__main__.py @@ -165,6 +165,11 @@ def f_clone(args: argparse.Namespace): if not args.from_file: subprocess.run(["git", "clone", args.clonee], cwd=path) + # add the cloned repo to gita; group is also supported + cloned_path = os.path.join(path, args.clonee.split("/")[-1].split(".")[0]) + args.paths = [cloned_path] + args.recursive = args.auto_group = args.bare = args.skip_submodule = False + f_add(args) return if args.preserve_path: @@ -497,12 +502,6 @@ def main(argv=None): help="Change to DIRECTORY before doing anything.", ) p_clone.add_argument( - "-f", - "--from-file", - action="store_true", - help="If set, clone repos in a config file rendered from `gita freeze`", - ) - p_clone.add_argument( "-p", "--preserve-path", dest="preserve_path", @@ -515,6 +514,19 @@ def main(argv=None): action="store_true", help="If set, show command without execution", ) + xgroup = p_clone.add_mutually_exclusive_group() + xgroup.add_argument( + "-g", + "--group", + choices=utils.get_groups(), + help="If set, add repo to the specified group after cloning, otherwise add to gita without group.", + ) + xgroup.add_argument( + "-f", + "--from-file", + action="store_true", + help="If set, clone repos in a config file rendered from `gita freeze`", + ) p_clone.set_defaults(func=f_clone) p_rename = subparsers.add_parser( diff --git a/gita/info.py b/gita/info.py index bfb463b..10d8bea 100644 --- a/gita/info.py +++ b/gita/info.py @@ -1,8 +1,8 @@ -import os import csv import subprocess from enum import Enum from pathlib import Path +from collections import namedtuple from functools import lru_cache, partial from typing import Tuple, List, Callable, Dict @@ -41,11 +41,11 @@ class Color(Enum): default_colors = { - "no-remote": Color.white.name, - "in-sync": Color.green.name, + "no_remote": Color.white.name, + "in_sync": Color.green.name, "diverged": Color.red.name, - "local-ahead": Color.purple.name, - "remote-ahead": Color.yellow.name, + "local_ahead": Color.purple.name, + "remote_ahead": Color.yellow.name, } @@ -195,49 +195,75 @@ def get_commit_time(prop: Dict[str, str]) -> str: return f"({result.stdout.strip()})" +default_symbols = { + "dirty": "*", + "staged": "+", + "untracked": "?", + "local_ahead": "↑", + "remote_ahead": "↓", + "diverged": "⇕", + "in_sync": "", + "no_remote": "∅", + "": "", +} + + +@lru_cache() +def get_symbols() -> Dict[str, str]: + """ + return status symbols with customization + """ + custom = {} + csv_config = Path(common.get_config_fname("symbols.csv")) + if csv_config.is_file(): + with open(csv_config, "r") as f: + reader = csv.DictReader(f) + custom = next(reader) + default_symbols.update(custom) + return default_symbols + + def get_repo_status(prop: Dict[str, str], no_colors=False) -> str: - head = get_head(prop["path"]) - dirty, staged, untracked, color = _get_repo_status(prop, no_colors) - info = f"{head:<10} [{dirty+staged+untracked}]" - if color: - return f"{color}{info:<17}{Color.end}" - return f"{info:<17}" + branch = get_head(prop["path"]) + dirty, staged, untracked, situ = _get_repo_status(prop) + symbols = get_symbols() + info = f"{branch:<10} [{symbols[dirty]+symbols[staged]+symbols[untracked]+symbols[situ]}]" + + if no_colors: + return f"{info:<18}" + colors = {situ: Color[name].value for situ, name in get_color_encoding().items()} + color = colors[situ] + return f"{color}{info:<18}{Color.end}" def get_repo_branch(prop: Dict[str, str]) -> str: return get_head(prop["path"]) -def _get_repo_status(prop: Dict[str, str], no_colors: bool) -> Tuple[str]: +def _get_repo_status(prop: Dict[str, str]) -> Tuple[str, str, str, str]: """ Return the status of one repo """ path = prop["path"] flags = prop["flags"] - dirty = "*" if run_quiet_diff(flags, [], path) else "" - staged = "+" if run_quiet_diff(flags, ["--cached"], path) else "" - untracked = "?" if has_untracked(flags, path) else "" - - if no_colors: - return dirty, staged, untracked, "" + dirty = "dirty" if run_quiet_diff(flags, [], path) else "" + staged = "staged" if run_quiet_diff(flags, ["--cached"], path) else "" + untracked = "untracked" if has_untracked(flags, path) else "" - colors = {situ: Color[name].value for situ, name in get_color_encoding().items()} diff_returncode = run_quiet_diff(flags, ["@{u}", "@{0}"], path) - has_no_remote = diff_returncode == 128 - has_no_diff = diff_returncode == 0 - if has_no_remote: - color = colors["no-remote"] - elif has_no_diff: - color = colors["in-sync"] + if diff_returncode == 128: + situ = "no_remote" + elif diff_returncode == 0: + situ = "in_sync" else: common_commit = get_common_commit(path) outdated = run_quiet_diff(flags, ["@{u}", common_commit], path) if outdated: diverged = run_quiet_diff(flags, ["@{0}", common_commit], path) - color = colors["diverged"] if diverged else colors["remote-ahead"] + situ = "diverged" if diverged else "remote_ahead" else: # local is ahead of remote - color = colors["local-ahead"] - return dirty, staged, untracked, color + situ = "local_ahead" + return dirty, staged, untracked, situ ALL_INFO_ITEMS = { @@ -7,7 +7,7 @@ with open("README.md", encoding="utf-8") as f: setup( name="gita", packages=["gita"], - version="0.16.5", + version="0.16.6", license="MIT", description="Manage multiple git repos with sanity", long_description=long_description, diff --git a/tests/test_main.py b/tests/test_main.py index 6d05867..a877160 100644 --- a/tests/test_main.py +++ b/tests/test_main.py @@ -130,18 +130,21 @@ class TestLsLl: [ ( PATH_FNAME, - "repo1 cmaster [dsu] \x1b[0m msg \nrepo2 cmaster [dsu] \x1b[0m msg \nxxx cmaster [dsu] \x1b[0m msg \n", + "repo1 \x1b[31mmaster [*+?⇕] \x1b[0m msg \nrepo2 \x1b[31mmaster [*+?⇕] \x1b[0m msg \nxxx \x1b[31mmaster [*+?⇕] \x1b[0m msg \n", ), (PATH_FNAME_EMPTY, ""), ( PATH_FNAME_CLASH, - "repo1 cmaster [dsu] \x1b[0m msg \nrepo2 cmaster [dsu] \x1b[0m msg \n", + "repo1 \x1b[31mmaster [*+?⇕] \x1b[0m msg \nrepo2 \x1b[31mmaster [*+?⇕] \x1b[0m msg \n", ), ], ) @patch("gita.utils.is_git", return_value=True) @patch("gita.info.get_head", return_value="master") - @patch("gita.info._get_repo_status", return_value=("d", "s", "u", "c")) + @patch( + "gita.info._get_repo_status", + return_value=("dirty", "staged", "untracked", "diverged"), + ) @patch("gita.info.get_commit_msg", return_value="msg") @patch("gita.info.get_commit_time", return_value="") @patch("gita.common.get_config_fname") @@ -566,7 +569,7 @@ def test_set_color(mock_get_fname, tmpdir): args = argparse.Namespace() args.color_cmd = "set" args.color = "b_white" - args.situation = "no-remote" + args.situation = "no_remote" with tmpdir.as_cwd(): csv_config = Path.cwd() / "colors.csv" mock_get_fname.return_value = csv_config @@ -576,11 +579,11 @@ def test_set_color(mock_get_fname, tmpdir): items = info.get_color_encoding() info.get_color_encoding.cache_clear() # avoid side effect assert items == { - "no-remote": "b_white", - "in-sync": "green", + "no_remote": "b_white", + "in_sync": "green", "diverged": "red", - "local-ahead": "purple", - "remote-ahead": "yellow", + "local_ahead": "purple", + "remote_ahead": "yellow", } diff --git a/tests/test_utils.py b/tests/test_utils.py index 1e4f125..2936f0e 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -115,17 +115,17 @@ def test_auto_group(repos, paths, expected): ( [{"abc": {"path": "/root/repo/", "type": "", "flags": []}}, False], True, - "abc \x1b[31mrepo [*+?] \x1b[0m msg xx", + "abc \x1b[31mrepo [*+?⇕] \x1b[0m msg xx", ), ( [{"abc": {"path": "/root/repo/", "type": "", "flags": []}}, True], True, - "abc repo [*+?] msg xx", + "abc repo [*+?⇕] msg xx", ), ( [{"repo": {"path": "/root/repo2/", "type": "", "flags": []}}, False], False, - "repo \x1b[32mrepo [?] \x1b[0m msg xx", + "repo \x1b[32mrepo [?] \x1b[0m msg xx", ), ], ) |