blob: 46ed1e5f4e55efb1992a3dd6d3f0c91b7e0fdf0d [file] [log] [blame]
Mike Frysinger1ca14432020-02-16 00:18:56 -05001#!/usr/bin/env python3
Aviv Keshet39853bd2016-09-22 15:12:05 -07002# Copyright 2016 The Chromium OS Authors. All rights reserved.
3# Use of this source code is governed by a BSD-style license that can be
4# found in the LICENSE file.
5
6"""Wrapper around chromite executable scripts that use virtualenv."""
7
Aviv Keshet39853bd2016-09-22 15:12:05 -07008import os
Allen Li465a0d62016-11-30 14:55:08 -08009import subprocess
Aviv Keshet39853bd2016-09-22 15:12:05 -070010import sys
Allen Li465a0d62016-11-30 14:55:08 -080011
Mike Frysinger807d8282022-04-28 22:45:17 -040012
Greg Edelstona4c9b3b2020-01-07 17:51:13 -070013try:
Alex Klein1699fab2022-09-08 08:46:06 -060014 import pytest # pylint: disable=import-error
15
16 wrapper3 = pytest.importorskip(
17 "wrapper3", reason="File must be run in venv"
18 )
Greg Edelstona4c9b3b2020-01-07 17:51:13 -070019except ImportError:
Alex Klein1699fab2022-09-08 08:46:06 -060020 import wrapper3
Aviv Keshet39853bd2016-09-22 15:12:05 -070021
Don Garrett863f90b2017-04-19 17:04:20 -070022_CHROMITE_DIR = os.path.realpath(
Alex Klein1699fab2022-09-08 08:46:06 -060023 os.path.join(os.path.abspath(__file__), "..", "..")
24)
Allen Li9f03f5b2016-12-13 15:23:52 -080025
Allen Li465a0d62016-11-30 14:55:08 -080026# _VIRTUALENV_DIR contains the scripts for working with venvs
Alex Klein1699fab2022-09-08 08:46:06 -060027_VIRTUALENV_DIR = os.path.join(_CHROMITE_DIR, "..", "infra_virtualenv")
28_CREATE_VENV_PATH = os.path.join(_VIRTUALENV_DIR, "bin", "create_venv3")
29_REQUIREMENTS = os.path.join(_CHROMITE_DIR, "venv", "requirements.txt")
Allen Li465a0d62016-11-30 14:55:08 -080030
Alex Klein1699fab2022-09-08 08:46:06 -060031_VENV_MARKER = "INSIDE_CHROMITE_VENV"
Allen Li9f03f5b2016-12-13 15:23:52 -080032
Allen Li465a0d62016-11-30 14:55:08 -080033
34def main():
Alex Klein1699fab2022-09-08 08:46:06 -060035 if _IsInsideVenv(os.environ):
36 # Don't bleed the marker into children processes that might use the wrapper
37 # themselves to run inside of the virtualenv.
38 os.environ.pop(_VENV_MARKER)
39 wrapper3.DoMain()
40 else:
41 venvdir = _CreateVenv()
42 _ExecInVenv(venvdir, sys.argv)
Allen Li465a0d62016-11-30 14:55:08 -080043
44
45def _CreateVenv():
Alex Klein1699fab2022-09-08 08:46:06 -060046 """Create or update chromite venv."""
47 result = subprocess.run(
48 [_CREATE_VENV_PATH, _REQUIREMENTS],
49 check=False,
50 stdout=subprocess.PIPE,
51 encoding="utf-8",
52 )
53 if result.returncode:
54 print(
55 f'{os.path.basename(sys.argv[0])}: error: {" ".join(result.args)}: '
56 f"exited {result.returncode}",
57 file=sys.stderr,
58 )
59 sys.exit(result.returncode)
60 return result.stdout.strip()
Allen Li465a0d62016-11-30 14:55:08 -080061
62
Allen Li68f42e22017-03-27 17:08:59 -070063def _ExecInVenv(venvdir, args):
Alex Klein1699fab2022-09-08 08:46:06 -060064 """Exec command in chromite venv.
Allen Li465a0d62016-11-30 14:55:08 -080065
Alex Klein1699fab2022-09-08 08:46:06 -060066 Args:
67 venvdir: virtualenv directory
68 args: Sequence of arguments.
69 """
70 venv_python = os.path.join(venvdir, "bin", "python")
71 os.execve(
72 venv_python,
73 [venv_python] + list(args),
74 _CreateVenvEnvironment(os.environ),
75 )
Allen Li465a0d62016-11-30 14:55:08 -080076
77
Allen Li9f03f5b2016-12-13 15:23:52 -080078def _CreateVenvEnvironment(env_dict):
Alex Klein1699fab2022-09-08 08:46:06 -060079 """Create environment for a virtualenv.
Allen Li9f03f5b2016-12-13 15:23:52 -080080
Alex Klein1699fab2022-09-08 08:46:06 -060081 This adds a special marker variable to a copy of the input environment dict
82 and returns the copy.
Allen Li9f03f5b2016-12-13 15:23:52 -080083
Alex Klein1699fab2022-09-08 08:46:06 -060084 Args:
85 env_dict: Environment variable dict to use as base, which is not modified.
Allen Li9f03f5b2016-12-13 15:23:52 -080086
Alex Klein1699fab2022-09-08 08:46:06 -060087 Returns:
88 New environment dict for a virtualenv.
89 """
90 new_env_dict = env_dict.copy()
91 new_env_dict[_VENV_MARKER] = "1"
92 new_env_dict.pop("PYTHONPATH", None)
93 return new_env_dict
Allen Li9f03f5b2016-12-13 15:23:52 -080094
95
96def _IsInsideVenv(env_dict):
Alex Klein1699fab2022-09-08 08:46:06 -060097 """Return whether the environment dict is running inside a virtualenv.
Allen Li9f03f5b2016-12-13 15:23:52 -080098
Alex Klein1699fab2022-09-08 08:46:06 -060099 This checks the environment dict for the special marker added by
100 _CreateVenvEnvironment().
Allen Li9f03f5b2016-12-13 15:23:52 -0800101
Alex Klein1699fab2022-09-08 08:46:06 -0600102 Args:
103 env_dict: Environment variable dict to check
Allen Li9f03f5b2016-12-13 15:23:52 -0800104
Alex Klein1699fab2022-09-08 08:46:06 -0600105 Returns:
106 A true value if inside virtualenv, else a false value.
107 """
108 # Checking sys.prefix or doing any kind of path check is unreliable because
109 # we check out chromite to weird places.
110 return env_dict.get(_VENV_MARKER, "")
Aviv Keshet39853bd2016-09-22 15:12:05 -0700111
112
Alex Klein1699fab2022-09-08 08:46:06 -0600113if __name__ == "__main__":
114 main()