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

Proposed by Robert Ancell
Status: Merged
Merged at revision: 2949
Proposed branch: lp:~robert-ancell/update-manager/ua-jammy-merge
Merge into: lp:~ubuntu-core-dev/update-manager/jammy
Diff against target: 374 lines (+113/-30)
5 files modified
UpdateManager/Core/UpdateList.py (+54/-13)
UpdateManager/Dialogs.py (+4/-12)
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-jammy-merge
Reviewer Review Type Date Requested Status
Ubuntu Core Development Team Pending
Review via email: mp+435908@code.launchpad.net
To post a comment you must log in.
2949. By Robert Ancell

Show pending Ubuntu pro packages (LP: #1990450)

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
1=== modified file 'UpdateManager/Core/UpdateList.py'
2--- UpdateManager/Core/UpdateList.py 2021-02-05 21:17:38 +0000
3+++ UpdateManager/Core/UpdateList.py 2023-01-17 22:47:53 +0000
4@@ -44,11 +44,12 @@
5
6
7 class UpdateItem():
8- def __init__(self, pkg, name, icon, to_remove):
9+ def __init__(self, pkg, name, icon, to_remove, sensitive=True):
10 self.icon = icon
11 self.name = name
12 self.pkg = pkg
13 self.to_remove = to_remove
14+ self.sensitive = sensitive
15
16 def is_selected(self):
17 if not self.to_remove:
18@@ -60,13 +61,13 @@
19 class UpdateGroup(UpdateItem):
20 _depcache = {}
21
22- def __init__(self, pkg, name, icon, to_remove):
23- UpdateItem.__init__(self, pkg, name, icon, to_remove)
24+ def __init__(self, pkg, name, icon, to_remove, sensitive=True):
25+ UpdateItem.__init__(self, pkg, name, icon, to_remove, sensitive)
26 self._items = set()
27 self._deps = set()
28 self.core_item = None
29 if pkg is not None:
30- self.core_item = UpdateItem(pkg, name, icon, to_remove)
31+ self.core_item = UpdateItem(pkg, name, icon, to_remove, sensitive)
32 self._items.add(self.core_item)
33
34 @property
35@@ -75,10 +76,11 @@
36 all_items.extend(self._items)
37 return sorted(all_items, key=lambda a: a.name.lower())
38
39- def add(self, pkg, cache=None, eventloop_callback=None, to_remove=False):
40+ def add(self, pkg, cache=None, eventloop_callback=None, to_remove=False,
41+ sensitive=True):
42 name = utils.get_package_label(pkg)
43 icon = Gio.ThemedIcon.new("package")
44- self._items.add(UpdateItem(pkg, name, icon, to_remove))
45+ self._items.add(UpdateItem(pkg, name, icon, to_remove, sensitive))
46 # If the pkg is in self._deps, stop here. We have already calculated
47 # the recursive dependencies for this package, no need to do it again.
48 if cache and pkg.name in cache and pkg.name not in self._deps:
49@@ -154,27 +156,29 @@
50
51
52 class UpdateApplicationGroup(UpdateGroup):
53- def __init__(self, pkg, application, to_remove):
54+ def __init__(self, pkg, application, to_remove, sensitive=True):
55 name = application.get_display_name()
56 icon = application.get_icon()
57 super(UpdateApplicationGroup, self).__init__(pkg, name, icon,
58- to_remove)
59+ to_remove, sensitive)
60
61
62 class UpdatePackageGroup(UpdateGroup):
63- def __init__(self, pkg, to_remove):
64+ def __init__(self, pkg, to_remove, sensitive=True):
65 name = utils.get_package_label(pkg)
66 icon = Gio.ThemedIcon.new("package")
67- super(UpdatePackageGroup, self).__init__(pkg, name, icon, to_remove)
68+ super(UpdatePackageGroup, self).__init__(pkg, name, icon, to_remove,
69+ sensitive)
70
71
72 class UpdateSystemGroup(UpdateGroup):
73- def __init__(self, cache, to_remove):
74+ def __init__(self, cache, to_remove, sensitive=True):
75 # Translators: the %s is a distro name, like 'Ubuntu' and 'base' as in
76 # the core components and packages.
77 name = _("%s base") % utils.get_ubuntu_flavor_name(cache=cache)
78 icon = Gio.ThemedIcon.new("distributor-logo")
79- super(UpdateSystemGroup, self).__init__(None, name, icon, to_remove)
80+ super(UpdateSystemGroup, self).__init__(None, name, icon, to_remove,
81+ sensitive)
82
83
84 class UpdateOrigin():
85@@ -216,6 +220,7 @@
86 self.security_groups = []
87 self.kernel_autoremove_groups = []
88 self.duplicate_groups = []
89+ self.ubuntu_pro_groups = []
90 self.num_updates = 0
91 self.random = random.Random()
92 self.ignored_phased_updates = []
93@@ -464,7 +469,8 @@
94
95 return app_groups + pkg_groups
96
97- def update(self, cache, eventloop_callback=None, duplicate_packages=[]):
98+ def update(self, cache, eventloop_callback=None, duplicate_packages=[],
99+ ua_security_packages=[]):
100 self.held_back = []
101
102 # do the upgrade
103@@ -476,6 +482,34 @@
104 kernel_autoremove_pkgs = []
105 duplicate_pkgs = []
106
107+ class FakeUbuntuProPackageCandidate:
108+ def __init__(self, source_name, version, size):
109+ self.source_name = source_name
110+ self.summary = source_name
111+ self.description = source_name
112+ self.version = version
113+ self.size = size
114+ self.downloadable = False
115+ self.record = {}
116+
117+ class FakeUbuntuProPackage:
118+ def __init__(self, package_name, version, size):
119+ self.name = package_name
120+ self.candidate = FakeUbuntuProPackageCandidate(package_name,
121+ version, size)
122+ self.marked_install = False
123+ self.marked_upgrade = False
124+
125+ def mark_install(self):
126+ pass
127+
128+ def mark_delete(self):
129+ pass
130+ fake_ua_packages = []
131+ for (package_name, version, size) in ua_security_packages:
132+ fake_ua_packages.append(FakeUbuntuProPackage(package_name,
133+ version, size))
134+
135 # Find all upgradable packages
136 for pkg in cache:
137 if pkg.is_upgradable or pkg.marked_install:
138@@ -541,3 +575,10 @@
139 cache, kernel_autoremove_pkgs, eventloop_callback, True)
140 self.duplicate_groups = self._make_groups(
141 cache, duplicate_pkgs, eventloop_callback, True)
142+ if len(fake_ua_packages) > 0:
143+ ubuntu_pro_group = UpdateGroup(None,
144+ "Ubuntu Pro (enable in Settings…)",
145+ None, False, False)
146+ for package in fake_ua_packages:
147+ ubuntu_pro_group.add(package)
148+ self.ubuntu_pro_groups = [ubuntu_pro_group]
149
150=== modified file 'UpdateManager/Dialogs.py'
151--- UpdateManager/Dialogs.py 2021-01-05 20:24:02 +0000
152+++ UpdateManager/Dialogs.py 2023-01-17 22:47:53 +0000
153@@ -153,25 +153,17 @@
154 codename = get_dist()
155 return di.is_lts(codename)
156
157- def _has_livepatch_settings_ui(self):
158- try:
159- return Gio.DesktopAppInfo \
160- .new('gnome-online-accounts-panel.desktop')
161- except Exception:
162- return None
163-
164 def on_livepatch_status_ready(self, active, cs, ps, fixes):
165 self.set_desc(None)
166
167 if not active:
168 if self._is_livepatch_supported() and \
169 self.settings_button and \
170- self._has_livepatch_settings_ui() and \
171 self.settings.get_int('launch-count') >= 4:
172- self.set_desc(_("<b>Tip:</b> You can use Livepatch to "
173- "keep your computer more secure between "
174- "restarts."))
175- self.settings_button.set_label(_("Settings & Livepatch…"))
176+ self.set_desc(_("<b>Tip:</b> You can use Livepatch with "
177+ "Ubuntu Pro to keep your computer more "
178+ "secure between restarts."))
179+ self.settings_button.set_label(_("Settings & Pro…"))
180 return
181
182 needs_reschedule = False
183
184=== modified file 'UpdateManager/UpdateManager.py'
185--- UpdateManager/UpdateManager.py 2021-12-10 20:29:40 +0000
186+++ UpdateManager/UpdateManager.py 2023-01-17 22:47:53 +0000
187@@ -36,6 +36,7 @@
188
189 import distro_info
190 import fnmatch
191+import json
192 import os
193 import subprocess
194 import sys
195@@ -85,6 +86,7 @@
196 self.unity = UnitySupport()
197 self.controller = None
198 self.cache = None
199+ self.ua_security_packages = []
200 self.update_list = None
201 self.meta_release = None
202 self.hwe_replacement_packages = None
203@@ -268,6 +270,27 @@
204 and pkg.installed:
205 self.oem_metapackages.add(pkg)
206
207+ def _get_ua_security_status(self):
208+ self.ua_security_packages = []
209+ try:
210+ p = subprocess.Popen(['ua', 'security-status', '--format=json'],
211+ stdout=subprocess.PIPE)
212+ except OSError:
213+ pass
214+ else:
215+ while p.poll() is None:
216+ while Gtk.events_pending():
217+ Gtk.main_iteration()
218+ time.sleep(0.05)
219+ s = json.load(p.stdout)
220+ for package in s.get('packages', []):
221+ status = package.get('status', '')
222+ if status == 'pending_attach':
223+ name = package.get('name', '')
224+ version = package.get('version', '')
225+ size = package.get('download_size', 0)
226+ self.ua_security_packages.append((name, version, size))
227+
228 def _make_available_pane(self, install_count, need_reboot=False,
229 cancelled_update=False, error_occurred=False):
230 self._check_hwe_support_status()
231@@ -423,6 +446,8 @@
232
233 self._check_oem_metapackages()
234
235+ self._get_ua_security_status()
236+
237 for pkgname in self.oem_metapackages:
238 try:
239 if not self.cache[pkgname].is_installed:
240@@ -433,7 +458,9 @@
241 self.update_list = UpdateList(self)
242 try:
243 self.update_list.update(self.cache, eventloop_callback=iterate,
244- duplicate_packages=self.duplicate_packages)
245+ duplicate_packages=self.duplicate_packages,
246+ ua_security_packages=self.
247+ ua_security_packages)
248 except SystemError as e:
249 header = _("Could not calculate the upgrade")
250 desc = _("An unresolvable problem occurred while "
251
252=== modified file 'UpdateManager/UpdatesAvailable.py'
253--- UpdateManager/UpdatesAvailable.py 2020-12-14 11:10:57 +0000
254+++ UpdateManager/UpdatesAvailable.py 2023-01-17 22:47:53 +0000
255@@ -74,7 +74,8 @@
256 # - screen reader does not say "Downloaded" for downloaded updates
257
258 # list constants
259-(LIST_NAME, LIST_UPDATE_DATA, LIST_SIZE, LIST_TOGGLE_ACTIVE) = range(4)
260+(LIST_NAME, LIST_UPDATE_DATA, LIST_SIZE, LIST_TOGGLE_ACTIVE,
261+ LIST_SENSITIVE) = range(5)
262
263 # NetworkManager enums
264 from .Core.roam import NetworkManagerHelper
265@@ -261,7 +262,7 @@
266 changes_buffer.create_tag("versiontag", weight=Pango.Weight.BOLD)
267
268 # the treeview (move into it's own code!)
269- self.store = Gtk.TreeStore(str, GObject.TYPE_PYOBJECT, str, bool)
270+ self.store = Gtk.TreeStore(str, GObject.TYPE_PYOBJECT, str, bool, bool)
271 self.treeview_update.set_model(None)
272
273 self.image_restart.set_from_gicon(self.get_restart_icon(),
274@@ -293,6 +294,8 @@
275 pkg_column.pack_start(pkg_toggle_renderer, False)
276 pkg_column.add_attribute(pkg_toggle_renderer,
277 'active', LIST_TOGGLE_ACTIVE)
278+ pkg_column.add_attribute(pkg_toggle_renderer,
279+ 'sensitive', LIST_SENSITIVE)
280 pkg_column.set_cell_data_func(pkg_toggle_renderer,
281 self.pkg_toggle_renderer_data_func)
282
283@@ -319,6 +322,8 @@
284 size_column = Gtk.TreeViewColumn(_("Download"), size_renderer,
285 text=LIST_SIZE)
286 size_column.set_sizing(Gtk.TreeViewColumnSizing.AUTOSIZE)
287+ size_column.add_attribute(size_renderer,
288+ 'sensitive', LIST_SENSITIVE)
289 self.treeview_update.append_column(size_column)
290
291 self.treeview_update.set_headers_visible(True)
292@@ -404,8 +409,11 @@
293 def restart_icon_renderer_data_func(self, cell_layout, renderer, model,
294 iter, user_data):
295 data = model.get_value(iter, LIST_UPDATE_DATA)
296+ sensitive = model.get_value(iter, LIST_SENSITIVE)
297 path = model.get_path(iter)
298
299+ renderer.set_sensitive(sensitive)
300+
301 requires_restart = False
302 if data.item and data.item.pkg:
303 requires_restart = self.pkg_requires_restart(data.item.pkg)
304@@ -433,6 +441,7 @@
305 if data.item:
306 activatable = data.item.pkg.name not in self.list.held_back
307 inconsistent = False
308+ renderer.set_sensitive(data.item.sensitive)
309 elif data.group:
310 activatable = True
311 inconsistent = data.group.selection_is_inconsistent()
312@@ -485,8 +494,11 @@
313 def pkg_label_renderer_data_func(self, cell_layout, renderer, model,
314 iter, user_data):
315 data = model.get_value(iter, LIST_UPDATE_DATA)
316+ sensitive = model.get_value(iter, LIST_SENSITIVE)
317 name = GLib.markup_escape_text(model.get_value(iter, LIST_NAME))
318
319+ renderer.set_sensitive(sensitive)
320+
321 if data.group:
322 markup = name
323 elif data.item:
324@@ -1000,6 +1012,7 @@
325 name,
326 UpdateData(groups, None, None),
327 humanize_size(total_size),
328+ True,
329 True
330 ]
331 return self.store.append(None, header_row)
332@@ -1023,7 +1036,8 @@
333 group.name,
334 UpdateData(None, group, group_is_item),
335 humanize_size(group.get_total_size()),
336- True
337+ True,
338+ group.sensitive
339 ]
340 group_iter = self.store.append(None, group_row)
341
342@@ -1034,7 +1048,8 @@
343 item.name,
344 UpdateData(None, None, item),
345 humanize_size(getattr(item.pkg.candidate, "size", 0)),
346- True
347+ True,
348+ group.sensitive
349 ]
350 self.store.append(group_iter, item_row)
351
352@@ -1077,6 +1092,8 @@
353 _("Duplicate packages to be removed"),
354 self.list.duplicate_groups)
355 self._add_groups(self.list.duplicate_groups)
356+ if self.list.ubuntu_pro_groups:
357+ self._add_groups(self.list.ubuntu_pro_groups)
358
359 self.treeview_update.set_model(self.store)
360 self.pkg_cell_area.indent_toplevel = (
361
362=== modified file 'debian/changelog'
363--- debian/changelog 2022-12-01 19:09:52 +0000
364+++ debian/changelog 2023-01-17 22:47:53 +0000
365@@ -1,3 +1,9 @@
366+update-manager (1:22.04.11) jammy; urgency=medium
367+
368+ * Show pending Ubuntu pro packages (LP: #1990450)
369+
370+ -- Robert Ancell <robert.ancell@canonical.com> Wed, 18 Jan 2023 11:05:40 +1300
371+
372 update-manager (1:22.04.10) jammy; urgency=medium
373
374 [ Renan Rodrigo ]

Subscribers

People subscribed via source and target branches