diff options
| author | Michael Vogt <michael.vogt@ubuntu.com> | 2010-07-02 16:46:35 +0200 |
|---|---|---|
| committer | Michael Vogt <michael.vogt@ubuntu.com> | 2010-07-02 16:46:35 +0200 |
| commit | 465b19e6ae3c6daeee0841d38ac93e0c19991c13 (patch) | |
| tree | fe7105c64632ccc9dc22520b6d70a18d5342c97b | |
| parent | 5a6c646ceffab7ce58106eccdccf884b6d332d58 (diff) | |
| parent | dd86db9ddb22b43867b5b4dc211f4440dec7aa6a (diff) | |
| download | python-apt-465b19e6ae3c6daeee0841d38ac93e0c19991c13.tar.gz | |
* merged lp:~kiwinote/python-apt/merge-gdebi-changes, this port the
DebPackage class fixes from gdebi into python-apt so that gdebi can
use the class from python-apt directly
* apt/debfile.py:
- check if the debfiles provides are in conflict with the systems
packages
* tests/test_debs/*.deb, tests/test_debfile.py:
- add automatic test based on the test debs from gdebi
| -rw-r--r-- | apt/cache.py | 24 | ||||
| -rw-r--r-- | apt/debfile.py | 280 | ||||
| -rw-r--r-- | apt/utils.py | 3 | ||||
| -rw-r--r-- | debian/changelog | 8 | ||||
| -rw-r--r-- | po/python-apt.pot | 191 | ||||
| -rw-r--r-- | tests/data/fake-packages/Packages | 21 | ||||
| -rw-r--r-- | tests/data/fake-packages/Packages.gz | bin | 0 -> 555 bytes | |||
| -rw-r--r-- | tests/test_apt_cache.py | 22 | ||||
| -rw-r--r-- | tests/test_debfile.py | 56 | ||||
| -rw-r--r-- | tests/test_debs/gdebi-test1.deb | bin | 0 -> 934 bytes | |||
| -rw-r--r-- | tests/test_debs/gdebi-test10.deb | bin | 0 -> 614 bytes | |||
| -rw-r--r-- | tests/test_debs/gdebi-test2.deb | bin | 0 -> 554 bytes | |||
| -rw-r--r-- | tests/test_debs/gdebi-test3.deb | bin | 0 -> 570 bytes | |||
| -rw-r--r-- | tests/test_debs/gdebi-test4.deb | bin | 0 -> 2306 bytes | |||
| -rw-r--r-- | tests/test_debs/gdebi-test5.deb | bin | 0 -> 2306 bytes | |||
| -rw-r--r-- | tests/test_debs/gdebi-test6.deb | bin | 0 -> 4312 bytes | |||
| -rw-r--r-- | tests/test_debs/gdebi-test7.deb | bin | 0 -> 578 bytes | |||
| -rw-r--r-- | tests/test_debs/gdebi-test8.deb | bin | 0 -> 598 bytes | |||
| -rw-r--r-- | tests/test_debs/gdebi-test9.deb | bin | 0 -> 586 bytes | |||
| -rw-r--r-- | tests/test_progress.py | 44 |
20 files changed, 513 insertions, 136 deletions
diff --git a/apt/cache.py b/apt/cache.py index 3962bb4f..26532c76 100644 --- a/apt/cache.py +++ b/apt/cache.py @@ -120,6 +120,7 @@ class Cache(object): """ if progress is None: progress = apt.progress.base.OpProgress() + self.op_progress = progress self._run_callbacks("cache_pre_open") self._cache = apt_pkg.Cache(progress) @@ -288,21 +289,28 @@ class Cache(object): else: return bool(pkg.has_provides and not pkg.has_versions) - def get_providing_packages(self, virtual, candidate_only=True): - """Return a list of all packages providing a virtual package. + def get_providing_packages(self, pkgname, candidate_only=True, + include_nonvirtual=False): + """Return a list of all packages providing a package. Return a list of packages which provide the virtual package of the - specified name. If 'candidate_only' is False, return all packages - with at least one version providing the virtual package. Otherwise, - return only those packages where the candidate version provides - the virtual package. + specified name. + + If 'candidate_only' is False, return all packages with at + least one version providing the virtual package. Otherwise, + return only those packages where the candidate version + provides the virtual package. + + If 'include_nonvirtual' is True then it will search for all + packages providing pkgname, even if pkgname is not itself + a virtual pkg. """ providers = set() get_candidate_ver = self._depcache.get_candidate_ver try: - vp = self._cache[virtual] - if vp.has_versions: + vp = self._cache[pkgname] + if vp.has_versions and not include_nonvirtual: return list(providers) except KeyError: return list(providers) diff --git a/apt/debfile.py b/apt/debfile.py index ccaa25e4..81cd1dd2 100644 --- a/apt/debfile.py +++ b/apt/debfile.py @@ -1,4 +1,4 @@ -# Copyright (c) 2005-2009 Canonical +# Copyright (c) 2005-2010 Canonical # # Author: Michael Vogt <michael.vogt@ubuntu.com> # @@ -17,45 +17,50 @@ # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 # USA """Classes for working with locally available Debian packages.""" +import apt +import apt_inst +import apt_pkg +import gzip import os import sys -import apt_inst -import apt_pkg from apt_pkg import gettext as _ - - -# Constants for comparing the local package file with the version in the cache -(VERSION_NONE, VERSION_OUTDATED, VERSION_SAME, VERSION_NEWER) = range(4) - +from StringIO import StringIO class NoDebArchiveException(IOError): """Exception which is raised if a file is no Debian archive.""" - class DebPackage(object): """A Debian Package (.deb file).""" + # Constants for comparing the local package file with the version + # in the cache + (VERSION_NONE, + VERSION_OUTDATED, + VERSION_SAME, + VERSION_NEWER) = range(4) + _supported_data_members = ("data.tar.gz", "data.tar.bz2", "data.tar.lzma") debug = 0 def __init__(self, filename=None, cache=None): + if cache is None: + cache = apt.Cache() self._cache = cache - self._need_pkgs = [] self._debfile = None self.pkgname = "" - self.filename = filename self._sections = {} - self._installed_conflicts = set() - self._failure_string = "" if filename: self.open(filename) def open(self, filename): - " open given debfile " + """ open given debfile """ + self._need_pkgs = [] + self._installed_conflicts = set() + self._failure_string = "" self.filename = filename - self._debfile = apt_inst.DebFile(self.filename) + self._debfile = apt_inst.DebFile(open(self.filename)) control = self._debfile.control.extractdata("control") self._sections = apt_pkg.TagSection(control) self.pkgname = self._sections["Package"] @@ -90,20 +95,35 @@ class DebPackage(object): # check for virtual pkgs if not depname in self._cache: if self._cache.is_virtual_package(depname): - self._dbg(3, "_isOrGroupSatisfied(): %s is virtual dep" % - depname) + self._dbg(3, "_is_or_group_satisfied(): %s is virtual dep" % depname) for pkg in self._cache.get_providing_packages(depname): if pkg.is_installed: return True continue - + # check real dependency inst = self._cache[depname].installed if inst is not None and apt_pkg.check_dep(inst.version, oper, ver): return True + + # if no real dependency is installed, check if there is + # a package installed that provides this dependency + # (e.g. scrollkeeper dependecies are provided by rarian-compat) + # but only do that if there is no version required in the + # dependency (we do not supprot versionized dependencies) + if not oper: + for ppkg in self._cache.get_providing_packages( + depname, include_nonvirtual=True): + if ppkg.is_installed: + self._dbg(3, "found installed '%s' that provides '%s'" % (ppkg.name, depname)) + return True return False def _satisfy_or_group(self, or_group): """Try to satisfy the or_group.""" + + or_found = False + virtual_pkg = None + for dep in or_group: depname, ver, oper = dep @@ -136,19 +156,18 @@ class DebPackage(object): or_str = "" for dep in or_group: or_str += dep[0] - if dep != or_group[-1]: + if ver and oper: + or_str += " (%s %s)" % (dep[2], dep[1]) + if dep != or_group[len(or_group)-1]: or_str += "|" - self._failure_string += _("Dependency is not satisfiable: %s\n" % - or_str) + self._failure_string += _("Dependency is not satisfiable: %s\n") % or_str return False def _check_single_pkg_conflict(self, pkgname, ver, oper): """Return True if a pkg conflicts with a real installed/marked pkg.""" # FIXME: deal with conflicts against its own provides # (e.g. Provides: ftp-server, Conflicts: ftp-server) - self._dbg(3, "_checkSinglePkgConflict() pkg='%s' ver='%s' oper='%s'" % - (pkgname, ver, oper)) - + self._dbg(3, "_check_single_pkg_conflict() pkg='%s' ver='%s' oper='%s'" % (pkgname, ver, oper)) pkg = self._cache[pkgname] if pkg.is_installed: pkgver = pkg.installed.version @@ -163,7 +182,7 @@ class DebPackage(object): if (apt_pkg.check_dep(pkgver, oper, ver) and not self.replaces_real_pkg(pkgname, oper, ver)): self._failure_string += _("Conflicts with the installed package " - "'%s'" % pkg.name) + "'%s'") % pkg.name return True return False @@ -171,6 +190,9 @@ class DebPackage(object): """Check the or-group for conflicts with installed pkgs.""" self._dbg(2, "_check_conflicts_or_group(): %s " % (or_group)) + or_found = False + virtual_pkg = None + for dep in or_group: depname = dep[0] ver = dep[1] @@ -187,7 +209,7 @@ class DebPackage(object): if self.pkgname == pkg.name: self._dbg(3, "conflict on self, ignoring") continue - if self._check_single_pkg_conflict(pkg.name, ver, + if self._check_single_pkg_conflict(pkg.name, ver, oper): self._installed_conflicts.add(pkg.name) continue @@ -209,7 +231,7 @@ class DebPackage(object): """List of package names on which this package depends on.""" depends = [] # find depends - for key in "Depends", "PreDepends": + for key in "Depends", "Pre-Depends": try: depends.extend(apt_pkg.parse_depends(self._sections[key])) except KeyError: @@ -240,7 +262,7 @@ class DebPackage(object): Return True if the deb packages replaces a real (not virtual) packages named (pkgname, oper, ver). """ - self._dbg(3, "replacesPkg() %s %s %s" % (pkgname, oper, ver)) + self._dbg(3, "replaces_real_pkg() %s %s %s" % (pkgname, oper, ver)) pkg = self._cache[pkgname] if pkg.is_installed: pkgver = pkg.installed.version @@ -270,6 +292,68 @@ class DebPackage(object): res = False return res + def check_breaks_existing_packages(self): + """ + check if installing the package would break exsisting + package on the system, e.g. system has: + smc depends on smc-data (= 1.4) + and user tries to installs smc-data 1.6 + """ + # show progress information as this step may take some time + size = float(len(self._cache)) + steps = int(size/50) + debver = self._sections["Version"] + # store what we provide so that we can later check against that + provides = [ x[0][0] for x in self.provides] + for (i, pkg) in enumerate(self._cache): + if i%steps == 0: + self._cache.op_progress.update(float(i)/size*100.0) + if not pkg.is_installed: + continue + # check if the exising dependencies are still satisfied + # with the package + ver = pkg._pkg.current_ver + for dep_or in pkg.installed.dependencies: + for dep in dep_or.or_dependencies: + if dep.name == self.pkgname: + if not apt_pkg.check_dep(debver, dep.relation, dep.version): + self._dbg(2, "would break (depends) %s" % pkg.name) + # TRANSLATORS: the first '%s' is the package that breaks, the second the dependency that makes it break, the third the relation (e.g. >=) and the latest the version for the releation + self._failure_string += _("Breaks existing package '%(pkgname)s' dependency %(depname)s (%(deprelation)s %(depversion)s)") % { + 'pkgname' : pkg.name, + 'depname' : dep.name, + 'deprelation' : dep.relation, + 'depversion' : dep.version} + self._cache.op_progress.done() + return False + # now check if there are conflicts against this package on + # the existing system + if "Conflicts" in ver.depends_list: + for conflicts_ver_list in ver.depends_list["Conflicts"]: + for c_or in conflicts_ver_list: + if c_or.target_pkg.name == self.pkgname: + if apt_pkg.check_dep(debver, c_or.comp_type, c_or.target_ver): + self._dbg(2, "would break (conflicts) %s" % pkg.name) + # TRANSLATORS: the first '%s' is the package that conflicts, the second the packagename that it conflicts with (so the name of the deb the user tries to install), the third is the relation (e.g. >=) and the last is the version for the relation + self._failure_string += _("Breaks existing package '%(pkgname)s' conflict: %(targetpkg)s (%(comptype)s %(targetver)s)") % { + 'pkgname' : pkg.name, + 'targetpkg' : c_or.target_pkg.name, + 'comptype' : c_or.comp_type, + 'targetver' : c_or.target_ver } + self._cache.op_progress.done() + return False + if c_or.target_pkg.name in provides: + self._dbg(2, "would break (conflicts) %s" % provides) + self._failure_string += _("Breaks existing package '%(pkgname)s' that conflict: '%(targetpkg)s'. But the '%(debfile)s' provides it via: '%(provides)s'") % { + 'provides' : ",".join(provides), + 'debfile' : self.filename, + 'targetpkg' : c_or.target_pkg.name, + 'pkgname' : pkg.name } + self._cache.op_progress.done() + return False + self._cache.op_progress.done() + return True + def compare_to_version_in_cache(self, use_installed=True): """Compare the package to the version available in the cache. @@ -277,42 +361,49 @@ class DebPackage(object): and if so in what version, returns one of (VERSION_NONE, VERSION_OUTDATED, VERSION_SAME, VERSION_NEWER). """ - self._dbg(3, "compareToVersionInCache") + self._dbg(3, "compare_to_version_in_cache") pkgname = self._sections["Package"] debver = self._sections["Version"] self._dbg(1, "debver: %s" % debver) if pkgname in self._cache: if use_installed and self._cache[pkgname].installed: cachever = self._cache[pkgname].installed.version - else: + elif not use_installed and self._cache[pkgname].candidate: cachever = self._cache[pkgname].candidate.version + else: + return self.VERSION_NONE if cachever is not None: - cmpres = apt_pkg.version_compare(cachever, debver) - self._dbg(1, "CompareVersion(debver,instver): %s" % cmpres) - if cmpres == 0: - return VERSION_SAME - elif cmpres < 0: - return VERSION_NEWER - elif cmpres > 0: - return VERSION_OUTDATED - return VERSION_NONE + cmp = apt_pkg.version_compare(cachever, debver) + self._dbg(1, "CompareVersion(debver,instver): %s" % cmp) + if cmp == 0: + return self.VERSION_SAME + elif cmp < 0: + return self.VERSION_NEWER + elif cmp > 0: + return self.VERSION_OUTDATED + return self.VERSION_NONE def check(self): """Check if the package is installable.""" self._dbg(3, "check_depends") # check arch + if not "Architecture" in self._sections: + self._dbg(1, "ERROR: no architecture field") + self._failure_string = _("No Architecture field in the package") + return False arch = self._sections["Architecture"] if arch != "all" and arch != apt_pkg.config.find("APT::Architecture"): self._dbg(1, "ERROR: Wrong architecture dude!") - self._failure_string = _("Wrong architecture '%s'" % arch) + self._failure_string = _("Wrong architecture '%s'") % arch return False # check version - if self.compare_to_version_in_cache() == VERSION_OUTDATED: - # the deb is older than the installed - self._failure_string = _("A later version is already installed") - return False + if self.compare_to_version_in_cache() == self.VERSION_OUTDATED: + if self._cache[self.pkgname].installed: + # the deb is older than the installed + self._failure_string = _("A later version is already installed") + return False # FIXME: this sort of error handling sux self._failure_string = "" @@ -321,6 +412,11 @@ class DebPackage(object): if not self.check_conflicts(): return False + # check if installing it would break anything on the + # current system + if not self.check_breaks_existing_packages(): + return False + # try to satisfy the dependencies if not self._satisfy_depends(self.depends): return False @@ -332,7 +428,7 @@ class DebPackage(object): if self._cache._depcache.broken_count > 0: self._failure_string = _("Failed to satisfy all dependencies " - "(broken cache)") + "(broken cache)") # clean the cache again self._cache.clear() return False @@ -352,17 +448,16 @@ class DebPackage(object): # check depends for or_group in depends: #print "or_group: %s" % or_group - #print "or_group satified: %s" % self._is_or_group_satisfied( - # or_group) + #print "or_group satified: %s" % self._is_or_group_satisfied(or_group) if not self._is_or_group_satisfied(or_group): if not self._satisfy_or_group(or_group): return False # now try it out in the cache for pkg in self._need_pkgs: try: - self._cache[pkg].mark_install(fromUser=False) - except SystemError: - self._failure_string = _("Cannot install '%s'" % pkg) + self._cache[pkg].mark_install(from_user=False) + except SystemError, e: + self._failure_string = _("Cannot install '%s'") % pkg self._cache.clear() return False return True @@ -398,6 +493,75 @@ class DebPackage(object): remove.append(pkg.name) return (install, remove, unauthenticated) + @property + def control_filelist(self): + """ return the list of files in control.tar.gt """ + try: + from debian.debfile import DebFile + except: + raise Exception(_("Python-debian module not available")) + content = [] + for name in DebFile(self.filename).control: + if name and name != ".": + content.append(name) + return sorted(content) + + def to_hex(self, in_data): + hex = "" + for (i, c) in enumerate(in_data): + if i%80 == 0: + hex += "\n" + hex += "%2.2x " % ord(c) + return hex + + def to_strish(self, in_data): + s = "" + for c in in_data: + if ord(c) < 10 or ord(c) > 127: + s += " " + else: + s += c + return s + + def _get_content(self, part, name, auto_decompress=True, auto_hex=True): + data = part.get_content(name) + # check for zip content + if name.endswith(".gz") and auto_decompress: + io = StringIO(data) + gz = gzip.GzipFile(fileobj=io) + data = _("Automatically decompressed:\n\n") + data += gz.read() + # auto-convert to hex + try: + data = unicode(data, "utf-8") + except Exception, e: + new_data = _("Automatically converted to printable ascii:\n") + new_data += self.to_strish(data) + return new_data + return data + + def control_content(self, name): + """ return the content of a specific control.tar.gz file """ + try: + from debian.debfile import DebFile + except: + raise Exception(_("Python-debian module not available")) + control = DebFile(self.filename).control + if name in control: + return self._get_content(control, name) + return "" + + def data_content(self, name): + """ return the content of a specific control.tar.gz file """ + try: + from debian.debfile import DebFile + except: + raise Exception(_("Python-debian module not available")) + data = DebFile(self.filename).data + if name in data: + return self._get_content(data, name) + return "" + def _dbg(self, level, msg): """Write debugging output to sys.stderr.""" if level <= self.debug: @@ -419,18 +583,18 @@ class DebPackage(object): install_progress.finishUpdate() return res - class DscSrcPackage(DebPackage): """A locally available source package.""" def __init__(self, filename=None, cache=None): DebPackage.__init__(self, None, cache) + self.filename = filename self._depends = [] self._conflicts = [] self.pkgname = "" self.binaries = [] - if filename is not None: - self.open(filename) + if self.filename is not None: + self.open(self.filename) @property def depends(self): @@ -446,7 +610,6 @@ class DscSrcPackage(DebPackage): """Open the package.""" depends_tags = ["Build-Depends", "Build-Depends-Indep"] conflicts_tags = ["Build-Conflicts", "Build-Conflicts-Indep"] - fobj = open(file) tagfile = apt_pkg.TagFile(fobj) try: @@ -481,11 +644,10 @@ class DscSrcPackage(DebPackage): if self._cache[pkgname]._pkg.essential: raise Exception(_("An essential package would be removed")) self._cache[pkgname].mark_delete() - # FIXME: a additional run of the checkConflicts() - # after _satisfyDepends() should probably be done + # FIXME: a additional run of the check_conflicts() + # after _satisfy_depends() should probably be done return self._satisfy_depends(self.depends) - def _test(): """Test function""" from apt.cache import Cache @@ -494,7 +656,7 @@ def _test(): cache = Cache() vp = "www-browser" - #print "%s virtual: %s" % (vp, cache.isVirtualPackage(vp)) + print "%s virtual: %s" % (vp, cache.is_virtual_package(vp)) providers = cache.get_providing_packages(vp) print "Providers for %s :" % vp for pkg in providers: @@ -508,6 +670,8 @@ def _test(): print "missing deps: %s" % d.missing_deps print d.required_changes + print d.filelist + print "Installing ..." ret = d.install(DpkgInstallProgress()) print ret diff --git a/apt/utils.py b/apt/utils.py index 80ba6d65..4b3da39f 100644 --- a/apt/utils.py +++ b/apt/utils.py @@ -33,6 +33,9 @@ def get_maintenance_end_date(release_date, m_months): support_end_year = (release_date.year + years + (release_date.month + months)/12) support_end_month = (release_date.month + months) % 12 + if support_end_month == 0: + support_end_month = 12 + support_end_year -= 1 return (support_end_year, support_end_month) diff --git a/debian/changelog b/debian/changelog index b1c7c1b5..b8ae49c1 100644 --- a/debian/changelog +++ b/debian/changelog @@ -15,6 +15,14 @@ python-apt (0.7.96) UNRELEASED; urgency=low - add new "dpkg_journal_dirty" property that can be used to detect a interrupted dpkg (the famous "E: dpkg was interrupted, you must manually run 'dpkg --configure -a'") + * merged lp:~kiwinote/python-apt/merge-gdebi-changes, this port the + DebPackage class fixes from gdebi into python-apt so that gdebi can + use the class from python-apt directly + * apt/debfile.py: + - check if the debfiles provides are in conflict with the systems + packages + * tests/test_debs/*.deb, tests/test_debfile.py: + - add automatic test based on the test debs from gdebi [ Martin Pitt ] * tests/test_apt_cache.py: Test accessing the record of all packages during diff --git a/po/python-apt.pot b/po/python-apt.pot index b67d7988..9c10c43f 100644 --- a/po/python-apt.pot +++ b/po/python-apt.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2010-03-03 19:34+0100\n" +"POT-Creation-Date: 2010-07-02 14:12+0200\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Language-Team: LANGUAGE <LL@li.org>\n" @@ -23,257 +23,267 @@ msgid "http://changelogs.ubuntu.com/changelogs/pool/%s/%s/%s/%s_%s/changelog" msgstr "" #. Description -#: ../data/templates/Ubuntu.info.in:12 +#: ../data/templates/Ubuntu.info.in:13 +msgid "Ubuntu 10.10 'Maverick Meerkat'" +msgstr "" + +#. Description +#: ../data/templates/Ubuntu.info.in:31 +msgid "Cdrom with Ubuntu 10.10 'Maverick Meerkat'" +msgstr "" + +#. Description +#: ../data/templates/Ubuntu.info.in:74 msgid "Ubuntu 10.04 'Lucid Lynx'" msgstr "" #. Description -#: ../data/templates/Ubuntu.info.in:30 +#: ../data/templates/Ubuntu.info.in:92 msgid "Cdrom with Ubuntu 10.04 'Lucid Lynx'" msgstr "" #. Description -#: ../data/templates/Ubuntu.info.in:72 +#: ../data/templates/Ubuntu.info.in:135 msgid "Ubuntu 9.10 'Karmic Koala'" msgstr "" #. Description -#: ../data/templates/Ubuntu.info.in:90 +#: ../data/templates/Ubuntu.info.in:153 msgid "Cdrom with Ubuntu 9.10 'Karmic Koala'" msgstr "" #. Description -#: ../data/templates/Ubuntu.info.in:132 +#: ../data/templates/Ubuntu.info.in:196 msgid "Ubuntu 9.04 'Jaunty Jackalope'" msgstr "" #. Description -#: ../data/templates/Ubuntu.info.in:150 +#: ../data/templates/Ubuntu.info.in:214 msgid "Cdrom with Ubuntu 9.04 'Jaunty Jackalope'" msgstr "" #. Description -#: ../data/templates/Ubuntu.info.in:192 +#: ../data/templates/Ubuntu.info.in:257 msgid "Ubuntu 8.10 'Intrepid Ibex'" msgstr "" #. Description -#: ../data/templates/Ubuntu.info.in:210 +#: ../data/templates/Ubuntu.info.in:275 msgid "Cdrom with Ubuntu 8.10 'Intrepid Ibex'" msgstr "" #. Description -#: ../data/templates/Ubuntu.info.in:253 +#: ../data/templates/Ubuntu.info.in:319 msgid "Ubuntu 8.04 'Hardy Heron'" msgstr "" #. Description -#: ../data/templates/Ubuntu.info.in:271 +#: ../data/templates/Ubuntu.info.in:337 msgid "Cdrom with Ubuntu 8.04 'Hardy Heron'" msgstr "" #. Description -#: ../data/templates/Ubuntu.info.in:308 +#: ../data/templates/Ubuntu.info.in:382 msgid "Ubuntu 7.10 'Gutsy Gibbon'" msgstr "" #. Description -#: ../data/templates/Ubuntu.info.in:326 +#: ../data/templates/Ubuntu.info.in:400 msgid "Cdrom with Ubuntu 7.10 'Gutsy Gibbon'" msgstr "" #. Description -#: ../data/templates/Ubuntu.info.in:361 +#: ../data/templates/Ubuntu.info.in:445 msgid "Ubuntu 7.04 'Feisty Fawn'" msgstr "" #. Description -#: ../data/templates/Ubuntu.info.in:379 +#: ../data/templates/Ubuntu.info.in:463 msgid "Cdrom with Ubuntu 7.04 'Feisty Fawn'" msgstr "" #. Description -#: ../data/templates/Ubuntu.info.in:413 +#: ../data/templates/Ubuntu.info.in:505 msgid "Ubuntu 6.10 'Edgy Eft'" msgstr "" #. CompDescription -#: ../data/templates/Ubuntu.info.in:418 +#: ../data/templates/Ubuntu.info.in:510 msgid "Community-maintained" msgstr "" #. CompDescription -#: ../data/templates/Ubuntu.info.in:424 +#: ../data/templates/Ubuntu.info.in:516 msgid "Restricted software" msgstr "" #. Description -#: ../data/templates/Ubuntu.info.in:431 +#: ../data/templates/Ubuntu.info.in:523 msgid "Cdrom with Ubuntu 6.10 'Edgy Eft'" msgstr "" #. Description -#: ../data/templates/Ubuntu.info.in:465 +#: ../data/templates/Ubuntu.info.in:565 msgid "Ubuntu 6.06 LTS 'Dapper Drake'" msgstr "" #. CompDescriptionLong -#: ../data/templates/Ubuntu.info.in:468 +#: ../data/templates/Ubuntu.info.in:568 msgid "Canonical-supported Open Source software" msgstr "" #. CompDescription -#: ../data/templates/Ubuntu.info.in:470 +#: ../data/templates/Ubuntu.info.in:570 msgid "Community-maintained (universe)" msgstr "" #. CompDescriptionLong -#: ../data/templates/Ubuntu.info.in:471 +#: ../data/templates/Ubuntu.info.in:571 msgid "Community-maintained Open Source software" msgstr "" #. CompDescription -#: ../data/templates/Ubuntu.info.in:473 +#: ../data/templates/Ubuntu.info.in:573 msgid "Non-free drivers" msgstr "" #. CompDescriptionLong -#: ../data/templates/Ubuntu.info.in:474 +#: ../data/templates/Ubuntu.info.in:574 msgid "Proprietary drivers for devices" msgstr "" #. CompDescription -#: ../data/templates/Ubuntu.info.in:476 +#: ../data/templates/Ubuntu.info.in:576 msgid "Restricted software (Multiverse)" msgstr "" #. CompDescriptionLong -#: ../data/templates/Ubuntu.info.in:477 +#: ../data/templates/Ubuntu.info.in:577 msgid "Software restricted by copyright or legal issues" msgstr "" #. Description -#: ../data/templates/Ubuntu.info.in:483 +#: ../data/templates/Ubuntu.info.in:583 msgid "Cdrom with Ubuntu 6.06 LTS 'Dapper Drake'" msgstr "" #. Description -#: ../data/templates/Ubuntu.info.in:495 +#: ../data/templates/Ubuntu.info.in:599 msgid "Important security updates" msgstr "" #. Description -#: ../data/templates/Ubuntu.info.in:500 +#: ../data/templates/Ubuntu.info.in:604 msgid "Recommended updates" msgstr "" #. Description -#: ../data/templates/Ubuntu.info.in:505 +#: ../data/templates/Ubuntu.info.in:609 msgid "Pre-released updates" msgstr "" #. Description -#: ../data/templates/Ubuntu.info.in:510 +#: ../data/templates/Ubuntu.info.in:614 msgid "Unsupported updates" msgstr "" #. Description -#: ../data/templates/Ubuntu.info.in:517 +#: ../data/templates/Ubuntu.info.in:625 msgid "Ubuntu 5.10 'Breezy Badger'" msgstr "" #. Description -#: ../data/templates/Ubuntu.info.in:531 +#: ../data/templates/Ubuntu.info.in:639 msgid "Cdrom with Ubuntu 5.10 'Breezy Badger'" msgstr "" #. Description -#: ../data/templates/Ubuntu.info.in:543 +#: ../data/templates/Ubuntu.info.in:655 msgid "Ubuntu 5.10 Security Updates" msgstr "" #. Description -#: ../data/templates/Ubuntu.info.in:548 +#: ../data/templates/Ubuntu.info.in:660 msgid "Ubuntu 5.10 Updates" msgstr "" #. Description -#: ../data/templates/Ubuntu.info.in:553 +#: ../data/templates/Ubuntu.info.in:665 msgid "Ubuntu 5.10 Backports" msgstr "" #. Description -#: ../data/templates/Ubuntu.info.in:560 +#: ../data/templates/Ubuntu.info.in:676 msgid "Ubuntu 5.04 'Hoary Hedgehog'" msgstr "" #. Description -#: ../data/templates/Ubuntu.info.in:574 +#: ../data/templates/Ubuntu.info.in:690 msgid "Cdrom with Ubuntu 5.04 'Hoary Hedgehog'" msgstr "" #. CompDescription -#: ../data/templates/Ubuntu.info.in:577 ../data/templates/Debian.info.in:149 +#: ../data/templates/Ubuntu.info.in:693 ../data/templates/Debian.info.in:149 msgid "Officially supported" msgstr "" #. Description -#: ../data/templates/Ubuntu.info.in:586 +#: ../data/templates/Ubuntu.info.in:706 msgid "Ubuntu 5.04 Security Updates" msgstr "" #. Description -#: ../data/templates/Ubuntu.info.in:591 +#: ../data/templates/Ubuntu.info.in:711 msgid "Ubuntu 5.04 Updates" msgstr "" #. Description -#: ../data/templates/Ubuntu.info.in:596 +#: ../data/templates/Ubuntu.info.in:716 msgid "Ubuntu 5.04 Backports" msgstr "" #. Description -#: ../data/templates/Ubuntu.info.in:602 +#: ../data/templates/Ubuntu.info.in:722 msgid "Ubuntu 4.10 'Warty Warthog'" msgstr "" #. CompDescription -#: ../data/templates/Ubuntu.info.in:608 +#: ../data/templates/Ubuntu.info.in:728 msgid "Community-maintained (Universe)" msgstr "" #. CompDescription -#: ../data/templates/Ubuntu.info.in:610 +#: ../data/templates/Ubuntu.info.in:730 msgid "Non-free (Multiverse)" msgstr "" #. Description -#: ../data/templates/Ubuntu.info.in:616 +#: ../data/templates/Ubuntu.info.in:736 msgid "Cdrom with Ubuntu 4.10 'Warty Warthog'" msgstr "" #. CompDescription -#: ../data/templates/Ubuntu.info.in:619 +#: ../data/templates/Ubuntu.info.in:739 msgid "No longer officially supported" msgstr "" #. CompDescription -#: ../data/templates/Ubuntu.info.in:621 +#: ../data/templates/Ubuntu.info.in:741 msgid "Restricted copyright" msgstr "" #. Description -#: ../data/templates/Ubuntu.info.in:628 +#: ../data/templates/Ubuntu.info.in:748 msgid "Ubuntu 4.10 Security Updates" msgstr "" #. Description -#: ../data/templates/Ubuntu.info.in:633 +#: ../data/templates/Ubuntu.info.in:753 msgid "Ubuntu 4.10 Updates" msgstr "" #. Description -#: ../data/templates/Ubuntu.info.in:638 +#: ../data/templates/Ubuntu.info.in:758 msgid "Ubuntu 4.10 Backports" msgstr "" @@ -384,11 +394,11 @@ msgstr "" msgid "Invalid unicode in description for '%s' (%s). Please report." msgstr "" -#: ../apt/package.py:999 ../apt/package.py:1105 +#: ../apt/package.py:1007 ../apt/package.py:1112 msgid "The list of changes is not available" msgstr "" -#: ../apt/package.py:1109 +#: ../apt/package.py:1118 #, python-format msgid "" "The list of changes is not available yet.\n" @@ -397,52 +407,97 @@ msgid "" "until the changes become available or try again later." msgstr "" -#: ../apt/package.py:1115 +#: ../apt/package.py:1125 msgid "" "Failed to download the list of changes. \n" "Please check your Internet connection." msgstr "" -#: ../apt/debfile.py:73 +#: ../apt/debfile.py:142 #, python-format -msgid "List of files for '%s' could not be read" +msgid "Dependency is not satisfiable: %s\n" msgstr "" -#: ../apt/debfile.py:141 +#: ../apt/debfile.py:163 #, python-format -msgid "Dependency is not satisfiable: %s\n" +msgid "Conflicts with the installed package '%s'" msgstr "" -#: ../apt/debfile.py:165 +#. TRANSLATORS: the first '%s' is the package that breaks, the second the dependency that makes it break, the third the relation (e.g. >=) and the latest the version for the releation +#: ../apt/debfile.py:297 #, python-format -msgid "Conflicts with the installed package '%s'" +msgid "" +"Breaks existing package '%(pkgname)s' dependency %(depname)s (%(deprelation)" +"s %(depversion)s)" msgstr "" -#: ../apt/debfile.py:308 +#. TRANSLATORS: the first '%s' is the package that conflicts, the second the packagename that it conflicts with (so the name of the deb the user tries to install), the third is the relation (e.g. >=) and the last is the version for the relation +#: ../apt/debfile.py:313 +#, python-format +msgid "" +"Breaks existing package '%(pkgname)s' conflict: %(targetpkg)s (%(comptype)s %" +"(targetver)s)" +msgstr "" + +#: ../apt/debfile.py:359 +msgid "No Architecture field in the package" +msgstr "" + +#: ../apt/debfile.py:364 #, python-format msgid "Wrong architecture '%s'" msgstr "" #. the deb is older than the installed -#: ../apt/debfile.py:314 +#: ../apt/debfile.py:371 msgid "A later version is already installed" msgstr "" -#: ../apt/debfile.py:334 +#: ../apt/debfile.py:396 msgid "Failed to satisfy all dependencies (broken cache)" msgstr "" -#: ../apt/debfile.py:365 +#: ../apt/debfile.py:425 #, python-format msgid "Cannot install '%s'" msgstr "" -#: ../apt/debfile.py:472 +#: ../apt/debfile.py:467 ../apt/debfile.py:513 ../apt/debfile.py:524 +msgid "Python-debian module not available" +msgstr "" + +#: ../apt/debfile.py:497 +msgid "" +"Automatically decompressed:\n" +"\n" +msgstr "" + +#: ../apt/debfile.py:503 +msgid "Automatically converted to printable ascii:\n" +msgstr "" + +#: ../apt/debfile.py:549 +msgid "List of files could not be read, please report this as a bug" +msgstr "" + +#: ../apt/debfile.py:552 +#, python-format +msgid "IOError during filelist read: %s" +msgstr "" + +#. Translators: it's for missing entries in the deb package, +#. e.g. a missing "Maintainer" field +#: ../apt/debfile.py:559 +#, python-format +msgid "%s is not available" +msgstr "" + +#: ../apt/debfile.py:632 #, python-format msgid "Install Build-Dependencies for source package '%s' that builds %s\n" msgstr "" -#: ../apt/debfile.py:482 +#: ../apt/debfile.py:642 msgid "An essential package would be removed" msgstr "" @@ -493,6 +548,6 @@ msgstr "" msgid "Please insert a Disc in the drive and press enter" msgstr "" -#: ../apt/cache.py:131 +#: ../apt/cache.py:135 msgid "Building data structures" msgstr "" diff --git a/tests/data/fake-packages/Packages b/tests/data/fake-packages/Packages new file mode 100644 index 00000000..9fbab957 --- /dev/null +++ b/tests/data/fake-packages/Packages @@ -0,0 +1,21 @@ +Package: 2vcard +Priority: optional +Section: universe/utils +Installed-Size: 108 +Maintainer: Arvind Autar <Autar022@planet.nl> +Architecture: amd64 +Version: 0.5-1ubuntu1 +Filename: pool/universe/2/2vcard/2vcard_0.5-1ubuntu1_amd64.deb +Size: 14164 +MD5sum: 105ea91f0a75417d0f9e8e9624513b2a +SHA1: d55beee01c08efc33cd131e106330dca72ee14be +SHA256: 4a72edaf87cdb826e5508b85311fcf0bec9b7e019a55740ded7feb1b9e197f11 +Description: A little perl script to convert an adressbook to VCARD file format + 2vcard is a little perl script that you can use to convert the popular vcard + file format. Currently 2vcard can only convert adressbooks and alias files from + the following formats: abook,eudora,juno,ldif,mutt,mh and pine. + . + The VCARD format is used by gnomecard, for example, which is turn is used by + the balsa email client. +Bugs: mailto:ubuntu-users@lists.ubuntu.com +Origin: Ubuntu diff --git a/tests/data/fake-packages/Packages.gz b/tests/data/fake-packages/Packages.gz Binary files differnew file mode 100644 index 00000000..506bc8d4 --- /dev/null +++ b/tests/data/fake-packages/Packages.gz diff --git a/tests/test_apt_cache.py b/tests/test_apt_cache.py index b27ed778..653a0f48 100644 --- a/tests/test_apt_cache.py +++ b/tests/test_apt_cache.py @@ -6,12 +6,15 @@ # are permitted in any medium without royalty provided the copyright # notice and this notice are preserved. """Unit tests for verifying the correctness of check_dep, etc in apt_pkg.""" +import os +import tempfile import unittest +import sys +sys.path.insert(0, "..") + import apt import apt_pkg -import os -import tempfile class TestAptCache(unittest.TestCase): @@ -42,6 +45,21 @@ class TestAptCache(unittest.TestCase): self.assert_(len(r['Description']) > 0) self.assert_(str(r).startswith('Package: %s\n' % pkg.name)) + def test_get_provided_packages(self): + cache = apt.Cache() + # a true virtual pkg + l = cache.get_providing_packages("mail-transport-agent") + self.assertTrue(len(l) > 0) + # this is a not virtual (transitional) package provided by another + l = cache.get_providing_packages("scrollkeeper") + self.assertEqual(l, []) + # now inlcude nonvirtual packages in the search (rarian-compat + # provides scrollkeeper) + l = cache.get_providing_packages("scrollkeeper", + include_nonvirtual=True) + self.assertTrue(len(l), 1) + + def test_dpkg_journal_dirty(self): # backup old value old_status = apt_pkg.Config.find_file("Dir::State::status") diff --git a/tests/test_debfile.py b/tests/test_debfile.py new file mode 100644 index 00000000..02e25117 --- /dev/null +++ b/tests/test_debfile.py @@ -0,0 +1,56 @@ +#!/usr/bin/python +# +# Copyright (C) 2010 Michael Vogt <mvo@ubuntu.com> +# +# Copying and distribution of this file, with or without modification, +# are permitted in any medium without royalty provided the copyright +# notice and this notice are preserved. +"""Unit tests for verifying the correctness of DebPackage in apt.debfile.""" +import os +import logging +import unittest + +import sys +sys.path.insert(0, "..") + +import apt.debfile + + +class TestDebfilee(unittest.TestCase): + """ test the apt cache """ + + TEST_DEBS = [ + # conflicts with apt + ('gdebi-test1.deb', False), + # impossible dependency + ('gdebi-test2.deb', False), + # or-group (impossible-dependency|apt) + ('gdebi-test3.deb', True), + # Conflicts: apt (<= 0.1) + ('gdebi-test4.deb', True), + # Conflicts: apt (>= 0.1) + ('gdebi-test5.deb', False), + # invalid unicode in descr + ('gdebi-test6.deb', True), + # provides/conflicts against "foobarbaz" + ('gdebi-test7.deb', True), + # provides/conflicts/replaces against "mail-transport-agent" + # (should fails if mail-transport-agent is installed) + ('gdebi-test8.deb', False), + # provides/conflicts against real pkg + ('gdebi-test9.deb', True), + # provides debconf-tiny and the real debconf conflicts with + ('gdebi-test10.deb', False), + ] + + def testDebFile(self): + deb = apt.debfile.DebPackage() + for (filename, expected_res) in self.TEST_DEBS: + logging.debug("testing %s, expecting %s" % (filename, expected_res)) + deb.open(os.path.join("test_debs", filename)) + res = deb.check() + self.assertEqual(res, expected_res) + +if __name__ == "__main__": + #logging.basicConfig(level=logging.DEBUG) + unittest.main() diff --git a/tests/test_debs/gdebi-test1.deb b/tests/test_debs/gdebi-test1.deb Binary files differnew file mode 100644 index 00000000..ea9991ac --- /dev/null +++ b/tests/test_debs/gdebi-test1.deb diff --git a/tests/test_debs/gdebi-test10.deb b/tests/test_debs/gdebi-test10.deb Binary files differnew file mode 100644 index 00000000..ca43ace6 --- /dev/null +++ b/tests/test_debs/gdebi-test10.deb diff --git a/tests/test_debs/gdebi-test2.deb b/tests/test_debs/gdebi-test2.deb Binary files differnew file mode 100644 index 00000000..307ac689 --- /dev/null +++ b/tests/test_debs/gdebi-test2.deb diff --git a/tests/test_debs/gdebi-test3.deb b/tests/test_debs/gdebi-test3.deb Binary files differnew file mode 100644 index 00000000..436b9258 --- /dev/null +++ b/tests/test_debs/gdebi-test3.deb diff --git a/tests/test_debs/gdebi-test4.deb b/tests/test_debs/gdebi-test4.deb Binary files differnew file mode 100644 index 00000000..9eb92d1b --- /dev/null +++ b/tests/test_debs/gdebi-test4.deb diff --git a/tests/test_debs/gdebi-test5.deb b/tests/test_debs/gdebi-test5.deb Binary files differnew file mode 100644 index 00000000..0c98c03f --- /dev/null +++ b/tests/test_debs/gdebi-test5.deb diff --git a/tests/test_debs/gdebi-test6.deb b/tests/test_debs/gdebi-test6.deb Binary files differnew file mode 100644 index 00000000..32fd1800 --- /dev/null +++ b/tests/test_debs/gdebi-test6.deb diff --git a/tests/test_debs/gdebi-test7.deb b/tests/test_debs/gdebi-test7.deb Binary files differnew file mode 100644 index 00000000..c0414990 --- /dev/null +++ b/tests/test_debs/gdebi-test7.deb diff --git a/tests/test_debs/gdebi-test8.deb b/tests/test_debs/gdebi-test8.deb Binary files differnew file mode 100644 index 00000000..439f8ca7 --- /dev/null +++ b/tests/test_debs/gdebi-test8.deb diff --git a/tests/test_debs/gdebi-test9.deb b/tests/test_debs/gdebi-test9.deb Binary files differnew file mode 100644 index 00000000..9901d906 --- /dev/null +++ b/tests/test_debs/gdebi-test9.deb diff --git a/tests/test_progress.py b/tests/test_progress.py new file mode 100644 index 00000000..2ab8ce5e --- /dev/null +++ b/tests/test_progress.py @@ -0,0 +1,44 @@ +#!/usr/bin/python +# +# Copyright (C) 2010 Michael Vogt <mvo@ubuntu.com> +# +# Copying and distribution of this file, with or without modification, +# are permitted in any medium without royalty provided the copyright +# notice and this notice are preserved. +"""Unit tests for verifying the correctness of apt.progress""" +import unittest + +import apt +import apt_pkg +import os + +class TestAcquireProgress(apt.progress.base.AcquireProgress): + def pulse(self, owner): + self.pulsed = True + +class TestProgress(unittest.TestCase): + + def setUp(self): + basedir = os.path.abspath(os.path.dirname(__file__)) + # setup apt_pkg config + apt_pkg.init() + apt_pkg.config.set("APT::Architecture", "amd64") + apt_pkg.config.set("Dir::Etc", basedir) + apt_pkg.config.set("Dir::Etc::sourceparts", "/xxx") + # setup lists dir + if not os.path.exists("./tmp/partial"): + os.makedirs("./tmp/partial") + apt_pkg.config.set("Dir::state::lists", "./tmp") + # create artifical line + deb_line = "deb file:%s/data/fake-packages/ /\n" % basedir + open("fetch_sources.list","w").write(deb_line) + apt_pkg.config.set("Dir::Etc::sourcelist", "fetch_sources.list") + + def test_acquire_progress(self): + progress = TestAcquireProgress() + cache = apt.Cache() + res = cache.update(progress) + self.assertTrue(progress.pulsed) + +if __name__ == "__main__": + unittest.main() |
