daisy_workflows/linux_common/utils/apt.py (56 lines of code) (raw):
#!/usr/bin/env python3
# Copyright 2021 Google Inc. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import logging
import typing
class Apt:
"""Facade for operating with apt to faciliate testing."""
def __init__(self, run):
"""
Args:
run: a function that matches the signature of guestfsprocess.run
"""
self._run = run
@staticmethod
def determine_version_to_install(current_version: str,
available_versions: typing.Set[str],
blocked_versions: typing.Set[str]) -> str:
non_blocked_versions = set()
for v in available_versions:
blocked = False
for b in blocked_versions:
if v.startswith(b):
blocked = True
break
if not blocked:
non_blocked_versions.add(v)
candidate = ''
for v in non_blocked_versions:
if v > current_version and v > candidate:
candidate = v
logging.debug({
'available_versions': available_versions,
'non_blocked_versions': non_blocked_versions,
'blocked_versions': blocked_versions,
'candidate': candidate,
})
return candidate
def get_package_version(self, g, package_name: str) -> str:
"""Returns the package version if it is installed, or an empty
string if not.
Args:
g: A mounted GuestFS instance
package_name: The package to check
"""
p = self._run(g, ['dpkg', '-s', package_name],
raiseOnError=False)
if p.code != 0:
return ''
for line in p.stdout.splitlines():
if line.startswith('Version: '):
parts = line.split(':')
if len(parts) == 2:
return parts[1].strip()
logging.debug('could not find version. dpkg output={}'.format(p))
return ''
def list_available_versions(self, g, package_name) -> typing.Set[str]:
"""Returns the versions of package_name that are available to install.
Args:
g: A mounted GuestFS instance
package_name: The package to check
"""
p = self._run(g, ['apt-cache', 'madison', package_name],
raiseOnError=False)
if p.code != 0:
return set()
logging.debug(p)
versions = set()
for line in p.stdout.splitlines():
parts = [s.strip() for s in line.split('|')]
if len(parts) == 3:
versions.add(parts[1])
else:
logging.debug('skipping line; expected format '
'"pkg | version | repo" not found. Line={}'.format(line))
return versions