diff: add --jobs support

Use multiprocessing to run diff in parallel.

Change-Id: I61e973d9c2cde039d5eebe8d0fe8bb63171ef447
Reviewed-on: https://gerrit-review.googlesource.com/c/git-repo/+/297483
Tested-by: Mike Frysinger <vapier@google.com>
Reviewed-by: Chris Mcdonald <cjmcdonald@google.com>
This commit is contained in:
Mike Frysinger 2021-02-16 18:18:01 -05:00
parent fbab6065d4
commit 69b4a9cf21
2 changed files with 41 additions and 5 deletions

View File

@ -832,10 +832,12 @@ class Project(object):
return 'DIRTY' return 'DIRTY'
def PrintWorkTreeDiff(self, absolute_paths=False): def PrintWorkTreeDiff(self, absolute_paths=False, output_redir=None):
"""Prints the status of the repository to stdout. """Prints the status of the repository to stdout.
""" """
out = DiffColoring(self.config) out = DiffColoring(self.config)
if output_redir:
out.redirect(output_redir)
cmd = ['diff'] cmd = ['diff']
if out.is_on: if out.is_on:
cmd.append('--color') cmd.append('--color')

View File

@ -12,7 +12,11 @@
# See the License for the specific language governing permissions and # See the License for the specific language governing permissions and
# limitations under the License. # limitations under the License.
from command import PagedCommand import functools
import io
import multiprocessing
from command import DEFAULT_LOCAL_JOBS, PagedCommand, WORKER_BATCH_SIZE
class Diff(PagedCommand): class Diff(PagedCommand):
@ -25,15 +29,45 @@ The -u option causes '%prog' to generate diff output with file paths
relative to the repository root, so the output can be applied relative to the repository root, so the output can be applied
to the Unix 'patch' command. to the Unix 'patch' command.
""" """
PARALLEL_JOBS = DEFAULT_LOCAL_JOBS
def _Options(self, p): def _Options(self, p):
super()._Options(p)
p.add_option('-u', '--absolute', p.add_option('-u', '--absolute',
dest='absolute', action='store_true', dest='absolute', action='store_true',
help='Paths are relative to the repository root') help='Paths are relative to the repository root')
def _DiffHelper(self, absolute, project):
"""Obtains the diff for a specific project.
Args:
absolute: Paths are relative to the root.
project: Project to get status of.
Returns:
The status of the project.
"""
buf = io.StringIO()
ret = project.PrintWorkTreeDiff(absolute, output_redir=buf)
return (ret, buf.getvalue())
def Execute(self, opt, args): def Execute(self, opt, args):
ret = 0 ret = 0
for project in self.GetProjects(args): all_projects = self.GetProjects(args)
# NB: Multiprocessing is heavy, so don't spin it up for one job.
if len(all_projects) == 1 or opt.jobs == 1:
for project in all_projects:
if not project.PrintWorkTreeDiff(opt.absolute): if not project.PrintWorkTreeDiff(opt.absolute):
ret = 1 ret = 1
else:
with multiprocessing.Pool(opt.jobs) as pool:
states = pool.imap(functools.partial(self._DiffHelper, opt.absolute),
all_projects, WORKER_BATCH_SIZE)
for (state, output) in states:
if output:
print(output, end='')
if not state:
ret = 1
return ret return ret