summaryrefslogtreecommitdiff
path: root/UpdateManager/UpdateManager.py
diff options
context:
space:
mode:
Diffstat (limited to 'UpdateManager/UpdateManager.py')
-rw-r--r--UpdateManager/UpdateManager.py235
1 files changed, 124 insertions, 111 deletions
diff --git a/UpdateManager/UpdateManager.py b/UpdateManager/UpdateManager.py
index 343dcd85..af1a1b8e 100644
--- a/UpdateManager/UpdateManager.py
+++ b/UpdateManager/UpdateManager.py
@@ -33,21 +33,24 @@ try:
except:
import fakegconf as gconf
import gobject
+import warnings
+warnings.filterwarnings("ignore", "apt API not stable yet", FutureWarning)
import apt
import apt_pkg
+
import gettext
import copy
import string
import sys
import os
import os.path
-import urllib2
import re
import locale
import tempfile
import pango
import subprocess
import pwd
+import urllib2
import time
import thread
import xml.sax.saxutils
@@ -111,16 +114,18 @@ class MyCache(apt.Cache):
def saveDistUpgrade(self):
""" this functions mimics a upgrade but will never remove anything """
self._depcache.Upgrade(True)
+ wouldDelete = self._depcache.DelCount
if self._depcache.DelCount > 0:
self.clear()
assert self._depcache.BrokenCount == 0 and self._depcache.DelCount == 0
self._depcache.Upgrade()
+ return wouldDelete
def get_changelog(self, name, lock):
# don't touch the gui in this function, it needs to be thread-safe
pkg = self[name]
- # get the src package name
+ # get the src package name
srcpkg = pkg.sourcePackageName
# assume "main" section
@@ -130,6 +135,7 @@ class MyCache(apt.Cache):
# get the source version, start with the binaries version
binver = pkg.candidateVersion
+ srcver = pkg.candidateVersion
#print "bin: %s" % binver
try:
# try to get the source version of the pkg, this differs
@@ -146,6 +152,9 @@ class MyCache(apt.Cache):
#print "srcver: %s" % srcver
section = srcrecords.Section
#print "srcsect: %s" % section
+ else:
+ # fail into the error handler
+ raise SystemError
except SystemError, e:
srcver = binver
@@ -201,12 +210,12 @@ class MyCache(apt.Cache):
except urllib2.HTTPError:
if lock.locked():
self.all_changes[name] = [_("The list of changes is not "
- "available yet. Please try again "
+ "available yet.\nPlease try again "
"later."), srcpkg]
except IOError:
if lock.locked():
self.all_changes[name] = [_("Failed to download the list "
- "of changes. Please "
+ "of changes. \nPlease "
"check your Internet "
"connection."), srcpkg]
if lock.locked():
@@ -219,38 +228,40 @@ class UpdateList:
self.importance = importance
self.description = desc
- def __init__(self, parent_window):
+ def __init__(self):
# a map of packages under their origin
pipe = os.popen("lsb_release -c -s")
dist = pipe.read().strip()
del pipe
- templates = [("%s-security" % dist, "Ubuntu", _("Important security updates"
- " of Ubuntu"), 10),
- ("%s-updates" % dist, "Ubuntu", _("Recommended updates of "
- "Ubuntu"), 9),
- ("%s-proposed" % dist, "Ubuntu", _("Proposed updates for Ubuntu"), 8),
- ("%s-backports" % dist, "Ubuntu", _("Backports of Ubuntu"), 7),
- (dist, "Ubuntu", _("Updates of Ubuntu"), 6)]
+ templates = [("%s-security" % dist, "Ubuntu", _("Important security updates")
+ , 10),
+ ("%s-updates" % dist, "Ubuntu", _("Recommended updates"), 9),
+ ("%s-proposed" % dist, "Ubuntu", _("Proposed updates"), 8),
+ ("%s-backports" % dist, "Ubuntu", _("Backports"), 7),
+ (dist, "Ubuntu", _("Distribution updates"), 6)]
self.pkgs = {}
self.matcher = {}
self.num_updates = 0
- self.parent_window = parent_window
for (origin, archive, desc, importance) in templates:
self.matcher[(origin, archive)] = self.UpdateOrigin(desc, importance)
self.unknown_origin = self.UpdateOrigin(_("Other updates"), -1)
def update(self, cache):
- held_back = []
- broken = []
+ self.held_back = []
# do the upgrade
- cache.saveDistUpgrade()
+ self.distUpgradeWouldDelete = cache.saveDistUpgrade()
# sort by origin
for pkg in cache:
- if pkg.markedUpgrade or pkg.markedInstall:
+ if pkg.isUpgradable:
+ if pkg.candidateOrigin == None:
+ # can happen for e.g. loged packages
+ # FIXME: do something more sensible here (but what?)
+ print "WARNING: upgradable but no canidateOrigin?!?: ", pkg.name
+ continue
# TRANSLATORS: updates from an 'unknown' origin
originstr = _("Other updates")
for aorigin in pkg.candidateOrigin:
@@ -264,38 +275,11 @@ class UpdateList:
self.pkgs[origin_node] = []
self.pkgs[origin_node].append(pkg)
self.num_updates = self.num_updates + 1
- elif pkg.isUpgradable:
- held_back.append(pkg.name)
+ if pkg.isUpgradable and not (pkg.markedUpgrade or pkg.markedInstall):
+ self.held_back.append(pkg.name)
for l in self.pkgs.keys():
self.pkgs[l].sort(lambda x,y: cmp(x.name,y.name))
-
- # check if we have held-back something
- if cache._depcache.KeepCount > 0:
- keepcount = cache._depcache.KeepCount
- msg = ("<big><b>%s</b></big>\n\n%s" % \
- (_("Cannot install all available updates"),
- _("Some of the updates require more extensive changes "
- "than expected.\n\n"
- "This usually means that you have enabled unoffical "
- "repositories, that it is not "
- "fully upgraded from the last distribution release or "
- "that you run a development release "
- "of the distribution.\n\n"
- "Would you like to perform a full distribution upgrade "
- "now?")))
- dialog = gtk.MessageDialog(self.parent_window, 0,
- gtk.MESSAGE_QUESTION,
- gtk.BUTTONS_YES_NO,"")
- dialog.set_default_response(gtk.RESPONSE_NO)
- dialog.set_markup(msg)
- dialog.set_title("")
- dialog.vbox.set_spacing(6)
- res = dialog.run()
- if res == gtk.RESPONSE_YES:
- os.execl("/usr/bin/gksu",
- "/usr/bin/gksu",
- "/usr/bin/update-manager --dist-upgrade")
- dialog.destroy()
+ self.keepcount = cache._depcache.KeepCount
class UpdateManagerDbusControler(dbus.service.Object):
@@ -371,26 +355,6 @@ class UpdateManager(SimpleGladeApp):
self.treeview_update.connect("button-press-event", self.show_context_menu)
- # proxy stuff
- # FIXME: move this into it's own function
- SYNAPTIC_CONF_FILE = "%s/.synaptic/synaptic.conf" % pwd.getpwuid(0)[5]
- if os.path.exists(SYNAPTIC_CONF_FILE):
- cnf = apt_pkg.newConfiguration()
- apt_pkg.ReadConfigFile(cnf, SYNAPTIC_CONF_FILE)
- use_proxy = cnf.FindB("Synaptic::useProxy", False)
- if use_proxy:
- proxy_host = cnf.Find("Synaptic::httpProxy")
- proxy_port = str(cnf.FindI("Synaptic::httpProxyPort"))
- if proxy_host and proxy_port:
- # FIXME: set the proxy for libapt here as well (e.g. for the
- # DistUpgradeFetcher
- proxy_support = urllib2.ProxyHandler({"http":"http://%s:%s" % (proxy_host, proxy_port)})
- opener = urllib2.build_opener(proxy_support)
- urllib2.install_opener(opener)
- # install a proxy environment too
- if not os.environ.has_key("http_proxy"):
- os.putenv("http_proxy",
- "http://%s:%s/" % (proxy_host, proxy_port))
# setup the help viewer and disable the help button if there
# is no viewer available
@@ -399,10 +363,46 @@ class UpdateManager(SimpleGladeApp):
self.button_help.set_sensitive(False)
self.gconfclient = gconf.client_get_default()
+ self.init_proxy()
+
# restore state
self.restore_state()
self.window_main.show()
+ def init_proxy(self):
+ # proxy settings, first check for http_proxy environment (always wins),
+ # then look into synaptics conffile, then into gconf
+ if os.getenv("http_proxy"):
+ return
+ SYNAPTIC_CONF_FILE = "%s/.synaptic/synaptic.conf" % pwd.getpwuid(0)[5]
+ proxy = None
+ if os.path.exists(SYNAPTIC_CONF_FILE):
+ cnf = apt_pkg.newConfiguration()
+ apt_pkg.ReadConfigFile(cnf, SYNAPTIC_CONF_FILE)
+ use_proxy = cnf.FindB("Synaptic::useProxy", False)
+ if use_proxy:
+ proxy_host = cnf.Find("Synaptic::httpProxy")
+ proxy_port = str(cnf.FindI("Synaptic::httpProxyPort"))
+ if proxy_host and proxy_port:
+ # FIXME: set the proxy for libapt here as well (e.g. for the
+ # DistUpgradeFetcher
+ proxy = "http://%s:%s/" % (proxy_host, proxy_port)
+ elif self.gconfclient.get_bool("/system/http_proxy/use_http_proxy"):
+ host = self.gconfclient.get_string("/system/http_proxy/host")
+ port = self.gconfclient.get_int("/system/http_proxy/port")
+ use_auth = self.gconfclient.get_bool("/system/http_proxy/use_authentication")
+ if use_auth:
+ auth_user = self.gconfclient.get_string("/system/http_proxy/authentication_user")
+ auth_pw = self.gconfclient.get_string("/system/http_proxy/authentication_password")
+ proxy = "http://%s:%s@%s:%s/" % (auth_user,auth_pass,host, port)
+ else:
+ proxy = "http://%s:%s/" % (host, port)
+ if proxy:
+ proxy_support = urllib2.ProxyHandler({"http":proxy})
+ opener = urllib2.build_opener(proxy_support)
+ urllib2.install_opener(opener)
+ os.putenv("http_proxy",proxy)
+
def header_column_func(self, cell_layout, renderer, model, iter):
pkg = model.get_value(iter, LIST_PKG)
if pkg == None:
@@ -419,7 +419,11 @@ class UpdateManager(SimpleGladeApp):
return
to_install = pkg.markedInstall or pkg.markedUpgrade
renderer.set_property("active", to_install)
-
+ if pkg.name in self.list.held_back:
+ renderer.set_property("activatable", False)
+ else:
+ renderer.set_property("activatable", True)
+
def package_column_view_func(self, cell_layout, renderer, model, iter):
self.header_column_func(cell_layout, renderer, model, iter)
@@ -532,8 +536,11 @@ class UpdateManager(SimpleGladeApp):
lock = thread.allocate_lock()
lock.acquire()
t=thread.start_new_thread(self.cache.get_changelog,(name,lock))
- changes_buffer.set_text(_("Downloading the list of changes..."))
- button = self.button_cancel_dl_changelog
+ changes_buffer.set_text("%s\n" % _("Downloading list of changes..."))
+ iter = changes_buffer.get_iter_at_line(1)
+ anchor = changes_buffer.create_child_anchor(iter)
+ button = gtk.Button(stock="gtk-cancel")
+ self.textview_changes.add_child_at_anchor(button, anchor)
button.show()
id = button.connect("clicked",
lambda w,lock: lock.release(), lock)
@@ -556,13 +563,13 @@ class UpdateManager(SimpleGladeApp):
"""
if event.type == gtk.gdk.BUTTON_PRESS and event.button == 3:
menu = gtk.Menu()
- item_select_none = gtk.MenuItem(_("Select _None"))
+ item_select_none = gtk.MenuItem(_("_Uncheck All"))
item_select_none.connect("activate", self.select_none_updgrades)
menu.add(item_select_none)
num_updates = self.cache.installCount
if num_updates == 0:
item_select_none.set_property("sensitive", False)
- item_select_all = gtk.MenuItem(_("Select _All"))
+ item_select_all = gtk.MenuItem(_("_Check All"))
item_select_all.connect("activate", self.select_all_updgrades)
menu.add(item_select_all)
menu.popup(None, None, None, 0, event.time)
@@ -587,23 +594,6 @@ class UpdateManager(SimpleGladeApp):
self.treeview_update.queue_draw()
self.setBusy(False)
- def humanize_size(self, bytes):
- """
- Convert a given size in bytes to a nicer better readable unit
- """
- if bytes == 0:
- # TRANSLATORS: download size is 0
- return _("None")
- elif bytes < 1024:
- # TRANSLATORS: download size of very small updates
- return _("1 KB")
- elif bytes < 1024 * 1024:
- # TRANSLATORS: download size of small updates, e.g. "250 KB"
- return locale.format(_("%.0f KB"), bytes/1024)
- else:
- # TRANSLATORS: download size of updates, e.g. "2.3 MB"
- return locale.format(_("%.1f MB"), bytes / 1024 / 1024)
-
def setBusy(self, flag):
""" Show a watch cursor if the app is busy for more than 0.3 sec.
Furthermore provide a loop to handle user interface events """
@@ -620,8 +610,8 @@ class UpdateManager(SimpleGladeApp):
self.button_install.set_sensitive(self.cache.installCount)
self.dl_size = self.cache.requiredDownload
# TRANSLATORS: b stands for Bytes
- self.label_downsize.set_markup(_("Download size: %s" % \
- self.humanize_size(self.dl_size)))
+ self.label_downsize.set_markup(_("Download size: %s") % \
+ humanize_size(self.dl_size))
def update_count(self):
"""activate or disable widgets and show dialog texts correspoding to
@@ -629,7 +619,7 @@ class UpdateManager(SimpleGladeApp):
self.refresh_updates_count()
num_updates = self.cache.installCount
if num_updates == 0:
- text_header= "<big><b>"+_("Your system is up-to-date")+"</b></big>"
+ text_header= "<big><b>%s</b></big>" % _("Your system is up-to-date")
text_download = ""
self.notebook_details.set_sensitive(False)
self.treeview_update.set_sensitive(False)
@@ -639,12 +629,12 @@ class UpdateManager(SimpleGladeApp):
self.textview_changes.get_buffer().set_text("")
self.textview_descr.get_buffer().set_text("")
else:
- text_header = "<big><b>" + \
- gettext.ngettext("You can install %s update",
- "You can install %s updates",
- num_updates) % \
- num_updates + "</b></big>"
- text_download = _("Download size: %s") % self.humanize_size(self.dl_size)
+ text_header = "<big><b>%s</b></big>" % \
+ (gettext.ngettext("You can install %s update",
+ "You can install %s updates",
+ num_updates) % \
+ num_updates)
+ text_download = _("Download size: %s") % humanize_size(self.dl_size)
self.notebook_details.set_sensitive(True)
self.treeview_update.set_sensitive(True)
self.button_install.grab_default()
@@ -668,7 +658,7 @@ class UpdateManager(SimpleGladeApp):
apt_pkg.PkgSystemUnLock()
except SystemError:
pass
- cmd = ["gksu", "--desktop", "/usr/share/applications/synaptic.desktop",
+ cmd = ["gksu", "--desktop", "/usr/share/applications/update-manager.desktop",
"--", "/usr/sbin/synaptic", "--hide-main-window",
"--non-interactive", "--parent-window-id", "%s" % (id) ]
if action == INSTALL:
@@ -726,6 +716,7 @@ class UpdateManager(SimpleGladeApp):
time.sleep(0.05)
while gtk.events_pending():
gtk.main_iteration()
+ self.label_cache_progress_title.set_label("<b><big>%s</big></b>" % _("Checking for updates"))
self.fillstore()
# Allow suspend after synaptic is finished
@@ -734,6 +725,7 @@ class UpdateManager(SimpleGladeApp):
self.window_main.set_sensitive(True)
self.window_main.window.set_cursor(None)
+
def inhibit_sleep(self):
"""Send a dbus signal to gnome-power-manager to not suspend
the system"""
@@ -755,9 +747,13 @@ class UpdateManager(SimpleGladeApp):
def toggled(self, renderer, path):
""" a toggle button in the listview was toggled """
- self.setBusy(True)
iter = self.store.get_iter(path)
pkg = self.store.get_value(iter, LIST_PKG)
+ # make sure that we don't allow to toggle deactivated updates
+ # this is needed for the call by the row activation callback
+ if pkg.name in self.list.held_back:
+ return False
+ self.setBusy(True)
# update the cache
if pkg.markedInstall or pkg.markedUpgrade:
pkg.markKeep()
@@ -809,9 +805,9 @@ class UpdateManager(SimpleGladeApp):
# clean most objects
self.dl_size = 0
- self.store.clear()
self.initCache()
- self.list = UpdateList(self.window_main)
+ self.store.clear()
+ self.list = UpdateList()
# fill them again
self.list.update(self.cache)
@@ -825,20 +821,21 @@ class UpdateManager(SimpleGladeApp):
for pkg in self.list.pkgs[origin]:
name = xml.sax.saxutils.escape(pkg.name)
summary = xml.sax.saxutils.escape(pkg.summary)
- contents = "<b>%s</b>\n<small>%s\n" % (name, summary)
+ contents = "<b>%s</b>\n<small>%s</small>" % (name, summary)
if pkg.installedVersion != None:
- contents += _("From version %s to %s") % \
- (pkg.installedVersion,
- pkg.candidateVersion)
+ version = _("From version %(old_version)s to %(new_version)s") %\
+ {"old_version" : pkg.installedVersion,
+ "new_version" : pkg.candidateVersion}
else:
- contents += _("Version %s") % pkg.candidateVersion
+ version = _("Version %s") % pkg.candidateVersion
#TRANSLATORS: the b stands for Bytes
- contents += " " + _("(Size: %s)") % self.humanize_size(pkg.packageSize)
- contents += "</small>"
+ size = _("(Size: %s)") % humanize_size(pkg.packageSize)
+ contents = "%s\n<small>%s %s</small>" % (contents, version, size)
self.store.append([contents, pkg.name, pkg])
self.update_count()
self.setBusy(False)
+ self.check_all_updates_installable()
return False
def dist_no_longer_supported(self, meta_release):
@@ -855,7 +852,7 @@ class UpdateManager(SimpleGladeApp):
dialog.set_markup(msg)
dialog.run()
dialog.destroy()
-
+
def on_button_dist_upgrade_clicked(self, button):
#print "on_button_dist_upgrade_clicked"
fetcher = DistUpgradeFetcher(self, self.new_dist)
@@ -894,7 +891,11 @@ class UpdateManager(SimpleGladeApp):
self.progressbar_cache,
self.label_cache,
self.window_main)
- self.cache = MyCache(progress)
+ if hasattr(self, "cache"):
+ self.cache.open(progress)
+ self.cache._initDepCache()
+ else:
+ self.cache = MyCache(progress)
except AssertionError:
# we assert a clean cache
msg=("<big><b>%s</b></big>\n\n%s"% \
@@ -929,6 +930,18 @@ class UpdateManager(SimpleGladeApp):
if res == gtk.RESPONSE_YES:
self.on_button_reload_clicked(None)
+ def check_all_updates_installable(self):
+ """ Check if all available updates can be installed and suggest
+ to run a distribution upgrade if not """
+ if self.list.distUpgradeWouldDelete > 0:
+ self.dialog_dist_upgrade.set_transient_for(self.window_main)
+ res = self.dialog_dist_upgrade.run()
+ self.dialog_dist_upgrade.hide()
+ if res == gtk.RESPONSE_YES:
+ os.execl("/usr/bin/gksu",
+ "/usr/bin/gksu", "--desktop",
+ "/usr/share/applications/update-manager.desktop",
+ "--", "/usr/bin/update-manager", "--dist-upgrade")
def main(self, options):
gconfclient = gconf.client_get_default()