Merge lp:~robert-ancell/update-manager/ua-bionic-merge into lp:~ubuntu-core-dev/update-manager/bionic

Proposed by Robert Ancell
Status: Merged
Merged at revision: 2841
Proposed branch: lp:~robert-ancell/update-manager/ua-bionic-merge
Merge into: lp:~ubuntu-core-dev/update-manager/bionic
Diff against target: 353 lines (+112/-22)
5 files modified
UpdateManager/Core/UpdateList.py (+53/-13)
UpdateManager/Dialogs.py (+4/-4)
UpdateManager/UpdateManager.py (+28/-1)
UpdateManager/UpdatesAvailable.py (+21/-4)
debian/changelog (+6/-0)
To merge this branch: bzr merge lp:~robert-ancell/update-manager/ua-bionic-merge
Reviewer Review Type Date Requested Status
Ubuntu Core Development Team Pending
Review via email: mp+435932@code.launchpad.net
To post a comment you must log in.
Revision history for this message
Robert Ancell (robert-ancell) wrote :

Merged because this has been uploaded as a SRU.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'UpdateManager/Core/UpdateList.py'
--- UpdateManager/Core/UpdateList.py 2018-10-03 17:45:08 +0000
+++ UpdateManager/Core/UpdateList.py 2023-01-18 03:42:01 +0000
@@ -43,11 +43,12 @@
4343
4444
45class UpdateItem():45class UpdateItem():
46 def __init__(self, pkg, name, icon, to_remove):46 def __init__(self, pkg, name, icon, to_remove, sensitive=True):
47 self.icon = icon47 self.icon = icon
48 self.name = name48 self.name = name
49 self.pkg = pkg49 self.pkg = pkg
50 self.to_remove = to_remove50 self.to_remove = to_remove
51 self.sensitive = sensitive
5152
52 def is_selected(self):53 def is_selected(self):
53 if not self.to_remove:54 if not self.to_remove:
@@ -59,13 +60,13 @@
59class UpdateGroup(UpdateItem):60class UpdateGroup(UpdateItem):
60 _depcache = {}61 _depcache = {}
6162
62 def __init__(self, pkg, name, icon, to_remove):63 def __init__(self, pkg, name, icon, to_remove, sensitive=True):
63 UpdateItem.__init__(self, pkg, name, icon, to_remove)64 UpdateItem.__init__(self, pkg, name, icon, to_remove, sensitive)
64 self._items = set()65 self._items = set()
65 self._deps = set()66 self._deps = set()
66 self.core_item = None67 self.core_item = None
67 if pkg is not None:68 if pkg is not None:
68 self.core_item = UpdateItem(pkg, name, icon, to_remove)69 self.core_item = UpdateItem(pkg, name, icon, to_remove, sensitive)
69 self._items.add(self.core_item)70 self._items.add(self.core_item)
7071
71 @property72 @property
@@ -74,10 +75,11 @@
74 all_items.extend(self._items)75 all_items.extend(self._items)
75 return sorted(all_items, key=lambda a: a.name.lower())76 return sorted(all_items, key=lambda a: a.name.lower())
7677
77 def add(self, pkg, cache=None, eventloop_callback=None, to_remove=False):78 def add(self, pkg, cache=None, eventloop_callback=None, to_remove=False,
79 sensitive=True):
78 name = utils.get_package_label(pkg)80 name = utils.get_package_label(pkg)
79 icon = Gio.ThemedIcon.new("package")81 icon = Gio.ThemedIcon.new("package")
80 self._items.add(UpdateItem(pkg, name, icon, to_remove))82 self._items.add(UpdateItem(pkg, name, icon, to_remove, sensitive))
81 # If the pkg is in self._deps, stop here. We have already calculated83 # If the pkg is in self._deps, stop here. We have already calculated
82 # the recursive dependencies for this package, no need to do it again.84 # the recursive dependencies for this package, no need to do it again.
83 if cache and pkg.name in cache and pkg.name not in self._deps:85 if cache and pkg.name in cache and pkg.name not in self._deps:
@@ -153,27 +155,29 @@
153155
154156
155class UpdateApplicationGroup(UpdateGroup):157class UpdateApplicationGroup(UpdateGroup):
156 def __init__(self, pkg, application, to_remove):158 def __init__(self, pkg, application, to_remove, sensitive=True):
157 name = application.get_display_name()159 name = application.get_display_name()
158 icon = application.get_icon()160 icon = application.get_icon()
159 super(UpdateApplicationGroup, self).__init__(pkg, name, icon,161 super(UpdateApplicationGroup, self).__init__(pkg, name, icon,
160 to_remove)162 to_remove, sensitive)
161163
162164
163class UpdatePackageGroup(UpdateGroup):165class UpdatePackageGroup(UpdateGroup):
164 def __init__(self, pkg, to_remove):166 def __init__(self, pkg, to_remove, sensitive=True):
165 name = utils.get_package_label(pkg)167 name = utils.get_package_label(pkg)
166 icon = Gio.ThemedIcon.new("package")168 icon = Gio.ThemedIcon.new("package")
167 super(UpdatePackageGroup, self).__init__(pkg, name, icon, to_remove)169 super(UpdatePackageGroup, self).__init__(pkg, name, icon, to_remove,
170 sensitive)
168171
169172
170class UpdateSystemGroup(UpdateGroup):173class UpdateSystemGroup(UpdateGroup):
171 def __init__(self, cache, to_remove):174 def __init__(self, cache, to_remove, sensitive=True):
172 # Translators: the %s is a distro name, like 'Ubuntu' and 'base' as in175 # Translators: the %s is a distro name, like 'Ubuntu' and 'base' as in
173 # the core components and packages.176 # the core components and packages.
174 name = _("%s base") % utils.get_ubuntu_flavor_name(cache=cache)177 name = _("%s base") % utils.get_ubuntu_flavor_name(cache=cache)
175 icon = Gio.ThemedIcon.new("distributor-logo")178 icon = Gio.ThemedIcon.new("distributor-logo")
176 super(UpdateSystemGroup, self).__init__(None, name, icon, to_remove)179 super(UpdateSystemGroup, self).__init__(None, name, icon, to_remove,
180 sensitive)
177181
178182
179class UpdateOrigin():183class UpdateOrigin():
@@ -213,6 +217,7 @@
213 self.update_groups = []217 self.update_groups = []
214 self.security_groups = []218 self.security_groups = []
215 self.kernel_autoremove_groups = []219 self.kernel_autoremove_groups = []
220 self.ubuntu_pro_groups = []
216 self.num_updates = 0221 self.num_updates = 0
217 self.random = random.Random()222 self.random = random.Random()
218 self.ignored_phased_updates = []223 self.ignored_phased_updates = []
@@ -472,7 +477,7 @@
472477
473 return app_groups + pkg_groups478 return app_groups + pkg_groups
474479
475 def update(self, cache, eventloop_callback=None):480 def update(self, cache, eventloop_callback=None, ua_security_packages=[]):
476 self.held_back = []481 self.held_back = []
477482
478 # do the upgrade483 # do the upgrade
@@ -482,6 +487,34 @@
482 upgrade_pkgs = []487 upgrade_pkgs = []
483 kernel_autoremove_pkgs = []488 kernel_autoremove_pkgs = []
484489
490 class FakeUbuntuProPackageCandidate:
491 def __init__(self, source_name, version, size):
492 self.source_name = source_name
493 self.summary = source_name
494 self.description = source_name
495 self.version = version
496 self.size = size
497 self.downloadable = False
498 self.record = {}
499
500 class FakeUbuntuProPackage:
501 def __init__(self, package_name, version, size):
502 self.name = package_name
503 self.candidate = FakeUbuntuProPackageCandidate(package_name,
504 version, size)
505 self.marked_install = False
506 self.marked_upgrade = False
507
508 def mark_install(self):
509 pass
510
511 def mark_delete(self):
512 pass
513 fake_ua_packages = []
514 for (package_name, version, size) in ua_security_packages:
515 fake_ua_packages.append(FakeUbuntuProPackage(package_name,
516 version, size))
517
485 # Find all upgradable packages518 # Find all upgradable packages
486 for pkg in cache:519 for pkg in cache:
487 if pkg.is_upgradable or pkg.marked_install:520 if pkg.is_upgradable or pkg.marked_install:
@@ -535,3 +568,10 @@
535 eventloop_callback)568 eventloop_callback)
536 self.kernel_autoremove_groups = self._make_groups(569 self.kernel_autoremove_groups = self._make_groups(
537 cache, kernel_autoremove_pkgs, eventloop_callback, True)570 cache, kernel_autoremove_pkgs, eventloop_callback, True)
571 if len(fake_ua_packages) > 0:
572 ubuntu_pro_group = UpdateGroup(None,
573 "Ubuntu Pro (enable in Settings…)",
574 None, False, False)
575 for package in fake_ua_packages:
576 ubuntu_pro_group.add(package)
577 self.ubuntu_pro_groups = [ubuntu_pro_group]
538578
=== modified file 'UpdateManager/Dialogs.py'
--- UpdateManager/Dialogs.py 2022-09-13 23:50:38 +0000
+++ UpdateManager/Dialogs.py 2023-01-18 03:42:01 +0000
@@ -161,10 +161,10 @@
161 if self._is_livepatch_supported() and \161 if self._is_livepatch_supported() and \
162 self.settings_button and \162 self.settings_button and \
163 self.settings.get_int('launch-count') >= 4:163 self.settings.get_int('launch-count') >= 4:
164 self.set_desc(_("<b>Tip:</b> You can use Livepatch to "164 self.set_desc(_("<b>Tip:</b> You can use Livepatch with "
165 "keep your computer more secure between "165 "Ubuntu Pro to keep your computer more "
166 "restarts."))166 "secure between restarts."))
167 self.settings_button.set_label(_("Settings & Livepatch…"))167 self.settings_button.set_label(_("Settings & Pro…"))
168 return168 return
169169
170 needs_reschedule = False170 needs_reschedule = False
171171
=== modified file 'UpdateManager/UpdateManager.py'
--- UpdateManager/UpdateManager.py 2022-09-13 23:50:56 +0000
+++ UpdateManager/UpdateManager.py 2023-01-18 03:42:01 +0000
@@ -36,6 +36,7 @@
3636
37import apt_pkg37import apt_pkg
38import distro_info38import distro_info
39import json
39import os40import os
40import subprocess41import subprocess
41import sys42import sys
@@ -85,6 +86,7 @@
85 self.unity = UnitySupport()86 self.unity = UnitySupport()
86 self.controller = None87 self.controller = None
87 self.cache = None88 self.cache = None
89 self.ua_security_packages = []
88 self.update_list = None90 self.update_list = None
89 self.meta_release = None91 self.meta_release = None
90 self.hwe_replacement_packages = None92 self.hwe_replacement_packages = None
@@ -247,6 +249,27 @@
247 cancelled_update, error_occurred)249 cancelled_update, error_occurred)
248 self._start_pane(pane)250 self._start_pane(pane)
249251
252 def _get_ua_security_status(self):
253 self.ua_security_packages = []
254 try:
255 p = subprocess.Popen(['ua', 'security-status', '--format=json'],
256 stdout=subprocess.PIPE)
257 except OSError:
258 pass
259 else:
260 while p.poll() is None:
261 while Gtk.events_pending():
262 Gtk.main_iteration()
263 time.sleep(0.05)
264 s = json.load(p.stdout)
265 for package in s.get('packages', []):
266 status = package.get('status', '')
267 if status == 'pending_attach':
268 name = package.get('name', '')
269 version = package.get('version', '')
270 size = package.get('download_size', 0)
271 self.ua_security_packages.append((name, version, size))
272
250 def _make_available_pane(self, install_count, need_reboot=False,273 def _make_available_pane(self, install_count, need_reboot=False,
251 cancelled_update=False, error_occurred=False):274 cancelled_update=False, error_occurred=False):
252 self._check_hwe_support_status()275 self._check_hwe_support_status()
@@ -406,9 +429,13 @@
406 Gtk.main_iteration()429 Gtk.main_iteration()
407 iterate()430 iterate()
408431
432 self._get_ua_security_status()
433
409 self.update_list = UpdateList(self)434 self.update_list = UpdateList(self)
410 try:435 try:
411 self.update_list.update(self.cache, eventloop_callback=iterate)436 self.update_list.update(self.cache, eventloop_callback=iterate,
437 ua_security_packages=self.
438 ua_security_packages)
412 except SystemError as e:439 except SystemError as e:
413 header = _("Could not calculate the upgrade")440 header = _("Could not calculate the upgrade")
414 desc = _("An unresolvable problem occurred while "441 desc = _("An unresolvable problem occurred while "
415442
=== modified file 'UpdateManager/UpdatesAvailable.py'
--- UpdateManager/UpdatesAvailable.py 2018-03-18 21:43:58 +0000
+++ UpdateManager/UpdatesAvailable.py 2023-01-18 03:42:01 +0000
@@ -74,7 +74,8 @@
74# - screen reader does not say "Downloaded" for downloaded updates74# - screen reader does not say "Downloaded" for downloaded updates
7575
76# list constants76# list constants
77(LIST_NAME, LIST_UPDATE_DATA, LIST_SIZE, LIST_TOGGLE_ACTIVE) = range(4)77(LIST_NAME, LIST_UPDATE_DATA, LIST_SIZE, LIST_TOGGLE_ACTIVE,
78 LIST_SENSITIVE) = range(5)
7879
79# NetworkManager enums80# NetworkManager enums
80from .Core.roam import NetworkManagerHelper81from .Core.roam import NetworkManagerHelper
@@ -261,7 +262,7 @@
261 changes_buffer.create_tag("versiontag", weight=Pango.Weight.BOLD)262 changes_buffer.create_tag("versiontag", weight=Pango.Weight.BOLD)
262263
263 # the treeview (move into it's own code!)264 # the treeview (move into it's own code!)
264 self.store = Gtk.TreeStore(str, GObject.TYPE_PYOBJECT, str, bool)265 self.store = Gtk.TreeStore(str, GObject.TYPE_PYOBJECT, str, bool, bool)
265 self.treeview_update.set_model(None)266 self.treeview_update.set_model(None)
266267
267 self.image_restart.set_from_gicon(self.get_restart_icon(),268 self.image_restart.set_from_gicon(self.get_restart_icon(),
@@ -293,6 +294,8 @@
293 pkg_column.pack_start(pkg_toggle_renderer, False)294 pkg_column.pack_start(pkg_toggle_renderer, False)
294 pkg_column.add_attribute(pkg_toggle_renderer,295 pkg_column.add_attribute(pkg_toggle_renderer,
295 'active', LIST_TOGGLE_ACTIVE)296 'active', LIST_TOGGLE_ACTIVE)
297 pkg_column.add_attribute(pkg_toggle_renderer,
298 'sensitive', LIST_SENSITIVE)
296 pkg_column.set_cell_data_func(pkg_toggle_renderer,299 pkg_column.set_cell_data_func(pkg_toggle_renderer,
297 self.pkg_toggle_renderer_data_func)300 self.pkg_toggle_renderer_data_func)
298301
@@ -319,6 +322,8 @@
319 size_column = Gtk.TreeViewColumn(_("Download"), size_renderer,322 size_column = Gtk.TreeViewColumn(_("Download"), size_renderer,
320 text=LIST_SIZE)323 text=LIST_SIZE)
321 size_column.set_sizing(Gtk.TreeViewColumnSizing.AUTOSIZE)324 size_column.set_sizing(Gtk.TreeViewColumnSizing.AUTOSIZE)
325 size_column.add_attribute(size_renderer,
326 'sensitive', LIST_SENSITIVE)
322 self.treeview_update.append_column(size_column)327 self.treeview_update.append_column(size_column)
323328
324 self.treeview_update.set_headers_visible(True)329 self.treeview_update.set_headers_visible(True)
@@ -404,8 +409,11 @@
404 def restart_icon_renderer_data_func(self, cell_layout, renderer, model,409 def restart_icon_renderer_data_func(self, cell_layout, renderer, model,
405 iter, user_data):410 iter, user_data):
406 data = model.get_value(iter, LIST_UPDATE_DATA)411 data = model.get_value(iter, LIST_UPDATE_DATA)
412 sensitive = model.get_value(iter, LIST_SENSITIVE)
407 path = model.get_path(iter)413 path = model.get_path(iter)
408414
415 renderer.set_sensitive(sensitive)
416
409 requires_restart = False417 requires_restart = False
410 if data.item and data.item.pkg:418 if data.item and data.item.pkg:
411 requires_restart = self.pkg_requires_restart(data.item.pkg)419 requires_restart = self.pkg_requires_restart(data.item.pkg)
@@ -433,6 +441,7 @@
433 if data.item:441 if data.item:
434 activatable = data.item.pkg.name not in self.list.held_back442 activatable = data.item.pkg.name not in self.list.held_back
435 inconsistent = False443 inconsistent = False
444 renderer.set_sensitive(data.item.sensitive)
436 elif data.group:445 elif data.group:
437 activatable = True446 activatable = True
438 inconsistent = data.group.selection_is_inconsistent()447 inconsistent = data.group.selection_is_inconsistent()
@@ -485,8 +494,11 @@
485 def pkg_label_renderer_data_func(self, cell_layout, renderer, model,494 def pkg_label_renderer_data_func(self, cell_layout, renderer, model,
486 iter, user_data):495 iter, user_data):
487 data = model.get_value(iter, LIST_UPDATE_DATA)496 data = model.get_value(iter, LIST_UPDATE_DATA)
497 sensitive = model.get_value(iter, LIST_SENSITIVE)
488 name = GLib.markup_escape_text(model.get_value(iter, LIST_NAME))498 name = GLib.markup_escape_text(model.get_value(iter, LIST_NAME))
489499
500 renderer.set_sensitive(sensitive)
501
490 if data.group:502 if data.group:
491 markup = name503 markup = name
492 elif data.item:504 elif data.item:
@@ -997,6 +1009,7 @@
997 name,1009 name,
998 UpdateData(groups, None, None),1010 UpdateData(groups, None, None),
999 humanize_size(total_size),1011 humanize_size(total_size),
1012 True,
1000 True1013 True
1001 ]1014 ]
1002 return self.store.append(None, header_row)1015 return self.store.append(None, header_row)
@@ -1020,7 +1033,8 @@
1020 group.name,1033 group.name,
1021 UpdateData(None, group, group_is_item),1034 UpdateData(None, group, group_is_item),
1022 humanize_size(group.get_total_size()),1035 humanize_size(group.get_total_size()),
1023 True1036 True,
1037 group.sensitive
1024 ]1038 ]
1025 group_iter = self.store.append(None, group_row)1039 group_iter = self.store.append(None, group_row)
10261040
@@ -1031,7 +1045,8 @@
1031 item.name,1045 item.name,
1032 UpdateData(None, None, item),1046 UpdateData(None, None, item),
1033 humanize_size(getattr(item.pkg.candidate, "size", 0)),1047 humanize_size(getattr(item.pkg.candidate, "size", 0)),
1034 True1048 True,
1049 group.sensitive
1035 ]1050 ]
1036 self.store.append(group_iter, item_row)1051 self.store.append(group_iter, item_row)
10371052
@@ -1063,6 +1078,8 @@
1063 _("Unused kernel updates to be removed"),1078 _("Unused kernel updates to be removed"),
1064 self.list.kernel_autoremove_groups)1079 self.list.kernel_autoremove_groups)
1065 self._add_groups(self.list.kernel_autoremove_groups)1080 self._add_groups(self.list.kernel_autoremove_groups)
1081 if self.list.ubuntu_pro_groups:
1082 self._add_groups(self.list.ubuntu_pro_groups)
10661083
1067 self.treeview_update.set_model(self.store)1084 self.treeview_update.set_model(self.store)
1068 self.pkg_cell_area.indent_toplevel = (1085 self.pkg_cell_area.indent_toplevel = (
10691086
=== modified file 'debian/changelog'
--- debian/changelog 2022-09-13 23:51:20 +0000
+++ debian/changelog 2023-01-18 03:42:01 +0000
@@ -1,3 +1,9 @@
1update-manager (1:18.04.11.15) bionic; urgency=medium
2
3 * Show pending Ubuntu pro packages (LP: #1990450)
4
5 -- Robert Ancell <robert.ancell@canonical.com> Wed, 18 Jan 2023 15:09:17 +1300
6
1update-manager (1:18.04.11.14) bionic; urgency=medium7update-manager (1:18.04.11.14) bionic; urgency=medium
28
3 * tests/test_meta_release_core.py: switch a test from using lucid to bionic9 * tests/test_meta_release_core.py: switch a test from using lucid to bionic

Subscribers

People subscribed via source and target branches