diff -Nru update-manager-16.04.12+zorin1/debian/changelog update-manager-16.04.13+zorin1/debian/changelog --- update-manager-16.04.12+zorin1/debian/changelog 2018-02-27 16:21:28.000000000 +0000 +++ update-manager-16.04.13+zorin1/debian/changelog 2018-05-22 20:44:19.000000000 +0000 @@ -1,8 +1,20 @@ -update-manager (1:16.04.12+zorin1) xenial; urgency=medium +update-manager (1:16.04.13+zorin1) xenial; urgency=medium * Made modifications for Zorin OS 12 - -- Artyom Zorin Tue, 27 Feb 2018 16:21:22 +0000 + -- Artyom Zorin Tue, 22 May 2018 21:44:14 +0100 + +update-manager (1:16.04.13) xenial; urgency=medium + + * Offer removal of unused autoremovable kernel packages + (LP: #1624644, #1675079) + * Support package removals in install backends and really remove packages + (LP: #1624644, #1675079) + * Keep PEP 8 checks happy + * Place .keep files in empty directories to keep them when converting the + repo to git (LP: #1758963) + + -- Balint Reczey Sun, 25 Mar 2018 20:10:49 +0100 update-manager (1:16.04.12) xenial-security; urgency=medium diff -Nru update-manager-16.04.12+zorin1/UpdateManager/backend/__init__.py update-manager-16.04.13+zorin1/UpdateManager/backend/__init__.py --- update-manager-16.04.12+zorin1/UpdateManager/backend/__init__.py 2016-04-07 18:00:42.000000000 +0000 +++ update-manager-16.04.13+zorin1/UpdateManager/backend/__init__.py 2018-03-25 19:10:49.000000000 +0000 @@ -33,6 +33,7 @@ # Get the packages which should be installed and update pkgs_install = [] pkgs_upgrade = [] + pkgs_remove = [] for pkg in self.window_main.cache: if pkg.marked_install: pkgname = pkg.name @@ -41,7 +42,9 @@ pkgs_install.append(pkgname) elif pkg.marked_upgrade: pkgs_upgrade.append(pkg.name) - self.commit(pkgs_install, pkgs_upgrade) + elif pkg.marked_delete: + pkgs_remove.append(pkg.name) + self.commit(pkgs_install, pkgs_upgrade, pkgs_remove) else: self.update() @@ -49,7 +52,7 @@ """Run a update to refresh the package list""" raise NotImplemented - def commit(self, pkgs_install, pkgs_upgrade): + def commit(self, pkgs_install, pkgs_upgrade, pkgs_remove): """Commit the cache changes """ raise NotImplemented diff -Nru update-manager-16.04.12+zorin1/UpdateManager/backend/InstallBackendAptdaemon.py update-manager-16.04.13+zorin1/UpdateManager/backend/InstallBackendAptdaemon.py --- update-manager-16.04.12+zorin1/UpdateManager/backend/InstallBackendAptdaemon.py 2017-08-10 22:08:15.000000000 +0000 +++ update-manager-16.04.13+zorin1/UpdateManager/backend/InstallBackendAptdaemon.py 2018-03-25 19:10:49.000000000 +0000 @@ -76,16 +76,16 @@ raise @inline_callbacks - def commit(self, pkgs_install, pkgs_upgrade): + def commit(self, pkgs_install, pkgs_upgrade, pkgs_remove): """Commit a list of package adds and removes""" try: apt.apt_pkg.pkgsystem_unlock() except SystemError: pass try: - reinstall = remove = purge = downgrade = [] + reinstall = purge = downgrade = [] trans = yield self.client.commit_packages( - pkgs_install, reinstall, remove, purge, pkgs_upgrade, + pkgs_install, reinstall, pkgs_remove, purge, pkgs_upgrade, downgrade, defer=True) trans.connect("progress-changed", self._on_progress_changed) yield self._show_transaction(trans, self.ACTION_INSTALL, @@ -243,5 +243,5 @@ app = UpdateManager(data_dir, options) b = InstallBackendAptdaemon(app, None) - b.commit(["2vcard"], []) + b.commit(["2vcard"], [], []) Gtk.main() diff -Nru update-manager-16.04.12+zorin1/UpdateManager/backend/InstallBackendSynaptic.py update-manager-16.04.13+zorin1/UpdateManager/backend/InstallBackendSynaptic.py --- update-manager-16.04.12+zorin1/UpdateManager/backend/InstallBackendSynaptic.py 2014-08-05 22:45:20.000000000 +0000 +++ update-manager-16.04.13+zorin1/UpdateManager/backend/InstallBackendSynaptic.py 2018-03-25 19:10:49.000000000 +0000 @@ -24,7 +24,8 @@ tempf = None self._run_synaptic(self.ACTION_UPDATE, opt, tempf) - def commit(self, pkgs_install, pkgs_upgrade, close_on_done=False): + def commit(self, pkgs_install, pkgs_upgrade, pkgs_remove, + close_on_done=False): # close when update was successful (its ok to use a Synaptic:: # option here, it will not get auto-saved, because synaptic does # not save options in non-interactive mode) @@ -40,6 +41,8 @@ tempf = tempfile.NamedTemporaryFile(mode="w+") for pkg_name in pkgs_install + pkgs_upgrade: tempf.write("%s\tinstall\n" % pkg_name) + for pkg_name in pkgs_remove: + tempf.write("%s\tdeinstall\n" % pkg_name) opt.append("--set-selections-file") opt.append("%s" % tempf.name) tempf.flush() diff -Nru update-manager-16.04.12+zorin1/UpdateManager/Core/MyCache.py update-manager-16.04.13+zorin1/UpdateManager/Core/MyCache.py --- update-manager-16.04.12+zorin1/UpdateManager/Core/MyCache.py 2017-08-10 22:08:15.000000000 +0000 +++ update-manager-16.04.13+zorin1/UpdateManager/Core/MyCache.py 2018-03-25 19:10:49.000000000 +0000 @@ -40,6 +40,7 @@ except ImportError: from httplib import BadStatusLine import socket +import subprocess import re import DistUpgrade.DistUpgradeCache from gettext import gettext as _ @@ -79,6 +80,21 @@ self.saveDistUpgrade() assert (self._depcache.broken_count == 0 and self._depcache.del_count == 0) + # generate versioned_kernel_pkgs_regexp for later use + apt_versioned_kernel_pkgs = apt_pkg.config.value_list( + "APT::VersionedKernelPackages") + if apt_versioned_kernel_pkgs: + self.versioned_kernel_pkgs_regexp = re.compile("(" + "|".join( + ["^" + p for p in apt_versioned_kernel_pkgs]) + ")") + running_kernel_version = subprocess.check_output( + ["uname", "-r"], universal_newlines=True).rstrip() + self.running_kernel_pkgs_regexp = re.compile("(" + "|".join( + [("^" + p + ".*" + running_kernel_version) + if not p.startswith(".*") else (running_kernel_version + p) + for p in apt_versioned_kernel_pkgs]) + ")") + else: + self.versioned_kernel_pkgs_regexp = None + self.running_kernel_pkgs_regexp = None def _dpkgJournalDirty(self): """ diff -Nru update-manager-16.04.12+zorin1/UpdateManager/Core/UpdateList.py update-manager-16.04.13+zorin1/UpdateManager/Core/UpdateList.py --- update-manager-16.04.12+zorin1/UpdateManager/Core/UpdateList.py 2017-08-10 22:08:15.000000000 +0000 +++ update-manager-16.04.13+zorin1/UpdateManager/Core/UpdateList.py 2018-03-25 19:10:49.000000000 +0000 @@ -43,25 +43,29 @@ class UpdateItem(): - def __init__(self, pkg, name, icon): + def __init__(self, pkg, name, icon, to_remove): self.icon = icon self.name = name self.pkg = pkg + self.to_remove = to_remove def is_selected(self): - return self.pkg.marked_install or self.pkg.marked_upgrade + if not self.to_remove: + return self.pkg.marked_install or self.pkg.marked_upgrade + else: + return self.pkg.marked_delete class UpdateGroup(UpdateItem): _depcache = {} - def __init__(self, pkg, name, icon): - UpdateItem.__init__(self, pkg, name, icon) + def __init__(self, pkg, name, icon, to_remove): + UpdateItem.__init__(self, pkg, name, icon, to_remove) self._items = set() self._deps = set() self.core_item = None if pkg is not None: - self.core_item = UpdateItem(pkg, name, icon) + self.core_item = UpdateItem(pkg, name, icon, to_remove) self._items.add(self.core_item) @property @@ -70,10 +74,10 @@ all_items.extend(self._items) return sorted(all_items, key=lambda a: a.name.lower()) - def add(self, pkg, cache=None, eventloop_callback=None): + def add(self, pkg, cache=None, eventloop_callback=None, to_remove=False): name = utils.get_package_label(pkg) icon = Gio.ThemedIcon.new("package") - self._items.add(UpdateItem(pkg, name, icon)) + self._items.add(UpdateItem(pkg, name, icon, to_remove)) # If the pkg is in self._deps, stop here. We have already calculated # the recursive dependencies for this package, no need to do it again. if cache and pkg.name in cache and pkg.name not in self._deps: @@ -140,6 +144,8 @@ len(pkgs_installing) < len(self.items)) def get_total_size(self): + if self.to_remove: + return 0 size = 0 for item in self.items: size += getattr(item.pkg.candidate, "size", 0) @@ -147,26 +153,27 @@ class UpdateApplicationGroup(UpdateGroup): - def __init__(self, pkg, application): + def __init__(self, pkg, application, to_remove): name = application.get_display_name() icon = application.get_icon() - super(UpdateApplicationGroup, self).__init__(pkg, name, icon) + super(UpdateApplicationGroup, self).__init__(pkg, name, icon, + to_remove) class UpdatePackageGroup(UpdateGroup): - def __init__(self, pkg): + def __init__(self, pkg, to_remove): name = utils.get_package_label(pkg) icon = Gio.ThemedIcon.new("package") - super(UpdatePackageGroup, self).__init__(pkg, name, icon) + super(UpdatePackageGroup, self).__init__(pkg, name, icon, to_remove) class UpdateSystemGroup(UpdateGroup): - def __init__(self, cache): + def __init__(self, cache, to_remove): # Translators: the %s is a distro name, like 'Ubuntu' and 'base' as in # the core components and packages. name = _("%s base") % utils.get_ubuntu_flavor_name(cache=cache) icon = Gio.ThemedIcon.new("distributor-logo") - super(UpdateSystemGroup, self).__init__(None, name, icon) + super(UpdateSystemGroup, self).__init__(None, name, icon, to_remove) class UpdateOrigin(): @@ -205,6 +212,7 @@ self.distUpgradeWouldDelete = 0 self.update_groups = [] self.security_groups = [] + self.kernel_autoremove_groups = [] self.num_updates = 0 self.random = random.Random() self.ignored_phased_updates = [] @@ -411,7 +419,7 @@ 'linux-tools-virtual', 'linux-virtual'] - def _make_groups(self, cache, pkgs, eventloop_callback): + def _make_groups(self, cache, pkgs, eventloop_callback, to_remove=False): if not pkgs: return [] ungrouped_pkgs = [] @@ -421,7 +429,7 @@ for pkg in pkgs: app = self._get_application_for_package(pkg) if app is not None: - app_group = UpdateApplicationGroup(pkg, app) + app_group = UpdateApplicationGroup(pkg, app, to_remove) app_groups.append(app_group) else: ungrouped_pkgs.append(pkg) @@ -435,14 +443,14 @@ if len(dep_groups) > 1: break if len(dep_groups) == 1: - dep_groups[0].add(pkg, cache, eventloop_callback) + dep_groups[0].add(pkg, cache, eventloop_callback, to_remove) ungrouped_pkgs.remove(pkg) system_group = None if ungrouped_pkgs: # Separate out system base packages. If we have already found an # application for all updates, don't bother. - meta_group = UpdateGroup(None, None, None) + meta_group = UpdateGroup(None, None, None, to_remove) flavor_package = utils.get_ubuntu_flavor_package(cache=cache) meta_pkgs = [flavor_package, "ubuntu-standard", "ubuntu-minimal"] meta_pkgs.extend(self._get_linux_packages()) @@ -452,10 +460,10 @@ for pkg in ungrouped_pkgs: if meta_group.is_dependency(pkg, cache, eventloop_callback): if system_group is None: - system_group = UpdateSystemGroup(cache) + system_group = UpdateSystemGroup(cache, to_remove) system_group.add(pkg) else: - pkg_groups.append(UpdatePackageGroup(pkg)) + pkg_groups.append(UpdatePackageGroup(pkg, to_remove)) app_groups.sort(key=lambda a: a.name.lower()) pkg_groups.sort(key=lambda a: a.name.lower()) @@ -472,6 +480,7 @@ security_pkgs = [] upgrade_pkgs = [] + kernel_autoremove_pkgs = [] # Find all upgradable packages for pkg in cache: @@ -502,12 +511,22 @@ if pkg.is_upgradable and not (pkg.marked_upgrade or pkg.marked_install): self.held_back.append(pkg.name) + continue + if (pkg.is_auto_removable and + (cache.versioned_kernel_pkgs_regexp and + cache.versioned_kernel_pkgs_regexp.match(pkg.name) and + not cache.running_kernel_pkgs_regexp.match(pkg.name))): + kernel_autoremove_pkgs.append(pkg) + pkg.mark_delete() if security_pkgs or upgrade_pkgs: # There's updates available. Initiate the desktop file cache. - pkg_names = [p.name for p in security_pkgs + upgrade_pkgs] + pkg_names = [p.name for p in + security_pkgs + upgrade_pkgs + kernel_autoremove_pkgs] self._populate_desktop_cache(pkg_names) self.update_groups = self._make_groups(cache, upgrade_pkgs, eventloop_callback) self.security_groups = self._make_groups(cache, security_pkgs, eventloop_callback) + self.kernel_autoremove_groups = self._make_groups( + cache, kernel_autoremove_pkgs, eventloop_callback, True) diff -Nru update-manager-16.04.12+zorin1/UpdateManager/UpdatesAvailable.py update-manager-16.04.13+zorin1/UpdateManager/UpdatesAvailable.py --- update-manager-16.04.12+zorin1/UpdateManager/UpdatesAvailable.py 2017-09-20 21:39:17.000000000 +0000 +++ update-manager-16.04.13+zorin1/UpdateManager/UpdatesAvailable.py 2018-03-25 19:10:49.000000000 +0000 @@ -280,7 +280,7 @@ self.pkg_cell_area = CellAreaPackage(False) pkg_column = Gtk.TreeViewColumn.new_with_area(self.pkg_cell_area) self.pkg_cell_area.column = pkg_column - pkg_column.set_title(_("Install")) + pkg_column.set_title(_("Install or remove")) pkg_column.set_property("spacing", 4) pkg_column.set_expand(True) self.treeview_update.append_column(pkg_column) @@ -953,7 +953,10 @@ if keep_packages: item.pkg.mark_keep() elif item.pkg.name not in self.list.held_back: - item.pkg.mark_install() + if not item.to_remove: + item.pkg.mark_install() + else: + item.pkg.mark_delete() except SystemError: pass @@ -1049,11 +1052,20 @@ self._add_groups(self.list.security_groups) if self.list.security_groups and self.list.update_groups: self._add_header(_("Other updates"), self.list.update_groups) + elif self.list.update_groups and self.list.kernel_autoremove_groups: + self._add_header(_("Updates"), self.list.update_groups) if self.list.update_groups: self._add_groups(self.list.update_groups) + if self.list.kernel_autoremove_groups: + self._add_header( + _("Unused kernel updates to be removed"), + self.list.kernel_autoremove_groups) + self._add_groups(self.list.kernel_autoremove_groups) self.treeview_update.set_model(self.store) - self.pkg_cell_area.indent_toplevel = bool(self.list.security_groups) + self.pkg_cell_area.indent_toplevel = ( + bool(self.list.security_groups) or + bool(self.list.kernel_autoremove_groups)) self.update_close_button() self.update_count() self.setBusy(False)