home *** CD-ROM | disk | FTP | other *** search
/ Mac Easy 2010 May / Mac Life Ubuntu.iso / casper / filesystem.squashfs / usr / share / pyshared / apt / package.py < prev    next >
Encoding:
Python Source  |  2009-03-30  |  27.5 KB  |  813 lines

  1. # package.py - apt package abstraction
  2. #
  3. #  Copyright (c) 2005 Canonical
  4. #
  5. #  Author: Michael Vogt <michael.vogt@ubuntu.com>
  6. #
  7. #  This program is free software; you can redistribute it and/or
  8. #  modify it under the terms of the GNU General Public License as
  9. #  published by the Free Software Foundation; either version 2 of the
  10. #  License, or (at your option) any later version.
  11. #
  12. #  This program is distributed in the hope that it will be useful,
  13. #  but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. #  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15. #  GNU General Public License for more details.
  16. #
  17. #  You should have received a copy of the GNU General Public License
  18. #  along with this program; if not, write to the Free Software
  19. #  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
  20. #  USA
  21. """Functionality related to packages."""
  22. import gettext
  23. import httplib
  24. import sys
  25. import re
  26. import socket
  27. import urllib2
  28.  
  29. import apt_pkg
  30.  
  31.  
  32. __all__ = 'BaseDependency', 'Dependency', 'Origin', 'Package', 'Record'
  33.  
  34.  
  35. def _(string):
  36.     """Return the translation of the string."""
  37.     return gettext.dgettext("python-apt", string)
  38.  
  39.  
  40. class BaseDependency(object):
  41.     """A single dependency.
  42.  
  43.     Attributes defined here:
  44.         name      - The name of the dependency
  45.         relation  - The relation (>>,>=,==,<<,<=,)
  46.         version   - The version depended on
  47.         preDepend - Boolean value whether this is a pre-dependency.
  48.     """
  49.  
  50.     def __init__(self, name, rel, ver, pre):
  51.         self.name = name
  52.         self.relation = rel
  53.         self.version = ver
  54.         self.preDepend = pre
  55.  
  56.  
  57. class Dependency(object):
  58.     """Represent an Or-group of dependencies.
  59.  
  60.     Attributes defined here:
  61.         or_dependencies - The possible choices
  62.     """
  63.  
  64.     def __init__(self, alternatives):
  65.         self.or_dependencies = alternatives
  66.  
  67.  
  68. class Origin(object):
  69.     """The origin of a version.
  70.  
  71.     Attributes defined here:
  72.         archive   - The archive (eg. unstable)
  73.         component - The component (eg. main)
  74.         label     - The Label, as set in the Release file
  75.         origin    - The Origin, as set in the Release file
  76.         site      - The hostname of the site.
  77.         trusted   - Boolean value whether this is trustworthy.
  78.     """
  79.  
  80.     def __init__(self, pkg, VerFileIter):
  81.         self.archive = VerFileIter.Archive
  82.         self.component = VerFileIter.Component
  83.         self.label = VerFileIter.Label
  84.         self.origin = VerFileIter.Origin
  85.         self.site = VerFileIter.Site
  86.         self.not_automatic = VerFileIter.NotAutomatic
  87.         # check the trust
  88.         indexfile = pkg._list.FindIndex(VerFileIter)
  89.         if indexfile and indexfile.IsTrusted:
  90.             self.trusted = True
  91.         else:
  92.             self.trusted = False
  93.  
  94.     def __repr__(self):
  95.         return ("<Origin component:'%s' archive:'%s' origin:'%s' label:'%s'"
  96.                 "site:'%s' isTrusted:'%s'>") % (self.component, self.archive,
  97.                                                 self.origin, self.label,
  98.                                                 self.site, self.trusted)
  99.  
  100.  
  101. class Record(object):
  102.     """Represent a pkgRecord.
  103.  
  104.     It can be accessed like a dictionary and can also give the original package
  105.     record if accessed as a string.
  106.     """
  107.  
  108.     def __init__(self, record_str):
  109.         self._rec = apt_pkg.ParseSection(record_str)
  110.  
  111.     def __str__(self):
  112.         return str(self._rec)
  113.  
  114.     def __getitem__(self, key):
  115.         return self._rec[key]
  116.  
  117.     def __contains__(self, key):
  118.         return self._rec.has_key(key)
  119.  
  120.     def __iter__(self):
  121.         return iter(self._rec.keys())
  122.  
  123.     def iteritems(self):
  124.         """An iterator over the (key, value) items of the record."""
  125.         for key in self._rec.keys():
  126.             yield key, self._rec[key]
  127.  
  128.     def get(self, key, default=None):
  129.         """Return record[key] if key in record, else `default`.
  130.  
  131.         The parameter `default` must be either a string or None.
  132.         """
  133.         return self._rec.get(key, default)
  134.  
  135.     def has_key(self, key):
  136.         """deprecated form of 'key in x'."""
  137.         return self._rec.has_key(key)
  138.  
  139.  
  140. class Package(object):
  141.     """Representation of a package in a cache.
  142.  
  143.     This class provides methods and properties for working with a package. It
  144.     lets you mark the package for installation, check if it is installed, and
  145.     much more.
  146.     """
  147.  
  148.     def __init__(self, cache, depcache, records, sourcelist, pcache, pkgiter):
  149.         """ Init the Package object """
  150.         self._cache = cache             # low level cache
  151.         self._depcache = depcache
  152.         self._records = records
  153.         self._pkg = pkgiter
  154.         self._list = sourcelist               # sourcelist
  155.         self._pcache = pcache           # python cache in cache.py
  156.         self._changelog = ""            # Cached changelog
  157.  
  158.     def _lookupRecord(self, UseCandidate=True):
  159.         """Internal helper that moves the Records to the right position.
  160.  
  161.         Must be called before _records is accessed.
  162.         """
  163.         if UseCandidate:
  164.             ver = self._depcache.GetCandidateVer(self._pkg)
  165.         else:
  166.             ver = self._pkg.CurrentVer
  167.  
  168.         # check if we found a version
  169.         if ver is None:
  170.             #print "No version for: %s (Candidate: %s)" % (self._pkg.Name,
  171.             #                                              UseCandidate)
  172.             return False
  173.  
  174.         if ver.FileList is None:
  175.             print "No FileList for: %s " % self._pkg.Name()
  176.             return False
  177.         f, index = ver.FileList.pop(0)
  178.         self._records.Lookup((f, index))
  179.         return True
  180.  
  181.     @property
  182.     def name(self):
  183.         """Return the name of the package."""
  184.         return self._pkg.Name
  185.  
  186.     @property
  187.     def id(self):
  188.         """Return a uniq ID for the package.
  189.  
  190.         This can be used eg. to store additional information about the pkg."""
  191.         return self._pkg.ID
  192.  
  193.     def __hash__(self):
  194.         """Return the hash of the object.
  195.  
  196.         This returns the same value as ID, which is unique."""
  197.         return self._pkg.ID
  198.  
  199.     @property
  200.     def installedVersion(self):
  201.         """Return the installed version as string."""
  202.         ver = self._pkg.CurrentVer
  203.         if ver is not None:
  204.             return ver.VerStr
  205.         else:
  206.             return None
  207.  
  208.     @property
  209.     def candidateVersion(self):
  210.         """Return the candidate version as string."""
  211.         ver = self._depcache.GetCandidateVer(self._pkg)
  212.         if ver is not None:
  213.             return ver.VerStr
  214.         else:
  215.             return None
  216.  
  217.     def _getDependencies(self, ver):
  218.         """Get the dependencies for a given version of a package."""
  219.         depends_list = []
  220.         depends = ver.DependsList
  221.         for t in ["PreDepends", "Depends"]:
  222.             try:
  223.                 for depVerList in depends[t]:
  224.                     base_deps = []
  225.                     for depOr in depVerList:
  226.                         base_deps.append(BaseDependency(depOr.TargetPkg.Name,
  227.                                         depOr.CompType, depOr.TargetVer,
  228.                                         (t == "PreDepends")))
  229.                     depends_list.append(Dependency(base_deps))
  230.             except KeyError:
  231.                 pass
  232.         return depends_list
  233.  
  234.     @property
  235.     def candidateDependencies(self):
  236.         """Return a list of candidate dependencies."""
  237.         candver = self._depcache.GetCandidateVer(self._pkg)
  238.         if candver is None:
  239.             return []
  240.         return self._getDependencies(candver)
  241.  
  242.     @property
  243.     def installedDependencies(self):
  244.         """Return a list of installed dependencies."""
  245.         ver = self._pkg.CurrentVer
  246.         if ver is None:
  247.             return []
  248.         return self._getDependencies(ver)
  249.  
  250.     @property
  251.     def architecture(self):
  252.         """Return the Architecture of the package"""
  253.         if not self._lookupRecord():
  254.             return None
  255.         sec = apt_pkg.ParseSection(self._records.Record)
  256.         try:
  257.             return sec["Architecture"]
  258.         except KeyError:
  259.             return None
  260.  
  261.     def _downloadable(self, useCandidate=True):
  262.         """Return True if the package is downloadable."""
  263.         if useCandidate:
  264.             ver = self._depcache.GetCandidateVer(self._pkg)
  265.         else:
  266.             ver = self._pkg.CurrentVer
  267.         if ver is None:
  268.             return False
  269.         return ver.Downloadable
  270.  
  271.     @property
  272.     def candidateDownloadable(self):
  273.         """Return True if the candidate is downloadable."""
  274.         return self._downloadable(True)
  275.  
  276.     @property
  277.     def installedDownloadable(self):
  278.         """Return True if the installed version is downloadable."""
  279.         return self._downloadable(False)
  280.  
  281.     @property
  282.     def sourcePackageName(self):
  283.         """Return the source package name as string."""
  284.         if not self._lookupRecord():
  285.             if not self._lookupRecord(False):
  286.                 return self._pkg.Name
  287.         src = self._records.SourcePkg
  288.         if src != "":
  289.             return src
  290.         else:
  291.             return self._pkg.Name
  292.  
  293.     @property
  294.     def homepage(self):
  295.         """Return the homepage field as string."""
  296.         if not self._lookupRecord():
  297.             return None
  298.         return self._records.Homepage
  299.  
  300.     @property
  301.     def section(self):
  302.         """Return the section of the package."""
  303.         return self._pkg.Section
  304.  
  305.     @property
  306.     def priority(self):
  307.         """Return the priority (of the candidate version)."""
  308.         ver = self._depcache.GetCandidateVer(self._pkg)
  309.         if ver:
  310.             return ver.PriorityStr
  311.         else:
  312.             return None
  313.  
  314.     @property
  315.     def installedPriority(self):
  316.         """Return the priority (of the installed version)."""
  317.         ver = self._depcache.GetCandidateVer(self._pkg)
  318.         if ver:
  319.             return ver.PriorityStr
  320.         else:
  321.             return None
  322.  
  323.     @property
  324.     def summary(self):
  325.         """Return the short description (one line summary)."""
  326.         if not self._lookupRecord():
  327.             return ""
  328.         ver = self._depcache.GetCandidateVer(self._pkg)
  329.         desc_iter = ver.TranslatedDescription
  330.         self._records.Lookup(desc_iter.FileList.pop(0))
  331.         return self._records.ShortDesc
  332.  
  333.     @property
  334.     def description(self, format=True, useDots=False):
  335.         """Return the formatted long description.
  336.  
  337.         Return the formated long description according to the Debian policy
  338.         (Chapter 5.6.13).
  339.         See http://www.debian.org/doc/debian-policy/ch-controlfields.html
  340.         for more information.
  341.         """
  342.         if not format:
  343.             return self.rawDescription
  344.         if not self._lookupRecord():
  345.             return ""
  346.         # get the translated description
  347.         ver = self._depcache.GetCandidateVer(self._pkg)
  348.         desc_iter = ver.TranslatedDescription
  349.         self._records.Lookup(desc_iter.FileList.pop(0))
  350.         desc = ""
  351.         try:
  352.             dsc = unicode(self._records.LongDesc, "utf-8")
  353.         except UnicodeDecodeError, err:
  354.             dsc = _("Invalid unicode in description for '%s' (%s). "
  355.                   "Please report.") % (self.name, err)
  356.         lines = dsc.split("\n")
  357.         for i in range(len(lines)):
  358.             # Skip the first line, since its a duplication of the summary
  359.             if i == 0:
  360.                 continue
  361.             raw_line = lines[i]
  362.             if raw_line.strip() == ".":
  363.                 # The line is just line break
  364.                 if not desc.endswith("\n"):
  365.                     desc += "\n"
  366.                 continue
  367.             elif raw_line.startswith("  "):
  368.                 # The line should be displayed verbatim without word wrapping
  369.                 if not desc.endswith("\n"):
  370.                     line = "\n%s\n" % raw_line[2:]
  371.                 else:
  372.                     line = "%s\n" % raw_line[2:]
  373.             elif raw_line.startswith(" "):
  374.                 # The line is part of a paragraph.
  375.                 if desc.endswith("\n") or desc == "":
  376.                     # Skip the leading white space
  377.                     line = raw_line[1:]
  378.                 else:
  379.                     line = raw_line
  380.             else:
  381.                 line = raw_line
  382.             # Use dots for lists
  383.             if useDots:
  384.                 line = re.sub(r"^(\s*)(\*|0|o|-) ", ur"\1\u2022 ", line, 1)
  385.             # Add current line to the description
  386.             desc += line
  387.         return desc
  388.  
  389.     @property
  390.     def rawDescription(self):
  391.         """return the long description (raw)."""
  392.         if not self._lookupRecord():
  393.             return ""
  394.         return self._records.LongDesc
  395.  
  396.     @property
  397.     def candidateRecord(self):
  398.         """Return the Record of the candidate version of the package."""
  399.         if not self._lookupRecord(True):
  400.             return None
  401.         return Record(self._records.Record)
  402.  
  403.     @property
  404.     def installedRecord(self):
  405.         """Return the Record of the candidate version of the package."""
  406.         if not self._lookupRecord(False):
  407.             return None
  408.         return Record(self._records.Record)
  409.  
  410.     # depcache states
  411.  
  412.     @property
  413.     def markedInstall(self):
  414.         """Return True if the package is marked for install."""
  415.         return self._depcache.MarkedInstall(self._pkg)
  416.  
  417.     @property
  418.     def markedUpgrade(self):
  419.         """Return True if the package is marked for upgrade."""
  420.         return self._depcache.MarkedUpgrade(self._pkg)
  421.  
  422.     @property
  423.     def markedDelete(self):
  424.         """Return True if the package is marked for delete."""
  425.         return self._depcache.MarkedDelete(self._pkg)
  426.  
  427.     @property
  428.     def markedKeep(self):
  429.         """Return True if the package is marked for keep."""
  430.         return self._depcache.MarkedKeep(self._pkg)
  431.  
  432.     @property
  433.     def markedDowngrade(self):
  434.         """ Package is marked for downgrade """
  435.         return self._depcache.MarkedDowngrade(self._pkg)
  436.  
  437.     @property
  438.     def markedReinstall(self):
  439.         """Return True if the package is marked for reinstall."""
  440.         return self._depcache.MarkedReinstall(self._pkg)
  441.  
  442.     @property
  443.     def isInstalled(self):
  444.         """Return True if the package is installed."""
  445.         return (self._pkg.CurrentVer is not None)
  446.  
  447.     @property
  448.     def isUpgradable(self):
  449.         """Return True if the package is upgradable."""
  450.         return self.isInstalled and self._depcache.IsUpgradable(self._pkg)
  451.  
  452.     @property
  453.     def isAutoRemovable(self):
  454.         """Return True if the package is no longer required.
  455.  
  456.         If the package has been installed automatically as a dependency of
  457.         another package, and if no packages depend on it anymore, the package
  458.         is no longer required.
  459.         """
  460.         return self.isInstalled and self._depcache.IsGarbage(self._pkg)
  461.  
  462.     # sizes
  463.  
  464.     @property
  465.     def packageSize(self):
  466.         """Return the size of the candidate deb package."""
  467.         ver = self._depcache.GetCandidateVer(self._pkg)
  468.         return ver.Size
  469.  
  470.     @property
  471.     def installedPackageSize(self):
  472.         """Return the size of the installed deb package."""
  473.         ver = self._pkg.CurrentVer
  474.         return ver.Size
  475.  
  476.     @property
  477.     def candidateInstalledSize(self, UseCandidate=True):
  478.         """Return the size of the candidate installed package."""
  479.         ver = self._depcache.GetCandidateVer(self._pkg)
  480.         if ver:
  481.             return ver.Size
  482.         else:
  483.             return None
  484.  
  485.     @property
  486.     def installedSize(self):
  487.         """Return the size of the currently installed package."""
  488.         ver = self._pkg.CurrentVer
  489.         if ver is None:
  490.             return 0
  491.         return ver.InstalledSize
  492.  
  493.     @property
  494.     def installedFiles(self):
  495.         """Return a list of files installed by the package.
  496.  
  497.         Return a list of unicode names of the files which have
  498.         been installed by this package
  499.         """
  500.         path = "/var/lib/dpkg/info/%s.list" % self.name
  501.         try:
  502.             file_list = open(path)
  503.             try:
  504.                 return file_list.read().decode().split("\n")
  505.             finally:
  506.                 file_list.close()
  507.         except EnvironmentError:
  508.             return []
  509.  
  510.     def getChangelog(self, uri=None, cancel_lock=None):
  511.         """
  512.         Download the changelog of the package and return it as unicode
  513.         string.
  514.  
  515.         The parameter `uri` refers to the uri of the changelog file. It may
  516.         contain multiple named variables which will be substitued. These
  517.         variables are (src_section, prefix, src_pkg, src_ver). An example is
  518.         the Ubuntu changelog:
  519.             "http://changelogs.ubuntu.com/changelogs/pool" \\
  520.                 "/%(src_section)s/%(prefix)s/%(src_pkg)s" \\
  521.                 "/%(src_pkg)s_%(src_ver)s/changelog"
  522.  
  523.         The parameter `cancel_lock` refers to an instance of threading.Lock,
  524.         which if set, prevents the download.
  525.         """
  526.         # Return a cached changelog if available
  527.         if self._changelog != "":
  528.             return self._changelog
  529.  
  530.         if uri is None:
  531.             if self.candidateOrigin[0].origin == "Debian":
  532.                 uri = "http://packages.debian.org/changelogs/pool" \
  533.                       "/%(src_section)s/%(prefix)s/%(src_pkg)s" \
  534.                       "/%(src_pkg)s_%(src_ver)s/changelog"
  535.             elif self.candidateOrigin[0].origin == "Ubuntu":
  536.                 uri = "http://changelogs.ubuntu.com/changelogs/pool" \
  537.                       "/%(src_section)s/%(prefix)s/%(src_pkg)s" \
  538.                       "/%(src_pkg)s_%(src_ver)s/changelog"
  539.             else:
  540.                 return _("The list of changes is not available")
  541.  
  542.         # get the src package name
  543.         src_pkg = self.sourcePackageName
  544.  
  545.         # assume "main" section
  546.         src_section = "main"
  547.         # use the section of the candidate as a starting point
  548.         section = self._depcache.GetCandidateVer(self._pkg).Section
  549.  
  550.         # get the source version, start with the binaries version
  551.         bin_ver = self.candidateVersion
  552.         src_ver = self.candidateVersion
  553.         #print "bin: %s" % binver
  554.         try:
  555.             # FIXME: This try-statement is too long ...
  556.             # try to get the source version of the pkg, this differs
  557.             # for some (e.g. libnspr4 on ubuntu)
  558.             # this feature only works if the correct deb-src are in the
  559.             # sources.list
  560.             # otherwise we fall back to the binary version number
  561.             src_records = apt_pkg.GetPkgSrcRecords()
  562.             src_rec = src_records.Lookup(src_pkg)
  563.             if src_rec:
  564.                 src_ver = src_records.Version
  565.                 #if apt_pkg.VersionCompare(binver, srcver) > 0:
  566.                 #    srcver = binver
  567.                 if not src_ver:
  568.                     src_ver = bin_ver
  569.                 #print "srcver: %s" % src_ver
  570.                 section = src_records.Section
  571.                 #print "srcsect: %s" % section
  572.             else:
  573.                 # fail into the error handler
  574.                 raise SystemError
  575.         except SystemError:
  576.             src_ver = bin_ver
  577.  
  578.         l = section.split("/")
  579.         if len(l) > 1:
  580.             src_section = l[0]
  581.  
  582.         # lib is handled special
  583.         prefix = src_pkg[0]
  584.         if src_pkg.startswith("lib"):
  585.             prefix = "lib" + src_pkg[3]
  586.  
  587.         # stip epoch
  588.         l = src_ver.split(":")
  589.         if len(l) > 1:
  590.             src_ver = "".join(l[1:])
  591.  
  592.         uri = uri % {"src_section": src_section,
  593.                      "prefix": prefix,
  594.                      "src_pkg": src_pkg,
  595.                      "src_ver": src_ver}
  596.  
  597.         timeout = socket.getdefaulttimeout()
  598.         
  599.         # FIXME: when python2.4 vanishes from the archive,
  600.         #        merge this into a single try..finally block (pep 341)
  601.         try:
  602.             try:
  603.                 # Set a timeout for the changelog download
  604.                 socket.setdefaulttimeout(2)
  605.  
  606.                 # Check if the download was canceled
  607.                 if cancel_lock and cancel_lock.isSet():
  608.                     return ""
  609.                 changelog_file = urllib2.urlopen(uri)
  610.                 # do only get the lines that are new
  611.                 changelog = ""
  612.                 regexp = "^%s \((.*)\)(.*)$" % (re.escape(src_pkg))
  613.  
  614.                 while True:
  615.                     # Check if the download was canceled
  616.                     if cancel_lock and cancel_lock.isSet():
  617.                         return ""
  618.                     # Read changelog line by line
  619.                     line_raw = changelog_file.readline()
  620.                     if line_raw == "":
  621.                         break
  622.                     # The changelog is encoded in utf-8, but since there isn't any
  623.                     # http header, urllib2 seems to treat it as ascii
  624.                     line = line_raw.decode("utf-8")
  625.  
  626.                     #print line.encode('utf-8')
  627.                     match = re.match(regexp, line)
  628.                     if match:
  629.                         # strip epoch from installed version
  630.                         # and from changelog too
  631.                         installed = self.installedVersion
  632.                         if installed and ":" in installed:
  633.                             installed = installed.split(":", 1)[1]
  634.                         changelog_ver = match.group(1)
  635.                         if changelog_ver and ":" in changelog_ver:
  636.                             changelog_ver = changelog_ver.split(":", 1)[1]
  637.                         if (installed and 
  638.                                 apt_pkg.VersionCompare(changelog_ver, installed) <= 0):
  639.                             break
  640.                     # EOF (shouldn't really happen)
  641.                     changelog += line
  642.  
  643.                 # Print an error if we failed to extract a changelog
  644.                 if len(changelog) == 0:
  645.                     changelog = _("The list of changes is not available")
  646.                 self._changelog = changelog
  647.  
  648.             except urllib2.HTTPError:
  649.                 return _("The list of changes is not available yet.\n\n"
  650.                          "Please use http://launchpad.net/ubuntu/+source/%s/%s/"
  651.                          "+changelog\n"
  652.                          "until the changes become available or try again "
  653.                          "later.") % (src_pkg, src_ver)
  654.             except (IOError, httplib.BadStatusLine):
  655.                 return _("Failed to download the list of changes. \nPlease "
  656.                          "check your Internet connection.")
  657.         finally:
  658.             socket.setdefaulttimeout(timeout)
  659.         return self._changelog
  660.  
  661.     @property
  662.     def candidateOrigin(self):
  663.         """Return the Origin() of the candidate version."""
  664.         ver = self._depcache.GetCandidateVer(self._pkg)
  665.         if not ver:
  666.             return None
  667.         origins = []
  668.         for (verFileIter, index) in ver.FileList:
  669.             origins.append(Origin(self, verFileIter))
  670.         return origins
  671.  
  672.     # depcache actions
  673.  
  674.     def markKeep(self):
  675.         """Mark a package for keep."""
  676.         self._pcache.cachePreChange()
  677.         self._depcache.MarkKeep(self._pkg)
  678.         self._pcache.cachePostChange()
  679.  
  680.     def markDelete(self, autoFix=True, purge=False):
  681.         """Mark a package for install.
  682.  
  683.         If autoFix is True, the resolver will be run, trying to fix broken
  684.         packages. This is the default.
  685.  
  686.         If purge is True, remove the configuration files of the package as
  687.         well. The default is to keep the configuration.
  688.         """
  689.         self._pcache.cachePreChange()
  690.         self._depcache.MarkDelete(self._pkg, purge)
  691.         # try to fix broken stuffsta
  692.         if autoFix and self._depcache.BrokenCount > 0:
  693.             Fix = apt_pkg.GetPkgProblemResolver(self._depcache)
  694.             Fix.Clear(self._pkg)
  695.             Fix.Protect(self._pkg)
  696.             Fix.Remove(self._pkg)
  697.             Fix.InstallProtect()
  698.             Fix.Resolve()
  699.         self._pcache.cachePostChange()
  700.  
  701.     def markInstall(self, autoFix=True, autoInst=True, fromUser=True):
  702.         """Mark a package for install.
  703.  
  704.         If autoFix is True, the resolver will be run, trying to fix broken
  705.         packages. This is the default.
  706.  
  707.         If autoInst is True, the dependencies of the packages will be installed
  708.         automatically. This is the default.
  709.  
  710.         If fromUser is True, this package will not be marked as automatically
  711.         installed. This is the default. Set it to False if you want to be able
  712.         to remove the package at a later stage if no other package depends on
  713.         it.
  714.         """
  715.         self._pcache.cachePreChange()
  716.         self._depcache.MarkInstall(self._pkg, autoInst, fromUser)
  717.         # try to fix broken stuff
  718.         if autoFix and self._depcache.BrokenCount > 0:
  719.             fixer = apt_pkg.GetPkgProblemResolver(self._depcache)
  720.             fixer.Clear(self._pkg)
  721.             fixer.Protect(self._pkg)
  722.             fixer.Resolve(True)
  723.         self._pcache.cachePostChange()
  724.  
  725.     def markUpgrade(self):
  726.         """Mark a package for upgrade."""
  727.         if self.isUpgradable:
  728.             self.markInstall()
  729.         else:
  730.             # FIXME: we may want to throw a exception here
  731.             sys.stderr.write(("MarkUpgrade() called on a non-upgrable pkg: "
  732.                               "'%s'\n") % self._pkg.Name)
  733.  
  734.     def commit(self, fprogress, iprogress):
  735.         """Commit the changes.
  736.  
  737.         The parameter `fprogress` refers to a FetchProgress() object, as
  738.         found in apt.progress.
  739.  
  740.         The parameter `iprogress` refers to an InstallProgress() object, as
  741.         found in apt.progress.
  742.         """
  743.         self._depcache.Commit(fprogress, iprogress)
  744.  
  745.  
  746. def _test():
  747.     """Self-test."""
  748.     print "Self-test for the Package modul"
  749.     import random
  750.     import apt
  751.     apt_pkg.init()
  752.     cache = apt_pkg.GetCache()
  753.     depcache = apt_pkg.GetDepCache(cache)
  754.     records = apt_pkg.GetPkgRecords(cache)
  755.     sourcelist = apt_pkg.GetPkgSourceList()
  756.  
  757.     pkgiter = cache["apt-utils"]
  758.     pkg = Package(cache, depcache, records, sourcelist, None, pkgiter)
  759.     print "Name: %s " % pkg.name
  760.     print "ID: %s " % pkg.id
  761.     print "Priority (Candidate): %s " % pkg.priority
  762.     print "Priority (Installed): %s " % pkg.installedPriority
  763.     print "Installed: %s " % pkg.installedVersion
  764.     print "Candidate: %s " % pkg.candidateVersion
  765.     print "CandidateDownloadable: %s" % pkg.candidateDownloadable
  766.     print "CandidateOrigins: %s" % pkg.candidateOrigin
  767.     print "SourcePkg: %s " % pkg.sourcePackageName
  768.     print "Section: %s " % pkg.section
  769.     print "Summary: %s" % pkg.summary
  770.     print "Description (formated) :\n%s" % pkg.description
  771.     print "Description (unformated):\n%s" % pkg.rawDescription
  772.     print "InstalledSize: %s " % pkg.installedSize
  773.     print "PackageSize: %s " % pkg.packageSize
  774.     print "Dependencies: %s" % pkg.installedDependencies
  775.     for dep in pkg.candidateDependencies:
  776.         print ",".join("%s (%s) (%s) (%s)" % (o.name, o.version, o.relation,
  777.                         o.preDepend) for o in dep.or_dependencies)
  778.     print "arch: %s" % pkg.architecture
  779.     print "homepage: %s" % pkg.homepage
  780.     print "rec: ", pkg.candidateRecord
  781.  
  782.  
  783.     # now test install/remove
  784.     progress = apt.progress.OpTextProgress()
  785.     cache = apt.Cache(progress)
  786.     print cache["2vcard"].getChangelog()
  787.     for i in True, False:
  788.         print "Running install on random upgradable pkgs with AutoFix: %s " % i
  789.         for pkg in cache:
  790.             if pkg.isUpgradable:
  791.                 if random.randint(0, 1) == 1:
  792.                     pkg.markInstall(i)
  793.         print "Broken: %s " % cache._depcache.BrokenCount
  794.         print "InstCount: %s " % cache._depcache.InstCount
  795.  
  796.     print
  797.     # get a new cache
  798.     for i in True, False:
  799.         print "Randomly remove some packages with AutoFix: %s" % i
  800.         cache = apt.Cache(progress)
  801.         for name in cache.keys():
  802.             if random.randint(0, 1) == 1:
  803.                 try:
  804.                     cache[name].markDelete(i)
  805.                 except SystemError:
  806.                     print "Error trying to remove: %s " % name
  807.         print "Broken: %s " % cache._depcache.BrokenCount
  808.         print "DelCount: %s " % cache._depcache.DelCount
  809.  
  810. # self-test
  811. if __name__ == "__main__":
  812.     _test()
  813.