[ChromiumOS] Add a launcher for Bazel
CrOS intends to provide a Bazel executable for our users in chromite/bin/bazel in our tree. We'd like the "bazel" command in depot_tools to call this executable. This adds a new launcher to depot_tools which searches for that bazel executable when located inside of a ChromiumOS checkout, and executes it. When located outside of a ChromiumOS checkout, this launcher "disappears", searching elsewhere in the PATH for another Bazel executable. Since other teams using depot_tools may want to start using Bazel in the future, this launcher is intended to have shared ownership: other teams are welcome to come add their search functions to the launcher if they require the same functionality as us. Bug: b:253268519 Change-Id: I61f6383d8b69b9eea622f37277678f898cc7fd6b Reviewed-on: https://chromium-review.googlesource.com/c/chromium/tools/depot_tools/+/4718785 Reviewed-by: Shuhei Takahashi <nya@chromium.org> Reviewed-by: Josip Sokcevic <sokcevic@chromium.org> Reviewed-by: Aaron Massey <aaronmassey@google.com> Commit-Queue: Jack Rosenthal <jrosenth@chromium.org> Auto-Submit: Jack Rosenthal <jrosenth@chromium.org> Commit-Queue: Josip Sokcevic <sokcevic@chromium.org>changes/85/4718785/9
parent
a8946f3d83
commit
6a505ad9ab
@ -0,0 +1,85 @@
|
|||||||
|
#!/usr/bin/env vpython3
|
||||||
|
# Copyright 2023 The ChromiumOS Authors
|
||||||
|
# Use of this source code is governed by a BSD-style license that can be
|
||||||
|
# found in the LICENSE file.
|
||||||
|
|
||||||
|
# [VPYTHON:BEGIN]
|
||||||
|
# python_version: "3.8"
|
||||||
|
# [VPYTHON:END]
|
||||||
|
"""Bazel launcher wrapper.
|
||||||
|
|
||||||
|
This script starts Bazel appropriate for the project you're working in. It's
|
||||||
|
currently used by ChromiumOS, but is intended for use and to be updated by any
|
||||||
|
depot_tools users who are using Bazel.
|
||||||
|
|
||||||
|
In the case this script is not able to detect which project you're working in,
|
||||||
|
it will fall back to using the next "bazel" executable in your PATH.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import itertools
|
||||||
|
import os
|
||||||
|
from pathlib import Path
|
||||||
|
import shutil
|
||||||
|
import sys
|
||||||
|
from typing import List, Optional
|
||||||
|
|
||||||
|
|
||||||
|
def _find_bazel_cros() -> Optional[Path]:
|
||||||
|
"""Find the bazel launcher for ChromiumOS."""
|
||||||
|
cwd = Path.cwd()
|
||||||
|
for parent in itertools.chain([cwd], cwd.parents):
|
||||||
|
bazel_launcher = parent / "chromite" / "bin" / "bazel"
|
||||||
|
if bazel_launcher.exists():
|
||||||
|
return bazel_launcher
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def _find_next_bazel_in_path() -> Optional[Path]:
|
||||||
|
"""The fallback method: search the remainder of PATH for bazel."""
|
||||||
|
# Remove depot_tools from PATH if present.
|
||||||
|
depot_tools = Path(__file__).resolve().parent
|
||||||
|
path_env = os.environ.get("PATH", os.defpath)
|
||||||
|
search_paths = []
|
||||||
|
for path in path_env.split(os.pathsep):
|
||||||
|
if Path(path).resolve() != depot_tools:
|
||||||
|
search_paths.append(path)
|
||||||
|
new_path_env = os.pathsep.join(search_paths)
|
||||||
|
bazel = shutil.which("bazel", path=new_path_env)
|
||||||
|
if bazel:
|
||||||
|
return Path(bazel)
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
# All functions used to search for Bazel (in order of search).
|
||||||
|
_SEARCH_FUNCTIONS = (
|
||||||
|
_find_bazel_cros,
|
||||||
|
_find_next_bazel_in_path,
|
||||||
|
)
|
||||||
|
|
||||||
|
_FIND_FAILURE_MSG = """\
|
||||||
|
ERROR: The depot_tools bazel launcher was unable to find an appropriate bazel
|
||||||
|
executable to use.
|
||||||
|
|
||||||
|
For ChromiumOS developers:
|
||||||
|
Make sure your current directory is inside a ChromiumOS checkout (e.g.,
|
||||||
|
~/chromiumos). If you're already in a ChromiumOS checkout, it may be because
|
||||||
|
you're working on a branch that's too old (i.e., prior to Bazel).
|
||||||
|
|
||||||
|
If you're not working on any of the above listed projects, this launcher assumes
|
||||||
|
that you have Bazel installed on your system somewhere else in PATH. Check that
|
||||||
|
it's actually installed."""
|
||||||
|
|
||||||
|
|
||||||
|
def main(argv: List[str]) -> int:
|
||||||
|
"""Main."""
|
||||||
|
for search_func in _SEARCH_FUNCTIONS:
|
||||||
|
bazel = search_func()
|
||||||
|
if bazel:
|
||||||
|
os.execv(bazel, [str(bazel), *argv])
|
||||||
|
|
||||||
|
print(_FIND_FAILURE_MSG, file=sys.stderr)
|
||||||
|
return 1
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
sys.exit(main(sys.argv[1:]))
|
@ -0,0 +1,94 @@
|
|||||||
|
#!/usr/bin/env vpython3
|
||||||
|
# Copyright 2023 The ChromiumOS Authors
|
||||||
|
# Use of this source code is governed by a BSD-style license that can be
|
||||||
|
# found in the LICENSE file.
|
||||||
|
|
||||||
|
# [VPYTHON:BEGIN]
|
||||||
|
# python_version: "3.8"
|
||||||
|
# [VPYTHON:END]
|
||||||
|
"""Tests for Bazel launcher."""
|
||||||
|
|
||||||
|
import os
|
||||||
|
from pathlib import Path
|
||||||
|
import site
|
||||||
|
import sys
|
||||||
|
import unittest
|
||||||
|
|
||||||
|
DEPOT_TOOLS_DIR = Path(__file__).resolve().parent.parent
|
||||||
|
site.addsitedir(DEPOT_TOOLS_DIR)
|
||||||
|
|
||||||
|
import bazel
|
||||||
|
from testing_support import trial_dir
|
||||||
|
|
||||||
|
|
||||||
|
class FindCrosUnittest(trial_dir.TestCase):
|
||||||
|
"""Test the _find_bazel_cros function."""
|
||||||
|
def setUp(self):
|
||||||
|
"""Create the checkout and chromite files."""
|
||||||
|
super().setUp()
|
||||||
|
self.checkout_dir = Path(self.root_dir) / "chromiumos"
|
||||||
|
self.chromite_dir = self.checkout_dir / "chromite"
|
||||||
|
self.launcher = self.chromite_dir / "bin" / "bazel"
|
||||||
|
self.launcher.parent.mkdir(exist_ok=True, parents=True)
|
||||||
|
self.launcher.write_bytes(b"")
|
||||||
|
self.launcher.chmod(0o775)
|
||||||
|
self.orig_dir = Path.cwd()
|
||||||
|
|
||||||
|
def tearDown(self):
|
||||||
|
os.chdir(self.orig_dir)
|
||||||
|
super().tearDown()
|
||||||
|
|
||||||
|
def test_at_checkout_base(self):
|
||||||
|
"""Test we find the launcher at the base of the checkout."""
|
||||||
|
os.chdir(self.checkout_dir)
|
||||||
|
self.assertEqual(bazel._find_bazel_cros(), self.launcher)
|
||||||
|
|
||||||
|
def test_in_checkout_subdir(self):
|
||||||
|
"""Test we find the launcher in a subdir of the checkout."""
|
||||||
|
os.chdir(self.chromite_dir)
|
||||||
|
self.assertEqual(bazel._find_bazel_cros(), self.launcher)
|
||||||
|
|
||||||
|
def test_out_of_checkout(self):
|
||||||
|
"""Test we don't find the launcher outside of the checkout."""
|
||||||
|
os.chdir(self.root_dir)
|
||||||
|
self.assertIsNone(bazel._find_bazel_cros())
|
||||||
|
|
||||||
|
|
||||||
|
class FindPathUnittest(trial_dir.TestCase):
|
||||||
|
"""Test the _find_next_bazel_in_path function."""
|
||||||
|
def setUp(self):
|
||||||
|
"""Create the checkout and chromite files."""
|
||||||
|
super().setUp()
|
||||||
|
|
||||||
|
self.bin_dir = Path(self.root_dir) / "bin"
|
||||||
|
self.bin_dir.mkdir(exist_ok=True, parents=True)
|
||||||
|
self.orig_path = os.environ.get("PATH", os.defpath)
|
||||||
|
|
||||||
|
# DEPOT_TOOLS_DIR is located twice in PATH for spice.
|
||||||
|
os.environ["PATH"] = os.pathsep.join([
|
||||||
|
str(DEPOT_TOOLS_DIR),
|
||||||
|
str(self.bin_dir),
|
||||||
|
str(DEPOT_TOOLS_DIR),
|
||||||
|
])
|
||||||
|
|
||||||
|
def tearDown(self):
|
||||||
|
"""Restore actions from setUp()."""
|
||||||
|
os.environ["PATH"] = self.orig_path
|
||||||
|
|
||||||
|
def test_not_in_path(self):
|
||||||
|
"""Test we don't find anything in PATH when not present."""
|
||||||
|
self.assertIsNone(bazel._find_next_bazel_in_path())
|
||||||
|
|
||||||
|
def test_in_path(self):
|
||||||
|
"""Test we find the next Bazel in PATH when present."""
|
||||||
|
if sys.platform == "win32":
|
||||||
|
launcher = self.bin_dir / "bazel.exe"
|
||||||
|
else:
|
||||||
|
launcher = self.bin_dir / "bazel"
|
||||||
|
launcher.write_bytes(b"")
|
||||||
|
launcher.chmod(0o755)
|
||||||
|
self.assertEqual(bazel._find_next_bazel_in_path(), launcher)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
unittest.main()
|
Loading…
Reference in New Issue