home *** CD-ROM | disk | FTP | other *** search
/ PC Welt 2006 November (DVD) / PCWELT_11_2006.ISO / casper / filesystem.squashfs / usr / lib / python2.4 / site-packages / GDebi / DebPackage.py < prev    next >
Encoding:
Python Source  |  2006-08-04  |  12.3 KB  |  367 lines

  1. import apt_inst, apt_pkg
  2. import apt
  3. import sys
  4. import os 
  5. from gettext import gettext as _
  6.  
  7.  
  8. class DebPackage(object):
  9.     debug = 0
  10.  
  11.     def __init__(self, cache, file):
  12.         cache.clear()
  13.         self._cache = cache
  14.         self.file = file
  15.         self._needPkgs = None
  16.         # read the deb
  17.         control = apt_inst.debExtractControl(open(file))
  18.         self._sections = apt_pkg.ParseSection(control)
  19.         self.pkgName = self._sections["Package"]
  20.  
  21.  
  22.     def _isOrGroupSatisfied(self, or_group):
  23.         """ this function gets a 'or_group' and analyzes if
  24.             at least one dependency of this group is already satisfied """
  25.         self._dbg(2,"_checkOrGroup(): %s " % (or_group))
  26.  
  27.         for dep in or_group:
  28.             depname = dep[0]
  29.             ver = dep[1]
  30.             oper = dep[2]
  31.  
  32.             # check for virtual pkgs
  33.             if not self._cache.has_key(depname):
  34.                 if self._cache.isVirtualPkg(depname):
  35.                     #print "%s is virtual" % depname
  36.                     for pkg in self._cache.getProvidersForVirtual(depname):
  37.                         if pkg.isInstalled:
  38.                             return True
  39.                 continue
  40.  
  41.             inst = self._cache[depname]
  42.             instver = inst.installedVersion
  43.             if instver != None and apt_pkg.CheckDep(instver,oper,ver) == True:
  44.                 return True
  45.  
  46.         return False
  47.             
  48.  
  49.     def _satisfyOrGroup(self, or_group):
  50.         """ try to satisfy the or_group """
  51.  
  52.         or_found = False
  53.         virtual_pkg = None
  54.  
  55.         for dep in or_group:
  56.             depname = dep[0]
  57.             ver = dep[1]
  58.             oper = dep[2]
  59.  
  60.             if not self._cache.has_key(depname):
  61.                 if self._cache.isVirtualPkg(depname):
  62.                     virtual_pkg = depname
  63.                 continue
  64.                 
  65.             # now check if we can satisfy the deps with the candidate(s)
  66.             # in the cache
  67.             cand = self._cache[depname]
  68.             candver = self._cache._depcache.GetCandidateVer(cand._pkg)
  69.             if not candver:
  70.                 continue
  71.             if not apt_pkg.CheckDep(candver.VerStr,oper,ver):
  72.                 continue
  73.  
  74.             # check if we need to install it
  75.             self._dbg(2,"Need to get: %s" % depname)
  76.             self._needPkgs.append(depname)
  77.             return True
  78.  
  79.         # check if this or group was ok
  80.         or_str = ""
  81.         for dep in or_group:
  82.             or_str += dep[0]
  83.             if dep != or_group[len(or_group)-1]:
  84.                 or_str += "|"
  85.         self._failureString += _("Dependency is not satisfiable: %s\n" % or_str)
  86.         return False
  87.  
  88.     def _checkSinglePkgConflict(self, pkgname, ver, oper):
  89.         """ returns true if a pkg conflicts with a real installed/marked
  90.             pkg """
  91.         pkgver = None
  92.         cand = self._cache[pkgname]
  93.         if cand.isInstalled:
  94.             pkgver = cand.installedVersion
  95.         elif cand.markedInstall:
  96.             pkgver = cand.candidateVersion
  97.         #print "pkg: %s" % pkgname
  98.         #print "ver: %s" % ver
  99.         #print "pkgver: %s " % pkgver
  100.         #print "oper: %s " % oper
  101.         if pkgver and apt_pkg.CheckDep(pkgver,oper,ver):
  102.             self._failureString += _("Conflicts with the installed package '%s'" % cand.name)
  103.             return True
  104.         return False
  105.  
  106.     def _checkConflictsOrGroup(self, or_group):
  107.         """ check the or-group for conflicts with installed pkgs """
  108.         self._dbg(2,"_checkConflictsOrGroup(): %s " % (or_group))
  109.  
  110.         or_found = False
  111.         virtual_pkg = None
  112.  
  113.         for dep in or_group:
  114.             depname = dep[0]
  115.             ver = dep[1]
  116.             oper = dep[2]
  117.  
  118.             # FIXME: conflicts with virutal pkgs needs to be
  119.             #        checked!
  120.             if not self._cache.has_key(depname):
  121.                 if self._cache.isVirtualPkg(depname):
  122.                     for pkg in self._cache.getProvidersForVirtual(depname):
  123.                         #print "conflicts virtual check: %s" % pkg.name
  124.                         if self._checkSinglePkgConflict(pkg.name,ver,oper):
  125.                             return True
  126.                 continue
  127.             if self._checkSinglePkgConflict(depname,ver,oper):
  128.                 return True
  129.             
  130.         return False
  131.  
  132.     def checkConflicts(self):
  133.         """ check if the pkg conflicts with a existing or to be installed
  134.             package. Return True if the pkg is ok """
  135.         
  136.         key = "Conflicts"
  137.         if self._sections.has_key(key):
  138.             conflicts = apt_pkg.ParseDepends(self._sections[key])
  139.             for or_group in conflicts:
  140.                 if self._checkConflictsOrGroup(or_group):
  141.                     #print "Conflicts with a exisiting pkg!"
  142.                     #self._failureString = "Conflicts with a exisiting pkg!"
  143.                     return False
  144.         return True
  145.  
  146.     # some constants
  147.     (NO_VERSION,
  148.      VERSION_OUTDATED,
  149.      VERSION_SAME,
  150.      VERSION_IS_NEWER) = range(4)
  151.     
  152.     def compareToVersionInCache(self, useInstalled=True):
  153.         """ checks if the pkg is already installed or availabe in the cache
  154.             and if so in what version, returns if the version of the deb
  155.             is not available,older,same,newer
  156.         """
  157.         self._dbg(3,"compareToVersionInCache")
  158.         pkgname = self._sections["Package"]
  159.         debver = self._sections["Version"]
  160.         self._dbg(1,"debver: %s" % debver)
  161.         if self._cache.has_key(pkgname):
  162.             if useInstalled:
  163.                 cachever = self._cache[pkgname].installedVersion
  164.             else:
  165.                 cachever = self._cache[pkgname].candidateVersion
  166.             if cachever != None:
  167.                 cmp = apt_pkg.VersionCompare(cachever,debver)
  168.                 self._dbg(1, "CompareVersion(debver,instver): %s" % cmp)
  169.                 if cmp == 0:
  170.                     return self.VERSION_SAME
  171.                 elif cmp < 0:
  172.                     return self.VERSION_IS_NEWER
  173.                 elif cmp > 0:
  174.                     return self.VERSION_OUTDATED
  175.         return self.NO_VERSION
  176.  
  177.     def checkDeb(self):
  178.         self._dbg(3,"checkDepends")
  179.         # init 
  180.         self._needPkgs = []
  181.         depends = []
  182.  
  183.         # check arch
  184.         arch = self._sections["Architecture"]
  185.         if  arch != "all" and arch != apt_pkg.CPU:
  186.             self._dbg(1,"ERROR: Wrong architecture dude!")
  187.             self._failureString = _("Wrong architecture '%s'" % arch)
  188.             return False
  189.  
  190.         # check version
  191.         res = self.compareToVersionInCache()
  192.         if res == self.VERSION_OUTDATED: # the deb is older than the installed
  193.             self._failureString = _("A later version is already installed")
  194.             return False
  195.  
  196.         # FIXME: this sort of error handling sux
  197.         self._failureString = ""
  198.             
  199.         # check conflicts
  200.         if not self.checkConflicts():
  201.             return False
  202.         
  203.         # find depends
  204.         for key in ["Depends","PreDepends"]:
  205.             if self._sections.has_key(key):
  206.                 depends.extend(apt_pkg.ParseDepends(self._sections[key]))
  207.  
  208.         # check depends
  209.         for or_group in depends:
  210.             #print "or_group: %s" % or_group
  211.             #print "or_group satified: %s" % self._isOrGroupSatisfied(or_group)
  212.             if not self._isOrGroupSatisfied(or_group):
  213.                 if not self._satisfyOrGroup(or_group):
  214.                     return False
  215.  
  216.         # now try it out in the cache
  217.             for pkg in self._needPkgs:
  218.                 try:
  219.                     self._cache[pkg].markInstall()
  220.                 except SystemError:
  221.                     self._failureString = _("Cannot install '%s'" % pkg)
  222.                     self._cache.clear()
  223.                     return False
  224.  
  225.         # check for conflicts again (this time with the packages that are
  226.         # makeed for install)
  227.         if not self.checkConflicts():
  228.             return False
  229.  
  230.         if self._cache._depcache.BrokenCount > 0:
  231.             self._failureString = _("Failed to satisfy all dependencies (broken cache)")
  232.             # clean the cache again
  233.             self._cache.clear()
  234.             return False
  235.  
  236.         return True
  237.  
  238.     def missingDeps(self):
  239.         self._dbg(1, "Installing: %s" % self._needPkgs)
  240.         if self._needPkgs == None:
  241.             self.checkDeb()
  242.         return self._needPkgs
  243.     missingDeps = property(missingDeps)
  244.  
  245.     def requiredChanges(self):
  246.         install = []
  247.         remove = []
  248.         unauthenticated = []
  249.         for pkg in self._cache:
  250.             if pkg.markedInstall or pkg.markedUpgrade:
  251.                 install.append(pkg.name)
  252.                 # check authentication, one authenticated origin is enough
  253.                 # libapt will skip non-authenticated origins then
  254.                 authenticated = False
  255.                 for origin in pkg.candidateOrigin:
  256.                     authenticated |= origin.trusted
  257.                 if not authenticated:
  258.                     unauthenticated.append(pkg.name)
  259.             if pkg.markedDelete:
  260.                 remove.append(pkg.name)
  261.         return (install,remove, unauthenticated)
  262.     requiredChanges = property(requiredChanges)
  263.  
  264.     def filelist(self):
  265.         """ return the list of files in the deb """
  266.         files = []
  267.         def extract_cb(What,Name,Link,Mode,UID,GID,Size,MTime,Major,Minor):
  268.             #print "%s '%s','%s',%u,%u,%u,%u,%u,%u,%u"\
  269.             #      % (What,Name,Link,Mode,UID,GID,Size, MTime, Major, Minor)
  270.             files.append(Name)
  271.         apt_inst.debExtract(open(self.file), extract_cb, "data.tar.gz")
  272.         return files
  273.     filelist = property(filelist)
  274.     
  275.     # properties
  276.     def __getitem__(self,item):
  277.         if not self._sections.has_key(item):
  278.             # Translators: it's for missing entries in the deb package,
  279.             # e.g. a missing "Maintainer" field
  280.             return _("%s is not available" % item)
  281.         return self._sections[item]
  282.  
  283.     def _dbg(self, level, msg):
  284.         """Write debugging output to sys.stderr.
  285.         """
  286.         if level <= self.debug:
  287.             print >> sys.stderr, msg
  288.  
  289.  
  290. class MyCache(apt.Cache):
  291.     """ helper to provide some additonal functions """
  292.  
  293.     def clear(self):
  294.         """ unmark all pkgs """
  295.         self._depcache.Init()
  296.  
  297.     def isVirtualPkg(self, pkgname):
  298.         """ this function returns true if pkgname is a virtual
  299.             pkg """
  300.         try:
  301.             virtual_pkg = self._cache[pkgname]
  302.         except KeyError:
  303.             return False
  304.  
  305.         if len(virtual_pkg.VersionList) == 0:
  306.             return True
  307.         return False
  308.  
  309.     def downloadable(self, pkg, useCandidate=True):
  310.         " check if the given pkg can be downloaded "
  311.         if useCandidate:
  312.             ver = self._depcache.GetCandidateVer(pkg._pkg)
  313.         else:
  314.             ver = pkg._pkg.CurrentVer
  315.         if ver == None:
  316.             return False
  317.         return ver.Downloadable
  318.  
  319.     def getProvidersForVirtual(self, virtual_pkg):
  320.         providers = []
  321.         try:
  322.             vp = self._cache[virtual_pkg]
  323.             if len(vp.VersionList) != 0:
  324.                 return providers
  325.         except IndexError:
  326.             return providers
  327.         for pkg in self:
  328.             v = self._depcache.GetCandidateVer(pkg._pkg)
  329.             if v == None:
  330.                 continue
  331.             for p in v.ProvidesList:
  332.                 #print virtual_pkg
  333.                 #print p[0]
  334.                 if virtual_pkg == p[0]:
  335.                     # we found a pkg that provides this virtual
  336.                     # pkg, check if the proivdes is any good
  337.                     providers.append(pkg)
  338.                     #cand = self._cache[pkg.name]
  339.                     #candver = self._cache._depcache.GetCandidateVer(cand._pkg)
  340.                     #instver = cand._pkg.CurrentVer
  341.                     #res = apt_pkg.CheckDep(candver.VerStr,oper,ver)
  342.                     #if res == True:
  343.                     #    self._dbg(1,"we can use %s" % pkg.name)
  344.                     #    or_found = True
  345.                     #    break
  346.         return providers
  347.  
  348. if __name__ == "__main__":
  349.  
  350.     cache = MyCache()
  351.  
  352.     vp = "www-browser"
  353.     print "%s virtual: %s" % (vp,cache.isVirtualPkg(vp))
  354.     providers = cache.getProvidersForVirtual(vp)
  355.     print "Providers for %s :" % vp
  356.     for pkg in providers:
  357.         print " %s" % pkg.name
  358.     
  359.     d = DebPackage(cache, sys.argv[1])
  360.     print "Deb: %s" % d.pkgName
  361.     if not d.checkDeb():
  362.         print "can't be satified"
  363.         print d._failureString
  364.     print "missing deps: %s" % d.missingDeps
  365.     print d.requiredChanges
  366.  
  367.