summaryrefslogtreecommitdiff
path: root/UpdateManager
diff options
context:
space:
mode:
authorMichael Vogt <michael.vogt@ubuntu.com>2006-10-27 09:57:49 +0200
committerMichael Vogt <michael.vogt@ubuntu.com>2006-10-27 09:57:49 +0200
commitbed5736c7cf31070540bd7e27ffb073db3d7c396 (patch)
treec733204d23625109cd282afcf2ac54539d300fd9 /UpdateManager
parent590c710c9feef18c9a23676aab1ce0fb7b6d2f75 (diff)
parentdcee921a1107db6e5c8042598641b422a77e24c2 (diff)
downloadpython-apt-bed5736c7cf31070540bd7e27ffb073db3d7c396.tar.gz
* merged from main
Diffstat (limited to 'UpdateManager')
-rw-r--r--UpdateManager/Common/DistInfo.py35
-rw-r--r--UpdateManager/Common/aptsources.py169
-rw-r--r--UpdateManager/Common/utils.py19
-rw-r--r--UpdateManager/DistUpgradeFetcher.py2
-rw-r--r--UpdateManager/GtkProgress.py13
-rw-r--r--UpdateManager/UpdateManager.py235
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()