summaryrefslogtreecommitdiffstats
path: root/subcmds/start.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/start.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/start.py')
-rw-r--r--subcmds/start.py62
1 files changed, 44 insertions, 18 deletions
diff --git a/subcmds/start.py b/subcmds/start.py
index 7684b6d7..25b229f1 100644
--- a/subcmds/start.py
+++ b/subcmds/start.py
@@ -12,10 +12,12 @@
12# See the License for the specific language governing permissions and 12# See the License for the specific language governing permissions and
13# limitations under the License. 13# limitations under the License.
14 14
15import functools
16import multiprocessing
15import os 17import os
16import sys 18import sys
17 19
18from command import Command 20from command import Command, DEFAULT_LOCAL_JOBS, WORKER_BATCH_SIZE
19from git_config import IsImmutable 21from git_config import IsImmutable
20from git_command import git 22from git_command import git
21import gitc_utils 23import gitc_utils
@@ -33,8 +35,10 @@ class Start(Command):
33'%prog' begins a new branch of development, starting from the 35'%prog' begins a new branch of development, starting from the
34revision specified in the manifest. 36revision specified in the manifest.
35""" 37"""
38 PARALLEL_JOBS = DEFAULT_LOCAL_JOBS
36 39
37 def _Options(self, p): 40 def _Options(self, p):
41 super()._Options(p)
38 p.add_option('--all', 42 p.add_option('--all',
39 dest='all', action='store_true', 43 dest='all', action='store_true',
40 help='begin branch in all projects') 44 help='begin branch in all projects')
@@ -51,6 +55,26 @@ revision specified in the manifest.
51 if not git.check_ref_format('heads/%s' % nb): 55 if not git.check_ref_format('heads/%s' % nb):
52 self.OptionParser.error("'%s' is not a valid name" % nb) 56 self.OptionParser.error("'%s' is not a valid name" % nb)
53 57
58 def _ExecuteOne(self, opt, nb, project):
59 """Start one project."""
60 # If the current revision is immutable, such as a SHA1, a tag or
61 # a change, then we can't push back to it. Substitute with
62 # dest_branch, if defined; or with manifest default revision instead.
63 branch_merge = ''
64 if IsImmutable(project.revisionExpr):
65 if project.dest_branch:
66 branch_merge = project.dest_branch
67 else:
68 branch_merge = self.manifest.default.revisionExpr
69
70 try:
71 ret = project.StartBranch(
72 nb, branch_merge=branch_merge, revision=opt.revision)
73 except Exception as e:
74 print('error: unable to checkout %s: %s' % (project.name, e), file=sys.stderr)
75 ret = False
76 return (ret, project)
77
54 def Execute(self, opt, args): 78 def Execute(self, opt, args):
55 nb = args[0] 79 nb = args[0]
56 err = [] 80 err = []
@@ -82,11 +106,8 @@ revision specified in the manifest.
82 if not os.path.exists(os.getcwd()): 106 if not os.path.exists(os.getcwd()):
83 os.chdir(self.manifest.topdir) 107 os.chdir(self.manifest.topdir)
84 108
85 pm = Progress('Starting %s' % nb, len(all_projects)) 109 pm = Progress('Syncing %s' % nb, len(all_projects))
86 for project in all_projects: 110 for project in all_projects:
87 pm.update()
88
89 if self.gitc_manifest:
90 gitc_project = self.gitc_manifest.paths[project.relpath] 111 gitc_project = self.gitc_manifest.paths[project.relpath]
91 # Sync projects that have not been opened. 112 # Sync projects that have not been opened.
92 if not gitc_project.already_synced: 113 if not gitc_project.already_synced:
@@ -99,20 +120,25 @@ revision specified in the manifest.
99 sync_buf = SyncBuffer(self.manifest.manifestProject.config) 120 sync_buf = SyncBuffer(self.manifest.manifestProject.config)
100 project.Sync_LocalHalf(sync_buf) 121 project.Sync_LocalHalf(sync_buf)
101 project.revisionId = gitc_project.old_revision 122 project.revisionId = gitc_project.old_revision
123 pm.update()
124 pm.end()
102 125
103 # If the current revision is immutable, such as a SHA1, a tag or 126 def _ProcessResults(results):
104 # a change, then we can't push back to it. Substitute with 127 for (result, project) in results:
105 # dest_branch, if defined; or with manifest default revision instead. 128 if not result:
106 branch_merge = '' 129 err.append(project)
107 if IsImmutable(project.revisionExpr): 130 pm.update()
108 if project.dest_branch:
109 branch_merge = project.dest_branch
110 else:
111 branch_merge = self.manifest.default.revisionExpr
112 131
113 if not project.StartBranch( 132 pm = Progress('Starting %s' % nb, len(all_projects))
114 nb, branch_merge=branch_merge, revision=opt.revision): 133 # NB: Multiprocessing is heavy, so don't spin it up for one job.
115 err.append(project) 134 if len(all_projects) == 1 or opt.jobs == 1:
135 _ProcessResults(self._ExecuteOne(opt, nb, x) for x in all_projects)
136 else:
137 with multiprocessing.Pool(opt.jobs) as pool:
138 results = pool.imap_unordered(
139 functools.partial(self._ExecuteOne, opt, nb), all_projects,
140 chunksize=WORKER_BATCH_SIZE)
141 _ProcessResults(results)
116 pm.end() 142 pm.end()
117 143
118 if err: 144 if err: