From c18286b8746318f614becc9c518452d6b7c47c49 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Mon, 6 Sep 2021 06:05:38 +0200 Subject: Merging upstream version 0.15.7. Signed-off-by: Daniel Baumann --- gita/__main__.py | 143 ++++++++++++++++++++++++++++++++++++------------------- 1 file changed, 95 insertions(+), 48 deletions(-) (limited to 'gita/__main__.py') diff --git a/gita/__main__.py b/gita/__main__.py index 8678d36..d38e78d 100644 --- a/gita/__main__.py +++ b/gita/__main__.py @@ -19,6 +19,7 @@ import sys import csv import argparse import subprocess +from functools import partial import pkg_resources from itertools import chain from pathlib import Path @@ -27,21 +28,37 @@ import glob from . import utils, info, common -def _group_name(name: str) -> str: +def _group_name(name: str, exclude_old_names=True) -> str: """ - + Return valid group name """ repos = utils.get_repos() if name in repos: print(f"Cannot use group name {name} since it's a repo name.") sys.exit(1) + if exclude_old_names: + if name in utils.get_groups(): + print(f"Cannot use group name {name} since it's already in use.") + sys.exit(1) + if name in {'none', 'auto'}: + print(f"Cannot use group name {name} since it's a reserved keyword.") + sys.exit(1) return name +def _path_name(name: str) -> str: + """ + Return absolute path without trailing / + """ + if name: + return os.path.abspath(name).rstrip(os.path.sep) + return '' + + def f_add(args: argparse.Namespace): repos = utils.get_repos() paths = args.paths - if args.main: + if 0: # add to global and tag as main main_repos = utils.add_repos(repos, paths, repo_type='m') # add sub-repo recursively and save to local config @@ -53,11 +70,11 @@ def f_add(args: argparse.Namespace): utils.add_repos({}, sub_paths, root=main_path) else: if args.recursive or args.auto_group: - paths = chain.from_iterable( + paths = (p.rstrip(os.path.sep) for p in chain.from_iterable( glob.glob(os.path.join(p, '**/'), recursive=True) - for p in args.paths) + for p in args.paths)) new_repos = utils.add_repos(repos, paths, is_bare=args.bare) - if args.auto_group: + if new_repos and args.auto_group: new_groups = utils.auto_group(new_repos, args.paths) if new_groups: print(f'Created {len(new_groups)} new group(s).') @@ -159,11 +176,24 @@ def f_ll(args: argparse.Namespace): ctx = utils.get_context() if args.group is None and ctx: args.group = ctx.stem + group_repos = None if args.group: # only display repos in this group - group_repos = utils.get_groups()[args.group] + group_repos = utils.get_groups()[args.group]['repos'] repos = {k: repos[k] for k in group_repos if k in repos} - for line in utils.describe(repos, no_colors=args.no_colors): - print(line) + if args.g: # display by group + if group_repos: + print(f'{args.group}:') + for line in utils.describe(repos, no_colors=args.no_colors): + print(' ', line) + else: + for g, g_repos in utils.get_groups().items(): + print(f'{g}:') + g_repos = {k: repos[k] for k in g_repos if k in repos} + for line in utils.describe(g_repos, no_colors=args.no_colors): + print(' ', line) + else: + for line in utils.describe(repos, no_colors=args.no_colors): + print(line) def f_ls(args: argparse.Namespace): @@ -180,69 +210,73 @@ def f_group(args: argparse.Namespace): if cmd == 'll': if 'to_show' in args and args.to_show: gname = args.to_show - print(' '.join(groups[gname])) + print(' '.join(groups[gname]['repos'])) else: - for group, repos in groups.items(): - print(f"{group}: {' '.join(repos)}") + for group, prop in groups.items(): + print(f"{info.Color.underline}{group}{info.Color.end}: {prop['path']}") + for r in prop['repos']: + print(' -', r) elif cmd == 'ls': print(' '.join(groups)) elif cmd == 'rename': new_name = args.new_name - if new_name in groups: - sys.exit(f'{new_name} already exists.') gname = args.gname groups[new_name] = groups[gname] del groups[gname] utils.write_to_groups_file(groups, 'w') # change context ctx = utils.get_context() - if ctx and str(ctx.stem) == gname: - # ctx.rename(ctx.with_stem(new_name)) # only works in py3.9 - ctx.rename(ctx.with_name(f'{new_name}.context')) + if ctx and ctx.stem == gname: + utils.replace_context(ctx, new_name) elif cmd == 'rm': ctx = utils.get_context() for name in args.to_ungroup: del groups[name] if ctx and str(ctx.stem) == name: - ctx.unlink() + utils.replace_context(ctx, '') utils.write_to_groups_file(groups, 'w') elif cmd == 'add': gname = args.gname if gname in groups: - gname_repos = set(groups[gname]) + gname_repos = set(groups[gname]['repos']) gname_repos.update(args.to_group) - groups[gname] = sorted(gname_repos) + groups[gname]['repos'] = sorted(gname_repos) + if 'gpath' in args: + groups[gname]['path'] = args.gpath utils.write_to_groups_file(groups, 'w') else: - utils.write_to_groups_file({gname: sorted(args.to_group)}, 'a+') + gpath = '' + if 'gpath' in args: + gpath = args.gpath + utils.write_to_groups_file( + {gname: {'repos': sorted(args.to_group), + 'path': gpath}}, + 'a+') elif cmd == 'rmrepo': gname = args.gname if gname in groups: - for repo in args.from_group: - try: - groups[gname].remove(repo) - except ValueError as e: - pass + group = {gname: {'repos': groups[gname]['repos'], + 'path': groups[gname]['path'] + }} + for repo in args.to_rm: + utils.delete_repo_from_groups(repo, group) + groups[gname] = group[gname] utils.write_to_groups_file(groups, 'w') def f_context(args: argparse.Namespace): choice = args.choice ctx = utils.get_context() - if choice is None: + if choice is None: # display current context if ctx: group = ctx.stem - print(f"{group}: {' '.join(utils.get_groups()[group])}") + print(f"{group}: {' '.join(utils.get_groups()[group]['repos'])}") + elif (Path(common.get_config_dir()) / 'auto.context').exists(): + print('auto: none detected!') else: print('Context is not set') - elif choice == 'none': # remove context - ctx and ctx.unlink() else: # set context - fname = Path(common.get_config_dir()) / (choice + '.context') - if ctx: - ctx.rename(fname) - else: - open(fname, 'w').close() + utils.replace_context(ctx, choice) def f_rm(args: argparse.Namespace): @@ -255,12 +289,19 @@ def f_rm(args: argparse.Namespace): main_paths = [prop['path'] for prop in repos.values() if prop['type'] == 'm'] # TODO: add test case to delete main repo from main repo # only local setting should be affected instead of the global one + group_updated = False for repo in args.repo: del repos[repo] + groups = utils.get_groups() + group_updated = group_updated or utils.delete_repo_from_groups(repo, groups) + if group_updated: + utils.write_to_groups_file(groups, 'w') + # If cwd is relative to any main repo, write to local config cwd = os.getcwd() + # TODO: delete main path mechanism for p in main_paths: - if utils.is_relative_to(cwd, p): + if utils.get_relative_path(cwd, p) is not None: utils.write_to_repo_file(repos, 'w', p) break else: # global config @@ -283,7 +324,7 @@ def f_git_cmd(args: argparse.Namespace): if k in repos: chosen[k] = repos[k] if k in groups: - for r in groups[k]: + for r in groups[k]['repos']: chosen[r] = repos[r] repos = chosen per_repo_cmds = [] @@ -343,7 +384,6 @@ def f_shell(args): chosen[r] = repos[r] repos = chosen cmds = ' '.join(args.man[i:]) # join the shell command into a single string - #cmds = args.man[i:] for name, prop in repos.items(): # TODO: pull this out as a function got = subprocess.run(cmds, cwd=prop['path'], shell=True, @@ -387,12 +427,10 @@ def main(argv=None): # bookkeeping sub-commands p_add = subparsers.add_parser('add', description='add repo(s)', help='add repo(s)') - p_add.add_argument('paths', nargs='+', type=os.path.abspath, help="repo(s) to add") + p_add.add_argument('paths', nargs='+', type=_path_name, help="repo(s) to add") xgroup = p_add.add_mutually_exclusive_group() xgroup.add_argument('-r', '--recursive', action='store_true', help="recursively add repo(s) in the given path(s).") - xgroup.add_argument('-m', '--main', action='store_true', - help="make main repo(s), sub-repos are recursively added.") xgroup.add_argument('-a', '--auto-group', action='store_true', help="recursively add repo(s) in the given path(s) " "and create hierarchical groups based on folder structure.") @@ -504,6 +542,8 @@ def main(argv=None): help="show repos in the chosen group") p_ll.add_argument('-C', '--no-colors', action='store_true', help='Disable coloring on the branch names.') + p_ll.add_argument('-g', action='store_true', + help='Show repo summaries by group.') p_ll.set_defaults(func=f_ll) p_context = subparsers.add_parser('context', @@ -512,8 +552,12 @@ def main(argv=None): ' When set, all operations apply only to repos in that group.') p_context.add_argument('choice', nargs='?', - choices=set().union(utils.get_groups(), {'none'}), - help="Without argument, show current context. Otherwise choose a group as context. To remove context, use 'none'. ") + choices=set().union(utils.get_groups(), {'none', 'auto'}), + help="Without this argument, show current context. " + "Otherwise choose a group as context, or use 'auto', " + "which sets the context/group automatically based on " + "the current working directory. " + "To remove context, use 'none'. ") p_context.set_defaults(func=f_context) p_ls = subparsers.add_parser( @@ -545,12 +589,16 @@ def main(argv=None): help="repo(s) to be grouped") pg_add.add_argument('-n', '--name', dest='gname', - type=_group_name, + type=partial(_group_name, exclude_old_names=False), metavar='group-name', - required=True, - help="group name") + required=True) + pg_add.add_argument('-p', '--path', + dest='gpath', + type=_path_name, + metavar='group-path') + pg_rmrepo = group_cmds.add_parser('rmrepo', description='remove repo(s) from a group.') - pg_rmrepo.add_argument('from_group', + pg_rmrepo.add_argument('to_rm', nargs='+', metavar='repo', choices=utils.get_repos(), @@ -641,6 +689,5 @@ def main(argv=None): else: p.print_help() # pragma: no cover - if __name__ == '__main__': main() # pragma: no cover -- cgit v1.2.3