diff options
| author | Michael Vogt <michael.vogt@ubuntu.com> | 2006-10-27 09:57:49 +0200 |
|---|---|---|
| committer | Michael Vogt <michael.vogt@ubuntu.com> | 2006-10-27 09:57:49 +0200 |
| commit | bed5736c7cf31070540bd7e27ffb073db3d7c396 (patch) | |
| tree | c733204d23625109cd282afcf2ac54539d300fd9 /UpdateManager | |
| parent | 590c710c9feef18c9a23676aab1ce0fb7b6d2f75 (diff) | |
| parent | dcee921a1107db6e5c8042598641b422a77e24c2 (diff) | |
| download | python-apt-bed5736c7cf31070540bd7e27ffb073db3d7c396.tar.gz | |
* merged from main
Diffstat (limited to 'UpdateManager')
| -rw-r--r-- | UpdateManager/Common/DistInfo.py | 35 | ||||
| -rw-r--r-- | UpdateManager/Common/aptsources.py | 169 | ||||
| -rw-r--r-- | UpdateManager/Common/utils.py | 19 | ||||
| -rw-r--r-- | UpdateManager/DistUpgradeFetcher.py | 2 | ||||
| -rw-r--r-- | UpdateManager/GtkProgress.py | 13 | ||||
| -rw-r--r-- | UpdateManager/UpdateManager.py | 235 |
6 files changed, 250 insertions, 223 deletions
diff --git a/UpdateManager/Common/DistInfo.py b/UpdateManager/Common/DistInfo.py index 79d5356c..57621f52 100644 --- a/UpdateManager/Common/DistInfo.py +++ b/UpdateManager/Common/DistInfo.py @@ -24,8 +24,9 @@ import os import gettext from os import getenv import ConfigParser +import string -_ = gettext.gettext +from gettext import gettext as _ class Suite: def __init__(self): @@ -38,6 +39,7 @@ class Suite: self.components = {} self.children = [] self.match_uri = None + self.valid_mirrors = [] self.distribution = None self.available = True @@ -46,7 +48,6 @@ class Component: self.name = "" self.description = "" self.description_long = "" - self.enabled = None class DistInfo: def __init__(self, @@ -83,7 +84,7 @@ class DistInfo: if suite: if component: suite.components["%s" % component.name] = \ - (component.description, component.enabled, + (component.description, component.description_long) component = None self.suites.append (suite) @@ -98,6 +99,13 @@ class DistInfo: for nanny in self.suites: if nanny.name == value: nanny.children.append(suite) + # reuse some properties of the parent suite + if suite.match_uri == None: + suite.match_uri = nanny.match_uri + if suite.valid_mirrors == None: + suite.valid_mirrors = nanny.valid_mirrors + if suite.base_uri == None: + suite.base_uri = nanny.base_uri elif field == 'Available': suite.available = value elif field == 'RepositoryType': @@ -107,17 +115,24 @@ class DistInfo: suite.match_uri = value elif field == 'MatchURI': suite.match_uri = value + elif field == 'MirrorsFile': + if os.path.exists(value): + suite.valid_mirrors = filter(lambda s: + ((s != "") and + (not s.startswith("#"))), + map(string.strip, + open(value))) + else: + print "WARNING: can't read '%s'" % value elif field == 'Description': suite.description = _(value) elif field == 'Component': if component: suite.components["%s" % component.name] = \ - (component.description, component.enabled, + (component.description, component.description_long) component = Component () component.name = value - elif field == 'Enabled': - component.enabled = bool(int(value)) elif field == 'CompDescription': component.description = _(value) elif field == 'CompDescriptionLong': @@ -125,7 +140,7 @@ class DistInfo: if suite: if component: suite.components["%s" % component.name] = \ - (component.description, component.enabled, + (component.description, component.description_long) component = None self.suites.append (suite) @@ -133,17 +148,17 @@ class DistInfo: if __name__ == "__main__": - d = DistInfo ("Ubuntu", "../../channels") + d = DistInfo ("Ubuntu", "../../data/channels") print d.changelogs_uri for suite in d.suites: print "\nSuite: %s" % suite.name print "Desc: %s" % suite.description print "BaseURI: %s" % suite.base_uri print "MatchURI: %s" % suite.match_uri + print "Mirrors: %s" % suite.valid_mirrors for component in suite.components: print " %s - %s - %s - %s" % (component, suite.components[component][0], - suite.components[component][1], - suite.components[component][2]) + suite.components[component][1]) for child in suite.children: print " %s" % child.description diff --git a/UpdateManager/Common/aptsources.py b/UpdateManager/Common/aptsources.py index 09673376..34b5b967 100644 --- a/UpdateManager/Common/aptsources.py +++ b/UpdateManager/Common/aptsources.py @@ -72,28 +72,26 @@ def uniq(s): """ simple and efficient way to return uniq list """ return list(set(s)) - - -# actual source.list entries class SourceEntry: - + """ single sources.list entry """ def __init__(self, line,file=None): - self.invalid = False - self.disabled = False - self.type = "" - self.uri = "" - self.dist = "" - self.comps = [] - self.comment = "" - self.line = line - if file == None: + self.invalid = False # is the source entry valid + self.disabled = False # is it disabled ('#' in front) + self.type = "" # what type (deb, deb-src) + self.uri = "" # base-uri + self.dist = "" # distribution (dapper, edgy, etc) + self.comps = [] # list of available componetns (may empty) + self.comment = "" # (optional) comment + self.line = line # the original sources.list line + if file == None: file = apt_pkg.Config.FindDir("Dir::Etc")+apt_pkg.Config.Find("Dir::Etc::sourcelist") - self.file = file + self.file = file # the file that the entry is located in self.parse(line) - self.template = None + self.template = None # type DistInfo.Suite self.children = [] - def __eq__(self, other): + def __eq__(self, other): + """ equal operator for two sources.list entries """ return (self.disabled == other.disabled and self.type == other.type and self.uri == other.uri and @@ -101,8 +99,9 @@ class SourceEntry: self.comps == other.comps) - # works mostely like split but takes [] into account def mysplit(self, line): + """ a split() implementation that understands the sources.list + format better and takes [] into account (for e.g. cdroms) """ line = string.strip(line) pieces = [] tmp = "" @@ -129,9 +128,9 @@ class SourceEntry: pieces.append(tmp) return pieces - - # parse a given source line and split it into the fields we need def parse(self,line): + """ parse a given sources.list (textual) line and break it up + into the field we have """ line = string.strip(self.line) #print line # check if the source is enabled/disabled @@ -177,11 +176,8 @@ class SourceEntry: else: self.comps = [] - #print self.__dict__ - - - # set enabled/disabled def set_enabled(self, new_value): + """ set a line to enabled or disabled """ self.disabled = not new_value # enable, remove all "#" from the start of the line if new_value == True: @@ -214,15 +210,17 @@ class SourceEntry: line += "\n" return line -# the SourceList file as a class class NullMatcher(object): + """ a Matcher that does nothing """ def match(self, s): return True class SourcesList: - def __init__(self, withMatcher=True, + """ represents the full sources.list + sources.list.d file """ + def __init__(self, + withMatcher=True, matcherPath="/usr/share/update-manager/channels/"): - self.list = [] # of Type SourceEntries + self.list = [] # the actual SourceEntries Type if withMatcher: self.matcher = SourceEntryMatcher(matcherPath) else: @@ -230,6 +228,7 @@ class SourcesList: self.refresh() def refresh(self): + """ update the list of known entries """ self.list = [] # read sources.list dir = apt_pkg.Config.FindDir("Dir::Etc") @@ -245,6 +244,8 @@ class SourcesList: self.matcher.match(source) def __iter__(self): + """ simple iterator to go over self.list, returns SourceEntry + types """ for entry in self.list: yield entry raise StopIteration @@ -298,6 +299,7 @@ class SourcesList: return new_entry def remove(self, source_entry): + """ remove the specified entry from the sources.list """ self.list.remove(source_entry) def restoreBackup(self, backup_ext): @@ -370,56 +372,6 @@ class SourcesList: #print self.parents return (parents, used_child_templates) -# templates for the add dialog -class SourceEntryTemplate(SourceEntry): - def __init__(self,a_type,uri,dist,description,comps): - self.comps_descriptions = [] - self.type = a_type - self.uri = uri - self.dist = dist - self.description = description - self.comps = comps - - def matches(self,source_entry): - """ check if a given source_entry matches this one """ - if (self.type != source_entry.type): - return False - if (self.dist != source_entry.dist): - return False - if not is_mirror(self.uri,source_entry.uri): - return False - for e_comp in source_entry.comps: - for t_comp in self.comps: - if e_comp == t_comp.name: break - else: - return False - return True - -class SourceCompTemplate: - def __init__(self, name, description, on_by_default): - self.name = name - self.description = description - self.on_by_default = on_by_default - -class SourceEntryTemplates: - - def __init__(self,datadir): - _ = gettext.gettext - self.templates = [] - - dinfo = DistInfo (base_dir=datadir+"channels/") - - for suite in dinfo.suites: - comps = [] - for comp in suite.components: - comps.append(SourceCompTemplate(comp.name, _(comp.description), - comp.enabled)) - self.templates.append (SourceEntryTemplate(suite.repository_type, - suite.base_uri, - suite.name, - suite.description, - comps)) - # matcher class to make a source entry look nice # lots of predefined matchers to make it i18n/gettext friendly class SourceEntryMatcher: @@ -444,7 +396,7 @@ class SourceEntryMatcher: f = os.path.basename(f) i = f.find(".info") f = f[0:i] - dist = DistInfo(f) + dist = DistInfo(f,base_dir=matcherPath) for suite in dist.suites: if suite.match_uri != None: self.templates.append(suite) @@ -455,12 +407,17 @@ class SourceEntryMatcher: _ = gettext.gettext found = False for template in self.templates: - #print "'%s'" %source.uri - if re.search(template.match_uri, source.uri) and \ - re.match(template.match_name, source.dist): + if (re.search(template.match_uri, source.uri) and + re.match(template.match_name, source.dist)): found = True source.template = template break + for mirror in template.valid_mirrors: + if (is_mirror(mirror,source.uri) and + re.match(template.match_name, source.dist)): + found = True + source.template = template + break return found class Distribution: @@ -568,7 +525,6 @@ class Distribution: self.source_code_sources.append(source) else: self.disabled_sources.append(source) - self.download_comps = set(comps) self.cdrom_comps = set(cdrom_comps) enabled_comps.extend(comps) @@ -644,27 +600,37 @@ class Distribution: sourceslist: an aptsource.sources_list comp: the component that should be enabled """ - def add_component_only_once(source, workpile): + def add_component_only_once(source, comps_per_dist): """ Check if we already added the component to the repository, since a repository could be splitted into different apt lines. If not add the component """ - if not (workpile.has_key(source.uri) and\ - source.dist in workpile[source.uri]): - if comp not in source.comps: - source.comps.append(comp) - if workpile.has_key(source.uri): - workpile[source.uri].append(source.dist) - else: - workpile[source.uri] = [source.dist] + # if we don't that distro, just reutnr (can happen for e.g. + # dapper-update only in deb-src + if not comps_per_dist.has_key(source.dist): + return + # if we have seen this component already for this distro, + # return (nothing to do + if comp in comps_per_dist[source.dist]: + return + # add it + source.comps.append(comp) + comps_per_dist[source.dist].add(comp) sources = [] sources.extend(self.main_sources) sources.extend(self.child_sources) sources.extend(self.source_code_sources) - # store repos to which the new component has been added - workpile = {} + # store what comps are enabled already per distro (where distro is + # e.g. "dapper", "dapper-updates") + comps_per_dist = {} + for s in sources: + if s.type != "deb": + continue + if not comps_per_dist.has_key(s.dist): + comps_per_dist[s.dist] = set() + map(comps_per_dist[s.dist].add, s.comps) # check if there is a main source at all if len(self.main_sources) < 1: # create a new main source @@ -672,12 +638,20 @@ class Distribution: else: # add the comp to all main, child and source code sources for source in sources: - add_component_only_once(source, workpile) + add_component_only_once(source, comps_per_dist) + # now do the same for source dists if self.get_source_code == True: - for source in self.source_code_sources: - if comp not in source.comps: - add_component_only_once(source, workpile) + comps_per_dist = {} + for s in self.source_code_sources: + if s.type != "deb-src": + continue + if not comps_per_dist.has_key(s.dist): + comps_per_dist[s.dist] = set() + map(comps_per_dist[s.dist].add, s.comps) + for source in self.source_code_sources: + if comp not in source.comps: + add_component_only_once(source, comps_per_dist) def disable_component(self, sourceslist, comp): @@ -715,3 +689,6 @@ if __name__ == "__main__": print is_mirror("http://archive.ubuntu.com/ubuntu", "http://de.archive.ubuntu.com/ubuntu/") + print is_mirror("http://archive.ubuntu.com/ubuntu/", + "http://de.archive.ubuntu.com/ubuntu") + diff --git a/UpdateManager/Common/utils.py b/UpdateManager/Common/utils.py index 099cbfed..1fcd022f 100644 --- a/UpdateManager/Common/utils.py +++ b/UpdateManager/Common/utils.py @@ -1,4 +1,6 @@ import gtk +from gettext import gettext as _ +import locale def str_to_bool(str): if str == "0" or str.upper() == "FALSE": @@ -21,3 +23,20 @@ def error(parent, summary, message): res = d.run() d.destroy() return + +def humanize_size(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) diff --git a/UpdateManager/DistUpgradeFetcher.py b/UpdateManager/DistUpgradeFetcher.py index af07cfb4..cda27e2f 100644 --- a/UpdateManager/DistUpgradeFetcher.py +++ b/UpdateManager/DistUpgradeFetcher.py @@ -219,7 +219,7 @@ class DistUpgradeFetcher(object): if not self.verifyDistUprader(): error(self.window_main, _("Verfication failed"), - _("Verfing the upgrade failed. There may be a problem " + _("Verifying the upgrade failed. There may be a problem " "with the network or with the server. ")) self.cleanup() return diff --git a/UpdateManager/GtkProgress.py b/UpdateManager/GtkProgress.py index 54f60384..cb635e87 100644 --- a/UpdateManager/GtkProgress.py +++ b/UpdateManager/GtkProgress.py @@ -25,6 +25,7 @@ import gtk import apt import apt_pkg from gettext import gettext as _ +from Common.utils import * # intervals of the start up progress # 3x caching and menu creation @@ -104,12 +105,14 @@ class GtkFetchProgress(apt.progress.FetchProgress): if currentItem > self.totalItems: currentItem = self.totalItems if self.currentCPS > 0: - statusText = (_("Downloading file %li of %li with %s/s" - % (currentItem, self.totalItems, - apt_pkg.SizeToStr(self.currentCPS)))) + statusText = (_("Downloading file %(current)li of %(total)li with " + "%(speed)s/s") % {"current" : currentItem, + "total" : self.totalItems, + "speed" : humanize_size(self.currentCPS)}) else: - statusText = (_("Downloading file %li of %li with unknown " - "speed") % (currentItem, self.totalItems)) + statusText = (_("Downloading file %(current)li of %(total)li") % \ + {"current" : currentItem, + "total" : self.totalItems }) self.progress.set_fraction(self.percent/100.0) self.status.set_markup("<i>%s</i>" % statusText) # TRANSLATORS: show the remaining time in a progress bar: 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() |
