diff --git a/usr/lib/linuxmint/mintUpdate/Classes.py b/usr/lib/linuxmint/mintUpdate/Classes.py index c09029e9..8475b6d1 100644 --- a/usr/lib/linuxmint/mintUpdate/Classes.py +++ b/usr/lib/linuxmint/mintUpdate/Classes.py @@ -7,6 +7,7 @@ import gettext import json import os +import re import subprocess import sys import time @@ -26,6 +27,22 @@ 'linux-modules-VERSION-KERNELTYPE', 'linux-modules-extra-VERSION-KERNELTYPE'] KERNEL_PKG_NAMES.append('linux-image-extra-VERSION-KERNELTYPE') # Naming convention in 16.04, until 4.15 series +# Matches the actual, version-specific kernel packages (linux-image-5.15.0-91-generic, +# linux-headers-5.15.0-91, linux-modules-iwlwifi-6.8.0-41-generic, ...) as opposed to +# meta packages (linux-generic, linux-generic-hwe-24.04, linux-virtual, ...), by +# looking for an embedded VERSION-ABI kernel version rather than enumerating package +# flavors. Meta package names never contain one (an HWE series suffix like +# "-hwe-24.04" has no third version component or ABI number). Apt normally marks +# versioned kernel packages as automatically installed when they're pulled in as a +# dependency of a meta package, which is what lets "apt autoremove" clean up +# superseded kernels. When mintupdate installs them directly by name (because no +# meta package tracks that exact version, or via the kernel selection window), they +# must be explicitly flagged the same way or they stick around forever. +REAL_KERNEL_PKG_RE = re.compile(r'^linux-.*-\d+\.\d+\.\d+-\d+') + +def is_real_kernel_package(name): + return bool(REAL_KERNEL_PKG_RE.match(name)) + CONFIGURED_KERNEL_TYPE = settings.get_string("selected-kernel-type") if CONFIGURED_KERNEL_TYPE not in SUPPORTED_KERNEL_TYPES: CONFIGURED_KERNEL_TYPE = "-generic" diff --git a/usr/lib/linuxmint/mintUpdate/kernelwindow.py b/usr/lib/linuxmint/mintUpdate/kernelwindow.py index 6fa64932..245c6d8e 100755 --- a/usr/lib/linuxmint/mintUpdate/kernelwindow.py +++ b/usr/lib/linuxmint/mintUpdate/kernelwindow.py @@ -452,7 +452,11 @@ def install_kernels(self, kernels): continue to_purge.append(name) else: - to_install.append(name) + # Flag it for aptkit as an automatic install so that + # "apt autoremove" (and mintupdate's own obsolete-kernel + # cleanup) can reclaim it once it's superseded, matching + # how a normal kernel upgrade marks these packages. + to_install.append(name + "#auto") # Clean out left-over meta package if kernel.installed: diff --git a/usr/lib/linuxmint/mintUpdate/mintUpdate.py b/usr/lib/linuxmint/mintUpdate/mintUpdate.py index 5fb993e7..473e4943 100755 --- a/usr/lib/linuxmint/mintUpdate/mintUpdate.py +++ b/usr/lib/linuxmint/mintUpdate/mintUpdate.py @@ -33,7 +33,7 @@ from kernelwindow import KernelWindow from preferences import PreferencesWindow -from Classes import MainloopTimer, PRIORITY_UPDATES, UpdateTracker +from Classes import MainloopTimer, PRIORITY_UPDATES, UpdateTracker, is_real_kernel_package from util import on_battery, _idle, _async, Inhibitor @@ -2197,7 +2197,15 @@ def install(self, widget): [True for pkg in update.package_names if "nvidia" in pkg]: self.reboot_required = True for package in update.package_names: - self.packages.append(package) + if update.type == "kernel" and is_real_kernel_package(package): + # Flag it for aptkit as an automatic install (see aptkit's + # _mark_packages_for_installation()), matching what a normal + # "apt upgrade" would do when a meta package pulls in a new + # kernel version. Otherwise apt records it as manually + # installed and "apt autoremove" never cleans it up. + self.packages.append(package + "#auto") + else: + self.packages.append(package) self.logger.write("Will install " + str(package)) iter = model.iter_next(iter)