Merge lp:~mterry/update-manager/stop-update into lp:update-manager

Proposed by Michael Terry on 2012-08-20
Status: Merged
Merged at revision: 2538
Proposed branch: lp:~mterry/update-manager/stop-update
Merge into: lp:update-manager
Diff against target: 389 lines (+173/-65)
7 files modified
UpdateManager/Dialogs.py (+12/-0)
UpdateManager/UpdateManager.py (+31/-14)
UpdateManager/UpdateProgress.py (+1/-6)
UpdateManager/UpdatesAvailable.py (+36/-36)
UpdateManager/backend/InstallBackendAptdaemon.py (+3/-0)
data/gtkbuilder/UpdateManager.ui (+40/-9)
tests/test_stop_update.py (+50/-0)
To merge this branch: bzr merge lp:~mterry/update-manager/stop-update
Reviewer Review Type Date Requested Status
Michael Vogt 2012-08-20 Approve on 2012-08-24
Review via email: mp+120318@code.launchpad.net

Description of the Change

mpt added some dialogs recently to the update-manager experience if the user stops an apt update. See https://wiki.ubuntu.com/SoftwareUpdates#Launching

This branch implements those changes (and does a little minor cleanup in UpdatesAvailable by dropping some support for num_updates == 0 which shouldn't ever happen now, after the redesign).

To post a comment you must log in.
Michael Vogt (mvo) wrote :

On Mon, Aug 20, 2012 at 02:45:38AM -0000, Michael Terry wrote:
[..]
> @@ -162,7 +163,7 @@
>
> self._start_pane(UpdateProgress(self))
>
> - def start_available(self):
> + def start_available(self, cancelled_update = False):
> self._look_busy()
> self.refresh_cache()
[..]
> === modified file 'UpdateManager/UpdatesAvailable.py'
> --- UpdateManager/UpdatesAvailable.py 2012-06-28 00:09:03 +0000
> +++ UpdateManager/UpdatesAvailable.py 2012-08-20 02:44:22 +0000
> @@ -81,7 +81,7 @@
>
> class UpdatesAvailable(SimpleGtkbuilderApp):
>
> - def __init__(self, app):
> + def __init__(self, app, header = None, desc = None):
> self.window_main = app
> self.datadir = app.datadir
> self.options = app.options

pep8 suggests to use "cancelled_update=False" (no space around the
"=").

Otherwise this looks good, would be nice to have a test, but to get it
in before UIF I'm fine with merging it now.

Thanks,
 Michael

Michael Vogt (mvo) :
review: Approve
2536. By Michael Terry on 2012-08-24

merge from trunk

2537. By Michael Terry on 2012-08-24

merge from trunk again

2538. By Michael Terry on 2012-08-24

fix pep8 and pyflakes issues

2539. By Michael Terry on 2012-08-24

adjust code to make the UpdateManager class slightly easier to unit test; add tests for stop-update code

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'UpdateManager/Dialogs.py'
2--- UpdateManager/Dialogs.py 2012-07-06 19:30:02 +0000
3+++ UpdateManager/Dialogs.py 2012-08-24 23:06:30 +0000
4@@ -106,6 +106,18 @@
5 self.label_desc.set_visible(bool(label))
6
7
8+class StoppedUpdatesDialog(Dialog):
9+ def __init__(self, window_main):
10+ Dialog.__init__(self, window_main)
11+ self.set_header(_("You stopped the check for updates."))
12+ self.add_settings_button()
13+ self.add_button(_("_Check Again"), self.check)
14+ self.focus_button = self.add_button(Gtk.STOCK_OK, self.close)
15+
16+ def check(self):
17+ self.window_main.start_update()
18+
19+
20 class NoUpdatesDialog(Dialog):
21 def __init__(self, window_main):
22 Dialog.__init__(self, window_main)
23
24=== modified file 'UpdateManager/UpdateManager.py'
25--- UpdateManager/UpdateManager.py 2012-08-24 20:20:11 +0000
26+++ UpdateManager/UpdateManager.py 2012-08-24 23:06:30 +0000
27@@ -46,6 +46,7 @@
28 ErrorDialog,
29 NeedRestartDialog,
30 NoUpdatesDialog,
31+ StoppedUpdatesDialog,
32 PartialUpgradeDialog,
33 UnsupportedDialog)
34 from .InstallProgress import InstallProgress
35@@ -162,18 +163,36 @@
36
37 self._start_pane(UpdateProgress(self))
38
39- def start_available(self):
40+ def start_available(self, cancelled_update=False):
41 self._look_busy()
42 self.refresh_cache()
43
44- if self.cache.install_count == 0:
45+ pane = self._make_available_pane(self.cache.install_count,
46+ os.path.exists(REBOOT_REQUIRED_FILE),
47+ cancelled_update)
48+ self._start_pane(pane)
49+
50+ def _make_available_pane(self, install_count, need_reboot,
51+ cancelled_update):
52+ if install_count == 0:
53 # Need Restart > New Release > No Updates
54- if os.path.exists(REBOOT_REQUIRED_FILE):
55- self._start_pane(NeedRestartDialog(self))
56- elif not self._check_meta_release():
57- self._start_pane(NoUpdatesDialog(self))
58+ if need_reboot:
59+ return NeedRestartDialog(self)
60+ pane = self._check_meta_release()
61+ if pane:
62+ return pane
63+ elif cancelled_update:
64+ return StoppedUpdatesDialog(self)
65+ else:
66+ return NoUpdatesDialog(self)
67 else:
68- self._start_pane(UpdatesAvailable(self))
69+ header = None
70+ desc = None
71+ if cancelled_update:
72+ header = _("You stopped the check for updates.")
73+ desc = _("Updated software is available from "
74+ "a previous check.")
75+ return UpdatesAvailable(self, header, desc)
76
77 def start_install(self):
78 self._start_pane(InstallProgress(self))
79@@ -192,7 +211,7 @@
80
81 def _check_meta_release(self):
82 if self.meta_release is None:
83- return False
84+ return None
85
86 if self.meta_release.downloading:
87 # Block until we get an answer
88@@ -202,22 +221,20 @@
89 # Check if there is anything to upgrade to or a known-broken upgrade
90 next = self.meta_release.upgradable_to
91 if not next or next.upgrade_broken:
92- return False
93+ return None
94
95 # Check for end-of-life
96 if self.meta_release.no_longer_supported:
97- self._start_pane(UnsupportedDialog(self, self.meta_release))
98- return True
99+ return UnsupportedDialog(self, self.meta_release)
100
101 # Check for new fresh release
102 settings = Gio.Settings("com.ubuntu.update-manager")
103 if (self.meta_release.new_dist and
104 (self.options.check_dist_upgrades or
105 settings.get_boolean("check-dist-upgrades"))):
106- self._start_pane(DistUpgradeDialog(self, self.meta_release))
107- return True
108+ return DistUpgradeDialog(self, self.meta_release)
109
110- return False
111+ return None
112
113 def _meta_release_wait_idle(self):
114 # 'downloading' is changed in a thread, but the signal
115
116=== modified file 'UpdateManager/UpdateProgress.py'
117--- UpdateManager/UpdateProgress.py 2012-06-27 22:01:50 +0000
118+++ UpdateManager/UpdateProgress.py 2012-08-24 23:06:30 +0000
119@@ -35,7 +35,6 @@
120 DeprecationWarning)
121
122 import os
123-import sys
124
125 from .backend import get_backend
126
127@@ -72,11 +71,7 @@
128 allow_sleep(self.sleep_dev, self.sleep_cookie)
129 self.sleep_cookie = self.sleep_dev = None
130
131- # Either launch main dialog and continue or quit altogether
132- if success:
133- self.window_main.start_available()
134- else:
135- sys.exit(0)
136+ self.window_main.start_available(not success)
137
138 def main(self):
139 self.invoke_manager()
140
141=== modified file 'UpdateManager/UpdatesAvailable.py'
142--- UpdateManager/UpdatesAvailable.py 2012-06-28 00:09:03 +0000
143+++ UpdateManager/UpdatesAvailable.py 2012-08-24 23:06:30 +0000
144@@ -81,7 +81,7 @@
145
146 class UpdatesAvailable(SimpleGtkbuilderApp):
147
148- def __init__(self, app):
149+ def __init__(self, app, header=None, desc=None):
150 self.window_main = app
151 self.datadir = app.datadir
152 self.options = app.options
153@@ -99,6 +99,9 @@
154 # workaround for LP: #945536
155 self.clearing_store = False
156
157+ self.custom_header = header
158+ self.custom_desc = desc
159+
160 self.button_close.grab_focus()
161 self.dl_size = 0
162 self.connected = True
163@@ -360,9 +363,6 @@
164 Gtk.MenuItem.new_with_mnemonic(_("_Deselect All"))
165 item_select_none.connect("activate", self.select_none_updgrades)
166 menu.append(item_select_none)
167- num_updates = self.cache.install_count
168- if num_updates == 0:
169- item_select_none.set_property("sensitive", False)
170 item_select_all = Gtk.MenuItem.new_with_mnemonic(_("Select _All"))
171 item_select_all.connect("activate", self.select_all_updgrades)
172 menu.append(item_select_all)
173@@ -462,38 +462,38 @@
174 """activate or disable widgets and show dialog texts correspoding to
175 the number of available updates"""
176 self.refresh_updates_count()
177- num_updates = self.cache.install_count
178-
179- if num_updates == 0:
180- text_header = _("The software on this computer is up to date.")
181- self.label_downsize.set_text("\n")
182- if self.cache.keep_count() == 0:
183- self.notebook_details.set_sensitive(False)
184- self.treeview_update.set_sensitive(False)
185- self.button_install.set_sensitive(False)
186- self.unity.set_install_menuitem_visible(False)
187- self.button_close.grab_default()
188- self.textview_changes.get_buffer().set_text("")
189- self.textview_descr.get_buffer().set_text("")
190- else:
191- # show different text on first run (UX team suggestion)
192- firstrun = self.settings.get_boolean("first-run")
193- if firstrun:
194- flavor = self.window_main.meta_release.flavor_name
195- version = self.window_main.meta_release.current_dist_version
196- text_header = _("Updated software has been issued since %s %s "
197- "was released. Do you want to install "
198- "it now?") % (flavor, version)
199- self.settings.set_boolean("first-run", False)
200- else:
201- text_header = _("Updated software is available for this "
202- "computer. Do you want to install it now?")
203- self.notebook_details.set_sensitive(True)
204- self.treeview_update.set_sensitive(True)
205- self.button_install.grab_default()
206- self.treeview_update.set_cursor(Gtk.TreePath.new_from_string("1"),
207- None, False)
208- self.label_header.set_markup(text_header)
209+
210+ text_header = None
211+ text_desc = None
212+
213+ if self.custom_header is not None:
214+ text_header = self.custom_header
215+ text_desc = self.custom_desc
216+ # show different text on first run (UX team suggestion)
217+ elif self.settings.get_boolean("first-run"):
218+ flavor = self.window_main.meta_release.flavor_name
219+ version = self.window_main.meta_release.current_dist_version
220+ text_header = _("Updated software has been issued since %s %s "
221+ "was released. Do you want to install "
222+ "it now?") % (flavor, version)
223+ self.settings.set_boolean("first-run", False)
224+ else:
225+ text_header = _("Updated software is available for this "
226+ "computer. Do you want to install it now?")
227+
228+ self.notebook_details.set_sensitive(True)
229+ self.treeview_update.set_sensitive(True)
230+ self.button_install.grab_default()
231+ self.treeview_update.set_cursor(Gtk.TreePath.new_from_string("1"),
232+ None, False)
233+ self.label_header.set_label(text_header)
234+
235+ if text_desc is not None:
236+ self.label_desc.set_label(text_desc)
237+ self.label_desc.show()
238+ else:
239+ self.label_desc.hide()
240+
241 return True
242
243 # Before we shrink the window, capture the size
244
245=== modified file 'UpdateManager/backend/InstallBackendAptdaemon.py'
246--- UpdateManager/backend/InstallBackendAptdaemon.py 2012-06-28 00:10:23 +0000
247+++ UpdateManager/backend/InstallBackendAptdaemon.py 2012-08-24 23:06:30 +0000
248@@ -125,6 +125,8 @@
249 progressbar_slot.add(progressbar)
250
251 self.button_cancel = AptCancelButton(trans)
252+ if action == self.UPDATE:
253+ self.button_cancel.set_label(Gtk.STOCK_STOP)
254 self.button_cancel.show()
255 button_cancel_slot = builder.get_object("button_cancel_slot")
256 button_cancel_slot.add(self.button_cancel)
257@@ -225,6 +227,7 @@
258 err_dia = AptErrorDialog(trans.error, self.window_main)
259 err_dia.run()
260 err_dia.hide()
261+ sys.exit(0)
262 elif status == EXIT_SUCCESS and close_on_done:
263 sys.exit(0)
264 # tell unity to hide the progress again
265
266=== modified file 'data/gtkbuilder/UpdateManager.ui'
267--- data/gtkbuilder/UpdateManager.ui 2012-06-18 21:14:43 +0000
268+++ data/gtkbuilder/UpdateManager.ui 2012-08-24 23:06:30 +0000
269@@ -40,16 +40,47 @@
270 </packing>
271 </child>
272 <child>
273- <object class="GtkLabel" id="label_header">
274+ <object class="GtkGrid" id="grid1">
275 <property name="visible">True</property>
276 <property name="can_focus">False</property>
277- <property name="xalign">0</property>
278- <property name="use_underline">True</property>
279- <property name="wrap">True</property>
280- <attributes>
281- <attribute name="weight" value="bold"/>
282- <attribute name="scale" value="1.25"/>
283- </attributes>
284+ <property name="margin_bottom">6</property>
285+ <property name="row_spacing">6</property>
286+ <property name="column_spacing">12</property>
287+ <child>
288+ <object class="GtkLabel" id="label_header">
289+ <property name="visible">True</property>
290+ <property name="can_focus">False</property>
291+ <property name="hexpand">True</property>
292+ <property name="xalign">0</property>
293+ <property name="wrap">True</property>
294+ <attributes>
295+ <attribute name="weight" value="bold"/>
296+ <attribute name="scale" value="1.25"/>
297+ </attributes>
298+ </object>
299+ <packing>
300+ <property name="left_attach">0</property>
301+ <property name="top_attach">0</property>
302+ <property name="width">1</property>
303+ <property name="height">1</property>
304+ </packing>
305+ </child>
306+ <child>
307+ <object class="GtkLabel" id="label_desc">
308+ <property name="can_focus">False</property>
309+ <property name="no_show_all">True</property>
310+ <property name="hexpand">True</property>
311+ <property name="xalign">0</property>
312+ <property name="wrap">True</property>
313+ <property name="max_width_chars">20</property>
314+ </object>
315+ <packing>
316+ <property name="left_attach">0</property>
317+ <property name="top_attach">1</property>
318+ <property name="width">1</property>
319+ <property name="height">1</property>
320+ </packing>
321+ </child>
322 </object>
323 <packing>
324 <property name="expand">False</property>
325@@ -462,8 +493,8 @@
326 <property name="receives_default">True</property>
327 <property name="use_action_appearance">False</property>
328 <property name="use_stock">True</property>
329+ <accelerator key="Q" signal="clicked" modifiers="GDK_CONTROL_MASK"/>
330 <accelerator key="W" signal="clicked" modifiers="GDK_CONTROL_MASK"/>
331- <accelerator key="Q" signal="clicked" modifiers="GDK_CONTROL_MASK"/>
332 </object>
333 <packing>
334 <property name="expand">False</property>
335
336=== added file 'tests/test_stop_update.py'
337--- tests/test_stop_update.py 1970-01-01 00:00:00 +0000
338+++ tests/test_stop_update.py 2012-08-24 23:06:30 +0000
339@@ -0,0 +1,50 @@
340+#!/usr/bin/python3
341+# -*- Mode: Python; indent-tabs-mode: nil; tab-width: 4; coding: utf-8 -*-
342+
343+import logging
344+import sys
345+import unittest
346+from mock import patch
347+
348+from UpdateManager.UpdateManager import UpdateManager
349+from UpdateManager.UpdatesAvailable import UpdatesAvailable
350+from UpdateManager import Dialogs
351+
352+import os
353+CURDIR = os.path.dirname(os.path.abspath(__file__))
354+
355+
356+class TestStopUpdate(unittest.TestCase):
357+
358+ def setUp(self):
359+ patcher = patch('UpdateManager.UpdateManager.UpdateManager')
360+ self.addCleanup(patcher.stop)
361+ self.manager = patcher.start()
362+ self.manager._check_meta_release.return_value = False
363+ self.manager.datadir = os.path.join(CURDIR, '..', 'data')
364+
365+ def test_stop_no_updates(self):
366+ # install_count, need_reboot, cancelled_update
367+ p = UpdateManager._make_available_pane(self.manager, 0, False, True)
368+ self.assertIsInstance(p, Dialogs.StoppedUpdatesDialog)
369+
370+ def test_no_stop_no_updates(self):
371+ # install_count, need_reboot, cancelled_update
372+ p = UpdateManager._make_available_pane(self.manager, 0, False, False)
373+ self.assertNotIsInstance(p, Dialogs.StoppedUpdatesDialog)
374+
375+ def test_stop_updates(self):
376+ # install_count, need_reboot, cancelled_update
377+ p = UpdateManager._make_available_pane(self.manager, 1, False, True)
378+ self.assertIsInstance(p, UpdatesAvailable)
379+ self.assertIsNotNone(p.custom_header)
380+
381+ def test_no_stop_updates(self):
382+ p = UpdateManager._make_available_pane(self.manager, 1, False, False)
383+ self.assertIsInstance(p, UpdatesAvailable)
384+ self.assertIsNone(p.custom_header)
385+
386+if __name__ == '__main__':
387+ if len(sys.argv) > 1 and sys.argv[1] == "-v":
388+ logging.basicConfig(level=logging.DEBUG)
389+ unittest.main()

Subscribers

People subscribed via source and target branches

to status/vote changes: