~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
2947.1.5 by Robert Ancell
Get package list from ua security-status
39
import json
2428.4.4 by Michael Terry
move cache from UpdatesAvailable to UpdateManager; use generic ErrorDialog class in a few places
40
import os
2622.1.1 by Dylan McCall
Defensive coding around package objects in UpdateList and UpdatesAvailable.
41
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
42
import sys
2622.1.1 by Dylan McCall
Defensive coding around package objects in UpdateList and UpdatesAvailable.
43
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
44
from gettext import gettext as _
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 = []
275
        try:
2957 by Sebastien Bacher
Update of the parsing for pro client changes
276
            p = subprocess.Popen(['pro', 'security-status', '--format=json'],
2953 by Steve Langasek
Fix autopkgtest regressions.
277
                                 stdout=subprocess.PIPE)
2947.1.5 by Robert Ancell
Get package list from ua security-status
278
        except OSError:
279
            pass
280
        else:
281
            while p.poll() is None:
282
                while Gtk.events_pending():
283
                    Gtk.main_iteration()
284
                time.sleep(0.05)
2947.1.13 by Robert Ancell
Use json.load instead of json.loads
285
            s = json.load(p.stdout)
2947.1.6 by Robert Ancell
Only show packages pending attach
286
            for package in s.get('packages', []):
287
                status = package.get('status', '')
288
                if status == 'pending_attach':
2957 by Sebastien Bacher
Update of the parsing for pro client changes
289
                    name = package.get('package', '')
2947.1.6 by Robert Ancell
Only show packages pending attach
290
                    version = package.get('version', '')
2953 by Steve Langasek
Fix autopkgtest regressions.
291
                    size = package.get('download_size', 0)
2947.1.7 by Robert Ancell
Add size to UA packages
292
                    self.ua_security_packages.append((name, version, size))
2947.1.5 by Robert Ancell
Get package list from ua security-status
293
2565.1.1 by Michael Terry
Allow user to continue if an update error occurs
294
    def _make_available_pane(self, install_count, need_reboot=False,
295
                             cancelled_update=False, error_occurred=False):
2727.1.1 by Brian Murray
Include HWE support tools and information. (LP: #1498059)
296
        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
297
        if install_count == 0:
2522.1.1 by Michael Terry
Update package cache and unity badge before showing restart-needed dialog
298
            # 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
299
            if need_reboot:
300
                return NeedRestartDialog(self)
2727.1.1 by Brian Murray
Include HWE support tools and information. (LP: #1498059)
301
            dist_upgrade = self._check_meta_release()
302
            if dist_upgrade:
303
                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
304
            elif cancelled_update:
305
                return StoppedUpdatesDialog(self)
2727.1.1 by Brian Murray
Include HWE support tools and information. (LP: #1498059)
306
            elif self.hwe_replacement_packages:
307
                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
308
            else:
2565.1.1 by Michael Terry
Allow user to continue if an update error occurs
309
                return NoUpdatesDialog(self, error_occurred=error_occurred)
2511.1.8 by Michael Terry
more pep8 fixes
310
        else:
2534.1.1 by Michael Terry
add you-stopped-update dialog
311
            header = None
312
            desc = None
2565.1.1 by Michael Terry
Allow user to continue if an update error occurs
313
            if error_occurred:
314
                desc = _("Some software couldn’t be checked for updates.")
315
            elif cancelled_update:
2534.1.1 by Michael Terry
add you-stopped-update dialog
316
                header = _("You stopped the check for updates.")
317
                desc = _("Updated software is available from "
318
                         "a previous check.")
2727.1.1 by Brian Murray
Include HWE support tools and information. (LP: #1498059)
319
            # Display HWE updates first as an old HWE stack is vulnerable
320
            elif self.hwe_replacement_packages:
321
                return HWEUpgradeDialog(self)
2664 by Marc Deslauriers
* Allow user to close the restart required dialog (LP: #1033226)
322
            return UpdatesAvailable(self, header, desc, need_reboot)
2511.1.8 by Michael Terry
more pep8 fixes
323
2835.1.1 by Balint Reczey
Print transaction error and let the user try again applying updates
324
    def start_error(self, update_and_retry, header, desc):
325
        if update_and_retry:
2565.1.1 by Michael Terry
Allow user to continue if an update error occurs
326
            self._start_pane(UpdateErrorDialog(self, header, desc))
327
        else:
328
            self._start_pane(ErrorDialog(self, header, desc))
2511.1.8 by Michael Terry
more pep8 fixes
329
330
    def _look_busy(self):
331
        self.set_sensitive(False)
332
        if self.get_window() is not None:
333
            self.get_window().set_cursor(Gdk.Cursor.new(Gdk.CursorType.WATCH))
334
2622.1.2 by Dylan McCall
UpdatesAvailable is now a Dialog subclass.
335
    def _look_ready(self):
336
        self.set_sensitive(True)
337
        if self.get_window() is not None:
338
            self.get_window().set_cursor(None)
339
            self.get_window().set_functions(Gdk.WMFunction.ALL)
340
2511.1.8 by Michael Terry
more pep8 fixes
341
    def _check_meta_release(self):
342
        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
343
            return None
2511.1.8 by Michael Terry
more pep8 fixes
344
345
        if self.meta_release.downloading:
346
            # Block until we get an answer
347
            GLib.idle_add(self._meta_release_wait_idle)
348
            Gtk.main()
349
350
        # Check if there is anything to upgrade to or a known-broken upgrade
351
        next = self.meta_release.upgradable_to
352
        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
353
            return None
2511.1.8 by Michael Terry
more pep8 fixes
354
355
        # Check for end-of-life
356
        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
357
            return UnsupportedDialog(self, self.meta_release)
2511.1.8 by Michael Terry
more pep8 fixes
358
359
        # Check for new fresh release
2662 by Martin Pitt
Stop using deprecated GObject constructors with positional arguments
360
        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
361
        if (self.meta_release.new_dist
362
                and (self.options.check_dist_upgrades
2840.1.1 by Balint Reczey
Fix PEP 8 warnings
363
                     or settings.get_boolean("check-dist-upgrades"))):
2864.1.1 by Brian Murray
UpdateManager/UpdateManager.py: Do not offer to upgrade systems running on
364
            if self.arch == 'i386':
365
                return NoUpgradeForYouDialog(self, self.meta_release,
366
                                             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
367
            return DistUpgradeDialog(self, self.meta_release)
2511.1.8 by Michael Terry
more pep8 fixes
368
2534.1.5 by Michael Terry
adjust code to make the UpdateManager class slightly easier to unit test; add tests for stop-update code
369
        return None
2511.1.8 by Michael Terry
more pep8 fixes
370
371
    def _meta_release_wait_idle(self):
372
        # 'downloading' is changed in a thread, but the signal
373
        # 'done_downloading' is done in our thread's event loop.  So we know
374
        # that it won't fire while we're in this function.
375
        if not self.meta_release.downloading:
376
            Gtk.main_quit()
377
        else:
378
            self.meta_release.connect("done_downloading", Gtk.main_quit)
379
        return False
380
2727.1.1 by Brian Murray
Include HWE support tools and information. (LP: #1498059)
381
    def _check_hwe_support_status(self):
382
        di = distro_info.UbuntuDistroInfo()
383
        codename = get_dist()
384
        lts = di.is_lts(codename)
385
        if not lts:
386
            return None
387
        HWE = "/usr/bin/hwe-support-status"
388
        if not os.path.exists(HWE):
389
            return None
390
        cmd = [HWE, "--show-replacements"]
391
        self._parse_hwe_support_status(cmd)
392
393
    def _parse_hwe_support_status(self, cmd):
394
        try:
395
            subprocess.check_output(cmd)
396
            # for debugging
397
            # print("nothing unsupported running")
398
        except subprocess.CalledProcessError as e:
399
            if e.returncode == 10:
400
                packages = e.output.strip().split()
401
                self.hwe_replacement_packages = []
402
                for pkgname in packages:
403
                    pkgname = pkgname.decode('utf-8')
2775 by Brian Murray
Fix a bunch of pep8 related errors.
404
                    if pkgname in self.cache and \
405
                            not self.cache[pkgname].is_installed:
2727.1.1 by Brian Murray
Include HWE support tools and information. (LP: #1498059)
406
                        self.hwe_replacement_packages.append(pkgname)
407
                # for debugging
408
                # print(self.hwe_replacement_packages)
409
2511.1.8 by Michael Terry
more pep8 fixes
410
    # fixme: we should probably abstract away all the stuff from libapt
411
    def refresh_cache(self):
412
        try:
413
            if self.cache is None:
414
                self.cache = MyCache(None)
415
            else:
416
                self.cache.open(None)
417
                self.cache._initDepCache()
418
        except AssertionError:
419
            # if the cache could not be opened for some reason,
420
            # let the release upgrader handle it, it deals
421
            # a lot better with this
422
            self._start_pane(PartialUpgradeDialog(self))
423
            # we assert a clean cache
424
            header = _("Software index is broken")
425
            desc = _("It is impossible to install or remove any software. "
426
                     "Please use the package manager \"Synaptic\" or run "
427
                     "\"sudo apt-get install -f\" in a terminal to fix "
428
                     "this issue at first.")
2887.1.1 by Brian Murray
UpdateManager/UpdateManager.py: when refreshing the cache and encountering
429
            self.start_error(False, header, desc)
430
            return
2511.1.8 by Michael Terry
more pep8 fixes
431
        except SystemError as e:
432
            header = _("Could not initialize the package information")
433
            desc = _("An unresolvable problem occurred while "
434
                     "initializing the package information.\n\n"
435
                     "Please report this bug against the 'update-manager' "
2537 by Michael Terry
fix a couple of pep8 errors
436
                     "package and include the following error "
437
                     "message:\n") + str(e)
2887.1.1 by Brian Murray
UpdateManager/UpdateManager.py: when refreshing the cache and encountering
438
            self.start_error(False, header, desc)
439
            return
2511.1.8 by Michael Terry
more pep8 fixes
440
441
        # 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
442
        def iterate():
443
            while Gtk.events_pending():
444
                Gtk.main_iteration()
445
        iterate()
2511.1.8 by Michael Terry
more pep8 fixes
446
2893.2.1 by Iain Lane
List OEM metapackages
447
        self._check_oem_metapackages()
448
2947.1.5 by Robert Ancell
Get package list from ua security-status
449
        self._get_ua_security_status()
450
2893.2.1 by Iain Lane
List OEM metapackages
451
        for pkgname in self.oem_metapackages:
452
            try:
453
                if not self.cache[pkgname].is_installed:
454
                    self.cache[pkgname].mark_install()
455
            except SystemError:
456
                pass
457
2511.1.8 by Michael Terry
more pep8 fixes
458
        self.update_list = UpdateList(self)
459
        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.
460
            self.update_list.update(self.cache, eventloop_callback=iterate,
2953 by Steve Langasek
Fix autopkgtest regressions.
461
                                    duplicate_packages=self.duplicate_packages,
462
                                    ua_security_packages=self.
463
                                    ua_security_packages)
2511.1.8 by Michael Terry
more pep8 fixes
464
        except SystemError as e:
465
            header = _("Could not calculate the upgrade")
466
            desc = _("An unresolvable problem occurred while "
467
                     "calculating the upgrade.\n\n"
468
                     "Please report this bug against the 'update-manager' "
2537 by Michael Terry
fix a couple of pep8 errors
469
                     "package and include the following error "
470
                     "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
471
            self.start_error(True, header, desc)
2511.1.8 by Michael Terry
more pep8 fixes
472
473
        if self.update_list.distUpgradeWouldDelete > 0:
474
            self._start_pane(PartialUpgradeDialog(self))
475
476
    def _setup_dbus(self):
2727.1.1 by Brian Murray
Include HWE support tools and information. (LP: #1498059)
477
        """ this sets up a dbus listener if none is installed already """
2511.1.8 by Michael Terry
more pep8 fixes
478
        # check if there is another g-a-i already and if not setup one
479
        # listening on dbus
480
        try:
481
            bus = dbus.SessionBus()
2853 by Brian Murray
debian/tests/control: really use pyflakes3 instead of pyflakes,
482
        except Exception:
2511.1.8 by Michael Terry
more pep8 fixes
483
            print("warning: could not initiate dbus")
484
            return
485
        try:
2511.1.14 by Michael Terry
auto-pep8'd some warnings
486
            proxy_obj = bus.get_object('org.freedesktop.UpdateManager',
2511.1.8 by Michael Terry
more pep8 fixes
487
                                       '/org/freedesktop/UpdateManagerObject')
488
            iface = dbus.Interface(proxy_obj,
489
                                   'org.freedesktop.UpdateManagerIFace')
490
            iface.bringToFront()
491
            #print("send bringToFront")
492
            sys.exit(0)
493
        except dbus.DBusException:
494
            #print("no listening object (%s) " % e)
495
            bus_name = dbus.service.BusName('org.freedesktop.UpdateManager',
496
                                            bus)
497
            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
498
499
500
class UpdateManagerDbusController(dbus.service.Object):
501
    """ this is a helper to provide the UpdateManagerIFace """
502
    def __init__(self, parent, bus_name,
503
                 object_path='/org/freedesktop/UpdateManagerObject'):
504
        dbus.service.Object.__init__(self, bus_name, object_path)
505
        self.parent = parent
2511.1.8 by Michael Terry
more pep8 fixes
506
        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
507
        self.alert_watcher.connect("network-alert", self._on_network_alert)
508
        self.connected = False
509
510
    @dbus.service.method('org.freedesktop.UpdateManagerIFace')
511
    def bringToFront(self):
512
        self.parent.present()
513
        return True
514
515
    @dbus.service.method('org.freedesktop.UpdateManagerIFace')
516
    def upgrade(self):
517
        try:
518
            self.parent.start_install()
519
            return True
2853 by Brian Murray
debian/tests/control: really use pyflakes3 instead of pyflakes,
520
        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
521
            return False
522
523
    def _on_network_alert(self, watcher, state):
524
        if state in NetworkManagerHelper.NM_STATE_CONNECTED_LIST:
525
            self.connected = True
526
        else:
527
            self.connected = False