~ubuntu-core-dev/update-manager/main

2428.3.1 by Michael Terry
bring some of AptDialog from aptdaemon into our code to have more control over its presentation (i.e. stuff the widgets inside of our own main window; split UpdateManager into a central point of control and put old widgets into UpdatesAvailable class
1
# UpdateManager.py
2511.1.8 by Michael Terry
more pep8 fixes
2
# -*- Mode: Python; indent-tabs-mode: nil; tab-width: 4; coding: utf-8 -*-
2511.1.14 by Michael Terry
auto-pep8'd some warnings
3
#
2428.3.1 by Michael Terry
bring some of AptDialog from aptdaemon into our code to have more control over its presentation (i.e. stuff the widgets inside of our own main window; split UpdateManager into a central point of control and put old widgets into UpdatesAvailable class
4
#  Copyright (c) 2012 Canonical
2511.1.14 by Michael Terry
auto-pep8'd some warnings
5
#
2428.3.1 by Michael Terry
bring some of AptDialog from aptdaemon into our code to have more control over its presentation (i.e. stuff the widgets inside of our own main window; split UpdateManager into a central point of control and put old widgets into UpdatesAvailable class
6
#  Author: Michael Terry <michael.terry@canonical.com>
2511.1.14 by Michael Terry
auto-pep8'd some warnings
7
#
8
#  This program is free software; you can redistribute it and/or
9
#  modify it under the terms of the GNU General Public License as
2428.3.1 by Michael Terry
bring some of AptDialog from aptdaemon into our code to have more control over its presentation (i.e. stuff the widgets inside of our own main window; split UpdateManager into a central point of control and put old widgets into UpdatesAvailable class
10
#  published by the Free Software Foundation; either version 2 of the
11
#  License, or (at your option) any later version.
2511.1.14 by Michael Terry
auto-pep8'd some warnings
12
#
2428.3.1 by Michael Terry
bring some of AptDialog from aptdaemon into our code to have more control over its presentation (i.e. stuff the widgets inside of our own main window; split UpdateManager into a central point of control and put old widgets into UpdatesAvailable class
13
#  This program is distributed in the hope that it will be useful,
14
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
15
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
#  GNU General Public License for more details.
2511.1.14 by Michael Terry
auto-pep8'd some warnings
17
#
2428.3.1 by Michael Terry
bring some of AptDialog from aptdaemon into our code to have more control over its presentation (i.e. stuff the widgets inside of our own main window; split UpdateManager into a central point of control and put old widgets into UpdatesAvailable class
18
#  You should have received a copy of the GNU General Public License
19
#  along with this program; if not, write to the Free Software
20
#  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
21
#  USA
22
23
from __future__ import absolute_import, print_function
24
25
from gi.repository import Gtk
2622.1.11 by Dylan McCall
Removed unnecessary resizing of main window during _start_pane.
26
from gi.repository import Gdk, GdkX11
2428.4.5 by Michael Terry
move meta release checking into main UpdateManager class; use dialog panes for those interactions rather than popup dialogs
27
from gi.repository import Gio
28
from gi.repository import GLib
2820 by Mathieu Trudel-Lapierre
Block style context changed signal while enforcing the main window's
29
from gi.repository import GObject
2428.3.1 by Michael Terry
bring some of AptDialog from aptdaemon into our code to have more control over its presentation (i.e. stuff the widgets inside of our own main window; split UpdateManager into a central point of control and put old widgets into UpdatesAvailable class
30
2633 by Martin Pitt
Drop unused imports and assignments to fix pyflakes errors.
31
GdkX11  # pyflakes
32
2428.3.1 by Michael Terry
bring some of AptDialog from aptdaemon into our code to have more control over its presentation (i.e. stuff the widgets inside of our own main window; split UpdateManager into a central point of control and put old widgets into UpdatesAvailable class
33
import warnings
2511.1.8 by Michael Terry
more pep8 fixes
34
warnings.filterwarnings("ignore", "Accessed deprecated property",
35
                        DeprecationWarning)
2428.3.1 by Michael Terry
bring some of AptDialog from aptdaemon into our code to have more control over its presentation (i.e. stuff the widgets inside of our own main window; split UpdateManager into a central point of control and put old widgets into UpdatesAvailable class
36
2727.1.1 by Brian Murray
Include HWE support tools and information. (LP: #1498059)
37
import distro_info
2893.2.1 by Iain Lane
List OEM metapackages
38
import fnmatch
2428.4.4 by Michael Terry
move cache from UpdatesAvailable to UpdateManager; use generic ErrorDialog class in a few places
39
import os
2622.1.1 by Dylan McCall
Defensive coding around package objects in UpdateList and UpdatesAvailable.
40
import subprocess
2428.3.1 by Michael Terry
bring some of AptDialog from aptdaemon into our code to have more control over its presentation (i.e. stuff the widgets inside of our own main window; split UpdateManager into a central point of control and put old widgets into UpdatesAvailable class
41
import sys
2622.1.1 by Dylan McCall
Defensive coding around package objects in UpdateList and UpdatesAvailable.
42
import time
2428.3.1 by Michael Terry
bring some of AptDialog from aptdaemon into our code to have more control over its presentation (i.e. stuff the widgets inside of our own main window; split UpdateManager into a central point of control and put old widgets into UpdatesAvailable class
43
from gettext import gettext as _
2956.1.1 by Robert Ancell
Use uaclient library instead of calling ua tool directly
44
from uaclient.api.u.pro.packages.updates.v1 import updates
2428.3.1 by Michael Terry
bring some of AptDialog from aptdaemon into our code to have more control over its presentation (i.e. stuff the widgets inside of our own main window; split UpdateManager into a central point of control and put old widgets into UpdatesAvailable class
45
46
import dbus
47
import dbus.service
48
from dbus.mainloop.glib import DBusGMainLoop
49
DBusGMainLoop(set_as_default=True)
50
51
from .UnitySupport import UnitySupport
2428.4.5 by Michael Terry
move meta release checking into main UpdateManager class; use dialog panes for those interactions rather than popup dialogs
52
from .Dialogs import (DistUpgradeDialog,
53
                      ErrorDialog,
2727.1.1 by Brian Murray
Include HWE support tools and information. (LP: #1498059)
54
                      HWEUpgradeDialog,
2428.4.5 by Michael Terry
move meta release checking into main UpdateManager class; use dialog panes for those interactions rather than popup dialogs
55
                      NeedRestartDialog,
56
                      NoUpdatesDialog,
2864.1.1 by Brian Murray
UpdateManager/UpdateManager.py: Do not offer to upgrade systems running on
57
                      NoUpgradeForYouDialog,
2727.1.1 by Brian Murray
Include HWE support tools and information. (LP: #1498059)
58
                      PartialUpgradeDialog,
2534.1.1 by Michael Terry
add you-stopped-update dialog
59
                      StoppedUpdatesDialog,
2565.1.1 by Michael Terry
Allow user to continue if an update error occurs
60
                      UnsupportedDialog,
61
                      UpdateErrorDialog)
2428.4.5 by Michael Terry
move meta release checking into main UpdateManager class; use dialog panes for those interactions rather than popup dialogs
62
from .MetaReleaseGObject import MetaRelease
2428.3.1 by Michael Terry
bring some of AptDialog from aptdaemon into our code to have more control over its presentation (i.e. stuff the widgets inside of our own main window; split UpdateManager into a central point of control and put old widgets into UpdatesAvailable class
63
from .UpdatesAvailable import UpdatesAvailable
64
from .Core.AlertWatcher import AlertWatcher
2428.4.4 by Michael Terry
move cache from UpdatesAvailable to UpdateManager; use generic ErrorDialog class in a few places
65
from .Core.MyCache import MyCache
2428.3.1 by Michael Terry
bring some of AptDialog from aptdaemon into our code to have more control over its presentation (i.e. stuff the widgets inside of our own main window; split UpdateManager into a central point of control and put old widgets into UpdatesAvailable class
66
from .Core.roam import NetworkManagerHelper
2428.4.4 by Michael Terry
move cache from UpdatesAvailable to UpdateManager; use generic ErrorDialog class in a few places
67
from .Core.UpdateList import UpdateList
2864.1.1 by Brian Murray
UpdateManager/UpdateManager.py: Do not offer to upgrade systems running on
68
from .Core.utils import get_arch, get_dist
2622.1.12 by Dylan McCall
Put back the "backend" module. It wasn't necessary to move it in this branch.
69
from .backend import (InstallBackend,
70
                      get_backend)
2428.3.1 by Michael Terry
bring some of AptDialog from aptdaemon into our code to have more control over its presentation (i.e. stuff the widgets inside of our own main window; split UpdateManager into a central point of control and put old widgets into UpdatesAvailable class
71
2428.4.1 by Michael Terry
add basic support for no-updates-needed and restart-needed dialogs
72
# file that signals if we need to reboot
73
REBOOT_REQUIRED_FILE = "/var/run/reboot-required"
74
2511.1.8 by Michael Terry
more pep8 fixes
75
2428.3.1 by Michael Terry
bring some of AptDialog from aptdaemon into our code to have more control over its presentation (i.e. stuff the widgets inside of our own main window; split UpdateManager into a central point of control and put old widgets into UpdatesAvailable class
76
class UpdateManager(Gtk.Window):
2622.1.7 by Dylan McCall
Every GUI component is now a Dialog subclass, inserted as a widget into the main window, by the main window.
77
    """ This class is the main window and work flow controller. The main
78
        window will show panes, and it will morph between them. """
2511.1.8 by Michael Terry
more pep8 fixes
79
80
    def __init__(self, datadir, options):
81
        Gtk.Window.__init__(self)
82
83
        # Public members
84
        self.datadir = datadir
85
        self.options = options
86
        self.unity = UnitySupport()
87
        self.controller = None
88
        self.cache = None
2947.1.5 by Robert Ancell
Get package list from ua security-status
89
        self.ua_security_packages = []
2511.1.8 by Michael Terry
more pep8 fixes
90
        self.update_list = None
91
        self.meta_release = None
2727.1.1 by Brian Murray
Include HWE support tools and information. (LP: #1498059)
92
        self.hwe_replacement_packages = None
2893.2.1 by Iain Lane
List OEM metapackages
93
        self.oem_metapackages = set()
2875.1.1 by Marcus Tomlinson
Fix TypeError crash in update()
94
        self.duplicate_packages = []
2864.1.1 by Brian Murray
UpdateManager/UpdateManager.py: Do not offer to upgrade systems running on
95
        self.arch = get_arch()
2511.1.8 by Michael Terry
more pep8 fixes
96
97
        # Basic GTK+ parameters
98
        self.set_title(_("Software Updater"))
99
        self.set_icon_name("system-software-update")
100
        self.set_position(Gtk.WindowPosition.CENTER)
2568.1.1 by Michael Terry
Keep dialog width at 33em
101
102
        # Keep window at a constant size
103
        ctx = self.get_style_context()
2820 by Mathieu Trudel-Lapierre
Block style context changed signal while enforcing the main window's
104
        self.style_changed = ctx.connect("changed",
105
                                         lambda ctx:
106
                                             self.resize_to_standard_width())
2511.1.8 by Michael Terry
more pep8 fixes
107
108
        # Signals
2622.1.8 by Dylan McCall
Fixed broken close buttons and certain dialogs failing to initialize.
109
        self.connect("delete-event", self._on_close)
2511.1.8 by Michael Terry
more pep8 fixes
110
111
        self._setup_dbus()
112
113
        # deal with no-focus-on-map
114
        if self.options and self.options.no_focus_on_map:
115
            self.set_focus_on_map(False)
116
            self.iconify()
117
            self.stick()
118
            self.set_urgency_hint(True)
119
            self.unity.set_urgency(True)
120
            self.initial_focus_id = self.connect(
121
                "focus-in-event", self.on_initial_focus_in)
122
123
        # Look for a new release in a thread
124
        self.meta_release = MetaRelease(
125
            self.options and self.options.devel_release,
2933 by Brian Murray
If --debug is used on the command line pass it along to the metarelease
126
            self.options and self.options.use_proposed,
127
            self.options and self.options.debug)
2511.1.8 by Michael Terry
more pep8 fixes
128
2622.1.7 by Dylan McCall
Every GUI component is now a Dialog subclass, inserted as a widget into the main window, by the main window.
129
    def begin_user_resizable(self, stored_width=0, stored_height=0):
130
        self.set_resizable(True)
131
        if stored_width > 0 and stored_height > 0:
132
            # There is a race here.  If we immediately resize, it often doesn't
133
            # take.  Using idle_add helps, but we *still* occasionally don't
134
            # restore the size correctly.  Help needed to track this down!
135
            GLib.idle_add(lambda: self.resize(stored_width, stored_height))
136
137
    def end_user_resizable(self):
138
        self.set_resizable(False)
139
2568.1.1 by Michael Terry
Keep dialog width at 33em
140
    def resize_to_standard_width(self):
141
        if self.get_resizable():
142
            return  # only size to a specific em if we are a static size
143
        num_em = 33  # per SoftwareUpdates spec
144
        dpi = self.get_screen().get_resolution()
145
        if dpi <= 0:
146
            dpi = 96
147
        ctx = self.get_style_context()
2823 by Mathieu Trudel-Lapierre
Fix my spelling mistake in the previous upload. Oops.
148
        GObject.signal_handler_block(ctx, self.style_changed)
2568.1.1 by Michael Terry
Keep dialog width at 33em
149
        size = ctx.get_property("font-size", Gtk.StateFlags.NORMAL)
150
        width = dpi / 72 * size * num_em
151
        self.set_size_request(width, -1)
2823 by Mathieu Trudel-Lapierre
Fix my spelling mistake in the previous upload. Oops.
152
        GObject.signal_handler_unblock(ctx, self.style_changed)
2568.1.1 by Michael Terry
Keep dialog width at 33em
153
2511.1.8 by Michael Terry
more pep8 fixes
154
    def on_initial_focus_in(self, widget, event):
155
        """callback run on initial focus-in (if started unmapped)"""
156
        self.unstick()
157
        self.set_urgency_hint(False)
158
        self.unity.set_urgency(False)
159
        self.disconnect(self.initial_focus_id)
160
        return False
161
2622.1.7 by Dylan McCall
Every GUI component is now a Dialog subclass, inserted as a widget into the main window, by the main window.
162
    def _start_pane(self, pane):
163
        if self.controller is not None:
164
            self.controller.stop()
165
            if isinstance(self.controller, Gtk.Widget):
166
                self.controller.destroy()
167
168
        self.controller = pane
169
        self._look_ready()
2622.1.11 by Dylan McCall
Removed unnecessary resizing of main window during _start_pane.
170
        self.end_user_resizable()
2511.1.8 by Michael Terry
more pep8 fixes
171
172
        if pane is None:
173
            return
174
2622.1.7 by Dylan McCall
Every GUI component is now a Dialog subclass, inserted as a widget into the main window, by the main window.
175
        if isinstance(pane, Gtk.Widget):
176
            self.add(pane)
2622.1.11 by Dylan McCall
Removed unnecessary resizing of main window during _start_pane.
177
            pane.start()
2622.1.10 by Dylan McCall
Removing ill-advised WrapLabel widget. Restored original behaviour for text wrapping in heading and description labels.
178
            self.show_all()
179
        else:
2622.1.11 by Dylan McCall
Removed unnecessary resizing of main window during _start_pane.
180
            pane.start()
2622.1.10 by Dylan McCall
Removing ill-advised WrapLabel widget. Restored original behaviour for text wrapping in heading and description labels.
181
            self.hide()
2511.1.8 by Michael Terry
more pep8 fixes
182
2622.1.8 by Dylan McCall
Fixed broken close buttons and certain dialogs failing to initialize.
183
    def _on_close(self, widget, data=None):
2691 by Michael Vogt
UpdateManager/UpdateManager.py: _on_close() should return the value to make
184
        return self.close()
2622.1.8 by Dylan McCall
Fixed broken close buttons and certain dialogs failing to initialize.
185
186
    def close(self):
2511.1.8 by Michael Terry
more pep8 fixes
187
        if not self.get_sensitive():
188
            return True
189
2658.1.1 by Sebastien Bacher
check if there is a controller before using it
190
        if self.controller:
191
            controller_close = self.controller.close()
192
            if controller_close:
193
                return controller_close
2511.1.8 by Michael Terry
more pep8 fixes
194
        self.exit()
195
196
    def exit(self):
197
        """ exit the application, save the state """
2622.1.7 by Dylan McCall
Every GUI component is now a Dialog subclass, inserted as a widget into the main window, by the main window.
198
        self._start_pane(None)
2428.3.1 by Michael Terry
bring some of AptDialog from aptdaemon into our code to have more control over its presentation (i.e. stuff the widgets inside of our own main window; split UpdateManager into a central point of control and put old widgets into UpdatesAvailable class
199
        sys.exit(0)
2511.1.8 by Michael Terry
more pep8 fixes
200
2622.1.1 by Dylan McCall
Defensive coding around package objects in UpdateList and UpdatesAvailable.
201
    def show_settings(self):
202
        cmd = ["/usr/bin/software-properties-gtk",
2786 by Brian Murray
UpdateManager.py: Workaround a crash when calling software-properties-gtk
203
               "--open-tab", "2"]
204
205
        if "WAYLAND_DISPLAY" not in os.environ:
206
            cmd += ["--toplevel", "%s" % self.get_window().get_xid()]
207
2622.1.2 by Dylan McCall
UpdatesAvailable is now a Dialog subclass.
208
        self._look_busy()
2622.1.1 by Dylan McCall
Defensive coding around package objects in UpdateList and UpdatesAvailable.
209
        try:
210
            p = subprocess.Popen(cmd)
211
        except OSError:
212
            pass
213
        else:
214
            while p.poll() is None:
215
                while Gtk.events_pending():
216
                    Gtk.main_iteration()
217
                time.sleep(0.05)
218
        finally:
219
            self.start_available()
220
2511.1.8 by Michael Terry
more pep8 fixes
221
    def start_update(self):
222
        if self.options.no_update:
223
            self.start_available()
224
            return
225
2622.1.7 by Dylan McCall
Every GUI component is now a Dialog subclass, inserted as a widget into the main window, by the main window.
226
        update_backend = get_backend(self, InstallBackend.ACTION_UPDATE)
227
        self._start_pane(update_backend)
228
2727.1.1 by Brian Murray
Include HWE support tools and information. (LP: #1498059)
229
    def start_install(self, hwe_upgrade=False):
2893.2.1 by Iain Lane
List OEM metapackages
230
        install_backend = get_backend(self, InstallBackend.ACTION_PRE_INSTALL)
2727.1.1 by Brian Murray
Include HWE support tools and information. (LP: #1498059)
231
        if hwe_upgrade:
232
            for pkgname in self.hwe_replacement_packages:
2734 by Brian Murray
UpdateManager/UpdateManager.py: when marking HWE packages for install pass
233
                try:
234
                    self.cache[pkgname].mark_install()
235
                except SystemError:
236
                    pass
2622.1.7 by Dylan McCall
Every GUI component is now a Dialog subclass, inserted as a widget into the main window, by the main window.
237
        self._start_pane(install_backend)
2511.1.8 by Michael Terry
more pep8 fixes
238
2568 by Michael Terry
whoops, fix typo in error-during-update branch that caused us to show a warning more often than needed
239
    def start_available(self, cancelled_update=False, error_occurred=False):
2511.1.8 by Michael Terry
more pep8 fixes
240
        self._look_busy()
241
        self.refresh_cache()
242
2887.1.1 by Brian Murray
UpdateManager/UpdateManager.py: when refreshing the cache and encountering
243
        if self.cache is None:
244
            return
245
2865 by Marcus Tomlinson
UpdateManager/backend/__init__.py: once apt upgrade completes, use the deb2snap.json file from ubuntu-release-upgrader to perform snap updates.
246
        pane = self._make_available_pane(self.cache.install_count
247
                                         + self.cache.del_count,
2534.1.5 by Michael Terry
adjust code to make the UpdateManager class slightly easier to unit test; add tests for stop-update code
248
                                         os.path.exists(REBOOT_REQUIRED_FILE),
2565.1.1 by Michael Terry
Allow user to continue if an update error occurs
249
                                         cancelled_update, error_occurred)
2534.1.5 by Michael Terry
adjust code to make the UpdateManager class slightly easier to unit test; add tests for stop-update code
250
        self._start_pane(pane)
251
2893.2.1 by Iain Lane
List OEM metapackages
252
    def _check_oem_metapackages(self):
253
        di = distro_info.UbuntuDistroInfo()
254
        codename = get_dist()
255
        lts = di.is_lts(codename)
256
        if not lts:
257
            return None
258
        OEM_PATH = os.path.join(GLib.get_user_runtime_dir(),
259
                                "ubuntu-drivers-oem.package-list")
260
        if not os.path.exists(OEM_PATH):
261
            return None
262
263
        # Packages that aren't installed but apply to this system
264
        with open(OEM_PATH, 'r') as f:
265
            self.oem_metapackages |= set(f.read().splitlines())
266
267
        # Packages that are already installed
268
        for pkg in self.cache:
269
            if fnmatch.fnmatch(pkg.name, 'oem-*-meta') \
270
               and pkg.installed:
271
                self.oem_metapackages.add(pkg)
272
2947.1.5 by Robert Ancell
Get package list from ua security-status
273
    def _get_ua_security_status(self):
274
        self.ua_security_packages = []
2956.1.1 by Robert Ancell
Use uaclient library instead of calling ua tool directly
275
        update_result = updates()
276
        for info in update_result.updates:
277
            if info.status == 'pending_attach':
278
                self.ua_security_packages.append((info.name, info.version, info.download_size))
2947.1.5 by Robert Ancell
Get package list from ua security-status
279
2565.1.1 by Michael Terry
Allow user to continue if an update error occurs
280
    def _make_available_pane(self, install_count, need_reboot=False,
281
                             cancelled_update=False, error_occurred=False):
2727.1.1 by Brian Murray
Include HWE support tools and information. (LP: #1498059)
282
        self._check_hwe_support_status()
2534.1.5 by Michael Terry
adjust code to make the UpdateManager class slightly easier to unit test; add tests for stop-update code
283
        if install_count == 0:
2522.1.1 by Michael Terry
Update package cache and unity badge before showing restart-needed dialog
284
            # Need Restart > New Release > No Updates
2534.1.5 by Michael Terry
adjust code to make the UpdateManager class slightly easier to unit test; add tests for stop-update code
285
            if need_reboot:
286
                return NeedRestartDialog(self)
2727.1.1 by Brian Murray
Include HWE support tools and information. (LP: #1498059)
287
            dist_upgrade = self._check_meta_release()
288
            if dist_upgrade:
289
                return dist_upgrade
2534.1.5 by Michael Terry
adjust code to make the UpdateManager class slightly easier to unit test; add tests for stop-update code
290
            elif cancelled_update:
291
                return StoppedUpdatesDialog(self)
2727.1.1 by Brian Murray
Include HWE support tools and information. (LP: #1498059)
292
            elif self.hwe_replacement_packages:
293
                return HWEUpgradeDialog(self)
2534.1.5 by Michael Terry
adjust code to make the UpdateManager class slightly easier to unit test; add tests for stop-update code
294
            else:
2565.1.1 by Michael Terry
Allow user to continue if an update error occurs
295
                return NoUpdatesDialog(self, error_occurred=error_occurred)
2511.1.8 by Michael Terry
more pep8 fixes
296
        else:
2534.1.1 by Michael Terry
add you-stopped-update dialog
297
            header = None
298
            desc = None
2565.1.1 by Michael Terry
Allow user to continue if an update error occurs
299
            if error_occurred:
300
                desc = _("Some software couldn’t be checked for updates.")
301
            elif cancelled_update:
2534.1.1 by Michael Terry
add you-stopped-update dialog
302
                header = _("You stopped the check for updates.")
303
                desc = _("Updated software is available from "
304
                         "a previous check.")
2727.1.1 by Brian Murray
Include HWE support tools and information. (LP: #1498059)
305
            # Display HWE updates first as an old HWE stack is vulnerable
306
            elif self.hwe_replacement_packages:
307
                return HWEUpgradeDialog(self)
2664 by Marc Deslauriers
* Allow user to close the restart required dialog (LP: #1033226)
308
            return UpdatesAvailable(self, header, desc, need_reboot)
2511.1.8 by Michael Terry
more pep8 fixes
309
2835.1.1 by Balint Reczey
Print transaction error and let the user try again applying updates
310
    def start_error(self, update_and_retry, header, desc):
311
        if update_and_retry:
2565.1.1 by Michael Terry
Allow user to continue if an update error occurs
312
            self._start_pane(UpdateErrorDialog(self, header, desc))
313
        else:
314
            self._start_pane(ErrorDialog(self, header, desc))
2511.1.8 by Michael Terry
more pep8 fixes
315
316
    def _look_busy(self):
317
        self.set_sensitive(False)
318
        if self.get_window() is not None:
319
            self.get_window().set_cursor(Gdk.Cursor.new(Gdk.CursorType.WATCH))
320
2622.1.2 by Dylan McCall
UpdatesAvailable is now a Dialog subclass.
321
    def _look_ready(self):
322
        self.set_sensitive(True)
323
        if self.get_window() is not None:
324
            self.get_window().set_cursor(None)
325
            self.get_window().set_functions(Gdk.WMFunction.ALL)
326
2511.1.8 by Michael Terry
more pep8 fixes
327
    def _check_meta_release(self):
328
        if self.meta_release is None:
2534.1.5 by Michael Terry
adjust code to make the UpdateManager class slightly easier to unit test; add tests for stop-update code
329
            return None
2511.1.8 by Michael Terry
more pep8 fixes
330
331
        if self.meta_release.downloading:
332
            # Block until we get an answer
333
            GLib.idle_add(self._meta_release_wait_idle)
334
            Gtk.main()
335
336
        # Check if there is anything to upgrade to or a known-broken upgrade
337
        next = self.meta_release.upgradable_to
338
        if not next or next.upgrade_broken:
2534.1.5 by Michael Terry
adjust code to make the UpdateManager class slightly easier to unit test; add tests for stop-update code
339
            return None
2511.1.8 by Michael Terry
more pep8 fixes
340
341
        # Check for end-of-life
342
        if self.meta_release.no_longer_supported:
2534.1.5 by Michael Terry
adjust code to make the UpdateManager class slightly easier to unit test; add tests for stop-update code
343
            return UnsupportedDialog(self, self.meta_release)
2511.1.8 by Michael Terry
more pep8 fixes
344
345
        # Check for new fresh release
2662 by Martin Pitt
Stop using deprecated GObject constructors with positional arguments
346
        settings = Gio.Settings.new("com.ubuntu.update-manager")
2841.1.1 by Balint Reczey
Ignore PEP 8 W503 instead of E502 and drop many added backslashes
347
        if (self.meta_release.new_dist
348
                and (self.options.check_dist_upgrades
2840.1.1 by Balint Reczey
Fix PEP 8 warnings
349
                     or settings.get_boolean("check-dist-upgrades"))):
2864.1.1 by Brian Murray
UpdateManager/UpdateManager.py: Do not offer to upgrade systems running on
350
            if self.arch == 'i386':
351
                return NoUpgradeForYouDialog(self, self.meta_release,
352
                                             self.arch)
2534.1.5 by Michael Terry
adjust code to make the UpdateManager class slightly easier to unit test; add tests for stop-update code
353
            return DistUpgradeDialog(self, self.meta_release)
2511.1.8 by Michael Terry
more pep8 fixes
354
2534.1.5 by Michael Terry
adjust code to make the UpdateManager class slightly easier to unit test; add tests for stop-update code
355
        return None
2511.1.8 by Michael Terry
more pep8 fixes
356
357
    def _meta_release_wait_idle(self):
358
        # 'downloading' is changed in a thread, but the signal
359
        # 'done_downloading' is done in our thread's event loop.  So we know
360
        # that it won't fire while we're in this function.
361
        if not self.meta_release.downloading:
362
            Gtk.main_quit()
363
        else:
364
            self.meta_release.connect("done_downloading", Gtk.main_quit)
365
        return False
366
2727.1.1 by Brian Murray
Include HWE support tools and information. (LP: #1498059)
367
    def _check_hwe_support_status(self):
368
        di = distro_info.UbuntuDistroInfo()
369
        codename = get_dist()
370
        lts = di.is_lts(codename)
371
        if not lts:
372
            return None
373
        HWE = "/usr/bin/hwe-support-status"
374
        if not os.path.exists(HWE):
375
            return None
376
        cmd = [HWE, "--show-replacements"]
377
        self._parse_hwe_support_status(cmd)
378
379
    def _parse_hwe_support_status(self, cmd):
380
        try:
381
            subprocess.check_output(cmd)
382
            # for debugging
383
            # print("nothing unsupported running")
384
        except subprocess.CalledProcessError as e:
385
            if e.returncode == 10:
386
                packages = e.output.strip().split()
387
                self.hwe_replacement_packages = []
388
                for pkgname in packages:
389
                    pkgname = pkgname.decode('utf-8')
2775 by Brian Murray
Fix a bunch of pep8 related errors.
390
                    if pkgname in self.cache and \
391
                            not self.cache[pkgname].is_installed:
2727.1.1 by Brian Murray
Include HWE support tools and information. (LP: #1498059)
392
                        self.hwe_replacement_packages.append(pkgname)
393
                # for debugging
394
                # print(self.hwe_replacement_packages)
395
2511.1.8 by Michael Terry
more pep8 fixes
396
    # fixme: we should probably abstract away all the stuff from libapt
397
    def refresh_cache(self):
398
        try:
399
            if self.cache is None:
400
                self.cache = MyCache(None)
401
            else:
402
                self.cache.open(None)
403
                self.cache._initDepCache()
404
        except AssertionError:
405
            # if the cache could not be opened for some reason,
406
            # let the release upgrader handle it, it deals
407
            # a lot better with this
408
            self._start_pane(PartialUpgradeDialog(self))
409
            # we assert a clean cache
410
            header = _("Software index is broken")
411
            desc = _("It is impossible to install or remove any software. "
412
                     "Please use the package manager \"Synaptic\" or run "
413
                     "\"sudo apt-get install -f\" in a terminal to fix "
414
                     "this issue at first.")
2887.1.1 by Brian Murray
UpdateManager/UpdateManager.py: when refreshing the cache and encountering
415
            self.start_error(False, header, desc)
416
            return
2511.1.8 by Michael Terry
more pep8 fixes
417
        except SystemError as e:
418
            header = _("Could not initialize the package information")
419
            desc = _("An unresolvable problem occurred while "
420
                     "initializing the package information.\n\n"
421
                     "Please report this bug against the 'update-manager' "
2537 by Michael Terry
fix a couple of pep8 errors
422
                     "package and include the following error "
423
                     "message:\n") + str(e)
2887.1.1 by Brian Murray
UpdateManager/UpdateManager.py: when refreshing the cache and encountering
424
            self.start_error(False, header, desc)
425
            return
2511.1.8 by Michael Terry
more pep8 fixes
426
427
        # Let the Gtk event loop breath if it hasn't had a chance.
2613.1.1 by Michael Terry
Allow Gtk loop to iterate when we're calculating all the dependencies for updates
428
        def iterate():
429
            while Gtk.events_pending():
430
                Gtk.main_iteration()
431
        iterate()
2511.1.8 by Michael Terry
more pep8 fixes
432
2893.2.1 by Iain Lane
List OEM metapackages
433
        self._check_oem_metapackages()
434
2947.1.5 by Robert Ancell
Get package list from ua security-status
435
        self._get_ua_security_status()
436
2893.2.1 by Iain Lane
List OEM metapackages
437
        for pkgname in self.oem_metapackages:
438
            try:
439
                if not self.cache[pkgname].is_installed:
440
                    self.cache[pkgname].mark_install()
441
            except SystemError:
442
                pass
443
2511.1.8 by Michael Terry
more pep8 fixes
444
        self.update_list = UpdateList(self)
445
        try:
2865 by Marcus Tomlinson
UpdateManager/backend/__init__.py: once apt upgrade completes, use the deb2snap.json file from ubuntu-release-upgrader to perform snap updates.
446
            self.update_list.update(self.cache, eventloop_callback=iterate,
2953 by Steve Langasek
Fix autopkgtest regressions.
447
                                    duplicate_packages=self.duplicate_packages,
448
                                    ua_security_packages=self.
449
                                    ua_security_packages)
2511.1.8 by Michael Terry
more pep8 fixes
450
        except SystemError as e:
451
            header = _("Could not calculate the upgrade")
452
            desc = _("An unresolvable problem occurred while "
453
                     "calculating the upgrade.\n\n"
454
                     "Please report this bug against the 'update-manager' "
2537 by Michael Terry
fix a couple of pep8 errors
455
                     "package and include the following error "
456
                     "message:\n") + str(e)
2587 by Michael Terry
Fix some calls to start_error to add an extra required argument; these calls must have been missed before
457
            self.start_error(True, header, desc)
2511.1.8 by Michael Terry
more pep8 fixes
458
459
        if self.update_list.distUpgradeWouldDelete > 0:
460
            self._start_pane(PartialUpgradeDialog(self))
461
462
    def _setup_dbus(self):
2727.1.1 by Brian Murray
Include HWE support tools and information. (LP: #1498059)
463
        """ this sets up a dbus listener if none is installed already """
2511.1.8 by Michael Terry
more pep8 fixes
464
        # check if there is another g-a-i already and if not setup one
465
        # listening on dbus
466
        try:
467
            bus = dbus.SessionBus()
2853 by Brian Murray
debian/tests/control: really use pyflakes3 instead of pyflakes,
468
        except Exception:
2511.1.8 by Michael Terry
more pep8 fixes
469
            print("warning: could not initiate dbus")
470
            return
471
        try:
2511.1.14 by Michael Terry
auto-pep8'd some warnings
472
            proxy_obj = bus.get_object('org.freedesktop.UpdateManager',
2511.1.8 by Michael Terry
more pep8 fixes
473
                                       '/org/freedesktop/UpdateManagerObject')
474
            iface = dbus.Interface(proxy_obj,
475
                                   'org.freedesktop.UpdateManagerIFace')
476
            iface.bringToFront()
477
            #print("send bringToFront")
478
            sys.exit(0)
479
        except dbus.DBusException:
480
            #print("no listening object (%s) " % e)
481
            bus_name = dbus.service.BusName('org.freedesktop.UpdateManager',
482
                                            bus)
483
            self.dbusController = UpdateManagerDbusController(self, bus_name)
2428.3.1 by Michael Terry
bring some of AptDialog from aptdaemon into our code to have more control over its presentation (i.e. stuff the widgets inside of our own main window; split UpdateManager into a central point of control and put old widgets into UpdatesAvailable class
484
485
486
class UpdateManagerDbusController(dbus.service.Object):
487
    """ this is a helper to provide the UpdateManagerIFace """
488
    def __init__(self, parent, bus_name,
489
                 object_path='/org/freedesktop/UpdateManagerObject'):
490
        dbus.service.Object.__init__(self, bus_name, object_path)
491
        self.parent = parent
2511.1.8 by Michael Terry
more pep8 fixes
492
        self.alert_watcher = AlertWatcher()
2428.3.1 by Michael Terry
bring some of AptDialog from aptdaemon into our code to have more control over its presentation (i.e. stuff the widgets inside of our own main window; split UpdateManager into a central point of control and put old widgets into UpdatesAvailable class
493
        self.alert_watcher.connect("network-alert", self._on_network_alert)
494
        self.connected = False
495
496
    @dbus.service.method('org.freedesktop.UpdateManagerIFace')
497
    def bringToFront(self):
498
        self.parent.present()
499
        return True
500
501
    @dbus.service.method('org.freedesktop.UpdateManagerIFace')
502
    def upgrade(self):
503
        try:
504
            self.parent.start_install()
505
            return True
2853 by Brian Murray
debian/tests/control: really use pyflakes3 instead of pyflakes,
506
        except Exception:
2428.3.1 by Michael Terry
bring some of AptDialog from aptdaemon into our code to have more control over its presentation (i.e. stuff the widgets inside of our own main window; split UpdateManager into a central point of control and put old widgets into UpdatesAvailable class
507
            return False
508
509
    def _on_network_alert(self, watcher, state):
510
        if state in NetworkManagerHelper.NM_STATE_CONNECTED_LIST:
511
            self.connected = True
512
        else:
513
            self.connected = False