Merge lp:~robert-ancell/update-manager/ua into lp:update-manager
- ua
- Merge into main
Proposed by
Robert Ancell
Status: | Merged |
---|---|
Approved by: | Robert Ancell |
Approved revision: | 2960 |
Merged at revision: | 2950 |
Proposed branch: | lp:~robert-ancell/update-manager/ua |
Merge into: | lp:update-manager |
Diff against target: |
328 lines (+97/-18) 4 files modified
UpdateManager/Core/UpdateList.py (+45/-13) UpdateManager/UpdateManager.py (+26/-1) UpdateManager/UpdatesAvailable.py (+20/-4) debian/changelog (+6/-0) |
To merge this branch: | bzr merge lp:~robert-ancell/update-manager/ua |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Julian Andres Klode | Approve | ||
Review via email: mp+430517@code.launchpad.net |
Commit message
Description of the change
To post a comment you must log in.
Revision history for this message
Julian Andres Klode (juliank) : | # |
Revision history for this message
Julian Andres Klode (juliank) wrote : | # |
Though tbh, we probably should ship a python library in ubuntu-
- 2959. By Robert Ancell
-
Remove unused code
- 2960. By Robert Ancell
-
Use json.load instead of json.loads
Revision history for this message
Robert Ancell (robert-ancell) wrote : | # |
I've fixed the small issues you pointed out.
As you discussed with Seb, we wont be able to access the cache directly in the timeframe required so this will have to be the current solution, right?
Revision history for this message
Julian Andres Klode (juliank) : | # |
review:
Approve
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 2022-09-27 23:18:51 +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,10 @@ |
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, sensitive=True): |
41 | name = utils.get_package_label(pkg) |
42 | icon = Gio.ThemedIcon.new("package") |
43 | - self._items.add(UpdateItem(pkg, name, icon, to_remove)) |
44 | + self._items.add(UpdateItem(pkg, name, icon, to_remove, sensitive)) |
45 | # If the pkg is in self._deps, stop here. We have already calculated |
46 | # the recursive dependencies for this package, no need to do it again. |
47 | if cache and pkg.name in cache and pkg.name not in self._deps: |
48 | @@ -154,27 +155,27 @@ |
49 | |
50 | |
51 | class UpdateApplicationGroup(UpdateGroup): |
52 | - def __init__(self, pkg, application, to_remove): |
53 | + def __init__(self, pkg, application, to_remove, sensitive=True): |
54 | name = application.get_display_name() |
55 | icon = application.get_icon() |
56 | super(UpdateApplicationGroup, self).__init__(pkg, name, icon, |
57 | - to_remove) |
58 | + to_remove, sensitive) |
59 | |
60 | |
61 | class UpdatePackageGroup(UpdateGroup): |
62 | - def __init__(self, pkg, to_remove): |
63 | + def __init__(self, pkg, to_remove, sensitive=True): |
64 | name = utils.get_package_label(pkg) |
65 | icon = Gio.ThemedIcon.new("package") |
66 | - super(UpdatePackageGroup, self).__init__(pkg, name, icon, to_remove) |
67 | + super(UpdatePackageGroup, self).__init__(pkg, name, icon, to_remove, sensitive) |
68 | |
69 | |
70 | class UpdateSystemGroup(UpdateGroup): |
71 | - def __init__(self, cache, to_remove): |
72 | + def __init__(self, cache, to_remove, sensitive=True): |
73 | # Translators: the %s is a distro name, like 'Ubuntu' and 'base' as in |
74 | # the core components and packages. |
75 | name = _("%s base") % utils.get_ubuntu_flavor_name(cache=cache) |
76 | icon = Gio.ThemedIcon.new("distributor-logo") |
77 | - super(UpdateSystemGroup, self).__init__(None, name, icon, to_remove) |
78 | + super(UpdateSystemGroup, self).__init__(None, name, icon, to_remove, sensitive) |
79 | |
80 | |
81 | class UpdateOrigin(): |
82 | @@ -216,6 +217,7 @@ |
83 | self.security_groups = [] |
84 | self.kernel_autoremove_groups = [] |
85 | self.duplicate_groups = [] |
86 | + self.ubuntu_pro_groups = [] |
87 | self.num_updates = 0 |
88 | self.random = random.Random() |
89 | self.ignored_phased_updates = [] |
90 | @@ -464,7 +466,7 @@ |
91 | |
92 | return app_groups + pkg_groups |
93 | |
94 | - def update(self, cache, eventloop_callback=None, duplicate_packages=[]): |
95 | + def update(self, cache, eventloop_callback=None, duplicate_packages=[], ua_security_packages=[]): |
96 | self.held_back = [] |
97 | |
98 | # do the upgrade |
99 | @@ -476,6 +478,31 @@ |
100 | kernel_autoremove_pkgs = [] |
101 | duplicate_pkgs = [] |
102 | |
103 | + class FakeUbuntuProPackageCandidate: |
104 | + def __init__ (self, source_name, version, size): |
105 | + self.source_name = source_name |
106 | + self.summary = source_name |
107 | + self.description = source_name |
108 | + self.version = version |
109 | + self.size = size |
110 | + self.downloadable = False |
111 | + self.record = {} |
112 | + class FakeUbuntuProPackage: |
113 | + def __init__ (self, package_name, version, size): |
114 | + self.name = package_name |
115 | + self.candidate = FakeUbuntuProPackageCandidate(package_name, version, size) |
116 | + self.marked_install = False |
117 | + self.marked_upgrade = False |
118 | + |
119 | + def mark_install(self): |
120 | + pass |
121 | + |
122 | + def mark_delete(self): |
123 | + pass |
124 | + fake_ua_packages = [] |
125 | + for (package_name, version, size) in ua_security_packages: |
126 | + fake_ua_packages.append(FakeUbuntuProPackage(package_name, version, size)) |
127 | + |
128 | # Find all upgradable packages |
129 | for pkg in cache: |
130 | if pkg.is_upgradable or pkg.marked_install: |
131 | @@ -541,3 +568,8 @@ |
132 | cache, kernel_autoremove_pkgs, eventloop_callback, True) |
133 | self.duplicate_groups = self._make_groups( |
134 | cache, duplicate_pkgs, eventloop_callback, True) |
135 | + if len(fake_ua_packages) > 0: |
136 | + ubuntu_pro_group = UpdateGroup(None, "Ubuntu Pro (enable in Settingsā¦)", None, False, False) |
137 | + for package in fake_ua_packages: |
138 | + ubuntu_pro_group.add(package) |
139 | + self.ubuntu_pro_groups = [ubuntu_pro_group] |
140 | |
141 | === modified file 'UpdateManager/UpdateManager.py' |
142 | --- UpdateManager/UpdateManager.py 2021-12-10 20:29:40 +0000 |
143 | +++ UpdateManager/UpdateManager.py 2022-09-27 23:18:51 +0000 |
144 | @@ -36,6 +36,7 @@ |
145 | |
146 | import distro_info |
147 | import fnmatch |
148 | +import json |
149 | import os |
150 | import subprocess |
151 | import sys |
152 | @@ -85,6 +86,7 @@ |
153 | self.unity = UnitySupport() |
154 | self.controller = None |
155 | self.cache = None |
156 | + self.ua_security_packages = [] |
157 | self.update_list = None |
158 | self.meta_release = None |
159 | self.hwe_replacement_packages = None |
160 | @@ -268,6 +270,27 @@ |
161 | and pkg.installed: |
162 | self.oem_metapackages.add(pkg) |
163 | |
164 | + def _get_ua_security_status(self): |
165 | + self.ua_security_packages = [] |
166 | + try: |
167 | + p = subprocess.Popen(['ua', 'security-status', '--format=json'], stdout=subprocess.PIPE) |
168 | + except OSError: |
169 | + pass |
170 | + else: |
171 | + while p.poll() is None: |
172 | + while Gtk.events_pending(): |
173 | + Gtk.main_iteration() |
174 | + time.sleep(0.05) |
175 | + s = json.load(p.stdout) |
176 | + ua_attached = s.get('summary', {}).get('ua', {}).get('attached', False) |
177 | + for package in s.get('packages', []): |
178 | + status = package.get('status', '') |
179 | + if status == 'pending_attach': |
180 | + name = package.get('name', '') |
181 | + version = package.get('version', '') |
182 | + size = package.get('download_size', 0) |
183 | + self.ua_security_packages.append((name, version, size)) |
184 | + |
185 | def _make_available_pane(self, install_count, need_reboot=False, |
186 | cancelled_update=False, error_occurred=False): |
187 | self._check_hwe_support_status() |
188 | @@ -423,6 +446,8 @@ |
189 | |
190 | self._check_oem_metapackages() |
191 | |
192 | + self._get_ua_security_status() |
193 | + |
194 | for pkgname in self.oem_metapackages: |
195 | try: |
196 | if not self.cache[pkgname].is_installed: |
197 | @@ -433,7 +458,7 @@ |
198 | self.update_list = UpdateList(self) |
199 | try: |
200 | self.update_list.update(self.cache, eventloop_callback=iterate, |
201 | - duplicate_packages=self.duplicate_packages) |
202 | + duplicate_packages=self.duplicate_packages, ua_security_packages=self.ua_security_packages) |
203 | except SystemError as e: |
204 | header = _("Could not calculate the upgrade") |
205 | desc = _("An unresolvable problem occurred while " |
206 | |
207 | === modified file 'UpdateManager/UpdatesAvailable.py' |
208 | --- UpdateManager/UpdatesAvailable.py 2020-12-14 11:10:57 +0000 |
209 | +++ UpdateManager/UpdatesAvailable.py 2022-09-27 23:18:51 +0000 |
210 | @@ -74,7 +74,7 @@ |
211 | # - screen reader does not say "Downloaded" for downloaded updates |
212 | |
213 | # list constants |
214 | -(LIST_NAME, LIST_UPDATE_DATA, LIST_SIZE, LIST_TOGGLE_ACTIVE) = range(4) |
215 | +(LIST_NAME, LIST_UPDATE_DATA, LIST_SIZE, LIST_TOGGLE_ACTIVE, LIST_SENSITIVE) = range(5) |
216 | |
217 | # NetworkManager enums |
218 | from .Core.roam import NetworkManagerHelper |
219 | @@ -261,7 +261,7 @@ |
220 | changes_buffer.create_tag("versiontag", weight=Pango.Weight.BOLD) |
221 | |
222 | # the treeview (move into it's own code!) |
223 | - self.store = Gtk.TreeStore(str, GObject.TYPE_PYOBJECT, str, bool) |
224 | + self.store = Gtk.TreeStore(str, GObject.TYPE_PYOBJECT, str, bool, bool) |
225 | self.treeview_update.set_model(None) |
226 | |
227 | self.image_restart.set_from_gicon(self.get_restart_icon(), |
228 | @@ -293,6 +293,8 @@ |
229 | pkg_column.pack_start(pkg_toggle_renderer, False) |
230 | pkg_column.add_attribute(pkg_toggle_renderer, |
231 | 'active', LIST_TOGGLE_ACTIVE) |
232 | + pkg_column.add_attribute(pkg_toggle_renderer, |
233 | + 'sensitive', LIST_SENSITIVE) |
234 | pkg_column.set_cell_data_func(pkg_toggle_renderer, |
235 | self.pkg_toggle_renderer_data_func) |
236 | |
237 | @@ -319,6 +321,8 @@ |
238 | size_column = Gtk.TreeViewColumn(_("Download"), size_renderer, |
239 | text=LIST_SIZE) |
240 | size_column.set_sizing(Gtk.TreeViewColumnSizing.AUTOSIZE) |
241 | + size_column.add_attribute(size_renderer, |
242 | + 'sensitive', LIST_SENSITIVE) |
243 | self.treeview_update.append_column(size_column) |
244 | |
245 | self.treeview_update.set_headers_visible(True) |
246 | @@ -404,8 +408,11 @@ |
247 | def restart_icon_renderer_data_func(self, cell_layout, renderer, model, |
248 | iter, user_data): |
249 | data = model.get_value(iter, LIST_UPDATE_DATA) |
250 | + sensitive = model.get_value(iter, LIST_SENSITIVE) |
251 | path = model.get_path(iter) |
252 | |
253 | + renderer.set_sensitive(sensitive) |
254 | + |
255 | requires_restart = False |
256 | if data.item and data.item.pkg: |
257 | requires_restart = self.pkg_requires_restart(data.item.pkg) |
258 | @@ -433,6 +440,7 @@ |
259 | if data.item: |
260 | activatable = data.item.pkg.name not in self.list.held_back |
261 | inconsistent = False |
262 | + renderer.set_sensitive(data.item.sensitive) |
263 | elif data.group: |
264 | activatable = True |
265 | inconsistent = data.group.selection_is_inconsistent() |
266 | @@ -485,8 +493,11 @@ |
267 | def pkg_label_renderer_data_func(self, cell_layout, renderer, model, |
268 | iter, user_data): |
269 | data = model.get_value(iter, LIST_UPDATE_DATA) |
270 | + sensitive = model.get_value(iter, LIST_SENSITIVE) |
271 | name = GLib.markup_escape_text(model.get_value(iter, LIST_NAME)) |
272 | |
273 | + renderer.set_sensitive(sensitive) |
274 | + |
275 | if data.group: |
276 | markup = name |
277 | elif data.item: |
278 | @@ -1000,6 +1011,7 @@ |
279 | name, |
280 | UpdateData(groups, None, None), |
281 | humanize_size(total_size), |
282 | + True, |
283 | True |
284 | ] |
285 | return self.store.append(None, header_row) |
286 | @@ -1023,7 +1035,8 @@ |
287 | group.name, |
288 | UpdateData(None, group, group_is_item), |
289 | humanize_size(group.get_total_size()), |
290 | - True |
291 | + True, |
292 | + group.sensitive |
293 | ] |
294 | group_iter = self.store.append(None, group_row) |
295 | |
296 | @@ -1034,7 +1047,8 @@ |
297 | item.name, |
298 | UpdateData(None, None, item), |
299 | humanize_size(getattr(item.pkg.candidate, "size", 0)), |
300 | - True |
301 | + True, |
302 | + group.sensitive |
303 | ] |
304 | self.store.append(group_iter, item_row) |
305 | |
306 | @@ -1077,6 +1091,8 @@ |
307 | _("Duplicate packages to be removed"), |
308 | self.list.duplicate_groups) |
309 | self._add_groups(self.list.duplicate_groups) |
310 | + if self.list.ubuntu_pro_groups: |
311 | + self._add_groups(self.list.ubuntu_pro_groups) |
312 | |
313 | self.treeview_update.set_model(self.store) |
314 | self.pkg_cell_area.indent_toplevel = ( |
315 | |
316 | === modified file 'debian/changelog' |
317 | --- debian/changelog 2022-08-26 01:52:12 +0000 |
318 | +++ debian/changelog 2022-09-27 23:18:51 +0000 |
319 | @@ -1,3 +1,9 @@ |
320 | +update-manager (1:22.10.1+ubuntupro1) kinetic; urgency=medium |
321 | + |
322 | + * Show pending Ubuntu pro packages |
323 | + |
324 | + -- Robert Ancell <robert.ancell@canonical.com> Fri, 01 Jul 2022 16:15:05 +1200 |
325 | + |
326 | update-manager (1:22.10.1) kinetic; urgency=medium |
327 | |
328 | * Build with snapd-glib 1.61 |
It's an interesting proof of concept, but I'd really like to see this done properly by investigating the cache to find out the Pro packages and then using the real Version objects vs. a query in a subprocess, see update-notifier's apt_check.py for example.
Then we also get the description and everything working correctly.