| #!/usr/bin/env python3 |
| # Copyright 2011 The ChromiumOS Authors |
| # Use of this source code is governed by a BSD-style license that can be |
| # found in the LICENSE file. |
| """Wrapper for chromite tools. |
| |
| The script is intend to be symlinked to any number of chromite tools, attempts |
| to find the path for chromite, and hands off to the right tool via exec if |
| possible. |
| |
| It is intended to used strictly outside of the chroot. |
| """ |
| |
| import enum |
| import os |
| from pathlib import Path |
| import subprocess |
| import sys |
| from typing import List, NamedTuple, Optional, Tuple |
| |
| # Min version of Python that we *want*. We warn for older versions. |
| MIN_PYTHON_VER_SOFT = (3, 8) |
| # Min version of Python that we *require*. We abort for older versions. |
| MIN_PYTHON_VER_HARD = (3, 8) |
| |
| DEPOT_TOOLS_DIR = Path(__file__).resolve().parent |
| |
| # Directory where cros-specific CIPD packages are installed. |
| CIPD_CACHE_DIR = DEPOT_TOOLS_DIR / '.cipd_bin_cros_python2' |
| |
| |
| class Checkout(NamedTuple): |
| """Some details about this checkout.""" |
| |
| root: Path |
| chromite_dir: Path |
| |
| |
| def _FindChromite(path: Path) -> Optional[Checkout]: |
| """Find the chromite dir in a repo, gclient, or submodule checkout.""" |
| path = path.resolve() |
| # Depending on the checkout type (whether repo chromeos or gclient chrome) |
| # Chromite lives in a different location. |
| roots = ( |
| # CrOS checkout using normal manifest. |
| ('.repo', 'chromite/.git'), |
| # CrOS checkout using CitC. |
| ('../.citc', 'chromite/__init__.py'), |
| # Chromium checkout using gclient+DEPS. |
| ('.gclient', 'src/third_party/chromite/.git'), |
| # Chromium checkout using git submodules (submodules at root). |
| ('.gitmodules', 'chromite/.git'), |
| # Chromium checkout using git submodules. |
| ('src/.gitmodules', 'src/third_party/chromite/.git'), |
| # Chromium checkout using CitC. |
| ('../.citc', 'third_party/chromite/__init__.py'), |
| ) |
| |
| while path != Path("/"): |
| for root, chromite_git_dir in roots: |
| if all((path / x).exists() for x in [root, chromite_git_dir]): |
| return Checkout(path, (path / chromite_git_dir).parent) |
| path = path.parent |
| return None |
| |
| |
| def _MissingErrorOut(target): |
| sys.stderr.write("""ERROR: Couldn't find the chromite tool %s. |
| |
| Please change to a directory inside your ChromiumOS source tree |
| and retry. If you need to setup a ChromiumOS source tree, see |
| https://chromium.googlesource.com/chromiumos/docs/+/HEAD/developer_guide.md |
| """ % target) |
| return 127 |
| |
| |
| def _CheckPythonVersion(): |
| """Verify active Python is new enough.""" |
| if sys.version_info >= MIN_PYTHON_VER_SOFT: |
| return |
| |
| progname = os.path.basename(sys.argv[0]) |
| print('%s: ChromiumOS requires Python-%s+, but "%s" is "%s"' % |
| (progname, '.'.join(str(x) for x in MIN_PYTHON_VER_SOFT), |
| sys.executable, sys.version.replace('\n', ' ')), |
| file=sys.stderr) |
| if sys.version_info < MIN_PYTHON_VER_HARD: |
| print('%s: fatal: giving up since Python is too old.' % (progname, ), |
| file=sys.stderr) |
| sys.exit(1) |
| |
| print( |
| 'warning: temporarily continuing anyways; you must upgrade soon to ' |
| 'maintain support.', |
| file=sys.stderr) |
| |
| |
| def _BootstrapVpython27(): |
| """Installs the vpython2.7 packages into the cipd cache directory.""" |
| subprocess.run([ |
| 'cipd', 'ensure', '-log-level', 'info', '-ensure-file', |
| DEPOT_TOOLS_DIR / 'cipd_manifest_cros_python2.txt', '-root', |
| CIPD_CACHE_DIR |
| ], |
| check=True) |
| |
| |
| def main(): |
| _CheckPythonVersion() |
| |
| result = _FindChromite(Path.cwd()) |
| target = os.path.basename(sys.argv[0]) |
| if result is None: |
| return _MissingErrorOut(target) |
| root, chromite_dir = result |
| |
| is_citc = (root.parent / ".citc").is_dir() |
| if is_citc: |
| # citc workspaces don't like dirty files like pyc. |
| os.environ["PYTHONDONTWRITEBYTECODE"] = "1" |
| |
| path = chromite_dir / "bin" / target |
| |
| # Check to see if this is a script requiring vpython2.7. |
| with path.open("rb") as fp: |
| shebang = next(fp).strip() |
| interpreter = shebang.split()[-1] |
| if interpreter in (b'python', b'python2', b'python2.7', b'vpython'): |
| _BootstrapVpython27() |
| vpython = CIPD_CACHE_DIR / 'vpython' |
| args = [vpython] |
| if interpreter != b'vpython': |
| args.extend( |
| ['-vpython-spec', DEPOT_TOOLS_DIR / 'cros_python2.vpython']) |
| args.append(path) |
| path = vpython |
| else: |
| args = [path] |
| |
| os.execv(path, args + sys.argv[1:]) |
| |
| |
| if __name__ == '__main__': |
| sys.exit(main()) |