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