xref: /aosp_15_r20/tools/acloud/setup/setup_common.py (revision 800a58d989c669b8eb8a71d8df53b1ba3d411444)
1*800a58d9SAndroid Build Coastguard Worker#!/usr/bin/env python
2*800a58d9SAndroid Build Coastguard Worker#
3*800a58d9SAndroid Build Coastguard Worker# Copyright 2018 - The Android Open Source Project
4*800a58d9SAndroid Build Coastguard Worker#
5*800a58d9SAndroid Build Coastguard Worker# Licensed under the Apache License, Version 2.0 (the "License");
6*800a58d9SAndroid Build Coastguard Worker# you may not use this file except in compliance with the License.
7*800a58d9SAndroid Build Coastguard Worker# You may obtain a copy of the License at
8*800a58d9SAndroid Build Coastguard Worker#
9*800a58d9SAndroid Build Coastguard Worker#     http://www.apache.org/licenses/LICENSE-2.0
10*800a58d9SAndroid Build Coastguard Worker#
11*800a58d9SAndroid Build Coastguard Worker# Unless required by applicable law or agreed to in writing, software
12*800a58d9SAndroid Build Coastguard Worker# distributed under the License is distributed on an "AS IS" BASIS,
13*800a58d9SAndroid Build Coastguard Worker# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14*800a58d9SAndroid Build Coastguard Worker# See the License for the specific language governing permissions and
15*800a58d9SAndroid Build Coastguard Worker# limitations under the License.
16*800a58d9SAndroid Build Coastguard Worker"""Common code used by acloud setup tools."""
17*800a58d9SAndroid Build Coastguard Worker
18*800a58d9SAndroid Build Coastguard Workerfrom __future__ import print_function
19*800a58d9SAndroid Build Coastguard Workerimport logging
20*800a58d9SAndroid Build Coastguard Workerimport re
21*800a58d9SAndroid Build Coastguard Workerimport subprocess
22*800a58d9SAndroid Build Coastguard Worker
23*800a58d9SAndroid Build Coastguard Workerfrom acloud import errors
24*800a58d9SAndroid Build Coastguard Workerfrom acloud.internal.lib import utils
25*800a58d9SAndroid Build Coastguard Worker
26*800a58d9SAndroid Build Coastguard Worker
27*800a58d9SAndroid Build Coastguard Workerlogger = logging.getLogger(__name__)
28*800a58d9SAndroid Build Coastguard Worker
29*800a58d9SAndroid Build Coastguard WorkerPKG_INSTALL_CMD = "sudo apt-get --assume-yes install %s"
30*800a58d9SAndroid Build Coastguard WorkerAPT_CHECK_CMD = "LANG=en_US.UTF-8 LANGUAGE=en_US:en apt-cache policy %s"
31*800a58d9SAndroid Build Coastguard Worker_INSTALLED_RE = re.compile(r"(.*\s*Installed:)(?P<installed_ver>.*\s?)")
32*800a58d9SAndroid Build Coastguard Worker_CANDIDATE_RE = re.compile(r"(.*\s*Candidate:)(?P<candidate_ver>.*\s?)")
33*800a58d9SAndroid Build Coastguard Worker
34*800a58d9SAndroid Build Coastguard Worker
35*800a58d9SAndroid Build Coastguard Workerdef CheckCmdOutput(cmd, print_cmd=True, **kwargs):
36*800a58d9SAndroid Build Coastguard Worker    """Helper function to run subprocess.check_output.
37*800a58d9SAndroid Build Coastguard Worker
38*800a58d9SAndroid Build Coastguard Worker    This function will return the command output for parsing the result and will
39*800a58d9SAndroid Build Coastguard Worker    raise Error if command return code was non-zero.
40*800a58d9SAndroid Build Coastguard Worker
41*800a58d9SAndroid Build Coastguard Worker    Args:
42*800a58d9SAndroid Build Coastguard Worker        cmd: String, the cmd string.
43*800a58d9SAndroid Build Coastguard Worker        print_cmd: True to print cmd to stdout.
44*800a58d9SAndroid Build Coastguard Worker        kwargs: Other option args to subprocess.
45*800a58d9SAndroid Build Coastguard Worker
46*800a58d9SAndroid Build Coastguard Worker    Returns:
47*800a58d9SAndroid Build Coastguard Worker        Return cmd output as a byte string.
48*800a58d9SAndroid Build Coastguard Worker        If the return code was non-zero it raises a CalledProcessError.
49*800a58d9SAndroid Build Coastguard Worker    """
50*800a58d9SAndroid Build Coastguard Worker    if print_cmd:
51*800a58d9SAndroid Build Coastguard Worker        print("Run command: %s" % cmd)
52*800a58d9SAndroid Build Coastguard Worker
53*800a58d9SAndroid Build Coastguard Worker    logger.debug("Run command: %s", cmd)
54*800a58d9SAndroid Build Coastguard Worker    return utils.CheckOutput(cmd, **kwargs)
55*800a58d9SAndroid Build Coastguard Worker
56*800a58d9SAndroid Build Coastguard Worker
57*800a58d9SAndroid Build Coastguard Workerdef InstallPackage(pkg):
58*800a58d9SAndroid Build Coastguard Worker    """Install package.
59*800a58d9SAndroid Build Coastguard Worker
60*800a58d9SAndroid Build Coastguard Worker    Args:
61*800a58d9SAndroid Build Coastguard Worker        pkg: String, the name of package.
62*800a58d9SAndroid Build Coastguard Worker
63*800a58d9SAndroid Build Coastguard Worker    Raises:
64*800a58d9SAndroid Build Coastguard Worker        PackageInstallError: package is not installed.
65*800a58d9SAndroid Build Coastguard Worker    """
66*800a58d9SAndroid Build Coastguard Worker    try:
67*800a58d9SAndroid Build Coastguard Worker        print(CheckCmdOutput(PKG_INSTALL_CMD % pkg,
68*800a58d9SAndroid Build Coastguard Worker                             shell=True,
69*800a58d9SAndroid Build Coastguard Worker                             stderr=subprocess.STDOUT))
70*800a58d9SAndroid Build Coastguard Worker    except subprocess.CalledProcessError as cpe:
71*800a58d9SAndroid Build Coastguard Worker        logger.error("Package install for %s failed: %s", pkg, cpe.output)
72*800a58d9SAndroid Build Coastguard Worker        raise errors.PackageInstallError(
73*800a58d9SAndroid Build Coastguard Worker            "Could not install package [" + pkg + "], :" + str(cpe.output))
74*800a58d9SAndroid Build Coastguard Worker
75*800a58d9SAndroid Build Coastguard Worker    if not PackageInstalled(pkg, compare_version=False):
76*800a58d9SAndroid Build Coastguard Worker        raise errors.PackageInstallError(
77*800a58d9SAndroid Build Coastguard Worker            "Package was not detected as installed after installation [" +
78*800a58d9SAndroid Build Coastguard Worker            pkg + "]")
79*800a58d9SAndroid Build Coastguard Worker
80*800a58d9SAndroid Build Coastguard Worker
81*800a58d9SAndroid Build Coastguard Workerdef IsPackageInAptList(pkg_name):
82*800a58d9SAndroid Build Coastguard Worker    """Check if the package is apt packages list.
83*800a58d9SAndroid Build Coastguard Worker
84*800a58d9SAndroid Build Coastguard Worker    Args:
85*800a58d9SAndroid Build Coastguard Worker        pkg_name: String, the package name.
86*800a58d9SAndroid Build Coastguard Worker
87*800a58d9SAndroid Build Coastguard Worker    Returns:
88*800a58d9SAndroid Build Coastguard Worker        True if package is in apt packages list.
89*800a58d9SAndroid Build Coastguard Worker    """
90*800a58d9SAndroid Build Coastguard Worker    try:
91*800a58d9SAndroid Build Coastguard Worker        pkg_info = CheckCmdOutput(
92*800a58d9SAndroid Build Coastguard Worker            APT_CHECK_CMD % pkg_name,
93*800a58d9SAndroid Build Coastguard Worker            print_cmd=False,
94*800a58d9SAndroid Build Coastguard Worker            shell=True,
95*800a58d9SAndroid Build Coastguard Worker            stderr=subprocess.STDOUT)
96*800a58d9SAndroid Build Coastguard Worker        if pkg_info:
97*800a58d9SAndroid Build Coastguard Worker            return True
98*800a58d9SAndroid Build Coastguard Worker        return False
99*800a58d9SAndroid Build Coastguard Worker    except subprocess.CalledProcessError as error:
100*800a58d9SAndroid Build Coastguard Worker        # Unable locate package name on repository.
101*800a58d9SAndroid Build Coastguard Worker        return False
102*800a58d9SAndroid Build Coastguard Worker
103*800a58d9SAndroid Build Coastguard Worker
104*800a58d9SAndroid Build Coastguard Workerdef PackageInstalled(pkg_name, compare_version=True):
105*800a58d9SAndroid Build Coastguard Worker    """Check if the package is installed or not.
106*800a58d9SAndroid Build Coastguard Worker
107*800a58d9SAndroid Build Coastguard Worker    This method will validate that the specified package is installed
108*800a58d9SAndroid Build Coastguard Worker    (via apt cache policy) and check if the installed version is up-to-date.
109*800a58d9SAndroid Build Coastguard Worker
110*800a58d9SAndroid Build Coastguard Worker    Args:
111*800a58d9SAndroid Build Coastguard Worker        pkg_name: String, the package name.
112*800a58d9SAndroid Build Coastguard Worker        compare_version: Boolean, True to compare version.
113*800a58d9SAndroid Build Coastguard Worker
114*800a58d9SAndroid Build Coastguard Worker    Returns:
115*800a58d9SAndroid Build Coastguard Worker        True if package is installed.and False if not installed or
116*800a58d9SAndroid Build Coastguard Worker        the pre-installed package is not the same version as the repo candidate
117*800a58d9SAndroid Build Coastguard Worker        version.
118*800a58d9SAndroid Build Coastguard Worker
119*800a58d9SAndroid Build Coastguard Worker    Raises:
120*800a58d9SAndroid Build Coastguard Worker        UnableToLocatePkgOnRepositoryError: Unable to locate package on repository.
121*800a58d9SAndroid Build Coastguard Worker    """
122*800a58d9SAndroid Build Coastguard Worker    try:
123*800a58d9SAndroid Build Coastguard Worker        pkg_info = CheckCmdOutput(
124*800a58d9SAndroid Build Coastguard Worker            APT_CHECK_CMD % pkg_name,
125*800a58d9SAndroid Build Coastguard Worker            print_cmd=False,
126*800a58d9SAndroid Build Coastguard Worker            shell=True,
127*800a58d9SAndroid Build Coastguard Worker            stderr=subprocess.STDOUT)
128*800a58d9SAndroid Build Coastguard Worker
129*800a58d9SAndroid Build Coastguard Worker        logger.debug("Check package install status")
130*800a58d9SAndroid Build Coastguard Worker        logger.debug(pkg_info)
131*800a58d9SAndroid Build Coastguard Worker    except subprocess.CalledProcessError as error:
132*800a58d9SAndroid Build Coastguard Worker        # Unable locate package name on repository.
133*800a58d9SAndroid Build Coastguard Worker        raise errors.UnableToLocatePkgOnRepositoryError(
134*800a58d9SAndroid Build Coastguard Worker            "Could not find package [" + pkg_name + "] on repository, :" +
135*800a58d9SAndroid Build Coastguard Worker            str(error.output) + ", have you forgotten to run 'apt update'?")
136*800a58d9SAndroid Build Coastguard Worker
137*800a58d9SAndroid Build Coastguard Worker    installed_ver = None
138*800a58d9SAndroid Build Coastguard Worker    candidate_ver = None
139*800a58d9SAndroid Build Coastguard Worker    for line in pkg_info.splitlines():
140*800a58d9SAndroid Build Coastguard Worker        match = _INSTALLED_RE.match(line)
141*800a58d9SAndroid Build Coastguard Worker        if match:
142*800a58d9SAndroid Build Coastguard Worker            installed_ver = match.group("installed_ver").strip()
143*800a58d9SAndroid Build Coastguard Worker            continue
144*800a58d9SAndroid Build Coastguard Worker        match = _CANDIDATE_RE.match(line)
145*800a58d9SAndroid Build Coastguard Worker        if match:
146*800a58d9SAndroid Build Coastguard Worker            candidate_ver = match.group("candidate_ver").strip()
147*800a58d9SAndroid Build Coastguard Worker            continue
148*800a58d9SAndroid Build Coastguard Worker
149*800a58d9SAndroid Build Coastguard Worker    # package isn't installed
150*800a58d9SAndroid Build Coastguard Worker    if installed_ver == "(none)":
151*800a58d9SAndroid Build Coastguard Worker        logger.debug("Package is not installed, status is (none)")
152*800a58d9SAndroid Build Coastguard Worker        return False
153*800a58d9SAndroid Build Coastguard Worker    # couldn't find the package
154*800a58d9SAndroid Build Coastguard Worker    if not (installed_ver and candidate_ver):
155*800a58d9SAndroid Build Coastguard Worker        logger.debug("Version info not found [installed: %s ,candidate: %s]",
156*800a58d9SAndroid Build Coastguard Worker                     installed_ver,
157*800a58d9SAndroid Build Coastguard Worker                     candidate_ver)
158*800a58d9SAndroid Build Coastguard Worker        return False
159*800a58d9SAndroid Build Coastguard Worker    # TODO(148116924):Setup process should ask user to update package if the
160*800a58d9SAndroid Build Coastguard Worker    # minimax required version is specified.
161*800a58d9SAndroid Build Coastguard Worker    if compare_version and installed_ver != candidate_ver:
162*800a58d9SAndroid Build Coastguard Worker        logger.warning("Package %s version at %s, expected %s",
163*800a58d9SAndroid Build Coastguard Worker                       pkg_name, installed_ver, candidate_ver)
164*800a58d9SAndroid Build Coastguard Worker    return True
165