Merge lp:~azzar1/software-properties/add-canonical-livepatch into lp:software-properties
- add-canonical-livepatch
- Merge into main
Status: | Merged | ||||
---|---|---|---|---|---|
Merged at revision: | 1011 | ||||
Proposed branch: | lp:~azzar1/software-properties/add-canonical-livepatch | ||||
Merge into: | lp:software-properties | ||||
Diff against target: |
2008 lines (+1176/-122) 13 files modified
data/gtkbuilder/dialog-auth.ui (+114/-0) data/gtkbuilder/dialog-livepatch-error.ui (+58/-0) data/gtkbuilder/main.ui (+90/-21) debian/changelog (+14/-0) debian/control (+4/-2) po/POTFILES.in (+2/-1) po/software-properties.pot (+166/-89) softwareproperties/GoaAuth.py (+113/-0) softwareproperties/SoftwareProperties.py (+153/-1) softwareproperties/dbus/SoftwarePropertiesDBus.py (+11/-0) softwareproperties/gtk/DialogAuth.py (+228/-0) softwareproperties/gtk/DialogLivepatchError.py (+57/-0) softwareproperties/gtk/SoftwarePropertiesGtk.py (+166/-8) |
||||
To merge this branch: | bzr merge lp:~azzar1/software-properties/add-canonical-livepatch | ||||
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Didier Roche-Tolomelli | Approve | ||
Review via email: mp+341427@code.launchpad.net |
Commit message
Add a "Enable Canonical Livepatch..." switch to software-
Description of the change
Add a "Enable Canonical Livepatch..." switch to software-
Andrea Azzarone (azzar1) wrote : | # |
Brian Murray (brian-murray) wrote : | # |
I'm not sure I'm the best person to evaluate all the gtk code so I've identified some other things mostly nit-picks but I do think using python3-distro-info would quite a good improvement.
Brian Murray (brian-murray) wrote : | # |
This may also require a Feature Freeze Exception given where we are in the release cycle.
Didier Roche-Tolomelli (didrocks) wrote : | # |
Good work! I'm having some remarks in addition to Brian's comment, please see them inline.
My major concern is error handling, which is using strings (empty strings or none) to tell that no error happened instead of using python exceptions. In some cases (see my inline reviews), it means that you even don't make difference between legit "no error executing this command" and "error without any output of the command", which is problematic IMHO.
The rest is majoritaly some syntax suggestions to make the code more readable and pythonish, not all required, but some changes may be beneficials IMHO.
Also:
* You should refresh the translation template file in po/software-
* Now that seb opened a FFe bug, refer to it in debian/changelog
Note that I didn't test it yet, will do once the changes are committed here.
Didier Roche-Tolomelli (didrocks) : | # |
Andrea Azzarone (azzar1) : | # |
Andrea Azzarone (azzar1) wrote : | # |
I pushed the fixes. Regarding class decorators I tried to use them but they fails to properly pass around the 'self' argument.
Didier Roche-Tolomelli (didrocks) wrote : | # |
Nice work!
I guess there are still some things to fix before getting it mergeable. I'll post the 3 followups here (in the previous commit, as answers) and there is one on the new commit (incoming).
Once those fixed, I'll do a test run ;)
Didier Roche-Tolomelli (didrocks) wrote : | # |
And here are the small comments on the new commit :)
Andrea Azzarone (azzar1) wrote : | # |
Two comments on the old commit.
- 1043. By Andrea Azzarone
-
Make title translatable.
- 1044. By Andrea Azzarone
-
Simplify the calls to SetLivepatchEna
bled.
Andrea Azzarone (azzar1) wrote : | # |
Pushed!
- 1045. By Andrea Azzarone
-
Refresh line numbers in po/software-
properties. pot.
Didier Roche-Tolomelli (didrocks) wrote : | # |
+1 on old diff changes
- 1046. By Andrea Azzarone
-
Set enabled to False by default.
Didier Roche-Tolomelli (didrocks) wrote : | # |
As discussed on IRC, thanks for the followup fix (yeah peer review, isn't it? ;)).
So, it's +1 from my side, just need some proper manual testing (as you can see, the typo was easily made :p).
Good work!
Didier Roche-Tolomelli (didrocks) wrote : | # |
Ok, trying it now:
- layout looks weird here (https:/
- is https:/
- once I end up in UAO, I don't really know what to do, I have 2 accounts (my personal Google one and my canonical one) which are already subscribed… Clicking on them doesn't mention livepatch or anything at all, what should I do?
Didier Roche-Tolomelli (didrocks) wrote : | # |
For reference, here is on what I end up clicking on "sign in" or cog menu: https:/
My canonical account is a SSO one.
After some debugging, it seems we need the g-o-a version (and daemon restart) from -proposed. So, a versioned dep in debian/control should be added.
I was then able to sign in. Note that (as known), once you put the email/password, it asks for the admin password, then *twice* the passcode for SSO (Note that it doesn't empty the field when asking for the second passcode, which it should, IMHO?) and then another sudo password for installing packages.
Then, sign in in first dialog is getting the correct status. However, after some seconds, I get an excl error dialog with Settings/Ignore. Clicking on Settings do nothing. Once closing that dialog the checked "Use Canonical Livepatch…" checkbox is unchecked. Andrea says it's due to livepatch. I can't go further in that direction thus.
Clicking sign out/sign in again, I see my SSO account in the list of "Use another account" selection, which the same "strange" styling.
Clicking on use another popups the dialog as before, clicking on mly sso account sent me back to previous state, signed in, as expected.
Note that even after restart g-o-a, I got multiple times this traceback:
Traceback (most recent call last):
File "/usr/lib/
_listbox_
self.
File "/usr/lib/
_spawn_
proxy.
GLib.Error: g-io-error-quark: Le délai d’attente est dépassé (24)
Anyway, there are some fixes needed, marking as such. We can then see if we upload that, but I want some design reviews or we'll need an UIFe anyway for those changes.
- 1047. By Andrea Azzarone
-
Remove settings button.
- 1048. By Andrea Azzarone
-
Don't show the "Settings..." button if software-
properties- window has not been closed. - 1049. By Andrea Azzarone
-
Wrap dbus in try/except and show warning instead of crash.
Andrea Azzarone (azzar1) wrote : | # |
> For reference, here is on what I end up clicking on "sign in" or cog menu:
> https:/
> My canonical account is a SSO one.
>
> After some debugging, it seems we need the g-o-a version (and daemon restart)
> from -proposed. So, a versioned dep in debian/control should be added.
Fixed.
>
> I was then able to sign in. Note that (as known), once you put the
> email/password, it asks for the admin password, then *twice* the passcode for
> SSO (Note that it doesn't empty the field when asking for the second passcode,
> which it should, IMHO?) and then another sudo password for installing
> packages.
Proposed a fix here: https:/
>
> Then, sign in in first dialog is getting the correct status. However, after
> some seconds, I get an excl error dialog with Settings/Ignore. Clicking on
> Settings do nothing. Once closing that dialog the checked "Use Canonical
> Livepatch…" checkbox is unchecked. Andrea says it's due to livepatch. I can't
> go further in that direction thus.
This is likely the bug we're getting: https:/
>
> Clicking sign out/sign in again, I see my SSO account in the list of "Use
> another account" selection, which the same "strange" styling.
> Clicking on use another popups the dialog as before, clicking on mly sso
> account sent me back to previous state, signed in, as expected.
>
> Note that even after restart g-o-a, I got multiple times this traceback:
> Traceback (most recent call last):
> File "/usr/lib/
> line 199, in
> _listbox_
> self.('add', 'ubuntusso')
> File "/usr/lib/
> line 138, in
> _spawn_
> proxy.call_
> GLib.Error: g-io-error-quark: Le délai d’attente est dépassé (24)
>
I try/except wrapped the calls to "_spawn_
>
> Anyway, there are some fixes needed, marking as such. We can then see if we
> upload that, but I want some design reviews or we'll need an UIFe anyway for
> those changes.
- 1050. By Andrea Azzarone
-
Bump dep for gir1.2-goa-1.0
- 1051. By Andrea Azzarone
-
Use a 10 minutes timeout and improve layout.
Andrea Azzarone (azzar1) wrote : | # |
I improved a little bit the layout and added a 10 minutes layout on that call too.
Didier Roche-Tolomelli (didrocks) wrote : | # |
Excellent work Andrea! I just had another test run, and things mostly LGTM, apart from the design issues we discussed and need a followup with design team + the g-o-a and livepatch known issues :)
For now, let's get that in to get wider testing.
Merging and sponsoring it for you
Didier Roche-Tolomelli (didrocks) wrote : | # |
My chaosmonkey personal instance said "Needs fixing", but I say "Approve" :)
Matthew Paul Thomas (mpt) wrote : | # |
> - layout looks weird here (https:/
Well spotted Didier. This is the UI equivalent of technical debt: the current implementation lags almost five years behind the current design <https:/
(a) There are too many tabs, which makes the whole window wider, which makes the Livepatch options look much more “floaty” than they would be otherwise.
(b) “Install updates from:” is still checkboxes, rather than a menu, which makes it odd that the Livepatch checkbox isn’t lined up with those ones.
(c) All the menus are needlessly wide, so it’s not obvious whether/that the block of menus is centered in the tab, which makes the Livepatch controls appear to be the only block that is centered in the tab, which makes it look out of place.
Fixing (a) or (b) probably seems like far too much work, five weeks before release, just to make Livepatch options look less weird. (Though of course that’s not the only reason to fix them.) Fixing (c) might be practical here, since it’s just changing widths and alignments.
Another way to improve the layout temporarily would be to remove the indentation from the “Install updates from:” checkboxes (which, even if they were supposed to still exist, would not be supposed to be indented anyway!), and then left-align the whole Livepatch block. That way all the checkboxes in the tab would line up.
Separately from all of that:
(d) “To use Livepatch you need to sign in” should be indented from the checkbox, not centered independently — that is, the word “To” should line up exactly with “Use” immediately above.
(e) As shown in the wireframes, the “Sign Out” button should always be exactly the same position and width as the “Sign In…” button.
(f) Therefore, the status text block should be fixed width, regardless of whether the text is “To use Livepatch you need to sign in.”, “Signed in as <email address hidden>.”, or “…<email address hidden> isn’t authorised to use Livepatch.”.
Andrea Azzarone (azzar1) wrote : | # |
With gtk is hard to implement (d). The problem is that it's not possible to align the label of the checkbox with the label below. One possible solution is to hard-code the paddings but this would break the layout for other themes.
Preview Diff
1 | === added file 'data/gtkbuilder/dialog-auth.ui' |
2 | --- data/gtkbuilder/dialog-auth.ui 1970-01-01 00:00:00 +0000 |
3 | +++ data/gtkbuilder/dialog-auth.ui 2018-03-21 15:53:10 +0000 |
4 | @@ -0,0 +1,114 @@ |
5 | +<?xml version="1.0" encoding="UTF-8"?> |
6 | +<!-- Generated with glade 3.20.4 --> |
7 | +<interface> |
8 | + <requires lib="gtk+" version="3.10"/> |
9 | + <object class="GtkDialog" id="dialog_auth"> |
10 | + <property name="can_focus">False</property> |
11 | + <property name="resizable">False</property> |
12 | + <property name="modal">True</property> |
13 | + <property name="destroy_with_parent">True</property> |
14 | + <property name="type_hint">dialog</property> |
15 | + <property name="deletable">False</property> |
16 | + <child internal-child="vbox"> |
17 | + <object class="GtkBox" id="box_dialog"> |
18 | + <property name="can_focus">False</property> |
19 | + <property name="orientation">vertical</property> |
20 | + <property name="spacing">2</property> |
21 | + <child internal-child="action_area"> |
22 | + <object class="GtkButtonBox" id="dialog-action_area1"> |
23 | + <property name="can_focus">False</property> |
24 | + </object> |
25 | + <packing> |
26 | + <property name="expand">False</property> |
27 | + <property name="fill">False</property> |
28 | + <property name="position">0</property> |
29 | + </packing> |
30 | + </child> |
31 | + <child> |
32 | + <object class="GtkGrid" id="main_grid"> |
33 | + <property name="visible">True</property> |
34 | + <property name="can_focus">False</property> |
35 | + <property name="border_width">12</property> |
36 | + <property name="row_spacing">12</property> |
37 | + <property name="column_spacing">12</property> |
38 | + <child> |
39 | + <object class="GtkLabel" id="label_title"> |
40 | + <property name="visible">True</property> |
41 | + <property name="can_focus">False</property> |
42 | + <property name="hexpand">True</property> |
43 | + <property name="label" translatable="yes">To enable Livepatch choose an Ubuntu Single Sign-on account.</property> |
44 | + <property name="wrap">True</property> |
45 | + <property name="xalign">0</property> |
46 | + </object> |
47 | + <packing> |
48 | + <property name="left_attach">0</property> |
49 | + <property name="top_attach">0</property> |
50 | + </packing> |
51 | + </child> |
52 | + <child> |
53 | + <object class="GtkFrame" id="main_frame"> |
54 | + <property name="visible">True</property> |
55 | + <property name="can_focus">False</property> |
56 | + <property name="label_xalign">0</property> |
57 | + <child> |
58 | + <object class="GtkListBox" id="listbox_accounts"> |
59 | + <property name="visible">True</property> |
60 | + <property name="can_focus">False</property> |
61 | + <property name="selection_mode">none</property> |
62 | + <child> |
63 | + <object class="GtkListBoxRow" id="listboxrow_new_account"> |
64 | + <property name="visible">True</property> |
65 | + <property name="can_focus">False</property> |
66 | + <child> |
67 | + <object class="GtkLabel" id="label_new_account"> |
68 | + <property name="height_request">48</property> |
69 | + <property name="visible">True</property> |
70 | + <property name="can_focus">False</property> |
71 | + <property name="halign">center</property> |
72 | + <property name="valign">center</property> |
73 | + <property name="label" translatable="yes"><b>Use another account...</b></property> |
74 | + <property name="use_markup">True</property> |
75 | + <property name="justify">center</property> |
76 | + </object> |
77 | + </child> |
78 | + </object> |
79 | + </child> |
80 | + </object> |
81 | + </child> |
82 | + </object> |
83 | + <packing> |
84 | + <property name="left_attach">0</property> |
85 | + <property name="top_attach">1</property> |
86 | + <property name="width">2</property> |
87 | + </packing> |
88 | + </child> |
89 | + </object> |
90 | + <packing> |
91 | + <property name="expand">False</property> |
92 | + <property name="fill">True</property> |
93 | + <property name="position">1</property> |
94 | + </packing> |
95 | + </child> |
96 | + </object> |
97 | + </child> |
98 | + <child type="titlebar"> |
99 | + <object class="GtkHeaderBar"> |
100 | + <property name="visible">True</property> |
101 | + <property name="can_focus">False</property> |
102 | + <property name="title" translatable="yes">Choose an account</property> |
103 | + <child> |
104 | + <object class="GtkButton" id="button_cancel"> |
105 | + <property name="label">gtk-cancel</property> |
106 | + <property name="visible">True</property> |
107 | + <property name="can_focus">True</property> |
108 | + <property name="receives_default">True</property> |
109 | + <property name="use_stock">True</property> |
110 | + </object> |
111 | + </child> |
112 | + </object> |
113 | + </child> |
114 | + <action-widgets> |
115 | + <action-widget response="-6">button_cancel</action-widget> |
116 | + </action-widgets> |
117 | + </object> |
118 | +</interface> |
119 | |
120 | === added file 'data/gtkbuilder/dialog-livepatch-error.ui' |
121 | --- data/gtkbuilder/dialog-livepatch-error.ui 1970-01-01 00:00:00 +0000 |
122 | +++ data/gtkbuilder/dialog-livepatch-error.ui 2018-03-21 15:53:10 +0000 |
123 | @@ -0,0 +1,58 @@ |
124 | +<?xml version="1.0" encoding="UTF-8"?> |
125 | +<!-- Generated with glade 3.18.3 --> |
126 | +<interface> |
127 | + <requires lib="gtk+" version="3.12"/> |
128 | + <object class="GtkMessageDialog" id="messagedialog_livepatch"> |
129 | + <property name="can_focus">False</property> |
130 | + <property name="type_hint">dialog</property> |
131 | + <property name="message_type">error</property> |
132 | + <property name="text" translatable="yes">Sorry, there’s been a problem in setting up Canonical Livepatch.</property> |
133 | + <child internal-child="vbox"> |
134 | + <object class="GtkBox" id="messagedialog-vbox1"> |
135 | + <property name="can_focus">False</property> |
136 | + <property name="orientation">vertical</property> |
137 | + <property name="spacing">2</property> |
138 | + <child internal-child="action_area"> |
139 | + <object class="GtkButtonBox" id="messagedialog-action_area1"> |
140 | + <property name="can_focus">False</property> |
141 | + <property name="layout_style">end</property> |
142 | + <child> |
143 | + <object class="GtkButton" id="button_settings"> |
144 | + <property name="label" translatable="yes">Settings…</property> |
145 | + <property name="visible">True</property> |
146 | + <property name="can_focus">True</property> |
147 | + <property name="receives_default">True</property> |
148 | + <signal name="clicked" handler="on_button_settings_clicked" swapped="no"/> |
149 | + </object> |
150 | + <packing> |
151 | + <property name="expand">True</property> |
152 | + <property name="fill">True</property> |
153 | + <property name="position">0</property> |
154 | + </packing> |
155 | + </child> |
156 | + <child> |
157 | + <object class="GtkButton" id="button_ignore"> |
158 | + <property name="label" translatable="yes">Ignore</property> |
159 | + <property name="visible">True</property> |
160 | + <property name="can_focus">True</property> |
161 | + <property name="receives_default">True</property> |
162 | + <property name="yalign">0.51999998092651367</property> |
163 | + <signal name="clicked" handler="on_button_ignore_clicked" swapped="no"/> |
164 | + </object> |
165 | + <packing> |
166 | + <property name="expand">True</property> |
167 | + <property name="fill">True</property> |
168 | + <property name="position">1</property> |
169 | + </packing> |
170 | + </child> |
171 | + </object> |
172 | + <packing> |
173 | + <property name="expand">False</property> |
174 | + <property name="fill">False</property> |
175 | + <property name="position">0</property> |
176 | + </packing> |
177 | + </child> |
178 | + </object> |
179 | + </child> |
180 | + </object> |
181 | +</interface> |
182 | |
183 | === modified file 'data/gtkbuilder/main.ui' |
184 | --- data/gtkbuilder/main.ui 2016-08-17 09:34:22 +0000 |
185 | +++ data/gtkbuilder/main.ui 2018-03-21 15:53:10 +0000 |
186 | @@ -1,6 +1,7 @@ |
187 | <?xml version="1.0" encoding="UTF-8"?> |
188 | +<!-- Generated with glade 3.18.3 --> |
189 | <interface> |
190 | - <!-- interface-requires gtk+ 3.0 --> |
191 | + <requires lib="gtk+" version="3.0"/> |
192 | <object class="GtkListStore" id="model_normal_updates_display"> |
193 | <columns> |
194 | <!-- column-name text --> |
195 | @@ -160,7 +161,6 @@ |
196 | <property name="visible">True</property> |
197 | <property name="can_focus">True</property> |
198 | <property name="receives_default">False</property> |
199 | - <property name="use_action_appearance">False</property> |
200 | <property name="use_underline">True</property> |
201 | <property name="xalign">0</property> |
202 | <property name="draw_indicator">True</property> |
203 | @@ -396,7 +396,6 @@ |
204 | <property name="can_focus">True</property> |
205 | <property name="can_default">True</property> |
206 | <property name="receives_default">True</property> |
207 | - <property name="use_action_appearance">False</property> |
208 | <signal name="clicked" handler="on_add_clicked" swapped="no"/> |
209 | </object> |
210 | <packing> |
211 | @@ -413,7 +412,6 @@ |
212 | <property name="can_focus">True</property> |
213 | <property name="can_default">True</property> |
214 | <property name="receives_default">True</property> |
215 | - <property name="use_action_appearance">False</property> |
216 | <signal name="clicked" handler="on_edit_clicked" swapped="no"/> |
217 | </object> |
218 | <packing> |
219 | @@ -430,7 +428,6 @@ |
220 | <property name="can_focus">True</property> |
221 | <property name="can_default">True</property> |
222 | <property name="receives_default">True</property> |
223 | - <property name="use_action_appearance">False</property> |
224 | <property name="use_stock">True</property> |
225 | <signal name="clicked" handler="on_remove_clicked" swapped="no"/> |
226 | </object> |
227 | @@ -459,7 +456,6 @@ |
228 | <property name="visible">True</property> |
229 | <property name="can_focus">True</property> |
230 | <property name="receives_default">True</property> |
231 | - <property name="use_action_appearance">False</property> |
232 | <signal name="clicked" handler="on_button_add_cdrom_clicked" swapped="no"/> |
233 | </object> |
234 | <packing> |
235 | @@ -570,8 +566,8 @@ |
236 | <object class="GtkLabel" id="label3"> |
237 | <property name="visible">True</property> |
238 | <property name="can_focus">False</property> |
239 | - <property name="xalign">1</property> |
240 | <property name="label" translatable="yes">Automatically check for updates:</property> |
241 | + <property name="xalign">1</property> |
242 | </object> |
243 | <packing> |
244 | <property name="expand">False</property> |
245 | @@ -613,8 +609,8 @@ |
246 | <object class="GtkLabel" id="label4"> |
247 | <property name="visible">True</property> |
248 | <property name="can_focus">False</property> |
249 | - <property name="xalign">1</property> |
250 | <property name="label" translatable="yes">When there are security updates:</property> |
251 | + <property name="xalign">1</property> |
252 | </object> |
253 | <packing> |
254 | <property name="expand">False</property> |
255 | @@ -656,8 +652,8 @@ |
256 | <object class="GtkLabel" id="label5"> |
257 | <property name="visible">True</property> |
258 | <property name="can_focus">False</property> |
259 | - <property name="xalign">1</property> |
260 | <property name="label" translatable="yes">When there are other updates:</property> |
261 | + <property name="xalign">1</property> |
262 | </object> |
263 | <packing> |
264 | <property name="expand">False</property> |
265 | @@ -700,6 +696,84 @@ |
266 | </packing> |
267 | </child> |
268 | <child> |
269 | + <object class="GtkAlignment" id="alignment3"> |
270 | + <property name="visible">True</property> |
271 | + <property name="can_focus">False</property> |
272 | + <property name="left_padding">12</property> |
273 | + <child> |
274 | + <object class="GtkGrid" id="grid_livepatch"> |
275 | + <property name="visible">True</property> |
276 | + <property name="can_focus">False</property> |
277 | + <property name="halign">center</property> |
278 | + <property name="hexpand">False</property> |
279 | + <property name="vexpand">False</property> |
280 | + <property name="row_spacing">6</property> |
281 | + <property name="column_spacing">6</property> |
282 | + <child> |
283 | + <object class="GtkBox" id="hbox_livepatch"> |
284 | + <property name="visible">True</property> |
285 | + <property name="can_focus">False</property> |
286 | + <property name="halign">center</property> |
287 | + <property name="spacing">6</property> |
288 | + <child> |
289 | + <object class="GtkLabel" id="label_livepatch_login"> |
290 | + <property name="visible">True</property> |
291 | + <property name="can_focus">False</property> |
292 | + </object> |
293 | + <packing> |
294 | + <property name="expand">False</property> |
295 | + <property name="fill">True</property> |
296 | + <property name="position">0</property> |
297 | + </packing> |
298 | + </child> |
299 | + <child> |
300 | + <object class="GtkButton" id="button_ubuntuone"> |
301 | + <property name="visible">True</property> |
302 | + <property name="can_focus">True</property> |
303 | + <property name="receives_default">True</property> |
304 | + <property name="xalign">0</property> |
305 | + </object> |
306 | + <packing> |
307 | + <property name="expand">False</property> |
308 | + <property name="fill">True</property> |
309 | + <property name="position">2</property> |
310 | + </packing> |
311 | + </child> |
312 | + </object> |
313 | + <packing> |
314 | + <property name="left_attach">1</property> |
315 | + <property name="top_attach">1</property> |
316 | + </packing> |
317 | + </child> |
318 | + <child> |
319 | + <object class="GtkCheckButton" id="checkbutton_livepatch"> |
320 | + <property name="label" translatable="yes">Use Canonical Livepatch to increase security between restarts</property> |
321 | + <property name="use_action_appearance">False</property> |
322 | + <property name="visible">True</property> |
323 | + <property name="can_focus">True</property> |
324 | + <property name="receives_default">False</property> |
325 | + <property name="use_underline">True</property> |
326 | + <property name="xalign">0</property> |
327 | + <property name="draw_indicator">True</property> |
328 | + </object> |
329 | + <packing> |
330 | + <property name="left_attach">1</property> |
331 | + <property name="top_attach">0</property> |
332 | + </packing> |
333 | + </child> |
334 | + <child> |
335 | + <placeholder/> |
336 | + </child> |
337 | + </object> |
338 | + </child> |
339 | + </object> |
340 | + <packing> |
341 | + <property name="expand">True</property> |
342 | + <property name="fill">True</property> |
343 | + <property name="position">2</property> |
344 | + </packing> |
345 | + </child> |
346 | + <child> |
347 | <object class="GtkAlignment" id="alignment15"> |
348 | <property name="visible">True</property> |
349 | <property name="can_focus">False</property> |
350 | @@ -713,8 +787,8 @@ |
351 | <object class="GtkLabel" id="label29"> |
352 | <property name="visible">True</property> |
353 | <property name="can_focus">False</property> |
354 | + <property name="label" translatable="yes">Notify me of a new Ubuntu version:</property> |
355 | <property name="xalign">1</property> |
356 | - <property name="label" translatable="yes">Notify me of a new Ubuntu version:</property> |
357 | </object> |
358 | <packing> |
359 | <property name="expand">False</property> |
360 | @@ -746,7 +820,7 @@ |
361 | <packing> |
362 | <property name="expand">False</property> |
363 | <property name="fill">False</property> |
364 | - <property name="position">2</property> |
365 | + <property name="position">3</property> |
366 | </packing> |
367 | </child> |
368 | </object> |
369 | @@ -775,9 +849,9 @@ |
370 | <object class="GtkLabel" id="label27"> |
371 | <property name="visible">True</property> |
372 | <property name="can_focus">False</property> |
373 | - <property name="xalign">0</property> |
374 | <property name="label" translatable="yes"><b>Trusted software providers</b></property> |
375 | <property name="use_markup">True</property> |
376 | + <property name="xalign">0</property> |
377 | </object> |
378 | <packing> |
379 | <property name="expand">False</property> |
380 | @@ -851,7 +925,6 @@ |
381 | <property name="has_tooltip">True</property> |
382 | <property name="tooltip_markup" translatable="yes">Import the public key from a trusted software provider</property> |
383 | <property name="tooltip_text" translatable="yes">Import the public key from a trusted software provider</property> |
384 | - <property name="use_action_appearance">False</property> |
385 | <property name="use_underline">True</property> |
386 | <signal name="clicked" handler="add_key_clicked" swapped="no"/> |
387 | </object> |
388 | @@ -868,7 +941,6 @@ |
389 | <property name="visible">True</property> |
390 | <property name="can_focus">True</property> |
391 | <property name="receives_default">True</property> |
392 | - <property name="use_action_appearance">False</property> |
393 | <property name="use_stock">True</property> |
394 | <signal name="clicked" handler="remove_key_clicked" swapped="no"/> |
395 | </object> |
396 | @@ -900,7 +972,6 @@ |
397 | <property name="has_tooltip">True</property> |
398 | <property name="tooltip_markup" translatable="yes">Restore the default keys of your distribution</property> |
399 | <property name="tooltip_text" translatable="yes">Restore the default keys of your distribution</property> |
400 | - <property name="use_action_appearance">False</property> |
401 | <property name="use_underline">True</property> |
402 | <signal name="clicked" handler="on_restore_clicked" swapped="no"/> |
403 | </object> |
404 | @@ -1001,8 +1072,8 @@ |
405 | <property name="visible">True</property> |
406 | <property name="can_focus">False</property> |
407 | <property name="halign">start</property> |
408 | + <property name="label" translatable="yes">No proprietary drivers are in use.</property> |
409 | <property name="xalign">0</property> |
410 | - <property name="label" translatable="yes">No proprietary drivers are in use.</property> |
411 | </object> |
412 | <packing> |
413 | <property name="expand">True</property> |
414 | @@ -1024,11 +1095,11 @@ |
415 | <object class="GtkLabel" id="label_disc"> |
416 | <property name="visible">True</property> |
417 | <property name="can_focus">False</property> |
418 | - <property name="xalign">0</property> |
419 | <property name="label" translatable="yes"><small>A proprietary driver has private code that Ubuntu developers can't review or improve. Security and other updates are dependent on the driver vendor.</small></property> |
420 | <property name="use_markup">True</property> |
421 | <property name="wrap">True</property> |
422 | - <property name="max-width-chars">50</property> |
423 | + <property name="max_width_chars">50</property> |
424 | + <property name="xalign">0</property> |
425 | </object> |
426 | <packing> |
427 | <property name="expand">False</property> |
428 | @@ -1090,7 +1161,7 @@ |
429 | <property name="label" translatable="yes">Use proposed updates if you’re willing to report bugs on any problems that occur.</property> |
430 | <property name="use_markup">True</property> |
431 | <property name="wrap">True</property> |
432 | - <property name="max-width-chars">110</property> |
433 | + <property name="max_width_chars">110</property> |
434 | </object> |
435 | </child> |
436 | </object> |
437 | @@ -1138,7 +1209,6 @@ |
438 | <property name="can_focus">True</property> |
439 | <property name="can_default">True</property> |
440 | <property name="receives_default">True</property> |
441 | - <property name="use_action_appearance">False</property> |
442 | <property name="use_underline">True</property> |
443 | <signal name="clicked" handler="on_button_revert_clicked" swapped="no"/> |
444 | </object> |
445 | @@ -1157,7 +1227,6 @@ |
446 | <property name="can_focus">True</property> |
447 | <property name="can_default">True</property> |
448 | <property name="receives_default">True</property> |
449 | - <property name="use_action_appearance">False</property> |
450 | <property name="use_stock">True</property> |
451 | <signal name="clicked" handler="on_close_button" swapped="no"/> |
452 | </object> |
453 | |
454 | === modified file 'debian/changelog' |
455 | --- debian/changelog 2018-03-06 16:06:38 +0000 |
456 | +++ debian/changelog 2018-03-21 15:53:10 +0000 |
457 | @@ -1,3 +1,17 @@ |
458 | +software-properties (0.96.24.25) UNRELEASED; urgency=medium |
459 | + |
460 | + * DialogAuth.py: Implement a dialog to choose between an ubuntu sso account or |
461 | + login into a new one. This interacts with gnome-online-accounts (LP: 1756364) |
462 | + * DialogLivepatchError: Implement a dialog to show livepatch related errors. |
463 | + * GoaAuth.py: Implement an utility function to store manage livepatch credentials. |
464 | + * SoftwareProperties.py: Implement functions used by the dbus API to |
465 | + enable/disable livepatch. |
466 | + * SoftwarePropertiesDbus.py: Add SetLivepatchEnabled to the dbus API. |
467 | + * SoftwarePropertiesGtk.py: Add a livepatch switch. |
468 | + * debian/control: Depends on gir1.2-goa-1.0, gir1.2-snapd-1 and gir1.2-secret-1. |
469 | + |
470 | + -- Andrea Azzarone <andrea.azzarone@canonical.com> Wed, 14 Mar 2018 20:24:31 +0100 |
471 | + |
472 | software-properties (0.96.24.23) bionic; urgency=medium |
473 | |
474 | * SoftwarePropertiesGtk.py: After installing proprietary drivers provide the |
475 | |
476 | === modified file 'debian/control' |
477 | --- debian/control 2018-03-06 15:47:27 +0000 |
478 | +++ debian/control 2018-03-21 15:53:10 +0000 |
479 | @@ -41,8 +41,9 @@ |
480 | Package: software-properties-common |
481 | Architecture: all |
482 | Depends: ${python3:Depends}, ${misc:Depends}, python3, |
483 | - python3-gi, gir1.2-glib-2.0, python-apt-common (>= 0.9), python3-dbus, |
484 | - python3-software-properties (= ${binary:Version}), ca-certificates |
485 | + python3-gi, gir1.2-glib-2.0, gir1.2-goa-1.0 (>= 3.27.92-1ubuntu1), gir1.2-secret-1, gir1.2-snapd-1, |
486 | + python-apt-common (>= 0.9), python3-dbus, python3-software-properties (= ${binary:Version}), |
487 | + ca-certificates |
488 | Breaks: python-software-properties (<< 0.85), python3-software-properties (<< 0.85) |
489 | Replaces: python-software-properties (<< 0.85), python3-software-properties (<< 0.85) |
490 | Description: manage the repositories that you install software from (common) |
491 | @@ -60,6 +61,7 @@ |
492 | python3-gi, |
493 | gir1.2-gtk-3.0, |
494 | python3-aptdaemon.gtk3widgets, |
495 | + python3-distro-info, |
496 | software-properties-common, |
497 | ubuntu-drivers-common (>= 1:0.2.75), |
498 | python3-gi, |
499 | |
500 | === modified file 'po/POTFILES.in' |
501 | --- po/POTFILES.in 2014-04-04 06:52:18 +0000 |
502 | +++ po/POTFILES.in 2018-03-21 15:53:10 +0000 |
503 | @@ -17,6 +17,7 @@ |
504 | softwareproperties/kde/DialogEdit.py |
505 | softwareproperties/__init__.py |
506 | softwareproperties/SoftwareProperties.py |
507 | +softwareproperties/gtk/DialogAuth.py |
508 | softwareproperties/gtk/DialogMirror.py |
509 | softwareproperties/gtk/CdromProgress.py |
510 | softwareproperties/gtk/SoftwarePropertiesGtk.py |
511 | @@ -38,4 +39,4 @@ |
512 | [type: gettext/glade]data/gtkbuilder/dialog-cache-outofdate.ui |
513 | [type: gettext/glade]data/gtkbuilder/dialog-mirror.ui |
514 | [type: gettext/glade]data/gtkbuilder/dialog-add.ui |
515 | - |
516 | +[type: gettext/glade]data/gtkbuilder/dialog-auth.ui |
517 | |
518 | === modified file 'po/software-properties.pot' |
519 | --- po/software-properties.pot 2016-09-09 07:14:08 +0000 |
520 | +++ po/software-properties.pot 2018-03-21 15:53:10 +0000 |
521 | @@ -8,7 +8,7 @@ |
522 | msgstr "" |
523 | "Project-Id-Version: PACKAGE VERSION\n" |
524 | "Report-Msgid-Bugs-To: Sebastian Heinlein <sebi@glatzor.de>\n" |
525 | -"POT-Creation-Date: 2016-09-09 03:13-0400\n" |
526 | +"POT-Creation-Date: 2018-03-21 15:05+0100\n" |
527 | "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" |
528 | "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" |
529 | "Language-Team: LANGUAGE <LL@li.org>\n" |
530 | @@ -41,8 +41,8 @@ |
531 | msgstr "" |
532 | |
533 | #: ../data/software-properties-kde.desktop.in.h:1 |
534 | -#: ../softwareproperties/gtk/SoftwarePropertiesGtk.py:674 |
535 | -#: ../softwareproperties/gtk/SoftwarePropertiesGtk.py:693 |
536 | +#: ../softwareproperties/gtk/SoftwarePropertiesGtk.py:685 |
537 | +#: ../softwareproperties/gtk/SoftwarePropertiesGtk.py:704 |
538 | msgid "Software Sources" |
539 | msgstr "" |
540 | |
541 | @@ -104,60 +104,64 @@ |
542 | msgstr "" |
543 | |
544 | #: ../add-apt-repository:74 |
545 | -msgid "Update package cache after adding" |
546 | -msgstr "" |
547 | - |
548 | -#: ../add-apt-repository:78 |
549 | +msgid "Do not update package cache after adding" |
550 | +msgstr "" |
551 | + |
552 | +#: ../add-apt-repository:77 |
553 | +msgid "Update package cache after adding (legacy option)" |
554 | +msgstr "" |
555 | + |
556 | +#: ../add-apt-repository:90 |
557 | msgid "Error: must run as root" |
558 | msgstr "" |
559 | |
560 | -#: ../add-apt-repository:82 |
561 | +#: ../add-apt-repository:94 |
562 | msgid "Error: need a repository as argument" |
563 | msgstr "" |
564 | |
565 | -#: ../add-apt-repository:85 |
566 | +#: ../add-apt-repository:97 |
567 | msgid "Error: need a single repository as argument" |
568 | msgstr "" |
569 | |
570 | -#: ../add-apt-repository:105 |
571 | +#: ../add-apt-repository:117 |
572 | #, c-format |
573 | msgid "'%s' distribution component disabled for all sources." |
574 | msgstr "" |
575 | |
576 | -#: ../add-apt-repository:107 |
577 | +#: ../add-apt-repository:119 |
578 | #, c-format |
579 | msgid "'%s' distribution component is already disabled for all sources." |
580 | msgstr "" |
581 | |
582 | -#: ../add-apt-repository:112 |
583 | +#: ../add-apt-repository:124 |
584 | #, c-format |
585 | msgid "'%s' distribution component enabled for all sources." |
586 | msgstr "" |
587 | |
588 | -#: ../add-apt-repository:114 |
589 | +#: ../add-apt-repository:126 |
590 | #, c-format |
591 | msgid "'%s' distribution component is already enabled for all sources." |
592 | msgstr "" |
593 | |
594 | -#: ../add-apt-repository:136 |
595 | +#: ../add-apt-repository:150 |
596 | #, c-format |
597 | msgid " More info: %s" |
598 | msgstr "" |
599 | |
600 | -#: ../add-apt-repository:140 |
601 | -msgid "Press [ENTER] to continue or ctrl-c to cancel removing it" |
602 | -msgstr "" |
603 | - |
604 | -#: ../add-apt-repository:142 |
605 | -msgid "Press [ENTER] to continue or ctrl-c to cancel adding it" |
606 | -msgstr "" |
607 | - |
608 | -#: ../add-apt-repository:160 ../add-apt-repository:164 |
609 | +#: ../add-apt-repository:154 |
610 | +msgid "Press [ENTER] to continue or Ctrl-c to cancel removing it." |
611 | +msgstr "" |
612 | + |
613 | +#: ../add-apt-repository:156 |
614 | +msgid "Press [ENTER] to continue or Ctrl-c to cancel adding it." |
615 | +msgstr "" |
616 | + |
617 | +#: ../add-apt-repository:178 ../add-apt-repository:182 |
618 | #, c-format |
619 | msgid "Error: '%s' doesn't exist in a sourcelist file" |
620 | msgstr "" |
621 | |
622 | -#: ../add-apt-repository:169 |
623 | +#: ../add-apt-repository:187 |
624 | #, c-format |
625 | msgid "Error: '%s' invalid" |
626 | msgstr "" |
627 | @@ -211,6 +215,7 @@ |
628 | |
629 | #: ../softwareproperties/kde/DialogMirror.py:220 |
630 | #: ../softwareproperties/gtk/DialogMirror.py:338 |
631 | +#: ../softwareproperties/gtk/SoftwarePropertiesGtk.py:1536 |
632 | msgid "Please check your Internet connection." |
633 | msgstr "" |
634 | |
635 | @@ -240,7 +245,7 @@ |
636 | msgstr "" |
637 | |
638 | #: ../softwareproperties/kde/SoftwarePropertiesKDE.py:172 |
639 | -#: ../softwareproperties/gtk/SoftwarePropertiesGtk.py:247 |
640 | +#: ../softwareproperties/gtk/SoftwarePropertiesGtk.py:258 |
641 | #, python-format |
642 | msgid "Every %s days" |
643 | msgstr "" |
644 | @@ -253,7 +258,7 @@ |
645 | |
646 | #. TRANS: %s stands for the distribution name e.g. Debian or Ubuntu |
647 | #: ../softwareproperties/kde/SoftwarePropertiesKDE.py:218 |
648 | -#: ../softwareproperties/gtk/SoftwarePropertiesGtk.py:307 |
649 | +#: ../softwareproperties/gtk/SoftwarePropertiesGtk.py:318 |
650 | #, python-format |
651 | msgid "%s Software" |
652 | msgstr "" |
653 | @@ -262,7 +267,7 @@ |
654 | #. first %s is the description of the component |
655 | #. second %s is the code name of the comp, eg main, universe |
656 | #: ../softwareproperties/kde/SoftwarePropertiesKDE.py:237 |
657 | -#: ../softwareproperties/gtk/SoftwarePropertiesGtk.py:320 |
658 | +#: ../softwareproperties/gtk/SoftwarePropertiesGtk.py:331 |
659 | #, python-format |
660 | msgid "%s (%s)" |
661 | msgstr "" |
662 | @@ -270,33 +275,33 @@ |
663 | #. add a separator and the option to choose another mirror from the list |
664 | #. #FIXME server_store.append(["sep", None, True]) |
665 | #: ../softwareproperties/kde/SoftwarePropertiesKDE.py:300 |
666 | -#: ../softwareproperties/gtk/SoftwarePropertiesGtk.py:450 |
667 | -#: ../softwareproperties/gtk/SoftwarePropertiesGtk.py:543 |
668 | +#: ../softwareproperties/gtk/SoftwarePropertiesGtk.py:461 |
669 | +#: ../softwareproperties/gtk/SoftwarePropertiesGtk.py:554 |
670 | msgid "Other..." |
671 | msgstr "" |
672 | |
673 | #: ../softwareproperties/kde/SoftwarePropertiesKDE.py:668 |
674 | -#: ../softwareproperties/gtk/SoftwarePropertiesGtk.py:966 |
675 | +#: ../softwareproperties/gtk/SoftwarePropertiesGtk.py:977 |
676 | msgid "Import key" |
677 | msgstr "" |
678 | |
679 | #: ../softwareproperties/kde/SoftwarePropertiesKDE.py:671 |
680 | -#: ../softwareproperties/gtk/SoftwarePropertiesGtk.py:980 |
681 | +#: ../softwareproperties/gtk/SoftwarePropertiesGtk.py:991 |
682 | msgid "Error importing selected file" |
683 | msgstr "" |
684 | |
685 | #: ../softwareproperties/kde/SoftwarePropertiesKDE.py:672 |
686 | -#: ../softwareproperties/gtk/SoftwarePropertiesGtk.py:981 |
687 | +#: ../softwareproperties/gtk/SoftwarePropertiesGtk.py:992 |
688 | msgid "The selected file may not be a GPG key file or it might be corrupt." |
689 | msgstr "" |
690 | |
691 | #: ../softwareproperties/kde/SoftwarePropertiesKDE.py:685 |
692 | -#: ../softwareproperties/gtk/SoftwarePropertiesGtk.py:997 |
693 | +#: ../softwareproperties/gtk/SoftwarePropertiesGtk.py:1008 |
694 | msgid "Error removing the key" |
695 | msgstr "" |
696 | |
697 | #: ../softwareproperties/kde/SoftwarePropertiesKDE.py:686 |
698 | -#: ../softwareproperties/gtk/SoftwarePropertiesGtk.py:998 |
699 | +#: ../softwareproperties/gtk/SoftwarePropertiesGtk.py:1009 |
700 | msgid "The key you selected could not be removed. Please report this as a bug." |
701 | msgstr "" |
702 | |
703 | @@ -317,7 +322,7 @@ |
704 | msgstr "" |
705 | |
706 | #: ../softwareproperties/kde/SoftwarePropertiesKDE.py:731 |
707 | -#: ../softwareproperties/gtk/SoftwarePropertiesGtk.py:832 |
708 | +#: ../softwareproperties/gtk/SoftwarePropertiesGtk.py:843 |
709 | msgid "Error scanning the CD" |
710 | msgstr "" |
711 | |
712 | @@ -359,15 +364,49 @@ |
713 | msgid "Source code" |
714 | msgstr "" |
715 | |
716 | -#: ../softwareproperties/SoftwareProperties.py:502 |
717 | -#: ../softwareproperties/SoftwareProperties.py:509 |
718 | +#: ../softwareproperties/SoftwareProperties.py:521 |
719 | +#: ../softwareproperties/SoftwareProperties.py:528 |
720 | msgid "(Source Code)" |
721 | msgstr "" |
722 | |
723 | -#: ../softwareproperties/SoftwareProperties.py:515 |
724 | +#: ../softwareproperties/SoftwareProperties.py:534 |
725 | msgid "Source Code" |
726 | msgstr "" |
727 | |
728 | +#: ../softwareproperties/SoftwareProperties.py:935 |
729 | +#: ../softwareproperties/SoftwareProperties.py:983 |
730 | +msgid "Canonical Livepatch snap cannot be installed." |
731 | +msgstr "" |
732 | + |
733 | +#: ../softwareproperties/SoftwareProperties.py:972 |
734 | +msgid "Canonical Livepatch snap cannot be enabled." |
735 | +msgstr "" |
736 | + |
737 | +#: ../softwareproperties/SoftwareProperties.py:986 |
738 | +msgid "Canonical Livepatch cannot be enabled." |
739 | +msgstr "" |
740 | + |
741 | +#: ../softwareproperties/SoftwareProperties.py:1001 |
742 | +msgid "Canonical Livepatch cannot be disabled." |
743 | +msgstr "" |
744 | + |
745 | +#: ../softwareproperties/gtk/DialogAuth.py:73 |
746 | +msgid "To continue choose an Ubuntu Single Sign-On account." |
747 | +msgstr "" |
748 | + |
749 | +#: ../softwareproperties/gtk/DialogAuth.py:74 |
750 | +msgid "Use another account…" |
751 | +msgstr "" |
752 | + |
753 | +#: ../softwareproperties/gtk/DialogAuth.py:76 |
754 | +msgid "To continue you need an Ubuntu Single Sign-On account." |
755 | +msgstr "" |
756 | + |
757 | +#: ../softwareproperties/gtk/DialogAuth.py:77 |
758 | +#: ../softwareproperties/gtk/SoftwarePropertiesGtk.py:1514 |
759 | +msgid "Sign In…" |
760 | +msgstr "" |
761 | + |
762 | #: ../softwareproperties/gtk/DialogMirror.py:250 |
763 | msgid "New mirror" |
764 | msgstr "" |
765 | @@ -377,137 +416,159 @@ |
766 | msgid "Completed %s of %s tests" |
767 | msgstr "" |
768 | |
769 | -#: ../softwareproperties/gtk/SoftwarePropertiesGtk.py:684 |
770 | -#: ../softwareproperties/gtk/SoftwarePropertiesGtk.py:703 |
771 | +#: ../softwareproperties/gtk/SoftwarePropertiesGtk.py:695 |
772 | +#: ../softwareproperties/gtk/SoftwarePropertiesGtk.py:714 |
773 | msgid "Active" |
774 | msgstr "" |
775 | |
776 | -#: ../softwareproperties/gtk/SoftwarePropertiesGtk.py:742 |
777 | +#: ../softwareproperties/gtk/SoftwarePropertiesGtk.py:753 |
778 | msgid "Key" |
779 | msgstr "" |
780 | |
781 | -#: ../softwareproperties/gtk/SoftwarePropertiesGtk.py:759 |
782 | +#: ../softwareproperties/gtk/SoftwarePropertiesGtk.py:770 |
783 | msgid "_Add key from paste data" |
784 | msgstr "" |
785 | |
786 | -#: ../softwareproperties/gtk/SoftwarePropertiesGtk.py:772 |
787 | #: ../softwareproperties/gtk/SoftwarePropertiesGtk.py:783 |
788 | +#: ../softwareproperties/gtk/SoftwarePropertiesGtk.py:794 |
789 | msgid "Error importing key" |
790 | msgstr "" |
791 | |
792 | -#: ../softwareproperties/gtk/SoftwarePropertiesGtk.py:773 |
793 | #: ../softwareproperties/gtk/SoftwarePropertiesGtk.py:784 |
794 | +#: ../softwareproperties/gtk/SoftwarePropertiesGtk.py:795 |
795 | msgid "The selected data may not be a GPG key file or it might be corrupt." |
796 | msgstr "" |
797 | |
798 | -#: ../softwareproperties/gtk/SoftwarePropertiesGtk.py:833 |
799 | +#: ../softwareproperties/gtk/SoftwarePropertiesGtk.py:844 |
800 | msgid "Could not find a suitable CD." |
801 | msgstr "" |
802 | |
803 | -#: ../softwareproperties/gtk/SoftwarePropertiesGtk.py:1043 |
804 | +#: ../softwareproperties/gtk/SoftwarePropertiesGtk.py:1059 |
805 | msgid "Applying changes..." |
806 | msgstr "" |
807 | |
808 | -#: ../softwareproperties/gtk/SoftwarePropertiesGtk.py:1124 |
809 | -#: ../data/gtkbuilder/main.ui.h:42 |
810 | +#: ../softwareproperties/gtk/SoftwarePropertiesGtk.py:1158 |
811 | +#: ../data/gtkbuilder/main.ui.h:43 |
812 | msgid "Re_vert" |
813 | msgstr "" |
814 | |
815 | -#: ../softwareproperties/gtk/SoftwarePropertiesGtk.py:1126 |
816 | +#: ../softwareproperties/gtk/SoftwarePropertiesGtk.py:1160 |
817 | msgid "_Apply Changes" |
818 | msgstr "" |
819 | |
820 | -#: ../softwareproperties/gtk/SoftwarePropertiesGtk.py:1128 |
821 | +#: ../softwareproperties/gtk/SoftwarePropertiesGtk.py:1162 |
822 | msgid "_Cancel" |
823 | msgstr "" |
824 | |
825 | -#: ../softwareproperties/gtk/SoftwarePropertiesGtk.py:1130 |
826 | +#: ../softwareproperties/gtk/SoftwarePropertiesGtk.py:1164 |
827 | msgid "_Restart..." |
828 | msgstr "" |
829 | |
830 | -#: ../softwareproperties/gtk/SoftwarePropertiesGtk.py:1145 |
831 | +#: ../softwareproperties/gtk/SoftwarePropertiesGtk.py:1179 |
832 | msgid "Searching for available drivers..." |
833 | msgstr "" |
834 | |
835 | -#: ../softwareproperties/gtk/SoftwarePropertiesGtk.py:1175 |
836 | +#: ../softwareproperties/gtk/SoftwarePropertiesGtk.py:1209 |
837 | msgid "An error occurred while searching for drivers." |
838 | msgstr "" |
839 | |
840 | -#: ../softwareproperties/gtk/SoftwarePropertiesGtk.py:1249 |
841 | +#: ../softwareproperties/gtk/SoftwarePropertiesGtk.py:1283 |
842 | msgid "This device is using the recommended driver." |
843 | msgstr "" |
844 | |
845 | -#: ../softwareproperties/gtk/SoftwarePropertiesGtk.py:1250 |
846 | +#: ../softwareproperties/gtk/SoftwarePropertiesGtk.py:1284 |
847 | msgid "This device is using an alternative driver." |
848 | msgstr "" |
849 | |
850 | -#: ../softwareproperties/gtk/SoftwarePropertiesGtk.py:1251 |
851 | +#: ../softwareproperties/gtk/SoftwarePropertiesGtk.py:1285 |
852 | msgid "This device is using a manually-installed driver." |
853 | msgstr "" |
854 | |
855 | -#: ../softwareproperties/gtk/SoftwarePropertiesGtk.py:1252 |
856 | +#: ../softwareproperties/gtk/SoftwarePropertiesGtk.py:1286 |
857 | msgid "This device is not working." |
858 | msgstr "" |
859 | |
860 | -#: ../softwareproperties/gtk/SoftwarePropertiesGtk.py:1261 |
861 | +#: ../softwareproperties/gtk/SoftwarePropertiesGtk.py:1295 |
862 | msgid "Continue using a manually installed driver" |
863 | msgstr "" |
864 | |
865 | -#: ../softwareproperties/gtk/SoftwarePropertiesGtk.py:1288 |
866 | +#: ../softwareproperties/gtk/SoftwarePropertiesGtk.py:1322 |
867 | msgid "Using {} from {}" |
868 | msgstr "" |
869 | |
870 | -#: ../softwareproperties/gtk/SoftwarePropertiesGtk.py:1290 |
871 | +#: ../softwareproperties/gtk/SoftwarePropertiesGtk.py:1324 |
872 | msgid "Using {}" |
873 | msgstr "" |
874 | |
875 | -#: ../softwareproperties/gtk/SoftwarePropertiesGtk.py:1297 |
876 | +#: ../softwareproperties/gtk/SoftwarePropertiesGtk.py:1331 |
877 | msgid "open source" |
878 | msgstr "" |
879 | |
880 | -#: ../softwareproperties/gtk/SoftwarePropertiesGtk.py:1299 |
881 | +#: ../softwareproperties/gtk/SoftwarePropertiesGtk.py:1333 |
882 | msgid "proprietary" |
883 | msgstr "" |
884 | |
885 | -#: ../softwareproperties/gtk/SoftwarePropertiesGtk.py:1302 |
886 | +#: ../softwareproperties/gtk/SoftwarePropertiesGtk.py:1336 |
887 | #, python-brace-format |
888 | msgid "{base_description} ({licence}, tested)" |
889 | msgstr "" |
890 | |
891 | -#: ../softwareproperties/gtk/SoftwarePropertiesGtk.py:1304 |
892 | +#: ../softwareproperties/gtk/SoftwarePropertiesGtk.py:1338 |
893 | #, python-brace-format |
894 | msgid "{base_description} ({licence})" |
895 | msgstr "" |
896 | |
897 | -#: ../softwareproperties/gtk/SoftwarePropertiesGtk.py:1324 |
898 | +#: ../softwareproperties/gtk/SoftwarePropertiesGtk.py:1358 |
899 | msgid "Do not use the device" |
900 | msgstr "" |
901 | |
902 | #. No drivers found. |
903 | -#: ../softwareproperties/gtk/SoftwarePropertiesGtk.py:1344 |
904 | +#: ../softwareproperties/gtk/SoftwarePropertiesGtk.py:1378 |
905 | msgid "No additional drivers available." |
906 | msgstr "" |
907 | |
908 | -#: ../softwareproperties/gtk/SoftwarePropertiesGtk.py:1362 |
909 | +#: ../softwareproperties/gtk/SoftwarePropertiesGtk.py:1396 |
910 | msgid "Unknown" |
911 | msgstr "" |
912 | |
913 | -#: ../softwareproperties/gtk/SoftwarePropertiesGtk.py:1411 |
914 | +#: ../softwareproperties/gtk/SoftwarePropertiesGtk.py:1445 |
915 | msgid "You need to restart the computer to complete the driver changes." |
916 | msgstr "" |
917 | |
918 | -#: ../softwareproperties/gtk/SoftwarePropertiesGtk.py:1425 |
919 | +#: ../softwareproperties/gtk/SoftwarePropertiesGtk.py:1459 |
920 | #, python-format |
921 | msgid "%(count)d proprietary driver in use." |
922 | msgid_plural "%(count)d proprietary drivers in use." |
923 | msgstr[0] "" |
924 | msgstr[1] "" |
925 | |
926 | -#: ../softwareproperties/gtk/SoftwarePropertiesGtk.py:1430 |
927 | -#: ../data/gtkbuilder/main.ui.h:37 |
928 | +#: ../softwareproperties/gtk/SoftwarePropertiesGtk.py:1464 |
929 | +#: ../data/gtkbuilder/main.ui.h:38 |
930 | msgid "No proprietary drivers are in use." |
931 | msgstr "" |
932 | |
933 | +#: ../softwareproperties/gtk/SoftwarePropertiesGtk.py:1502 |
934 | +msgid "Sign Out" |
935 | +msgstr "" |
936 | + |
937 | +#: ../softwareproperties/gtk/SoftwarePropertiesGtk.py:1506 |
938 | +#, python-format |
939 | +msgid "Signed in as %s" |
940 | +msgstr "" |
941 | + |
942 | +#: ../softwareproperties/gtk/SoftwarePropertiesGtk.py:1509 |
943 | +#, python-format |
944 | +msgid "%s isn't authorized to use Livepatch." |
945 | +msgstr "" |
946 | + |
947 | +#: ../softwareproperties/gtk/SoftwarePropertiesGtk.py:1515 |
948 | +msgid "To use Livepatch you need to sign in." |
949 | +msgstr "" |
950 | + |
951 | +#: ../softwareproperties/gtk/SoftwarePropertiesGtk.py:1535 |
952 | +msgid "Error enabling Canonical Livepatch" |
953 | +msgstr "" |
954 | + |
955 | #: ../softwareproperties/gtk/DialogAddSourcesList.py:46 |
956 | msgid "Add Software Channels" |
957 | msgstr "" |
958 | @@ -542,23 +603,23 @@ |
959 | msgstr "" |
960 | |
961 | #. some known keys |
962 | -#: ../softwareproperties/AptAuth.py:39 |
963 | +#: ../softwareproperties/AptAuth.py:40 |
964 | msgid "Ubuntu Archive Automatic Signing Key <ftpmaster@ubuntu.com>" |
965 | msgstr "" |
966 | |
967 | -#: ../softwareproperties/AptAuth.py:40 |
968 | +#: ../softwareproperties/AptAuth.py:41 |
969 | msgid "Ubuntu CD Image Automatic Signing Key <cdimage@ubuntu.com>" |
970 | msgstr "" |
971 | |
972 | -#: ../softwareproperties/AptAuth.py:41 |
973 | +#: ../softwareproperties/AptAuth.py:42 |
974 | msgid "Ubuntu Archive Automatic Signing Key (2012) <ftpmaster@ubuntu.com>" |
975 | msgstr "" |
976 | |
977 | -#: ../softwareproperties/AptAuth.py:42 |
978 | +#: ../softwareproperties/AptAuth.py:43 |
979 | msgid "Ubuntu CD Image Automatic Signing Key (2012) <cdimage@ubuntu.com>" |
980 | msgstr "" |
981 | |
982 | -#: ../softwareproperties/AptAuth.py:43 |
983 | +#: ../softwareproperties/AptAuth.py:44 |
984 | msgid "Ubuntu Extras Archive Automatic Signing Key <ftpmaster@ubuntu.com>" |
985 | msgstr "" |
986 | |
987 | @@ -679,65 +740,69 @@ |
988 | msgstr "" |
989 | |
990 | #: ../data/gtkbuilder/main.ui.h:27 |
991 | +msgid "Use Canonical Livepatch to increase security between restarts" |
992 | +msgstr "" |
993 | + |
994 | +#: ../data/gtkbuilder/main.ui.h:28 |
995 | msgid "Notify me of a new Ubuntu version:" |
996 | msgstr "" |
997 | |
998 | -#: ../data/gtkbuilder/main.ui.h:28 |
999 | +#: ../data/gtkbuilder/main.ui.h:29 |
1000 | msgid "Updates" |
1001 | msgstr "" |
1002 | |
1003 | -#: ../data/gtkbuilder/main.ui.h:29 |
1004 | +#: ../data/gtkbuilder/main.ui.h:30 |
1005 | msgid "<b>Trusted software providers</b>" |
1006 | msgstr "" |
1007 | |
1008 | -#: ../data/gtkbuilder/main.ui.h:30 |
1009 | +#: ../data/gtkbuilder/main.ui.h:31 |
1010 | msgid " " |
1011 | msgstr "" |
1012 | |
1013 | -#: ../data/gtkbuilder/main.ui.h:31 |
1014 | +#: ../data/gtkbuilder/main.ui.h:32 |
1015 | msgid "" |
1016 | "Keys are used to authenticate the correct source of software and so protect " |
1017 | "your computer from malicious software" |
1018 | msgstr "" |
1019 | |
1020 | -#: ../data/gtkbuilder/main.ui.h:32 |
1021 | +#: ../data/gtkbuilder/main.ui.h:33 |
1022 | msgid "_Import Key File..." |
1023 | msgstr "" |
1024 | |
1025 | -#: ../data/gtkbuilder/main.ui.h:33 |
1026 | +#: ../data/gtkbuilder/main.ui.h:34 |
1027 | msgid "Import the public key from a trusted software provider" |
1028 | msgstr "" |
1029 | |
1030 | -#: ../data/gtkbuilder/main.ui.h:34 |
1031 | +#: ../data/gtkbuilder/main.ui.h:35 |
1032 | msgid "Restore _Defaults" |
1033 | msgstr "" |
1034 | |
1035 | -#: ../data/gtkbuilder/main.ui.h:35 |
1036 | +#: ../data/gtkbuilder/main.ui.h:36 |
1037 | msgid "Restore the default keys of your distribution" |
1038 | msgstr "" |
1039 | |
1040 | -#: ../data/gtkbuilder/main.ui.h:36 |
1041 | +#: ../data/gtkbuilder/main.ui.h:37 |
1042 | msgid "Authentication" |
1043 | msgstr "" |
1044 | |
1045 | -#: ../data/gtkbuilder/main.ui.h:38 |
1046 | +#: ../data/gtkbuilder/main.ui.h:39 |
1047 | msgid "" |
1048 | "<small>A proprietary driver has private code that Ubuntu developers can't " |
1049 | "review or improve. Security and other updates are dependent on the driver " |
1050 | "vendor.</small>" |
1051 | msgstr "" |
1052 | |
1053 | -#: ../data/gtkbuilder/main.ui.h:39 |
1054 | +#: ../data/gtkbuilder/main.ui.h:40 |
1055 | msgid "Additional Drivers" |
1056 | msgstr "" |
1057 | |
1058 | -#: ../data/gtkbuilder/main.ui.h:40 |
1059 | +#: ../data/gtkbuilder/main.ui.h:41 |
1060 | msgid "" |
1061 | "Use proposed updates if you’re willing to report bugs on any problems that " |
1062 | "occur." |
1063 | msgstr "" |
1064 | |
1065 | -#: ../data/gtkbuilder/main.ui.h:41 |
1066 | +#: ../data/gtkbuilder/main.ui.h:42 |
1067 | msgid "Developer Options" |
1068 | msgstr "" |
1069 | |
1070 | @@ -801,3 +866,15 @@ |
1071 | #: ../data/gtkbuilder/dialog-add.ui.h:3 |
1072 | msgid "_Add Source" |
1073 | msgstr "" |
1074 | + |
1075 | +#: ../data/gtkbuilder/dialog-auth.ui.h:1 |
1076 | +msgid "To enable Livepatch choose an Ubuntu Single Sign-on account." |
1077 | +msgstr "" |
1078 | + |
1079 | +#: ../data/gtkbuilder/dialog-auth.ui.h:2 |
1080 | +msgid "<b>Use another account...</b>" |
1081 | +msgstr "" |
1082 | + |
1083 | +#: ../data/gtkbuilder/dialog-auth.ui.h:3 |
1084 | +msgid "Choose an account" |
1085 | +msgstr "" |
1086 | |
1087 | === added file 'softwareproperties/GoaAuth.py' |
1088 | --- softwareproperties/GoaAuth.py 1970-01-01 00:00:00 +0000 |
1089 | +++ softwareproperties/GoaAuth.py 2018-03-21 15:53:10 +0000 |
1090 | @@ -0,0 +1,113 @@ |
1091 | +# |
1092 | +# Copyright (c) 2018 Canonical |
1093 | +# |
1094 | +# Authors: |
1095 | +# Andrea Azzarone <andrea.azzarone@canonical.com> |
1096 | +# |
1097 | +# This program is free software; you can redistribute it and/or |
1098 | +# modify it under the terms of the GNU General Public License as |
1099 | +# published by the Free Software Foundation; either version 2 of the |
1100 | +# License, or (at your option) any later version. |
1101 | +# |
1102 | +# This program is distributed in the hope that it will be useful, |
1103 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
1104 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1105 | +# GNU General Public License for more details. |
1106 | +# |
1107 | +# You should have received a copy of the GNU General Public License |
1108 | +# along with this program; if not, write to the Free Software |
1109 | +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 |
1110 | +# USA |
1111 | + |
1112 | +import gi |
1113 | +gi.require_version('Goa', '1.0') |
1114 | +gi.require_version('Secret', '1') |
1115 | +from gi.repository import Goa, GObject, Secret |
1116 | + |
1117 | +SECRETS_SCHEMA = Secret.Schema.new('com.ubuntu.SotwareProperties', |
1118 | + Secret.SchemaFlags.NONE, |
1119 | + {'key': Secret.SchemaAttributeType.STRING}) |
1120 | + |
1121 | +class GoaAuth(GObject.GObject): |
1122 | + |
1123 | + # Properties |
1124 | + logged = GObject.Property(type=bool, default=False) |
1125 | + |
1126 | + def __init__(self): |
1127 | + GObject.GObject.__init__(self) |
1128 | + |
1129 | + self.goa_client = Goa.Client.new_sync(None) |
1130 | + self.account = None |
1131 | + self._load() |
1132 | + |
1133 | + def login(self, account): |
1134 | + assert(account) |
1135 | + self._update_state(account) |
1136 | + self._store() |
1137 | + |
1138 | + def logout(self): |
1139 | + self._update_state(None) |
1140 | + self._store() |
1141 | + |
1142 | + @GObject.Property |
1143 | + def username(self): |
1144 | + if self.account is None: |
1145 | + return None |
1146 | + return self.account.props.presentation_identity |
1147 | + |
1148 | + @GObject.Property |
1149 | + def token(self): |
1150 | + if self.account is None: |
1151 | + return None |
1152 | + |
1153 | + obj = self.goa_client.lookup_by_id(self.account.props.id) |
1154 | + if obj is None: |
1155 | + return None |
1156 | + |
1157 | + pbased = obj.get_password_based() |
1158 | + if pbased is None: |
1159 | + return None |
1160 | + |
1161 | + return pbased.call_get_password_sync('livepatch') |
1162 | + |
1163 | + def _update_state_from_account_id(self, account_id): |
1164 | + if account_id: |
1165 | + # Make sure the account-id is valid |
1166 | + obj = self.goa_client.lookup_by_id(account_id) |
1167 | + if obj is None: |
1168 | + self._update_state(None) |
1169 | + return |
1170 | + |
1171 | + account = obj.get_account() |
1172 | + if account is None: |
1173 | + self._update_state(None) |
1174 | + return |
1175 | + |
1176 | + self._update_state(account) |
1177 | + else: |
1178 | + self._update_state(None) |
1179 | + |
1180 | + def _update_state(self, account): |
1181 | + self.account = account |
1182 | + if self.account is None: |
1183 | + self.logged = False |
1184 | + else: |
1185 | + try: |
1186 | + account.call_ensure_credentials_sync(None) |
1187 | + except Exception: |
1188 | + self.logged = False |
1189 | + else: |
1190 | + self.account.connect('notify::attention-needed', lambda o, v: self.logout()) |
1191 | + self.logged = True |
1192 | + |
1193 | + def _load(self): |
1194 | + # Retrieve the stored account-id |
1195 | + account_id = Secret.password_lookup_sync(SECRETS_SCHEMA, {'key': 'account-id'}, None) |
1196 | + self._update_state_from_account_id(account_id) |
1197 | + |
1198 | + def _store(self): |
1199 | + if self.logged: |
1200 | + account_id = self.account.props.id |
1201 | + Secret.password_store(SECRETS_SCHEMA, {'key': 'account-id'}, None, 'com.ubuntu.SoftwareProperties', account_id) |
1202 | + else: |
1203 | + Secret.password_clear(SECRETS_SCHEMA, {'key': 'account-id'}, None, None, None) |
1204 | |
1205 | === modified file 'softwareproperties/SoftwareProperties.py' |
1206 | --- softwareproperties/SoftwareProperties.py 2017-03-01 17:35:37 +0000 |
1207 | +++ softwareproperties/SoftwareProperties.py 2018-03-21 15:53:10 +0000 |
1208 | @@ -1,11 +1,12 @@ |
1209 | # software-properties backend |
1210 | # |
1211 | -# Copyright (c) 2004-2007 Canonical Ltd. |
1212 | +# Copyright (c) 2004-2018 Canonical Ltd. |
1213 | # 2004-2005 Michiel Sikkes |
1214 | # |
1215 | # Author: Michiel Sikkes <michiel@eyesopened.nl> |
1216 | # Michael Vogt <mvo@debian.org> |
1217 | # Sebastian Heinlein <glatzor@ubuntu.com> |
1218 | +# Andrea Azzarone <andrea.azzarone@canonical.com> |
1219 | # |
1220 | # This program is free software; you can redistribute it and/or |
1221 | # modify it under the terms of the GNU General Public License as |
1222 | @@ -31,6 +32,7 @@ |
1223 | import os |
1224 | import glob |
1225 | import shutil |
1226 | +import subprocess |
1227 | import threading |
1228 | import atexit |
1229 | import tempfile |
1230 | @@ -63,6 +65,10 @@ |
1231 | from . import ppa |
1232 | from . import cloudarchive |
1233 | |
1234 | +import gi |
1235 | +gi.require_version('Snapd', '1') |
1236 | +from gi.repository import Gio, Snapd |
1237 | + |
1238 | _SHORTCUT_FACTORIES = [ |
1239 | ppa.shortcut_handler, |
1240 | cloudarchive.shortcut_handler, |
1241 | @@ -88,6 +94,9 @@ |
1242 | RELEASE_UPGRADES_LTS : 'lts', |
1243 | RELEASE_UPGRADES_NEVER : 'never', |
1244 | } |
1245 | + |
1246 | + # file to monitor canonical-livepatch status |
1247 | + LIVEPATCH_RUNNING_FILE = '/var/snap/canonical-livepatch/common/machine-token' |
1248 | |
1249 | def __init__(self, datadir=None, options=None, rootdir="/"): |
1250 | """ Provides the core functionality to configure the used software |
1251 | @@ -126,6 +135,8 @@ |
1252 | # apt-key stuff |
1253 | self.apt_key = AptAuth(rootdir=rootdir) |
1254 | |
1255 | + self.cancellable = Gio.Cancellable() |
1256 | + |
1257 | atexit.register(self.wait_for_threads) |
1258 | |
1259 | def wait_for_threads(self): |
1260 | @@ -858,6 +869,147 @@ |
1261 | except: |
1262 | return False |
1263 | |
1264 | + # |
1265 | + # Livepatch |
1266 | + # |
1267 | + def init_snapd(self): |
1268 | + self.snapd_client = Snapd.Client() |
1269 | + |
1270 | + def get_livepatch_snap_async(self, callback): |
1271 | + assert self.snapd_client |
1272 | + self.snapd_client.list_one_async('canonical-livepatch', |
1273 | + self.cancellable, |
1274 | + self.on_list_one_ready_cb, |
1275 | + callback) |
1276 | + |
1277 | + def on_list_one_ready_cb(self, source_object, result, user_data): |
1278 | + callback = user_data |
1279 | + try: |
1280 | + snap = source_object.list_one_finish(result) |
1281 | + except: |
1282 | + snap = None |
1283 | + if snap: |
1284 | + if callback: |
1285 | + callback(snap) |
1286 | + return |
1287 | + else: |
1288 | + assert self.snapd_client |
1289 | + self.snapd_client.find_async(Snapd.FindFlags.MATCH_NAME, |
1290 | + 'canonical-livepatch', |
1291 | + self.cancellable, |
1292 | + self.on_find_ready_cb, |
1293 | + callback) |
1294 | + |
1295 | + def on_find_ready_cb(self, source_object, result, user_data): |
1296 | + callback = user_data |
1297 | + try: |
1298 | + snaps = source_object.find_finish(result)[0] |
1299 | + except: |
1300 | + snaps = list() |
1301 | + snap = snaps[0] if len(snaps) else None |
1302 | + if callback: |
1303 | + callback(snap) |
1304 | + |
1305 | + def get_livepatch_snap_status(self, snap): |
1306 | + if snap is None: |
1307 | + return Snapd.SnapStatus.UNKNOWN |
1308 | + return snap.get_status() |
1309 | + |
1310 | + # glib-snapd does not keep track of the status of the snap. Use this decorator |
1311 | + # to make it easy to write async functions that will always have an updated |
1312 | + # snap object. |
1313 | + def require_livepatch_snap(func): |
1314 | + def get_livepatch_snap_and_call(*args, **kwargs): |
1315 | + return args[0].get_livepatch_snap_async(lambda snap: func(snap=snap, *args, **kwargs)) |
1316 | + return get_livepatch_snap_and_call |
1317 | + |
1318 | + def is_livepatch_enabled(self): |
1319 | + file = Gio.File.new_for_path(path=self.LIVEPATCH_RUNNING_FILE) |
1320 | + return file.query_exists(None) |
1321 | + |
1322 | + @require_livepatch_snap |
1323 | + def set_livepatch_enabled_async(self, enabled, token, callback, snap=None): |
1324 | + status = self.get_livepatch_snap_status(snap) |
1325 | + if status == Snapd.SnapStatus.UNKNOWN: |
1326 | + if callback: |
1327 | + callback(True, _("Canonical Livepatch snap cannot be installed.")) |
1328 | + elif status == Snapd.SnapStatus.ACTIVE: |
1329 | + if enabled: |
1330 | + error = self.enable_livepatch_service(token) |
1331 | + else: |
1332 | + error = self.disable_livepatch_service() |
1333 | + if callback: |
1334 | + callback(len(error) > 0, error) |
1335 | + elif status == Snapd.SnapStatus.INSTALLED: |
1336 | + if enabled: |
1337 | + self.snapd_client.enable_async(name='canonical-livepatch', |
1338 | + cancellable=self.cancellable, |
1339 | + callback=self.livepatch_enable_snap_cb, |
1340 | + user_data=(callback, token)) |
1341 | + else: |
1342 | + if callback: |
1343 | + callback(False, "") |
1344 | + elif status == Snapd.SnapStatus.AVAILABLE: |
1345 | + if enabled: |
1346 | + self.snapd_client.install_async(name='canonical-livepatch', |
1347 | + channel='edge', # Remove this once bionic is officialy supported. |
1348 | + cancellable=self.cancellable, |
1349 | + callback=self.livepatch_install_snap_cb, |
1350 | + user_data=(callback, token)) |
1351 | + else: |
1352 | + if callback: |
1353 | + callback(False, "") |
1354 | + |
1355 | + def livepatch_enable_snap_cb(self, source_object, result, user_data): |
1356 | + (callback, token) = user_data |
1357 | + try: |
1358 | + if source_object.enable_finish(result): |
1359 | + error = self.enable_livepatch_service(token) |
1360 | + if callback: |
1361 | + callback(len(error) > 0, error) |
1362 | + except Exception: |
1363 | + if callback: |
1364 | + callback(True, _("Canonical Livepatch snap cannot be enabled.")) |
1365 | + |
1366 | + def livepatch_install_snap_cb(self, source_object, result, user_data): |
1367 | + (callback, token) = user_data |
1368 | + try: |
1369 | + if source_object.install_finish(result): |
1370 | + error = self.enable_livepatch_service(token) |
1371 | + if callback: |
1372 | + callback(len(error) > 0, error) |
1373 | + except Exception: |
1374 | + if callback: |
1375 | + callback(True, _("Canonical Livepatch snap cannot be installed.")) |
1376 | + |
1377 | + def enable_livepatch_service(self, token): |
1378 | + generic_error = _("Canonical Livepatch cannot be enabled.") |
1379 | + |
1380 | + if self.is_livepatch_enabled(): |
1381 | + return "" |
1382 | + |
1383 | + try: |
1384 | + subprocess.check_output(['/snap/bin/canonical-livepatch', 'enable', token], stderr=subprocess.STDOUT) |
1385 | + return "" |
1386 | + except subprocess.CalledProcessError as e: |
1387 | + return e.output if e.output else generic_error |
1388 | + except: |
1389 | + return generic_error |
1390 | + |
1391 | + |
1392 | + def disable_livepatch_service(self): |
1393 | + generic_error = _("Canonical Livepatch cannot be disabled.") |
1394 | + |
1395 | + if not self.is_livepatch_enabled(): |
1396 | + return "" |
1397 | + |
1398 | + try: |
1399 | + subprocess.check_output(['/snap/bin/canonical-livepatch', 'disable'], stderr=subprocess.STDOUT) |
1400 | + return "" |
1401 | + except subprocess.CalledProcessError as e: |
1402 | + return e.output if e.output else generic_error |
1403 | + except: |
1404 | + return generic_error |
1405 | |
1406 | def shortcut_handler(shortcut): |
1407 | for factory in _SHORTCUT_FACTORIES: |
1408 | |
1409 | === modified file 'softwareproperties/dbus/SoftwarePropertiesDBus.py' |
1410 | --- softwareproperties/dbus/SoftwarePropertiesDBus.py 2015-11-01 12:39:02 +0000 |
1411 | +++ softwareproperties/dbus/SoftwarePropertiesDBus.py 2018-03-21 15:53:10 +0000 |
1412 | @@ -61,6 +61,8 @@ |
1413 | self.enforce_polkit = True |
1414 | logging.debug("waiting for connections") |
1415 | |
1416 | + self.init_snapd() |
1417 | + |
1418 | # override set_modified_sourceslist to emit a signal |
1419 | def save_sourceslist(self): |
1420 | super(SoftwarePropertiesDBus, self).save_sourceslist() |
1421 | @@ -317,6 +319,15 @@ |
1422 | sender, conn, "com.ubuntu.softwareproperties.applychanges") |
1423 | return self.update_keys() |
1424 | |
1425 | + # LivePatch |
1426 | + @dbus.service.method(DBUS_INTERFACE_NAME, |
1427 | + sender_keyword="sender", connection_keyword="conn", |
1428 | + in_signature='bs', out_signature='bs', async_callbacks=('reply_handler', 'error_handler')) |
1429 | + def SetLivepatchEnabled(self, enabled, token, reply_handler, error_handler, sender=None, conn=None): |
1430 | + self._check_policykit_privilege( |
1431 | + sender, conn, "com.ubuntu.softwareproperties.applychanges") |
1432 | + self.set_livepatch_enabled_async(enabled, token, reply_handler) |
1433 | + |
1434 | # helper from jockey |
1435 | def _check_policykit_privilege(self, sender, conn, privilege): |
1436 | '''Verify that sender has a given PolicyKit privilege. |
1437 | |
1438 | === added file 'softwareproperties/gtk/DialogAuth.py' |
1439 | --- softwareproperties/gtk/DialogAuth.py 1970-01-01 00:00:00 +0000 |
1440 | +++ softwareproperties/gtk/DialogAuth.py 2018-03-21 15:53:10 +0000 |
1441 | @@ -0,0 +1,228 @@ |
1442 | +# |
1443 | +# Copyright (c) 2018 Canonical |
1444 | +# |
1445 | +# Authors: |
1446 | +# Andrea Azzarone <andrea.azzarone@canonical.com> |
1447 | +# |
1448 | +# This program is free software; you can redistribute it and/or |
1449 | +# modify it under the terms of the GNU General Public License as |
1450 | +# published by the Free Software Foundation; either version 2 of the |
1451 | +# License, or (at your option) any later version. |
1452 | +# |
1453 | +# This program is distributed in the hope that it will be useful, |
1454 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
1455 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1456 | +# GNU General Public License for more details. |
1457 | +# |
1458 | +# You should have received a copy of the GNU General Public License |
1459 | +# along with this program; if not, write to the Free Software |
1460 | +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 |
1461 | +# USA |
1462 | + |
1463 | +import os |
1464 | + |
1465 | +from gettext import gettext as _ |
1466 | +from softwareproperties.gtk.utils import ( |
1467 | + setup_ui, |
1468 | +) |
1469 | + |
1470 | +import gi |
1471 | +gi.require_version('Goa', '1.0') |
1472 | +from gi.repository import Gio, GLib, Goa, GObject, Gtk |
1473 | +import logging |
1474 | + |
1475 | + |
1476 | +class DialogAuth: |
1477 | + |
1478 | + def __init__(self, parent, datadir): |
1479 | + """setup up the gtk dialog""" |
1480 | + self.parent = parent |
1481 | + |
1482 | + setup_ui(self, os.path.join(datadir, "gtkbuilder", |
1483 | + "dialog-auth.ui"), domain="software-properties") |
1484 | + self.label_title.set_max_width_chars(50) |
1485 | + |
1486 | + self.dialog = self.dialog_auth |
1487 | + self.dialog.use_header_bar = True |
1488 | + self.dialog.set_transient_for(parent) |
1489 | + |
1490 | + self.listboxrow_new_account.account = None |
1491 | + |
1492 | + self.account = None |
1493 | + self.dispose_on_new_account = False |
1494 | + self.goa_client = Goa.Client.new_sync(None) |
1495 | + |
1496 | + self.listbox_accounts.connect('row-activated', self._listbox_accounts_row_activated_cb) |
1497 | + |
1498 | + # Be ready to other accounts |
1499 | + self.goa_client.connect('account-added', self._account_added_cb) |
1500 | + self.goa_client.connect('account-removed', self._account_removed_cb) |
1501 | + |
1502 | + self._setup_listbox_accounts() |
1503 | + self._check_ui() |
1504 | + |
1505 | + def run(self): |
1506 | + res = self.dialog.run() |
1507 | + self.dialog.hide() |
1508 | + return res |
1509 | + |
1510 | + def _check_ui(self): |
1511 | + rows = self.listbox_accounts.get_children() |
1512 | + has_accounts = len(rows) > 1 |
1513 | + |
1514 | + if has_accounts: |
1515 | + title = _('To continue choose an Ubuntu Single Sign-On account.') |
1516 | + new_account = _('Use another account…') |
1517 | + else: |
1518 | + title = _('To continue you need an Ubuntu Single Sign-On account.') |
1519 | + new_account = _('Sign In…') |
1520 | + |
1521 | + self.label_title.set_text(title) |
1522 | + self.label_new_account.set_markup('<b>{}</b>'.format(new_account)) |
1523 | + |
1524 | + def _setup_listbox_accounts(self): |
1525 | + for obj in self.goa_client.get_accounts(): |
1526 | + account = obj.get_account() |
1527 | + if self._is_account_supported(account): |
1528 | + self._add_account(account) |
1529 | + |
1530 | + def _is_account_supported(self, account): |
1531 | + return account.props.provider_type == 'ubuntusso' |
1532 | + |
1533 | + def _add_account(self, account): |
1534 | + row = self._create_row(account) |
1535 | + self.listbox_accounts.prepend(row) |
1536 | + self._check_ui() |
1537 | + |
1538 | + def _remove_account(self, account): |
1539 | + for row in self.listbox_accounts.get_children(): |
1540 | + if row.account == account: |
1541 | + row.destroy() |
1542 | + self._check_ui() |
1543 | + break |
1544 | + |
1545 | + def _build_dbus_params(self, action, arg): |
1546 | + builder = GLib.VariantBuilder.new(GLib.VariantType.new('av')) |
1547 | + |
1548 | + if action is None and arg is None: |
1549 | + s = GLib.Variant.new_string('') |
1550 | + v = GLib.Variant.new_variant(s) |
1551 | + builder.add_value(v) |
1552 | + else: |
1553 | + if action is not None: |
1554 | + s = GLib.Variant.new_string(action) |
1555 | + v = GLib.Variant.new_variant(s) |
1556 | + builder.add_value(v) |
1557 | + if arg is not None: |
1558 | + s = GLib.Variant.new_string(arg) |
1559 | + v = GLib.Variant.new_variant(s) |
1560 | + builder.add_value(v) |
1561 | + |
1562 | + array = GLib.Variant.new_tuple(GLib.Variant.new_string('online-accounts'), builder.end()) |
1563 | + array = GLib.Variant.new_variant(array) |
1564 | + |
1565 | + param = GLib.Variant.new_tuple( |
1566 | + GLib.Variant.new_string('launch-panel'), |
1567 | + GLib.Variant.new_array(GLib.VariantType.new('v'), [array]), |
1568 | + GLib.Variant.new_array(GLib.VariantType.new('{sv}'), None)) |
1569 | + return param |
1570 | + |
1571 | + def _spawn_goa_with_args(self, action, arg): |
1572 | + proxy = Gio.DBusProxy.new_for_bus_sync(Gio.BusType.SESSION, |
1573 | + Gio.DBusProxyFlags.NONE, None, |
1574 | + 'org.gnome.ControlCenter', |
1575 | + '/org/gnome/ControlCenter', |
1576 | + 'org.gtk.Actions', None) |
1577 | + |
1578 | + param = self._build_dbus_params(action, arg) |
1579 | + timeout = 10*60*1000 # 10 minutes should be enough to create an account |
1580 | + proxy.call_sync('Activate', param, Gio.DBusCallFlags.NONE, timeout, None) |
1581 | + |
1582 | + def _create_row(self, account): |
1583 | + identity = account.props.presentation_identity |
1584 | + provider_name = account.props.provider_name |
1585 | + |
1586 | + row = Gtk.ListBoxRow.new() |
1587 | + row.show() |
1588 | + |
1589 | + hbox = Gtk.Box.new(Gtk.Orientation.HORIZONTAL, 6) |
1590 | + hbox.set_hexpand(True) |
1591 | + hbox.show() |
1592 | + |
1593 | + image = Gtk.Image.new_from_icon_name('avatar-default', Gtk.IconSize.DIALOG) |
1594 | + image.set_pixel_size(48) |
1595 | + image.show() |
1596 | + hbox.pack_start(image, False, False, 0) |
1597 | + |
1598 | + vbox = Gtk.Box.new(Gtk.Orientation.VERTICAL, 2) |
1599 | + vbox.set_valign(Gtk.Align.CENTER) |
1600 | + vbox.show() |
1601 | + hbox.pack_start(vbox, False, False, 0) |
1602 | + |
1603 | + if identity: |
1604 | + ilabel = Gtk.Label.new() |
1605 | + ilabel.set_halign(Gtk.Align.START) |
1606 | + ilabel.set_markup('<b>{}</b>'.format(identity)) |
1607 | + ilabel.show() |
1608 | + vbox.pack_start(ilabel, True, True, 0) |
1609 | + |
1610 | + if provider_name: |
1611 | + plabel = Gtk.Label.new() |
1612 | + plabel.set_halign(Gtk.Align.START) |
1613 | + plabel.set_markup('<small><span foreground=\"#555555\">{}</span></small>'.format(provider_name)) |
1614 | + plabel.show() |
1615 | + vbox.pack_start(plabel, True, True, 0) |
1616 | + |
1617 | + warning_icon = Gtk.Image.new_from_icon_name('dialog-warning-symbolic', Gtk.IconSize.BUTTON) |
1618 | + warning_icon.set_no_show_all(True) |
1619 | + warning_icon.set_margin_end (15) |
1620 | + hbox.pack_end(warning_icon, False, False, 0) |
1621 | + |
1622 | + row.add(hbox) |
1623 | + |
1624 | + account.bind_property('attention-needed', warning_icon, 'visible', |
1625 | + GObject.BindingFlags.DEFAULT | GObject.BindingFlags.SYNC_CREATE) |
1626 | + |
1627 | + row.account = account |
1628 | + return row |
1629 | + |
1630 | + # Signals handlers |
1631 | + def _listbox_accounts_row_activated_cb(self, listbox, row): |
1632 | + account = row.account |
1633 | + |
1634 | + if account is None: |
1635 | + # TODO (azzar1): there is no easy way to put this to false |
1636 | + # if the user close the windows without adding an account. |
1637 | + # We need to discuss with goa's upstream to support such usercases |
1638 | + try: |
1639 | + self._spawn_goa_with_args('add', 'ubuntusso') |
1640 | + self.dispose_on_new_account = True |
1641 | + except GLib.Error as e: |
1642 | + logging.warning ('Failed to spawing gnome-control-center: %s', e.message) |
1643 | + else: |
1644 | + if account.props.attention_needed: |
1645 | + try: |
1646 | + self._spawn_goa_with_args(account.props.id, None) |
1647 | + except GLib.Error as e: |
1648 | + logging.warning ('Failed to spawing gnome-control-center: %s', e.message) |
1649 | + else: |
1650 | + self.account = account |
1651 | + self.dialog.response(Gtk.ResponseType.OK) |
1652 | + |
1653 | + def _account_added_cb(self, goa_client, goa_object): |
1654 | + account = goa_object.get_account() |
1655 | + if not self._is_account_supported(account): |
1656 | + return |
1657 | + if not self.dispose_on_new_account: |
1658 | + self._add_account(account) |
1659 | + else: |
1660 | + self.account = account |
1661 | + self.dialog.response(Gtk.ResponseType.OK) |
1662 | + |
1663 | + def _account_removed_cb(self, goa_client, goa_object): |
1664 | + account = goa_object.get_account() |
1665 | + if self._is_account_supported(account): |
1666 | + self._remove_account(account) |
1667 | + |
1668 | + |
1669 | + |
1670 | |
1671 | === added file 'softwareproperties/gtk/DialogLivepatchError.py' |
1672 | --- softwareproperties/gtk/DialogLivepatchError.py 1970-01-01 00:00:00 +0000 |
1673 | +++ softwareproperties/gtk/DialogLivepatchError.py 2018-03-21 15:53:10 +0000 |
1674 | @@ -0,0 +1,57 @@ |
1675 | +# |
1676 | +# Copyright (c) 2017-2018 Canonical |
1677 | +# |
1678 | +# Authors: |
1679 | +# Andrea Azzarone <andrea.azzarone@canonical.com> |
1680 | +# |
1681 | +# This program is free software; you can redistribute it and/or |
1682 | +# modify it under the terms of the GNU General Public License as |
1683 | +# published by the Free Software Foundation; either version 2 of the |
1684 | +# License, or (at your option) any later version. |
1685 | +# |
1686 | +# This program is distributed in the hope that it will be useful, |
1687 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
1688 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1689 | +# GNU General Public License for more details. |
1690 | +# |
1691 | +# You should have received a copy of the GNU General Public License |
1692 | +# along with this program; if not, write to the Free Software |
1693 | +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 |
1694 | +# USA |
1695 | + |
1696 | +import os |
1697 | + |
1698 | +from softwareproperties.gtk.utils import ( |
1699 | + setup_ui, |
1700 | +) |
1701 | + |
1702 | + |
1703 | +class DialogLivepatchError: |
1704 | + |
1705 | + RESPONSE_SETTINGS = 100 |
1706 | + RESPONSE_IGNORE = 101 |
1707 | + |
1708 | + def __init__(self, parent, datadir): |
1709 | + """setup up the gtk dialog""" |
1710 | + self.parent = parent |
1711 | + |
1712 | + setup_ui(self, os.path.join(datadir, "gtkbuilder", |
1713 | + "dialog-livepatch-error.ui"), domain="software-properties") |
1714 | + |
1715 | + self.dialog = self.messagedialog_livepatch |
1716 | + self.dialog.use_header_bar = True |
1717 | + self.dialog.set_transient_for(parent) |
1718 | + |
1719 | + def run(self, error, show_settings_button): |
1720 | + self.dialog.format_secondary_markup( |
1721 | + "The error was: \"%s\"" % error.strip()) |
1722 | + self.button_settings.set_visible(show_settings_button) |
1723 | + res = self.dialog.run() |
1724 | + self.dialog.hide() |
1725 | + return res |
1726 | + |
1727 | + def on_button_settings_clicked(self, b, d=None): |
1728 | + self.dialog.response(self.RESPONSE_SETTINGS) |
1729 | + |
1730 | + def on_button_ignore_clicked(self, b, d=None): |
1731 | + self.dialog.response(self.RESPONSE_IGNORE) |
1732 | |
1733 | === modified file 'softwareproperties/gtk/SoftwarePropertiesGtk.py' |
1734 | --- softwareproperties/gtk/SoftwarePropertiesGtk.py 2018-03-06 15:47:27 +0000 |
1735 | +++ softwareproperties/gtk/SoftwarePropertiesGtk.py 2018-03-21 15:53:10 +0000 |
1736 | @@ -1,11 +1,12 @@ |
1737 | # GTK+ based frontend to software-properties |
1738 | # |
1739 | -# Copyright (c) 2004-2007 Canonical Ltd. |
1740 | +# Copyright (c) 2004-2018 Canonical Ltd. |
1741 | # 2004-2005 Michiel Sikkes |
1742 | # |
1743 | # Author: Michiel Sikkes <michiel@eyesopened.nl> |
1744 | # Michael Vogt <mvo@debian.org> |
1745 | # Sebastian Heinlein <glatzor@ubuntu.com> |
1746 | +# Andrea Azzarone <andrea.azzarone@canonical.com> |
1747 | # |
1748 | # This program is free software; you can redistribute it and/or |
1749 | # modify it under the terms of the GNU General Public License as |
1750 | @@ -26,6 +27,9 @@ |
1751 | |
1752 | import apt |
1753 | import apt_pkg |
1754 | +import aptsources.distro |
1755 | +from datetime import datetime |
1756 | +import distro_info |
1757 | import dbus |
1758 | from gettext import gettext as _ |
1759 | import gettext |
1760 | @@ -48,8 +52,11 @@ |
1761 | from .DialogEdit import DialogEdit |
1762 | from .DialogCacheOutdated import DialogCacheOutdated |
1763 | from .DialogAddSourcesList import DialogAddSourcesList |
1764 | +from .DialogLivepatchError import DialogLivepatchError |
1765 | +from .DialogAuth import DialogAuth |
1766 | |
1767 | import softwareproperties |
1768 | +from softwareproperties.GoaAuth import GoaAuth |
1769 | import softwareproperties.distro |
1770 | from softwareproperties.SoftwareProperties import SoftwareProperties |
1771 | import softwareproperties.SoftwareProperties |
1772 | @@ -78,6 +85,8 @@ |
1773 | STORE_VISIBLE |
1774 | ) = list(range(5)) |
1775 | |
1776 | +LIVEPATCH_TIMEOUT = 1200 |
1777 | + |
1778 | |
1779 | def error(parent_window, summary, msg): |
1780 | """ show a error dialog """ |
1781 | @@ -182,6 +191,8 @@ |
1782 | self.show_distro() |
1783 | # Setup and show the Additonal Drivers tab |
1784 | self.init_drivers() |
1785 | + # Setup and show the LivePatch tab |
1786 | + self.init_livepatch() |
1787 | |
1788 | # Connect to switch-page before setting initial tab. Otherwise the |
1789 | # first switch goes unnoticed. |
1790 | @@ -283,7 +294,7 @@ |
1791 | |
1792 | def set_security_update_level(self): |
1793 | """Fetch the security level, Enable/Disable and set the value appropriately""" |
1794 | - |
1795 | + |
1796 | # Security Updates |
1797 | level_sec = self.get_update_automation_level() |
1798 | if level_sec == None: |
1799 | @@ -298,7 +309,7 @@ |
1800 | self.combobox_security_updates.set_active(1) # Download automatically |
1801 | elif level_sec == softwareproperties.UPDATE_INST_SEC: |
1802 | self.combobox_security_updates.set_active(2) # Download and install automatically |
1803 | - |
1804 | + |
1805 | |
1806 | def init_distro(self): |
1807 | """Setup the user interface elements to represent the distro""" |
1808 | @@ -493,7 +504,7 @@ |
1809 | except dbus.DBusException as e: |
1810 | if e._dbus_error_name == 'com.ubuntu.SoftwareProperties.PermissionDeniedByPolicy': |
1811 | logging.error("Authentication canceled, changes have not been saved") |
1812 | - |
1813 | + |
1814 | combo_handler = self.handlers[self.combobox_security_updates] |
1815 | self.combobox_security_updates.handler_block(combo_handler) |
1816 | self.set_security_update_level() |
1817 | @@ -520,13 +531,13 @@ |
1818 | except dbus.DBusException as e: |
1819 | if e._dbus_error_name == 'com.ubuntu.SoftwareProperties.PermissionDeniedByPolicy': |
1820 | logging.error("Authentication canceled, changes have not been saved") |
1821 | - |
1822 | + |
1823 | combo_handler = self.handlers[self.combobox_release_upgrades] |
1824 | self.combobox_release_upgrades.handler_block(combo_handler) |
1825 | i = self.get_release_upgrades_policy() |
1826 | self.combobox_release_upgrades.set_active(i) |
1827 | self.combobox_release_upgrades.handler_unblock(combo_handler) |
1828 | - |
1829 | + |
1830 | |
1831 | def on_combobox_server_changed(self, combobox): |
1832 | """ |
1833 | @@ -880,7 +891,7 @@ |
1834 | except dbus.DBusException as e: |
1835 | if e._dbus_error_name == 'com.ubuntu.SoftwareProperties.PermissionDeniedByPolicy': |
1836 | logging.error("Authentication canceled, changes have not been saved") |
1837 | - |
1838 | + |
1839 | update_days = self.get_update_interval() |
1840 | combo_handler = self.handlers[self.combobox_update_interval] |
1841 | for key in self.combobox_interval_mapping: |
1842 | @@ -1012,6 +1023,7 @@ |
1843 | def on_delete_event(self, widget, args): |
1844 | """Close the window if requested""" |
1845 | self.on_close_button(widget) |
1846 | + return self.quit_when_livepatch_responds |
1847 | |
1848 | def on_close_button(self, widget): |
1849 | """Show a dialog that a reload of the channel information is required |
1850 | @@ -1021,7 +1033,11 @@ |
1851 | d = DialogCacheOutdated(self.window_main, |
1852 | self.datadir) |
1853 | d.run() |
1854 | - self.quit() |
1855 | + if self.waiting_livepatch_response: |
1856 | + self.quit_when_livepatch_responds = True |
1857 | + self.hide() |
1858 | + else: |
1859 | + self.quit() |
1860 | |
1861 | def on_button_add_cdrom_clicked(self, widget): |
1862 | """ when a cdrom is requested for adding """ |
1863 | @@ -1446,3 +1462,145 @@ |
1864 | % {'count': self.nonfree_drivers}) |
1865 | else: |
1866 | self.label_driver_action.set_label(_("No proprietary drivers are in use.")) |
1867 | + |
1868 | + # |
1869 | + # Livepatch |
1870 | + # |
1871 | + def init_livepatch(self): |
1872 | + self.goa_auth = GoaAuth() |
1873 | + self.waiting_livepatch_response = False |
1874 | + self.quit_when_livepatch_responds = False |
1875 | + |
1876 | + if not self.is_livepatch_supported(): |
1877 | + self.grid_livepatch.set_visible(False) |
1878 | + return |
1879 | + |
1880 | + self.checkbutton_livepatch.set_active(self.is_livepatch_enabled()) |
1881 | + self.on_goa_auth_changed() |
1882 | + |
1883 | + # hacky way to monitor if livepatch is enabled or not |
1884 | + file = Gio.File.new_for_path(path=self.LIVEPATCH_RUNNING_FILE) |
1885 | + self.lp_monitor = file.monitor_file(Gio.FileMonitorFlags.NONE) |
1886 | + |
1887 | + # connect to signals |
1888 | + self.handlers[self.goa_auth] = \ |
1889 | + self.goa_auth.connect('notify::logged', lambda o, p: self.on_goa_auth_changed()) |
1890 | + self.handlers[self.checkbutton_livepatch] = \ |
1891 | + self.checkbutton_livepatch.connect('toggled', self.on_checkbutton_livepatch_toggled) |
1892 | + self.handlers[self.button_ubuntuone] = \ |
1893 | + self.button_ubuntuone.connect('clicked', self.on_button_ubuntuone_clicked) |
1894 | + self.handlers[self.lp_monitor] = \ |
1895 | + self.lp_monitor.connect('changed', self.on_livepatch_status_changed) |
1896 | + |
1897 | + def is_livepatch_supported(self): |
1898 | + distro = aptsources.distro.get_distro() |
1899 | + di = distro_info.UbuntuDistroInfo() |
1900 | + return di.is_lts(distro.codename) and distro.codename in di.supported(datetime.now().date()) |
1901 | + |
1902 | + def on_goa_auth_changed(self): |
1903 | + if self.goa_auth.logged: |
1904 | + self.button_ubuntuone.set_label(_('Sign Out')) |
1905 | + |
1906 | + if self.goa_auth.token: |
1907 | + self.checkbutton_livepatch.set_sensitive(True) |
1908 | + self.label_livepatch_login.set_label(_('Signed in as %s' % self.goa_auth.username)) |
1909 | + else: |
1910 | + self.checkbutton_livepatch.set_sensitive(False) |
1911 | + text = _('%s isn\'t authorized to use Livepatch.' % self.goa_auth.username) |
1912 | + text = "<span color='red'>" + text + "</span>" |
1913 | + self.label_livepatch_login.set_markup(text) |
1914 | + else: |
1915 | + self.checkbutton_livepatch.set_sensitive(False) |
1916 | + self.button_ubuntuone.set_label(_('Sign In…')) |
1917 | + self.label_livepatch_login.set_label(_('To use Livepatch you need to sign in.')) |
1918 | + |
1919 | + def on_livepatch_status_changed(self, file_monitor, file, other_file, event_type): |
1920 | + if not self.waiting_livepatch_response: |
1921 | + self.checkbutton_livepatch.set_active(self.is_livepatch_enabled()) |
1922 | + |
1923 | + def on_button_ubuntuone_clicked(self, button): |
1924 | + if self.goa_auth.logged: |
1925 | + self.do_logout() |
1926 | + else: |
1927 | + self.do_login() |
1928 | + |
1929 | + def do_login(self): |
1930 | + try: |
1931 | + # Show login dialog! |
1932 | + dialog = DialogAuth(self.window_main, self.datadir) |
1933 | + response = dialog.run() |
1934 | + except Exception as e: |
1935 | + logging.error(e) |
1936 | + error(self.window_main, |
1937 | + _("Error enabling Canonical Livepatch"), |
1938 | + _("Please check your Internet connection.")) |
1939 | + else: |
1940 | + if response == Gtk.ResponseType.OK: |
1941 | + self.goa_auth.login(dialog.account) |
1942 | + if self.goa_auth.logged: |
1943 | + self.checkbutton_livepatch.set_active(True) |
1944 | + |
1945 | + def do_logout(self): |
1946 | + self.goa_auth.logout() |
1947 | + self.checkbutton_livepatch.set_active(False) |
1948 | + |
1949 | + def on_checkbutton_livepatch_toggled(self, checkbutton): |
1950 | + if self.waiting_livepatch_response: |
1951 | + return |
1952 | + |
1953 | + self.waiting_livepatch_response = True |
1954 | + |
1955 | + token = '' |
1956 | + enabled = False |
1957 | + if self.checkbutton_livepatch.get_active(): |
1958 | + enabled = True |
1959 | + token = self.goa_auth.token if self.goa_auth.token else '' |
1960 | + self.backend.SetLivepatchEnabled(enabled, token, |
1961 | + reply_handler=self.livepatch_enabled_reply_handler, |
1962 | + error_handler=self.livepatch_enabled_error_handler, |
1963 | + timeout=LIVEPATCH_TIMEOUT) |
1964 | + |
1965 | + def livepatch_enabled_reply_handler(self, is_error, prompt): |
1966 | + self.sync_checkbutton_livepatch(is_error, prompt) |
1967 | + |
1968 | + def livepatch_enabled_error_handler(self, e): |
1969 | + if e._dbus_error_name == 'com.ubuntu.SoftwareProperties.PermissionDeniedByPolicy': |
1970 | + logging.error("Authentication canceled, changes have not been saved") |
1971 | + self.sync_checkbutton_livepatch(is_error=True, prompt=None) |
1972 | + else: |
1973 | + self.sync_checkbutton_livepatch(is_error=True, prompt=str(e)) |
1974 | + |
1975 | + def sync_checkbutton_livepatch(self, is_error, prompt): |
1976 | + if is_error: |
1977 | + self.waiting_livepatch_response = False |
1978 | + self.checkbutton_livepatch.handler_block(self.handlers[self.checkbutton_livepatch]) |
1979 | + self.checkbutton_livepatch.set_active(self.is_livepatch_enabled()) |
1980 | + self.checkbutton_livepatch.handler_unblock(self.handlers[self.checkbutton_livepatch]) |
1981 | + |
1982 | + if prompt: |
1983 | + dialog = DialogLivepatchError(self.window_main, self.datadir) |
1984 | + response = dialog.run(prompt, show_settings_button=self.quit_when_livepatch_responds) |
1985 | + if response == DialogLivepatchError.RESPONSE_SETTINGS: |
1986 | + self.window_main.show() |
1987 | + self.quit_when_livepatch_responds = False |
1988 | + else: |
1989 | + do_dbus_call = False |
1990 | + if self.is_livepatch_enabled() and not self.checkbutton_livepatch.get_active(): |
1991 | + do_dbus_call = True |
1992 | + enabled = False |
1993 | + token = '' |
1994 | + elif not self.is_livepatch_enabled() and self.checkbutton_livepatch.get_active(): |
1995 | + do_dbus_call = True |
1996 | + enabled = True |
1997 | + token = self.goa_auth.token if self.goa_auth.token else '' |
1998 | + else: |
1999 | + self.waiting_livepatch_response = False |
2000 | + |
2001 | + if do_dbus_call: |
2002 | + self.backend.SetLivepatchEnabled(enabled, token, |
2003 | + reply_handler=self.livepatch_enabled_reply_handler, |
2004 | + error_handler=self.livepatch_enabled_error_handler, |
2005 | + timeout=LIVEPATCH_TIMEOUT) |
2006 | + |
2007 | + if self.quit_when_livepatch_responds: |
2008 | + self.on_close_button(self.button_close) |
At the moment bionic in the stable canonical-livepatch snap. We might want to install the edge snap for the moment or:
1) let the enabling fail
2) hide the ui