summaryrefslogtreecommitdiffstats
path: root/gita/__main__.py
diff options
context:
space:
mode:
Diffstat (limited to 'gita/__main__.py')
-rw-r--r--gita/__main__.py143
1 files changed, 95 insertions, 48 deletions
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