Resolve git.bat to git.exe without using shell=True

In order for git to be run on Windows and ultimately run git.exe it is
normally necessary to pass shell=True to Popen or else invoke git.bat,
or both. However this means invoking cmd.exe every time we want to
invoke git.exe, which can end up being over 1,500 invocations of cmd.exe
when running the "update" stage of gclient sync. This makes the "update"
stage take about 1.45x as long to run - it's a significant overhead.
Even with optimizations to the update stage of gclient sync in the NOP
case this repeated invocation of cmd.exe still costs about 0.8 s of a
4.9 s "update" stage.

This change teaches git_common how to find git.exe instead of just
git.bat by parsing the .exe name out of the .bat file.

Bug: 332982922
Change-Id: I4e052444276d55c0496144b9816fe365a95a56d6
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/tools/depot_tools/+/5462405
Reviewed-by: Josip Sokcevic <sokcevic@chromium.org>
Commit-Queue: Bruce Dawson <brucedawson@chromium.org>
changes/05/5462405/6
Bruce Dawson 1 year ago committed by LUCI CQ
parent 3ea849f363
commit 09c232e7c0

@ -53,6 +53,18 @@ def win_find_git():
for candidate in ('git.exe', 'git.bat'):
path = os.path.join(elem, candidate)
if os.path.isfile(path):
# shell=True or invoking git.bat causes Windows to invoke
# cmd.exe to run git.bat. The extra processes add significant
# overhead (most visible in the "update" stage of gclient sync)
# so we want to avoid it whenever possible, by extracting the
# path to git.exe from git.bat in depot_tools.
if candidate == 'git.bat':
git_bat = open(path).readlines()
new_path = os.path.join(elem, git_bat[-1][6:-5])
if (git_bat[-1].startswith('"%~dp0')
and git_bat[-1].endswith('" %*\n')
and new_path.endswith('.exe')):
path = new_path
return path
raise ValueError('Could not find Git on PATH.')

Loading…
Cancel
Save