This file is indexed.

/usr/lib/python3/dist-packages/UpdateManager/backend/InstallBackendAptdaemon.py is in python3-update-manager 1:16.04.3.

This file is owned by root:root, with mode 0o644.

The actual contents of the file can be viewed below.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
#!/usr/bin/env python
# -*- Mode: Python; indent-tabs-mode: nil; tab-width: 4; coding: utf-8 -*-
# (c) 2005-2012 Canonical, GPL
# (C) 2008-2009 Sebastian Heinlein <devel@glatzor.de>

from __future__ import print_function

from gi.repository import Gtk

from aptdaemon import client, errors
from defer import inline_callbacks
from aptdaemon.gtk3widgets import (AptCancelButton,
                                   AptConfigFileConflictDialog,
                                   AptDetailsExpander,
                                   AptMediumRequiredDialog,
                                   AptProgressBar)
from aptdaemon.enums import (EXIT_SUCCESS,
                             EXIT_FAILED,
                             STATUS_COMMITTING,
                             get_error_description_from_enum,
                             get_error_string_from_enum,
                             get_status_string_from_enum)

from UpdateManager.backend import InstallBackend
from UpdateManager.UnitySupport import UnitySupport
from UpdateManager.Dialogs import BuilderDialog

from gettext import gettext as _

import apt
import dbus
import os


class InstallBackendAptdaemon(InstallBackend, BuilderDialog):
    """Makes use of aptdaemon to refresh the cache and to install updates."""

    def __init__(self, window_main, action):
        InstallBackend.__init__(self, window_main, action)
        ui_path = os.path.join(window_main.datadir,
                               "gtkbuilder/UpdateProgress.ui")
        BuilderDialog.__init__(self, window_main, ui_path,
                               "pane_update_progress")

        self.client = client.AptClient()
        self.unity = UnitySupport()
        self._expanded_size = None
        self.button_cancel = None

    def close(self):
        if self.button_cancel:
            self.button_cancel.clicked()
            return True
        else:
            return False

    @inline_callbacks
    def update(self):
        """Refresh the package list"""
        try:
            apt.apt_pkg.pkgsystem_unlock()
        except SystemError:
            pass
        try:
            trans = yield self.client.update_cache(defer=True)
            yield self._show_transaction(trans, self.ACTION_UPDATE,
                                         _("Checking for updates…"), False)
        except errors.NotAuthorizedError:
            self._action_done(self.ACTION_UPDATE,
                              authorized=False, success=False,
                              error_string=None, error_desc=None)
        except:
            self._action_done(self.ACTION_UPDATE,
                              authorized=True, success=False,
                              error_string=None, error_desc=None)
            raise

    @inline_callbacks
    def commit(self, pkgs_install, pkgs_upgrade):
        """Commit a list of package adds and removes"""
        try:
            apt.apt_pkg.pkgsystem_unlock()
        except SystemError:
            pass
        try:
            reinstall = remove = purge = downgrade = []
            trans = yield self.client.commit_packages(
                pkgs_install, reinstall, remove, purge, pkgs_upgrade,
                downgrade, defer=True)
            trans.connect("progress-changed", self._on_progress_changed)
            yield self._show_transaction(trans, self.ACTION_INSTALL,
                                         _("Installing updates…"), True)
        except errors.NotAuthorizedError as e:
            self._action_done(self.ACTION_INSTALL,
                              authorized=False, success=False,
                              error_string=None, error_desc=None)
        except dbus.DBusException as e:
            #print(e, e.get_dbus_name())
            if e.get_dbus_name() != "org.freedesktop.DBus.Error.NoReply":
                raise
            self._action_done(self.ACTION_INSTALL,
                              authorized=False, success=False,
                              error_string=None, error_desc=None)
        except Exception as e:
            self._action_done(self.ACTION_INSTALL,
                              authorized=True, success=False,
                              error_string=None, error_desc=None)
            raise

    def _on_progress_changed(self, trans, progress):
        #print("_on_progress_changed", progress)
        self.unity.set_progress(progress)

    def _on_details_changed(self, trans, details, label_details):
        label_details.set_label(details)

    def _on_status_changed(self, trans, status, label_details, expander):
        label_details.set_label(get_status_string_from_enum(status))
        # Also resize the window if we switch from download details to
        # the terminal window
        if (status == STATUS_COMMITTING and expander and
                expander.terminal.get_visible()):
            self._resize_to_show_details(expander)

    @inline_callbacks
    def _show_transaction(self, trans, action, header, show_details):
        self.label_header.set_label(header)

        progressbar = AptProgressBar(trans)
        progressbar.show()
        self.progressbar_slot.add(progressbar)

        self.button_cancel = AptCancelButton(trans)
        if action == self.ACTION_UPDATE:
            self.button_cancel.set_label(Gtk.STOCK_STOP)
        self.button_cancel.show()
        self.button_cancel_slot.add(self.button_cancel)

        if show_details:
            expander = AptDetailsExpander(trans)
            expander.set_vexpand(True)
            expander.set_hexpand(True)
            expander.show_all()
            expander.connect("notify::expanded", self._on_expanded)
            self.expander_slot.add(expander)
            self.expander_slot.show()
        else:
            expander = None

        trans.connect("status-details-changed", self._on_details_changed,
                      self.label_details)
        trans.connect("status-changed", self._on_status_changed,
                      self.label_details, expander)
        trans.connect("finished", self._on_finished, action)
        trans.connect("medium-required", self._on_medium_required)
        trans.connect("config-file-conflict", self._on_config_file_conflict)

        yield trans.set_debconf_frontend("gnome")
        yield trans.run()

    def _on_expanded(self, expander, param):
        # Make the dialog resizable if the expander is expanded
        # try to restore a previous size
        if not expander.get_expanded():
            self._expanded_size = (expander.terminal.get_visible(),
                                   self.window_main.get_size())
            self.window_main.end_user_resizable()
        elif self._expanded_size:
            term_visible, (stored_width, stored_height) = self._expanded_size
            # Check if the stored size was for the download details or
            # the terminal widget
            if term_visible != expander.terminal.get_visible():
                # The stored size was for the download details, so we need
                # get a new size for the terminal widget
                self._resize_to_show_details(expander)
            else:
                self.window_main.begin_user_resizable(stored_width,
                                                      stored_height)
        else:
            self._resize_to_show_details(expander)

    def _resize_to_show_details(self, expander):
        """Resize the window to show the expanded details.

        Unfortunately the expander only expands to the preferred size of the
        child widget (e.g showing all 80x24 chars of the Vte terminal) if
        the window is rendered the first time and the terminal is also visible.
        If the expander is expanded afterwards the window won't change its
        size anymore. So we have to do this manually. See LP#840942
        """
        if expander.get_expanded():
            win_width, win_height = self.window_main.get_size()
            exp_width = expander.get_allocation().width
            exp_height = expander.get_allocation().height
            if expander.terminal.get_visible():
                terminal_width = expander.terminal.get_char_width() * 80
                terminal_height = expander.terminal.get_char_height() * 24
                new_width = terminal_width - exp_width + win_width
                new_height = terminal_height - exp_height + win_height
            else:
                new_width = win_width + 100
                new_height = win_height + 200
            self.window_main.begin_user_resizable(new_width, new_height)

    def _on_medium_required(self, transaction, medium, drive):
        dialog = AptMediumRequiredDialog(medium, drive, self.window_main)
        res = dialog.run()
        dialog.hide()
        if res == Gtk.ResponseType.OK:
            transaction.provide_medium(medium)
        else:
            transaction.cancel()

    def _on_config_file_conflict(self, transaction, old, new):
        dialog = AptConfigFileConflictDialog(old, new, self.window_main)
        res = dialog.run()
        dialog.hide()
        if res == Gtk.ResponseType.YES:
            transaction.resolve_config_file_conflict(old, "replace")
        else:
            transaction.resolve_config_file_conflict(old, "keep")

    def _on_finished(self, trans, status, action):
        error_string = None
        error_desc = None
        if status == EXIT_FAILED:
            error_string = get_error_string_from_enum(trans.error.code)
            error_desc = get_error_description_from_enum(trans.error.code)
        # tell unity to hide the progress again
        self.unity.set_progress(-1)
        is_success = (status == EXIT_SUCCESS)
        self._action_done(action,
                          authorized=True, success=is_success,
                          error_string=error_string, error_desc=error_desc)


if __name__ == "__main__":
    import mock
    options = mock.Mock()
    data_dir = "/usr/share/update-manager"

    from UpdateManager.UpdateManager import UpdateManager
    app = UpdateManager(data_dir, options)

    b = InstallBackendAptdaemon(app, None)
    b.commit(["2vcard"], [])
    Gtk.main()