Add aptitude_with_progress_bar()

This commit is contained in:
Alexandre Aubin 2024-01-02 20:59:40 +01:00 committed by Félix Piédallu
parent f6fbd69c39
commit ac4e9cd216
2 changed files with 111 additions and 26 deletions

View file

@ -48,6 +48,7 @@ from yunohost.utils.system import (
ynh_packages_version,
dpkg_is_broken,
dpkg_lock_available,
_apt_log_line_is_relevant,
)
from yunohost.utils.error import YunohostError, YunohostValidationError
from yunohost.log import is_unit_operation, OperationLogger
@ -530,32 +531,6 @@ def tools_upgrade(operation_logger, target=None):
operation_logger.success()
def _apt_log_line_is_relevant(line):
irrelevants = [
"service sudo-ldap already provided",
"Reading database ...",
"Preparing to unpack",
"Selecting previously unselected package",
"Created symlink /etc/systemd",
"Replacing config file",
"Creating config file",
"Installing new version of config file",
"Installing new config file as you requested",
", does not exist on system.",
"unable to delete old directory",
"update-alternatives:",
"Configuration file '/etc",
"==> Modified (by you or by a script) since installation.",
"==> Package distributor has shipped an updated version.",
"==> Keeping old config file as default.",
"is a disabled or a static unit",
" update-rc.d: warning: start and stop actions are no longer supported; falling back to defaults",
"insserv: warning: current stop runlevel",
"insserv: warning: current start runlevel",
]
return line.rstrip() and all(i not in line.rstrip() for i in irrelevants)
@is_unit_operation()
def tools_shutdown(operation_logger, force=False):
shutdown = force

View file

@ -211,3 +211,113 @@ def _dump_sources_list():
if line.startswith("#") or not line.strip():
continue
yield filename.replace("/etc/apt/", "") + ":" + line.strip()
def aptitude_with_progress_bar(cmd):
from moulinette.utils.process import call_async_output
msg_to_verb = {
"Preparing for removal": "Removing",
"Preparing to configure": "Installing",
"Removing": "Removing",
"Unpacking": "Installing",
"Configuring": "Installing",
"Installing": "Installing",
"Installed": "Installing",
"Preparing": "Installing",
"Done": "Done",
"Failed?": "Failed?",
}
disable_progress_bar = False
if cmd.startswith("update"):
# the status-fd does stupid stuff for 'aptitude update', percentage is always zero except last iteration
disable_progress_bar = True
def log_apt_status_to_progress_bar(data):
if disable_progress_bar:
return
t, package, percent, msg = data.split(":", 3)
# We only display the stuff related to download once
if t == "dlstatus":
if log_apt_status_to_progress_bar.download_message_displayed is False:
logger.info("Downloading...")
log_apt_status_to_progress_bar.download_message_displayed = True
return
if package == "dpkg-exec":
return
if package and log_apt_status_to_progress_bar.previous_package and package == log_apt_status_to_progress_bar.previous_package:
return
try:
percent = round(float(percent), 1)
except Exception:
return
verb = "Processing"
for m, v in msg_to_verb.items():
if msg.startswith(m):
verb = v
log_apt_status_to_progress_bar.previous_package = package
width = 20
done = "#" * int(width * percent / 100)
remain = "." * (width - len(done))
logger.info(f"[{done}{remain}] > {percent}% {verb} {package}\r")
log_apt_status_to_progress_bar.previous_package = None
log_apt_status_to_progress_bar.download_message_displayed = False
def strip_boring_dpkg_reading_database(s):
return re.sub(r'(\(Reading database ... \d*%?|files and directories currently installed.\))', '', s)
callbacks = (
lambda l: logger.debug(strip_boring_dpkg_reading_database(l).rstrip() + "\r"),
lambda l: logger.warning(l.rstrip() + "\r"), # ... aptitude has no stderr ? :| if _apt_log_line_is_relevant(l.rstrip()) else logger.debug(l.rstrip() + "\r"),
lambda l: log_apt_status_to_progress_bar(l.rstrip()),
)
cmd = (
f'LC_ALL=C DEBIAN_FRONTEND=noninteractive APT_LISTCHANGES_FRONTEND=none aptitude {cmd} --quiet=2 -o=Dpkg::Use-Pty=0 -o "APT::Status-Fd=$YNH_STDINFO"'
)
logger.debug(f"Running: {cmd}")
ret = call_async_output(cmd, callbacks, shell=True)
if log_apt_status_to_progress_bar.previous_package is not None and ret == 0:
log_apt_status_to_progress_bar("done::100:Done")
elif ret != 0:
raise YunohostError(f"Failed to run command 'aptitude {cmd}'", raw_msg=True)
def _apt_log_line_is_relevant(line):
irrelevants = [
"service sudo-ldap already provided",
"Reading database ...",
"Preparing to unpack",
"Selecting previously unselected package",
"Created symlink /etc/systemd",
"Replacing config file",
"Creating config file",
"Installing new version of config file",
"Installing new config file as you requested",
", does not exist on system.",
"unable to delete old directory",
"update-alternatives:",
"Configuration file '/etc",
"==> Modified (by you or by a script) since installation.",
"==> Package distributor has shipped an updated version.",
"==> Keeping old config file as default.",
"is a disabled or a static unit",
" update-rc.d: warning: start and stop actions are no longer supported; falling back to defaults",
"insserv: warning: current stop runlevel",
"insserv: warning: current start runlevel",
]
return line.rstrip() and all(i not in line.rstrip() for i in irrelevants)