From 6e8c18239d9dc4da5045778d5ed87888611bf848 Mon Sep 17 00:00:00 2001 From: Andrew Grieve Date: Tue, 3 Oct 2023 20:36:59 +0000 Subject: [PATCH] Cache values in gclient_paths.py Several clients of this module call its methods repeatedly. Cache them to speed them up. E.g. "autosiso" calls FindGclientRoot() 5 times before building E.g. "git cl format" calls it 5 times in one of my CLs. Bug: None Change-Id: I70995c2def9689d46a89896640cc748d9629df3b Reviewed-on: https://chromium-review.googlesource.com/c/chromium/tools/depot_tools/+/4904697 Reviewed-by: Josip Sokcevic Commit-Queue: Josip Sokcevic --- gclient_paths.py | 33 ++++++++++++++++++++++----------- tests/gclient_paths_test.py | 4 +++- 2 files changed, 25 insertions(+), 12 deletions(-) diff --git a/gclient_paths.py b/gclient_paths.py index 1cfa213f1..3e4522a5a 100644 --- a/gclient_paths.py +++ b/gclient_paths.py @@ -8,6 +8,7 @@ # particularly for modules that are not builtin (see sys.builtin_modules_names, # os isn't built in, but it's essential to this file). +import functools import logging import os import sys @@ -19,6 +20,7 @@ import subprocess2 # pylint: disable=line-too-long +@functools.lru_cache def FindGclientRoot(from_dir, filename='.gclient'): """Tries to find the gclient root.""" real_from_dir = os.path.abspath(from_dir) @@ -65,10 +67,9 @@ def FindGclientRoot(from_dir, filename='.gclient'): return None -def GetPrimarySolutionPath(): - """Returns the full path to the primary solution. (gclient_root + src)""" - - gclient_root = FindGclientRoot(os.getcwd()) +@functools.lru_cache +def _GetPrimarySolutionPathInternal(cwd): + gclient_root = FindGclientRoot(cwd) if gclient_root: # Some projects' top directory is not named 'src'. source_dir_name = GetGClientPrimarySolutionName(gclient_root) or 'src' @@ -76,7 +77,7 @@ def GetPrimarySolutionPath(): # Some projects might not use .gclient. Try to see whether we're in a git # checkout that contains a 'buildtools' subdir. - top_dir = os.getcwd() + top_dir = cwd try: top_dir = subprocess2.check_output( ['git', 'rev-parse', '--show-toplevel'], stderr=subprocess2.DEVNULL) @@ -90,13 +91,13 @@ def GetPrimarySolutionPath(): return None -def GetBuildtoolsPath(): - """Returns the full path to the buildtools directory. - This is based on the root of the checkout containing the current directory.""" +def GetPrimarySolutionPath(): + """Returns the full path to the primary solution. (gclient_root + src)""" + return _GetPrimarySolutionPathInternal(os.getcwd()) - # Overriding the build tools path by environment is highly unsupported and - # may break without warning. Do not rely on this for anything important. - override = os.environ.get('CHROMIUM_BUILDTOOLS_PATH') + +@functools.lru_cache +def _GetBuildtoolsPathInternal(cwd, override): if override is not None: return override @@ -117,6 +118,15 @@ def GetBuildtoolsPath(): return None +def GetBuildtoolsPath(): + """Returns the full path to the buildtools directory. + This is based on the root of the checkout containing the current directory.""" + # Overriding the build tools path by environment is highly unsupported and + # may break without warning. Do not rely on this for anything important. + override = os.environ.get('CHROMIUM_BUILDTOOLS_PATH') + return _GetBuildtoolsPathInternal(os.getcwd(), override) + + def GetBuildtoolsPlatformBinaryPath(): """Returns the full path to the binary directory for the current platform.""" buildtools_path = GetBuildtoolsPath() @@ -141,6 +151,7 @@ def GetExeSuffix(): return '' +@functools.lru_cache def GetGClientPrimarySolutionName(gclient_root_dir_path): """Returns the name of the primary solution in the .gclient file specified.""" gclient_config_file = os.path.join(gclient_root_dir_path, '.gclient') diff --git a/tests/gclient_paths_test.py b/tests/gclient_paths_test.py index 72e0d92be..8800a22f8 100644 --- a/tests/gclient_paths_test.py +++ b/tests/gclient_paths_test.py @@ -26,6 +26,8 @@ class TestBase(unittest.TestCase): super(TestBase, self).setUp() self.file_tree = {} self.root = 'C:\\' if sys.platform == 'win32' else '/' + # Use unique roots for each test to avoid cache hits from @lru_cache. + self.root += self._testMethodName self.cwd = self.root mock.patch('gclient_utils.FileRead', self.read).start() mock.patch('os.environ', {}).start() @@ -48,7 +50,7 @@ class TestBase(unittest.TestCase): def make_file_tree(self, file_tree): self.file_tree = { - self.root + path: content + os.path.join(self.root, path): content for path, content in file_tree.items() }