From 6f180c0a2304d46773904e815715ab57e427760b Mon Sep 17 00:00:00 2001 From: Richard Wang Date: Wed, 12 Jun 2024 04:02:48 +0000 Subject: [PATCH] Use $HOME/.config/depot_tools on linux for .cfg files Or $XDG_CONFIG_HOME/.config/depot_tools if set A followup CL can add support for win/macos. Bug: b/345092320 Change-Id: I877baa4d7fd912b42cfcd88ad0aa347b700a89f2 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/tools/depot_tools/+/5604606 Commit-Queue: Richard Wang Reviewed-by: Takuto Ikuta Reviewed-by: Josip Sokcevic --- .gitignore | 2 +- metrics.py | 3 +- ninjalog_uploader_wrapper.py | 3 +- reclient_metrics.py | 4 +- tests/metrics_test.py | 3 +- tests/utils_test.py | 73 ++++++++++++++++++++++++++++++++++++ utils.py | 31 +++++++++++++++ 7 files changed, 114 insertions(+), 5 deletions(-) diff --git a/.gitignore b/.gitignore index 22b610ad45..e2e03d6b5d 100644 --- a/.gitignore +++ b/.gitignore @@ -84,7 +84,7 @@ testing_support/google_appengine *~ *.swp -# Ignore the monitoring config. It is unique for each user. +# Ignore win/mac monitoring config. It is unique for each depot_tools checkout. /metrics.cfg # Ignore the ninjalog upload config. diff --git a/metrics.py b/metrics.py index 627db84aed..0f0083d277 100644 --- a/metrics.py +++ b/metrics.py @@ -17,9 +17,10 @@ import detect_host_arch import gclient_utils import metrics_utils import subprocess2 +import utils DEPOT_TOOLS = os.path.dirname(os.path.abspath(__file__)) -CONFIG_FILE = os.path.join(DEPOT_TOOLS, 'metrics.cfg') +CONFIG_FILE = utils.depot_tools_config_path('metrics.cfg') UPLOAD_SCRIPT = os.path.join(DEPOT_TOOLS, 'upload_metrics.py') DEFAULT_COUNTDOWN = 10 diff --git a/ninjalog_uploader_wrapper.py b/ninjalog_uploader_wrapper.py index f17a05363d..563144edad 100755 --- a/ninjalog_uploader_wrapper.py +++ b/ninjalog_uploader_wrapper.py @@ -11,10 +11,11 @@ import sys import ninjalog_uploader import subprocess2 +import utils THIS_DIR = os.path.dirname(__file__) UPLOADER = os.path.join(THIS_DIR, "ninjalog_uploader.py") -CONFIG = os.path.join(THIS_DIR, "ninjalog.cfg") +CONFIG = utils.depot_tools_config_path("ninjalog.cfg") VERSION = 3 diff --git a/reclient_metrics.py b/reclient_metrics.py index 934c45e0bd..6d3771ff87 100755 --- a/reclient_metrics.py +++ b/reclient_metrics.py @@ -10,8 +10,10 @@ import os import subprocess import sys +import utils + THIS_DIR = os.path.dirname(__file__) -CONFIG = os.path.join(THIS_DIR, 'reclient_metrics.cfg') +CONFIG = utils.depot_tools_config_path('reclient_metrics.cfg') VERSION = 1 diff --git a/tests/metrics_test.py b/tests/metrics_test.py index 9e026280f8..c011ebc6df 100644 --- a/tests/metrics_test.py +++ b/tests/metrics_test.py @@ -14,6 +14,7 @@ sys.path.insert(0, ROOT_DIR) import metrics import metrics_utils +import utils # TODO: Should fix these warnings. # pylint: disable=line-too-long @@ -30,7 +31,7 @@ class TimeMock(object): class MetricsCollectorTest(unittest.TestCase): def setUp(self): - self.config_file = os.path.join(ROOT_DIR, 'metrics.cfg') + self.config_file = utils.depot_tools_config_path('metrics.cfg') self.collector = metrics.MetricsCollector() # Keep track of the URL requests, file reads/writes and subprocess diff --git a/tests/utils_test.py b/tests/utils_test.py index 15cd3fe8ea..5d0ca81673 100755 --- a/tests/utils_test.py +++ b/tests/utils_test.py @@ -5,7 +5,9 @@ import logging import os +import shutil import sys +import tempfile import unittest from unittest import mock @@ -41,6 +43,77 @@ class GitCacheTest(unittest.TestCase): self.assertEqual(version, 'unknown') +class ConfigDirTest(unittest.TestCase): + + @mock.patch('sys.platform', 'win') + def testWin(self): + self.assertEqual(DEPOT_TOOLS_ROOT, utils.depot_tools_config_dir()) + + @mock.patch('sys.platform', 'darwin') + def testMac(self): + self.assertEqual(DEPOT_TOOLS_ROOT, utils.depot_tools_config_dir()) + + @mock.patch('sys.platform', 'foo') + def testOther(self): + self.assertEqual(DEPOT_TOOLS_ROOT, utils.depot_tools_config_dir()) + + @mock.patch('sys.platform', 'linux') + @mock.patch.dict('os.environ', {}) + def testLinuxDefault(self): + self.assertEqual( + os.path.join(os.path.expanduser('~/.config'), 'depot_tools'), + utils.depot_tools_config_dir()) + + @mock.patch('sys.platform', 'linux') + @mock.patch.dict('os.environ', {'XDG_CONFIG_HOME': '/my/home'}) + def testLinuxCustom(self): + self.assertEqual(os.path.join('/my/home', 'depot_tools'), + utils.depot_tools_config_dir()) + + +class ConfigPathTest(unittest.TestCase): + + def setUp(self): + self.temp_dir = tempfile.mkdtemp(prefix='utils_test') + self.config_dir = os.path.join(self.temp_dir, 'test_files') + + self.isfile = mock.Mock() + self.move = mock.Mock() + + mock.patch('os.path.isfile', self.isfile).start() + mock.patch('shutil.move', self.move).start() + mock.patch('utils.depot_tools_config_dir', + lambda: self.config_dir).start() + + self.addCleanup(mock.patch.stopall) + self.addCleanup(shutil.rmtree, self.temp_dir) + + def testCreatesConfigDir(self): + # Ensure "legacy path" doesn't exist so that nothing gets moved. + def EnsureLegacyPathNotExists(path): + return path != os.path.join(DEPOT_TOOLS_ROOT, 'metrics.cfg') + + self.isfile.side_effect = EnsureLegacyPathNotExists + + self.assertEqual(os.path.join(self.config_dir, 'metrics.cfg'), + utils.depot_tools_config_path('metrics.cfg')) + self.assertTrue(os.path.exists(self.config_dir)) + self.move.assert_not_called() + + def testMovesLegacy(self): + # Ensure "legacy path" exists so that it gets moved. + def EnsureLegacyPathExists(path): + return path == os.path.join(DEPOT_TOOLS_ROOT, 'metrics.cfg') + + self.isfile.side_effect = EnsureLegacyPathExists + + self.assertEqual(os.path.join(self.config_dir, 'metrics.cfg'), + utils.depot_tools_config_path('metrics.cfg')) + self.move.assert_called_once_with( + os.path.join(DEPOT_TOOLS_ROOT, 'metrics.cfg'), + os.path.join(self.config_dir, 'metrics.cfg')) + + if __name__ == '__main__': logging.basicConfig( level=logging.DEBUG if '-v' in sys.argv else logging.ERROR) diff --git a/utils.py b/utils.py index a85d2f722e..5500dbf64f 100644 --- a/utils.py +++ b/utils.py @@ -3,7 +3,12 @@ # found in the LICENSE file. import os +import pathlib +import shutil import subprocess +import sys + +DEPOT_TOOLS_ROOT = os.path.dirname(os.path.abspath(__file__)) def depot_tools_version(): @@ -23,3 +28,29 @@ def depot_tools_version(): return 'recipes.cfg-%d' % (mtime) except Exception: return 'unknown' + + +def depot_tools_config_dir(): + # Use depot tools path for mac, windows. + if not sys.platform.startswith('linux'): + return DEPOT_TOOLS_ROOT + + # Use $XDG_CONFIG_HOME/depot_tools or $HOME/.config/depot_tools on linux. + config_root = os.getenv('XDG_CONFIG_HOME', os.path.expanduser('~/.config')) + return os.path.join(config_root, 'depot_tools') + + +def depot_tools_config_path(file): + config_dir = depot_tools_config_dir() + expected_path = os.path.join(config_dir, file) + + # Silently create config dir if necessary. + pathlib.Path(config_dir).mkdir(parents=True, exist_ok=True) + + # Silently migrate cfg from legacy path if it exists. + if not os.path.isfile(expected_path): + legacy_path = os.path.join(DEPOT_TOOLS_ROOT, file) + if os.path.isfile(legacy_path): + shutil.move(legacy_path, expected_path) + + return expected_path