diff options
author | Michael Vogt <michael.vogt@ubuntu.com> | 2012-09-11 14:32:24 +0200 |
---|---|---|
committer | Michael Vogt <michael.vogt@ubuntu.com> | 2012-09-11 14:32:24 +0200 |
commit | ad6946e73ca11f79ffd306b511883131dc7babe6 (patch) | |
tree | d6d27694adae0663ab0ee0526e69d07242483415 | |
parent | 4c81d32aada5b78fff4724efb1e039dd429c09f3 (diff) | |
parent | 8ec008808cd6083a633685a732dfe9b8a58a89da (diff) | |
download | apt-ad6946e73ca11f79ffd306b511883131dc7babe6.tar.gz |
merged from lp:~donkult/apt/sid
-rw-r--r-- | apt-pkg/algorithms.cc | 5 | ||||
-rw-r--r-- | apt-pkg/deb/deblistparser.cc | 22 | ||||
-rw-r--r-- | apt-pkg/deb/dpkgpm.cc | 8 | ||||
-rw-r--r-- | apt-pkg/pkgcache.cc | 6 | ||||
-rw-r--r-- | apt-pkg/pkgcachegen.cc | 55 | ||||
-rw-r--r-- | debian/changelog | 7 | ||||
-rw-r--r-- | test/integration/framework | 12 | ||||
-rwxr-xr-x | test/integration/test-bug-686346-package-missing-architecture | 87 |
8 files changed, 188 insertions, 14 deletions
diff --git a/apt-pkg/algorithms.cc b/apt-pkg/algorithms.cc index 2f5fcc7a..1b0161ff 100644 --- a/apt-pkg/algorithms.cc +++ b/apt-pkg/algorithms.cc @@ -194,6 +194,11 @@ bool pkgSimulate::Remove(PkgIterator iPkg,bool Purge) { // Adapt the iterator PkgIterator Pkg = Sim.FindPkg(iPkg.Name(), iPkg.Arch()); + if (Pkg.end() == true) + { + std::cerr << (Purge ? "Purg" : "Remv") << " invalid package " << iPkg.FullName() << std::endl; + return false; + } Flags[Pkg->ID] = 3; Sim.MarkDelete(Pkg); diff --git a/apt-pkg/deb/deblistparser.cc b/apt-pkg/deb/deblistparser.cc index 12c6ab4c..b84bd6fd 100644 --- a/apt-pkg/deb/deblistparser.cc +++ b/apt-pkg/deb/deblistparser.cc @@ -645,6 +645,8 @@ bool debListParser::ParseDepends(pkgCache::VerIterator &Ver, a != Architectures.end(); ++a) if (NewDepends(Ver,Package,*a,Version,Op,Type) == false) return false; + if (NewDepends(Ver,Package,"none",Version,Op,Type) == false) + return false; } else if (MultiArchEnabled == true && found != string::npos && strcmp(Package.c_str() + found, ":any") != 0) @@ -658,8 +660,18 @@ bool debListParser::ParseDepends(pkgCache::VerIterator &Ver, if (NewDepends(Ver,Package,Arch,Version,Op,Type) == false) return false; } - else if (NewDepends(Ver,Package,pkgArch,Version,Op,Type) == false) - return false; + else + { + if (NewDepends(Ver,Package,pkgArch,Version,Op,Type) == false) + return false; + if ((Type == pkgCache::Dep::Conflicts || + Type == pkgCache::Dep::DpkgBreaks || + Type == pkgCache::Dep::Replaces) && + NewDepends(Ver, Package, + (pkgArch != "none") ? "none" : _config->Find("APT::Architecture"), + Version,Op,Type) == false) + return false; + } if (Start == Stop) break; } @@ -753,13 +765,15 @@ bool debListParser::Step() drop the whole section. A missing arch tag only happens (in theory) inside the Status file, so that is a positive return */ string const Architecture = Section.FindS("Architecture"); - if (Architecture.empty() == true) - return true; if (Arch.empty() == true || Arch == "any" || MultiArchEnabled == false) { if (APT::Configuration::checkArchitecture(Architecture) == true) return true; + /* parse version stanzas without an architecture only in the status file + (and as misfortune bycatch flat-archives) */ + if ((Arch.empty() == true || Arch == "any") && Architecture.empty() == true) + return true; } else { diff --git a/apt-pkg/deb/dpkgpm.cc b/apt-pkg/deb/dpkgpm.cc index ae9143e0..c9df41d3 100644 --- a/apt-pkg/deb/dpkgpm.cc +++ b/apt-pkg/deb/dpkgpm.cc @@ -1131,7 +1131,9 @@ bool pkgDPkgPM::Go(int OutStatusFd) if (I->Op == Item::Configure && disappearedPkgs.find(I->Pkg.Name()) != disappearedPkgs.end()) continue; // We keep this here to allow "smooth" transitions from e.g. multiarch dpkg/ubuntu to dpkg/debian - if (dpkgMultiArch == false && (I->Pkg.Arch() == nativeArch || !strcmp(I->Pkg.Arch(), "all"))) + if (dpkgMultiArch == false && (I->Pkg.Arch() == nativeArch || + strcmp(I->Pkg.Arch(), "all") == 0 || + strcmp(I->Pkg.Arch(), "none") == 0)) { char const * const name = I->Pkg.Name(); ADDARG(name); @@ -1148,7 +1150,9 @@ bool pkgDPkgPM::Go(int OutStatusFd) } else PkgVer = Cache[I->Pkg].InstVerIter(Cache); - if (PkgVer.end() == false) + if (strcmp(I->Pkg.Arch(), "none") == 0) + ; // never arch-qualify a package without an arch + else if (PkgVer.end() == false) name.append(":").append(PkgVer.Arch()); else _error->Warning("Can not find PkgVer for '%s'", name.c_str()); diff --git a/apt-pkg/pkgcache.cc b/apt-pkg/pkgcache.cc index 9acb7da7..353172d8 100644 --- a/apt-pkg/pkgcache.cc +++ b/apt-pkg/pkgcache.cc @@ -238,7 +238,7 @@ pkgCache::PkgIterator pkgCache::FindPkg(const string &Name) { // --------------------------------------------------------------------- /* Returns 0 on error, pointer to the package otherwise */ pkgCache::PkgIterator pkgCache::FindPkg(const string &Name, string const &Arch) { - if (MultiArchCache() == false) { + if (MultiArchCache() == false && Arch != "none") { if (Arch == "native" || Arch == "all" || Arch == "any" || Arch == NativeArch()) return SingleArchFindPkg(Name); @@ -376,6 +376,10 @@ pkgCache::PkgIterator pkgCache::GrpIterator::FindPreferredPkg(bool const &Prefer if (Pkg.end() == false && (PreferNonVirtual == false || Pkg->VersionList != 0)) return Pkg; } + // packages without an architecture + Pkg = FindPkg("none"); + if (Pkg.end() == false && (PreferNonVirtual == false || Pkg->VersionList != 0)) + return Pkg; if (PreferNonVirtual == true) return FindPreferredPkg(false); diff --git a/apt-pkg/pkgcachegen.cc b/apt-pkg/pkgcachegen.cc index f70cbd02..54b07c46 100644 --- a/apt-pkg/pkgcachegen.cc +++ b/apt-pkg/pkgcachegen.cc @@ -195,12 +195,26 @@ bool pkgCacheGenerator::MergeList(ListParser &List, string const Version = List.Version(); if (Version.empty() == true && Arch.empty() == true) { + // package descriptions if (MergeListGroup(List, PackageName) == false) return false; + continue; } if (Arch.empty() == true) - Arch = _config->Find("APT::Architecture"); + { + // use the pseudo arch 'none' for arch-less packages + Arch = "none"; + /* We might built a SingleArchCache here, which we don't want to blow up + just for these :none packages to a proper MultiArchCache, so just ensure + that we have always a native package structure first for SingleArch */ + pkgCache::PkgIterator NP; + if (NewPackage(NP, PackageName, _config->Find("APT::Architecture")) == false) + // TRANSLATOR: The first placeholder is a package name, + // the other two should be copied verbatim as they include debug info + return _error->Error(_("Error occurred while processing %s (%s%d)"), + PackageName.c_str(), "NewPackage", 0); + } // Get a pointer to the package structure pkgCache::PkgIterator Pkg; @@ -418,6 +432,42 @@ bool pkgCacheGenerator::MergeListVersion(ListParser &List, pkgCache::PkgIterator return _error->Error(_("Error occurred while processing %s (%s%d)"), Pkg.Name(), "AddImplicitDepends", 1); } + /* :none packages are packages without an architecture. They are forbidden by + debian-policy, so usually they will only be in (old) dpkg status files - + and dpkg will complain about them - and are pretty rare. We therefore do + usually not create conflicts while the parent is created, but only if a :none + package (= the target) appears. This creates incorrect dependencies on :none + for architecture-specific dependencies on the package we copy from, but we + will ignore this bug as architecture-specific dependencies are only allowed + in jessie and until then the :none packages should be extinct (hopefully). + In other words: This should work long enough to allow graceful removal of + these packages, it is not supposed to allow users to keep using them … */ + if (strcmp(Pkg.Arch(), "none") == 0) + { + pkgCache::PkgIterator M = Grp.FindPreferredPkg(); + if (M.end() == false && Pkg != M) + { + pkgCache::DepIterator D = M.RevDependsList(); + Dynamic<pkgCache::DepIterator> DynD(D); + for (; D.end() == false; ++D) + { + if ((D->Type != pkgCache::Dep::Conflicts && + D->Type != pkgCache::Dep::DpkgBreaks && + D->Type != pkgCache::Dep::Replaces) || + D.ParentPkg().Group() == Grp) + continue; + + map_ptrloc *OldDepLast = NULL; + pkgCache::VerIterator ConVersion = D.ParentVer(); + // duplicate the Conflicts/Breaks/Replaces for :none arch + if (D->Version == 0) + NewDepends(Pkg, ConVersion, "", 0, D->Type, OldDepLast); + else + NewDepends(Pkg, ConVersion, D.TargetVer(), + D->CompareOp, D->Type, OldDepLast); + } + } + } } if (unlikely(AddImplicitDepends(Grp, Pkg, Ver) == false)) return _error->Error(_("Error occurred while processing %s (%s%d)"), @@ -871,6 +921,9 @@ bool pkgCacheGenerator::ListParser::NewDepends(pkgCache::VerIterator &Ver, // Locate the target package pkgCache::PkgIterator Pkg = Grp.FindPkg(Arch); + // we don't create 'none' packages and their dependencies if we can avoid it … + if (Pkg.end() == true && Arch == "none") + return true; Dynamic<pkgCache::PkgIterator> DynPkg(Pkg); if (Pkg.end() == true) { if (unlikely(Owner->NewPackage(Pkg, PackageName, Arch) == false)) diff --git a/debian/changelog b/debian/changelog index d813f035..569136b7 100644 --- a/debian/changelog +++ b/debian/changelog @@ -5,6 +5,10 @@ apt (0.9.7.5) UNRELEASED; urgency=low * Portuguese (Américo Monteiro) (Closes: #686975) [ David Kalnischkies ] + * handle packages without a mandatory architecture (debian-policy §5.3) + by introducing a pseudo-architecture 'none' so that the small group of + users with these packages can get right of them without introducing too + much hassle for other users (Closes: #686346) * apt-pkg/cdrom.cc: - copy only configured translation files from a CD-ROM and not all available translation files preventing new installs with d-i from @@ -29,6 +33,9 @@ apt (0.9.7.5) UNRELEASED; urgency=low - do not warn about files which have a record in the Release file, but are not present on the CD to mirror the behavior of the other methods and to allow uncompressed indexes to be dropped without scaring users + * apt-pkg/pkgcachegen.cc: + - do not create 'native' (or now 'none') package structures as a side + effect of description translation parsing as it pollutes the cache -- David Kalnischkies <kalnischkies@gmail.com> Sun, 26 Aug 2012 10:49:17 +0200 diff --git a/test/integration/framework b/test/integration/framework index 57bf555a..1c4872c8 100644 --- a/test/integration/framework +++ b/test/integration/framework @@ -468,7 +468,7 @@ insertpackage() { local PRIORITY="${6:-optional}" local ARCHS="" for arch in $(echo "$ARCH" | sed -e 's#,#\n#g' | sed -e "s#^native\$#$(getarchitecture 'native')#"); do - if [ "$arch" = "all" ]; then + if [ "$arch" = 'all' -o "$arch" = 'none' ]; then ARCHS="$(getarchitectures)" else ARCHS="$arch" @@ -482,9 +482,9 @@ insertpackage() { Priority: $PRIORITY Section: other Installed-Size: 42 -Maintainer: Joe Sixpack <joe@example.org> -Architecture: $arch -Version: $VERSION +Maintainer: Joe Sixpack <joe@example.org>" >> $FILE + test "$arch" = 'none' || echo "Architecture: $arch" >> $FILE + echo "Version: $VERSION Filename: pool/main/${NAME}/${NAME}_${VERSION}_${arch}.deb" >> $FILE test -z "$DEPENDENCIES" || echo "$DEPENDENCIES" >> $FILE echo "Description: an autogenerated dummy ${NAME}=${VERSION}/${RELEASE} @@ -534,8 +534,8 @@ Priority: $PRIORITY Section: other Installed-Size: 42 Maintainer: Joe Sixpack <joe@example.org> -Architecture: $arch Version: $VERSION" >> $FILE + test "$arch" = 'none' || echo "Architecture: $arch" >> $FILE test -z "$DEPENDENCIES" || echo "$DEPENDENCIES" >> $FILE echo "Description: an autogenerated dummy ${NAME}=${VERSION}/installed If you find such a package installed on your system, @@ -818,7 +818,7 @@ testnopackage() { testdpkginstalled() { msgtest "Test for correctly installed package(s) with" "dpkg -l $*" - local PKGS="$(dpkg -l $* | grep '^i' | wc -l)" + local PKGS="$(dpkg -l $* 2>/dev/null | grep '^i' | wc -l)" if [ "$PKGS" != $# ]; then echo $PKGS dpkg -l $* | grep '^[a-z]' diff --git a/test/integration/test-bug-686346-package-missing-architecture b/test/integration/test-bug-686346-package-missing-architecture new file mode 100755 index 00000000..b0e0aa3c --- /dev/null +++ b/test/integration/test-bug-686346-package-missing-architecture @@ -0,0 +1,87 @@ +#!/bin/sh +set -e + +TESTDIR=$(readlink -f $(dirname $0)) +. $TESTDIR/framework +setupenvironment +configarchitecture 'amd64' + +insertinstalledpackage 'pkgb' 'none' '1' +insertinstalledpackage 'pkgd' 'none' '1' +insertpackage 'unstable' 'pkga' 'amd64' '2' 'Depends: pkgb' +insertpackage 'unstable' 'pkgb' 'amd64' '2' +insertpackage 'unstable' 'pkgc' 'amd64' '1' 'Conflicts: pkgb' +insertpackage 'unstable' 'pkge' 'none' '1' + +setupaptarchive + +testequal 'Reading package lists... +Building dependency tree... +The following packages will be REMOVED: + pkgb:none +The following NEW packages will be installed: + pkgc +0 upgraded, 1 newly installed, 1 to remove and 0 not upgraded. +Remv pkgb:none [1] +Inst pkgc (1 unstable [amd64]) +Conf pkgc (1 unstable [amd64])' aptget install pkgc -s + +testequal 'Reading package lists... +Building dependency tree... +The following extra packages will be installed: + pkgb +The following packages will be REMOVED: + pkgb:none +The following NEW packages will be installed: + pkga pkgb +0 upgraded, 2 newly installed, 1 to remove and 0 not upgraded. +Remv pkgb:none [1] +Inst pkgb (2 unstable [amd64]) +Inst pkga (2 unstable [amd64]) +Conf pkgb (2 unstable [amd64]) +Conf pkga (2 unstable [amd64])' aptget install pkga -s + +# ensure that arch-less stanzas from Packages files are ignored +msgtest 'Package is distributed in the Packages files' 'pkge' +grep -q 'Package: pkge' $(find aptarchive -name 'Packages') && msgpass || msgfail +testnopackage pkge +testnopackage pkge:none +testnopackage pkge:* + +# do not automatically change from none-arch to whatever-arch as +# this breaks other none packages and dpkg has this ruleset as +# this difference seems so important that it has to be maintained … +testequal 'Reading package lists... +Building dependency tree... +0 upgraded, 0 newly installed, 0 to remove and 0 not upgraded.' aptget dist-upgrade -s + +# pkgd has no update with an architecture +testdpkginstalled pkgd +msgtest 'Test apt-get purge' 'pkgd' +aptget purge pkgd -y >/dev/null 2>&1 && msgpass || msgfail +testdpkgnotinstalled pkgd + +# there is a pkgb with an architecture +testdpkginstalled pkgb +msgtest 'Test apt-get purge' 'pkgb:none' +aptget purge pkgb:none -y >/dev/null 2>&1 && msgpass || msgfail +testdpkgnotinstalled pkgb + +# check that dependencies are created after the none package exists in the cache +rm rootdir/var/cache/apt/*.bin +insertinstalledpackage 'pkgb' 'none' '1' +insertinstalledpackage 'pkgf' 'none' '1' 'Conflicts: pkgb' +insertinstalledpackage 'pkgg' 'amd64' '1' 'Conflicts: pkgb' +insertinstalledpackage 'pkgb' 'amd64' '2' +testequal "Reading package lists... +Building dependency tree... +Reading state information... +You might want to run 'apt-get -f install' to correct these. +The following packages have unmet dependencies: + pkgb : Conflicts: pkgb:none but 1 is installed + pkgb:none : Conflicts: pkgb but 2 is installed + pkgf:none : Conflicts: pkgb:none but 1 is installed + Conflicts: pkgb but 2 is installed + pkgg : Conflicts: pkgb but 2 is installed + Conflicts: pkgb:none but 1 is installed +E: Unmet dependencies. Try using -f." aptget check |