home *** CD-ROM | disk | FTP | other *** search
/ Mac Easy 2010 May / Mac Life Ubuntu.iso / casper / filesystem.squashfs / usr / share / pyshared / UpdateManager / Core / MyCache.py < prev    next >
Encoding:
Python Source  |  2009-04-27  |  10.1 KB  |  247 lines

  1. # MyCache.py 
  2. #  
  3. #  Copyright (c) 2004-2008 Canonical
  4. #  
  5. #  Author: Michael Vogt <mvo@debian.org>
  6. #  This program is free software; you can redistribute it and/or 
  7. #  modify it under the terms of the GNU General Public License as 
  8. #  published by the Free Software Foundation; either version 2 of the
  9. #  License, or (at your option) any later version.
  10. #  This program is distributed in the hope that it will be useful,
  11. #  but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. #  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13. #  GNU General Public License for more details.
  14. #  You should have received a copy of the GNU General Public License
  15. #  along with this program; if not, write to the Free Software
  16. #  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
  17. #  USA
  18.  
  19. import warnings
  20. warnings.filterwarnings("ignore", "apt API not stable yet", FutureWarning)
  21. import apt
  22. import apt_pkg
  23. import os
  24. import string
  25. import urllib2
  26. import httplib
  27. import socket
  28. import re
  29. import DistUpgrade.DistUpgradeCache
  30. from DistUpgrade.DistUpgradeCache import NotEnoughFreeSpaceError
  31. from gettext import gettext as _
  32.  
  33. SYNAPTIC_PINFILE = "/var/lib/synaptic/preferences"
  34. CHANGELOGS_URI="http://changelogs.ubuntu.com/changelogs/pool/%s/%s/%s/%s_%s/%s"
  35.  
  36.  
  37. class MyCache(DistUpgrade.DistUpgradeCache.MyCache):
  38.     def __init__(self, progress, rootdir=None):
  39.         apt.Cache.__init__(self, progress, rootdir)
  40.         # raise if we have packages in reqreinst state
  41.         # and let the caller deal with that (runs partial upgrade)
  42.         assert len(self.reqReinstallPkgs) == 0
  43.         # init the regular cache
  44.         self._initDepCache()
  45.         self.all_changes = {}
  46.         self.all_news = {}
  47.         # on broken packages, try to fix via saveDistUpgrade()
  48.         if self._depcache.BrokenCount > 0:
  49.             self.saveDistUpgrade()
  50.         assert (self._depcache.BrokenCount == 0 and 
  51.                 self._depcache.DelCount == 0)
  52.  
  53.     def _initDepCache(self):
  54.         #apt_pkg.Config.Set("Debug::pkgPolicy","1")
  55.         #self.depcache = apt_pkg.GetDepCache(self.cache)
  56.         #self._depcache = apt_pkg.GetDepCache(self._cache)
  57.         self._depcache.ReadPinFile()
  58.         if os.path.exists(SYNAPTIC_PINFILE):
  59.             self._depcache.ReadPinFile(SYNAPTIC_PINFILE)
  60.         self._depcache.Init()
  61.     def clear(self):
  62.         self._initDepCache()
  63.     @property
  64.     def requiredDownload(self):
  65.         """ get the size of the packages that are required to download """
  66.         pm = apt_pkg.GetPackageManager(self._depcache)
  67.         fetcher = apt_pkg.GetAcquire()
  68.         pm.GetArchives(fetcher, self._list, self._records)
  69.         return fetcher.FetchNeeded
  70.     @property
  71.     def installCount(self):
  72.         return self._depcache.InstCount
  73.     def saveDistUpgrade(self):
  74.         """ this functions mimics a upgrade but will never remove anything """
  75.         self._depcache.Upgrade(True)
  76.         wouldDelete = self._depcache.DelCount
  77.         if self._depcache.DelCount > 0:
  78.             self.clear()
  79.         assert self._depcache.BrokenCount == 0 and self._depcache.DelCount == 0
  80.         self._depcache.Upgrade()
  81.         return wouldDelete
  82.     def matchPackageOrigin(self, pkg, matcher):
  83.         """ match 'pkg' origin against 'matcher', take versions between
  84.             installedVersion and candidateVersion into account too
  85.             Useful if installed pkg A v1.0 is available in both
  86.             -updates (as v1.2) and -security (v1.1). we want to display
  87.             it as a security update then
  88.         """
  89.         inst_ver = pkg._pkg.CurrentVer
  90.         cand_ver = self._depcache.GetCandidateVer(pkg._pkg)
  91.         # init matcher with candidateVer
  92.         update_origin = matcher[(None,None)]
  93.         for(verFileIter,index) in cand_ver.FileList:
  94.             if matcher.has_key((verFileIter.Archive, verFileIter.Origin)):
  95.                 indexfile = pkg._pcache._list.FindIndex(verFileIter)
  96.                 if indexfile: # and indexfile.IsTrusted:
  97.                     match = matcher[verFileIter.Archive, verFileIter.Origin]
  98.                     update_origin = match
  99.         # if the candidate comes from a unknown source (e.g. a PPA) skip
  100.         # skip the shadow logic below as it would put e.g. a PPA package
  101.         # in "Recommended updates" when the version in the PPA 
  102.         # is higher than the one in %s-updates
  103.         if update_origin.importance < 0:
  104.             return update_origin
  105.         # for known packages, check if we have higher versions that
  106.         # "shadow" this one
  107.         for ver in pkg._pkg.VersionList:
  108.             # discard is < than installed ver
  109.             if (inst_ver and
  110.                 apt_pkg.VersionCompare(ver.VerStr, inst_ver.VerStr) <= 0):
  111.                 #print "skipping '%s' " % ver.VerStr
  112.                 continue
  113.             # check if we have a match
  114.             for(verFileIter,index) in ver.FileList:
  115.                 if matcher.has_key((verFileIter.Archive, verFileIter.Origin)):
  116.                     indexfile = pkg._pcache._list.FindIndex(verFileIter)
  117.                     if indexfile: # and indexfile.IsTrusted:
  118.                         match = matcher[verFileIter.Archive, verFileIter.Origin]
  119.                         if match.importance > update_origin.importance:
  120.                             update_origin = match
  121.         return update_origin
  122.  
  123.     def _strip_epoch(self, verstr):
  124.         " strip of the epoch "
  125.         l = string.split(verstr,":")
  126.         if len(l) > 1:
  127.             verstr = "".join(l[1:])
  128.         return verstr
  129.         
  130.     def _get_changelog_or_news(self, name, fname, strict_versioning=False):
  131.         " helper that fetches the file in question "
  132.         # don't touch the gui in this function, it needs to be thread-safe
  133.         pkg = self[name]
  134.  
  135.         # get the src package name
  136.         srcpkg = pkg.sourcePackageName
  137.  
  138.         # assume "main" section 
  139.         src_section = "main"
  140.         # use the section of the candidate as a starting point
  141.         section = pkg._pcache._depcache.GetCandidateVer(pkg._pkg).Section
  142.  
  143.         # get the source version, start with the binaries version
  144.         binver = pkg.candidateVersion
  145.         srcver_epoch = pkg.candidateVersion
  146.         srcver = self._strip_epoch(srcver_epoch)
  147.         #print "bin: %s" % binver
  148.  
  149.         l = section.split("/")
  150.         if len(l) > 1:
  151.             src_section = l[0]
  152.  
  153.         # lib is handled special
  154.         prefix = srcpkg[0]
  155.         if srcpkg.startswith("lib"):
  156.             prefix = "lib" + srcpkg[3]
  157.  
  158.         uri = CHANGELOGS_URI % (src_section,prefix,srcpkg,srcpkg, srcver, fname)
  159.         # print "Trying: %s " % uri
  160.         changelog = urllib2.urlopen(uri)
  161.         #print changelog.read()
  162.         # do only get the lines that are new
  163.         alllines = ""
  164.         regexp = "^%s \((.*)\)(.*)$" % (re.escape(srcpkg))
  165.         
  166.         i=0
  167.         while True:
  168.             line = changelog.readline()
  169.             if line == "":
  170.                 break
  171.             match = re.match(regexp,line)
  172.             if match:
  173.                 # strip epoch from installed version
  174.                 # and from changelog too
  175.                 installed = pkg.installedVersion
  176.                 if installed and ":" in installed:
  177.                     installed = installed.split(":",1)[1]
  178.                 changelogver = match.group(1)
  179.                 if changelogver and ":" in changelogver:
  180.                     changelogver = changelogver.split(":",1)[1]
  181.                 # we test for "==" here for changelogs 
  182.                 # to ensure that the version
  183.                 # is actually really in the changelog - if not
  184.                 # just display it all, this catches cases like:
  185.                 # gcc-defaults with "binver=4.3.1" and srcver=1.76
  186.                 # 
  187.                 # for NEWS.Debian we do require the changelogver > installed
  188.                 if strict_versioning:
  189.                     if (installed and 
  190.                         apt_pkg.VersionCompare(changelogver,installed)<0):
  191.                         break
  192.                 else:
  193.                     if (installed and 
  194.                         apt_pkg.VersionCompare(changelogver,installed)==0):
  195.                         break
  196.             alllines = alllines + line
  197.         return alllines
  198.         
  199.     def get_news_and_changelog(self, name, lock):
  200.         self.get_news(name)
  201.         self.get_changelog(name)
  202.         lock.release()        
  203.     
  204.     def get_news(self, name):
  205.         " get the NEWS.Debian file from the changelogs location "
  206.         try:
  207.             news = self._get_changelog_or_news(name, "NEWS.Debian", True)
  208.         except Exception, e:
  209.             return
  210.         if news:
  211.             self.all_news[name] = news
  212.                     
  213.     def get_changelog(self, name):
  214.         " get the changelog file from the changelog location "
  215.         origins = self[name].candidateOrigin
  216.         if not "Ubuntu" in [o.origin for o in origins]:
  217.             # FIXME: better string, but we are in string freeze
  218.             self.all_changes[name] = _("Failed to detect distribution")
  219.             return
  220.         srcpkg = self[name].sourcePackageName
  221.         srcver_epoch = self[name].candidateVersion.replace(':', '%3A')
  222.         try:
  223.             changelog = self._get_changelog_or_news(name, "changelog")
  224.             if len(changelog) == 0:
  225.                 changelog = _("The changelog does not contain any relevant changes.\n\n"
  226.                               "Please use http://launchpad.net/ubuntu/+source/%s/%s/+changelog\n"
  227.                               "until the changes become available or try again "
  228.                               "later.") % (srcpkg, srcver_epoch)
  229.         except urllib2.HTTPError, e:
  230.             changelog = _("The list of changes is not available yet.\n\n"
  231.                           "Please use http://launchpad.net/ubuntu/+source/%s/%s/+changelog\n"
  232.                           "until the changes become available or try again "
  233.                           "later.") % (srcpkg, srcver_epoch)
  234.         except (IOError, httplib.BadStatusLine, socket.error), e:
  235.             print "caught exception: ", e
  236.             changelog = _("Failed to download the list "
  237.                           "of changes. \nPlease "
  238.                           "check your Internet "
  239.                           "connection.")
  240.         self.all_changes[name] = changelog
  241.  
  242.  
  243.  
  244.