summaryrefslogtreecommitdiffstats
path: root/subcmds/abandon.py
diff options
context:
space:
mode:
Diffstat (limited to 'subcmds/abandon.py')
-rw-r--r--subcmds/abandon.py59
1 files changed, 39 insertions, 20 deletions
diff --git a/subcmds/abandon.py b/subcmds/abandon.py
index 359c431b..b82a2dbf 100644
--- a/subcmds/abandon.py
+++ b/subcmds/abandon.py
@@ -13,9 +13,12 @@
13# limitations under the License. 13# limitations under the License.
14 14
15from collections import defaultdict 15from collections import defaultdict
16import functools
17import itertools
18import multiprocessing
16import sys 19import sys
17 20
18from command import Command 21from command import Command, DEFAULT_LOCAL_JOBS, WORKER_BATCH_SIZE
19from git_command import git 22from git_command import git
20from progress import Progress 23from progress import Progress
21 24
@@ -31,8 +34,10 @@ deleting it (and all its history) from your local repository.
31 34
32It is equivalent to "git branch -D <branchname>". 35It is equivalent to "git branch -D <branchname>".
33""" 36"""
37 PARALLEL_JOBS = DEFAULT_LOCAL_JOBS
34 38
35 def _Options(self, p): 39 def _Options(self, p):
40 super()._Options(p)
36 p.add_option('-q', '--quiet', 41 p.add_option('-q', '--quiet',
37 action='store_true', default=False, 42 action='store_true', default=False,
38 help='be quiet') 43 help='be quiet')
@@ -51,35 +56,49 @@ It is equivalent to "git branch -D <branchname>".
51 else: 56 else:
52 args.insert(0, "'All local branches'") 57 args.insert(0, "'All local branches'")
53 58
59 def _ExecuteOne(self, opt, nb, project):
60 """Abandon one project."""
61 if opt.all:
62 branches = project.GetBranches()
63 else:
64 branches = [nb]
65
66 ret = {}
67 for name in branches:
68 status = project.AbandonBranch(name)
69 if status is not None:
70 ret[name] = status
71 return (ret, project)
72
54 def Execute(self, opt, args): 73 def Execute(self, opt, args):
55 nb = args[0] 74 nb = args[0]
56 err = defaultdict(list) 75 err = defaultdict(list)
57 success = defaultdict(list) 76 success = defaultdict(list)
58 all_projects = self.GetProjects(args[1:]) 77 all_projects = self.GetProjects(args[1:])
59 78
60 pm = Progress('Abandon %s' % nb, len(all_projects)) 79 def _ProcessResults(states):
61 for project in all_projects: 80 for (results, project) in states:
62 pm.update() 81 for branch, status in results.items():
63
64 if opt.all:
65 branches = list(project.GetBranches().keys())
66 else:
67 branches = [nb]
68
69 for name in branches:
70 status = project.AbandonBranch(name)
71 if status is not None:
72 if status: 82 if status:
73 success[name].append(project) 83 success[branch].append(project)
74 else: 84 else:
75 err[name].append(project) 85 err[branch].append(project)
76 pm.end() 86 pm.update()
77 87
78 width = 25 88 pm = Progress('Abandon %s' % nb, len(all_projects))
79 for name in branches: 89 # NB: Multiprocessing is heavy, so don't spin it up for one job.
80 if width < len(name): 90 if len(all_projects) == 1 or opt.jobs == 1:
81 width = len(name) 91 _ProcessResults(self._ExecuteOne(opt, nb, x) for x in all_projects)
92 else:
93 with multiprocessing.Pool(opt.jobs) as pool:
94 states = pool.imap_unordered(
95 functools.partial(self._ExecuteOne, opt, nb), all_projects,
96 chunksize=WORKER_BATCH_SIZE)
97 _ProcessResults(states)
98 pm.end()
82 99
100 width = max(itertools.chain(
101 [25], (len(x) for x in itertools.chain(success, err))))
83 if err: 102 if err:
84 for br in err.keys(): 103 for br in err.keys():
85 err_msg = "error: cannot abandon %s" % br 104 err_msg = "error: cannot abandon %s" % br