summaryrefslogtreecommitdiffstats
path: root/subcmds/abandon.py
diff options
context:
space:
mode:
authorMike Frysinger <vapier@google.com>2021-02-18 23:37:33 -0500
committerMike Frysinger <vapier@google.com>2021-02-27 19:45:14 +0000
commit8dbc07aced638b0d625870e283307e348046c82f (patch)
tree37b4e940ff1c96fd136458e91b87907533bd7233 /subcmds/abandon.py
parent8d2a6df1fda2d766d92f554a7ffea499420e4f7a (diff)
downloadgit-repo-8dbc07aced638b0d625870e283307e348046c82f.tar.gz
abandon/start: add --jobs support
Use multiprocessing to run in parallel. When operating on multiple projects, this can greatly speed things up. Across 1000 repos, it goes from ~30sec to ~3sec with the default -j8. Change-Id: I0dc62d704c022dd02cac0bd67fe79224f4e34095 Reviewed-on: https://gerrit-review.googlesource.com/c/git-repo/+/297484 Tested-by: Mike Frysinger <vapier@google.com> Reviewed-by: Chris Mcdonald <cjmcdonald@google.com>
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