xref: /aosp_15_r20/external/autotest/client/common_lib/check_version.py (revision 9c5db1993ded3edbeafc8092d69fe5de2ee02df7)
1*9c5db199SXin Li# This file must use Python 1.5 syntax.
2*9c5db199SXin Liimport glob
3*9c5db199SXin Liimport logging
4*9c5db199SXin Liimport os
5*9c5db199SXin Liimport re
6*9c5db199SXin Liimport sys
7*9c5db199SXin Li
8*9c5db199SXin LiPY_GLOBS = {
9*9c5db199SXin Li        3: ['/usr/bin/python3*', '/usr/local/bin/python3*'],
10*9c5db199SXin Li        2: ['/usr/bin/python2*', '/usr/local/bin/python2*']
11*9c5db199SXin Li}
12*9c5db199SXin Li
13*9c5db199SXin Li
14*9c5db199SXin Liclass check_python_version:
15*9c5db199SXin Li
16*9c5db199SXin Li    def __init__(self, desired_version=3):
17*9c5db199SXin Li        # In order to ease the migration to Python3, disable the restart logic
18*9c5db199SXin Li        # when AUTOTEST_NO_RESTART is set. This makes it possible to run
19*9c5db199SXin Li        # autotest locally as Python3 before any other environment is switched
20*9c5db199SXin Li        # to Python3.
21*9c5db199SXin Li        if os.getenv("AUTOTEST_NO_RESTART"):
22*9c5db199SXin Li            return
23*9c5db199SXin Li        self.desired_version = desired_version
24*9c5db199SXin Li
25*9c5db199SXin Li        # The change to prefer 2.4 really messes up any systems which have both
26*9c5db199SXin Li        # the new and old version of Python, but where the newer is default.
27*9c5db199SXin Li        # This is because packages, libraries, etc are all installed into the
28*9c5db199SXin Li        # new one by default. Some things (like running under mod_python) just
29*9c5db199SXin Li        # plain don't handle python restarting properly. I know that I do some
30*9c5db199SXin Li        # development under ipython and whenever I run (or do anything that
31*9c5db199SXin Li        # runs) 'import common' it restarts my shell. Overall, the change was
32*9c5db199SXin Li        # fairly annoying for me (and I can't get around having 2.4 and 2.5
33*9c5db199SXin Li        # installed with 2.5 being default).
34*9c5db199SXin Li        if sys.version_info.major != self.desired_version:
35*9c5db199SXin Li            try:
36*9c5db199SXin Li                # We can't restart when running under mod_python.
37*9c5db199SXin Li                from mod_python import apache
38*9c5db199SXin Li            except ImportError:
39*9c5db199SXin Li                self.restart()
40*9c5db199SXin Li
41*9c5db199SXin Li    def extract_version(self, path):
42*9c5db199SXin Li        """Return a matching python version to the provided path."""
43*9c5db199SXin Li        match = re.search(r'/python(\d+)\.(\d+)$', path)
44*9c5db199SXin Li        if match:
45*9c5db199SXin Li            return (int(match.group(1)), int(match.group(2)))
46*9c5db199SXin Li        else:
47*9c5db199SXin Li            return None
48*9c5db199SXin Li
49*9c5db199SXin Li    def find_desired_python(self):
50*9c5db199SXin Li        """Returns the path of the desired python interpreter."""
51*9c5db199SXin Li        pythons = []
52*9c5db199SXin Li        for glob_str in PY_GLOBS[self.desired_version]:
53*9c5db199SXin Li            pythons.extend(glob.glob(glob_str))
54*9c5db199SXin Li
55*9c5db199SXin Li        possible_versions = []
56*9c5db199SXin Li        for python in pythons:
57*9c5db199SXin Li            version = self.extract_version(python)
58*9c5db199SXin Li            if not version:
59*9c5db199SXin Li                continue
60*9c5db199SXin Li            # Autotest in Python2 is written to 2.4 and above.
61*9c5db199SXin Li            if self.desired_version == 2:
62*9c5db199SXin Li                if version < (2, 4):
63*9c5db199SXin Li                    continue
64*9c5db199SXin Li            if self.desired_version == 3:
65*9c5db199SXin Li                # Autotest in Python3 is written to 3.6 and above.
66*9c5db199SXin Li                if version < (3, 6):
67*9c5db199SXin Li                    continue
68*9c5db199SXin Li            possible_versions.append((version, python))
69*9c5db199SXin Li
70*9c5db199SXin Li        possible_versions.sort()
71*9c5db199SXin Li
72*9c5db199SXin Li        if not possible_versions:
73*9c5db199SXin Li            raise ValueError('Python %s.x not found' % self.desired_version)
74*9c5db199SXin Li
75*9c5db199SXin Li        # Return the lowest compatible major version possible
76*9c5db199SXin Li        return possible_versions[0][1]
77*9c5db199SXin Li
78*9c5db199SXin Li    def restart(self):
79*9c5db199SXin Li        python = self.find_desired_python()
80*9c5db199SXin Li        sys.stderr.write('NOTE: %s switching to %s\n' %
81*9c5db199SXin Li                         (os.path.basename(sys.argv[0]), python))
82*9c5db199SXin Li        sys.argv.insert(0, '-u')
83*9c5db199SXin Li        sys.argv.insert(0, python)
84*9c5db199SXin Li        os.execv(sys.argv[0], sys.argv)
85