Просмотр исходного кода

merged from lp:~donkult/apt/sid

Michael Vogt лет назад: 14
Родитель
Сommit
ad6946e73c

+ 5 - 0
apt-pkg/algorithms.cc

@@ -194,6 +194,11 @@ bool pkgSimulate::Remove(PkgIterator iPkg,bool Purge)
 {
 {
    // Adapt the iterator
    // Adapt the iterator
    PkgIterator Pkg = Sim.FindPkg(iPkg.Name(), iPkg.Arch());
    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;
    Flags[Pkg->ID] = 3;
    Sim.MarkDelete(Pkg);
    Sim.MarkDelete(Pkg);

+ 18 - 4
apt-pkg/deb/deblistparser.cc

@@ -645,6 +645,8 @@ bool debListParser::ParseDepends(pkgCache::VerIterator &Ver,
 	      a != Architectures.end(); ++a)
 	      a != Architectures.end(); ++a)
 	    if (NewDepends(Ver,Package,*a,Version,Op,Type) == false)
 	    if (NewDepends(Ver,Package,*a,Version,Op,Type) == false)
 	       return false;
 	       return false;
+	 if (NewDepends(Ver,Package,"none",Version,Op,Type) == false)
+	    return false;
       }
       }
       else if (MultiArchEnabled == true && found != string::npos &&
       else if (MultiArchEnabled == true && found != string::npos &&
 	       strcmp(Package.c_str() + found, ":any") != 0)
 	       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)
 	 if (NewDepends(Ver,Package,Arch,Version,Op,Type) == false)
 	    return 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)
       if (Start == Stop)
 	 break;
 	 break;
    }
    }
@@ -753,13 +765,15 @@ bool debListParser::Step()
          drop the whole section. A missing arch tag only happens (in theory)
          drop the whole section. A missing arch tag only happens (in theory)
          inside the Status file, so that is a positive return */
          inside the Status file, so that is a positive return */
       string const Architecture = Section.FindS("Architecture");
       string const Architecture = Section.FindS("Architecture");
-      if (Architecture.empty() == true)
-	 return true;
 
 
       if (Arch.empty() == true || Arch == "any" || MultiArchEnabled == false)
       if (Arch.empty() == true || Arch == "any" || MultiArchEnabled == false)
       {
       {
 	 if (APT::Configuration::checkArchitecture(Architecture) == true)
 	 if (APT::Configuration::checkArchitecture(Architecture) == true)
 	    return 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
       else
       {
       {

+ 6 - 2
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())
 	    if (I->Op == Item::Configure && disappearedPkgs.find(I->Pkg.Name()) != disappearedPkgs.end())
 	       continue;
 	       continue;
 	    // We keep this here to allow "smooth" transitions from e.g. multiarch dpkg/ubuntu to dpkg/debian
 	    // 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();
 	       char const * const name = I->Pkg.Name();
 	       ADDARG(name);
 	       ADDARG(name);
@@ -1148,7 +1150,9 @@ bool pkgDPkgPM::Go(int OutStatusFd)
                }
                }
 	       else
 	       else
 		  PkgVer = Cache[I->Pkg].InstVerIter(Cache);
 		  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());
                   name.append(":").append(PkgVer.Arch());
                else
                else
                   _error->Warning("Can not find PkgVer for '%s'", name.c_str());
                   _error->Warning("Can not find PkgVer for '%s'", name.c_str());

+ 5 - 1
apt-pkg/pkgcache.cc

@@ -238,7 +238,7 @@ pkgCache::PkgIterator pkgCache::FindPkg(const string &Name) {
 // ---------------------------------------------------------------------
 // ---------------------------------------------------------------------
 /* Returns 0 on error, pointer to the package otherwise */
 /* Returns 0 on error, pointer to the package otherwise */
 pkgCache::PkgIterator pkgCache::FindPkg(const string &Name, string const &Arch) {
 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" ||
 		if (Arch == "native" || Arch == "all" || Arch == "any" ||
 		    Arch == NativeArch())
 		    Arch == NativeArch())
 			return SingleArchFindPkg(Name);
 			return SingleArchFindPkg(Name);
@@ -376,6 +376,10 @@ pkgCache::PkgIterator pkgCache::GrpIterator::FindPreferredPkg(bool const &Prefer
 		if (Pkg.end() == false && (PreferNonVirtual == false || Pkg->VersionList != 0))
 		if (Pkg.end() == false && (PreferNonVirtual == false || Pkg->VersionList != 0))
 			return Pkg;
 			return Pkg;
 	}
 	}
+	// packages without an architecture
+	Pkg = FindPkg("none");
+	if (Pkg.end() == false && (PreferNonVirtual == false || Pkg->VersionList != 0))
+		return Pkg;
 
 
 	if (PreferNonVirtual == true)
 	if (PreferNonVirtual == true)
 		return FindPreferredPkg(false);
 		return FindPreferredPkg(false);

+ 54 - 1
apt-pkg/pkgcachegen.cc

@@ -195,12 +195,26 @@ bool pkgCacheGenerator::MergeList(ListParser &List,
       string const Version = List.Version();
       string const Version = List.Version();
       if (Version.empty() == true && Arch.empty() == true)
       if (Version.empty() == true && Arch.empty() == true)
       {
       {
+	 // package descriptions
 	 if (MergeListGroup(List, PackageName) == false)
 	 if (MergeListGroup(List, PackageName) == false)
 	    return false;
 	    return false;
+	 continue;
       }
       }
 
 
       if (Arch.empty() == true)
       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
       // Get a pointer to the package structure
       pkgCache::PkgIterator Pkg;
       pkgCache::PkgIterator Pkg;
@@ -418,6 +432,42 @@ bool pkgCacheGenerator::MergeListVersion(ListParser &List, pkgCache::PkgIterator
 	       return _error->Error(_("Error occurred while processing %s (%s%d)"),
 	       return _error->Error(_("Error occurred while processing %s (%s%d)"),
 				    Pkg.Name(), "AddImplicitDepends", 1);
 				    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))
    if (unlikely(AddImplicitDepends(Grp, Pkg, Ver) == false))
       return _error->Error(_("Error occurred while processing %s (%s%d)"),
       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
    // Locate the target package
    pkgCache::PkgIterator Pkg = Grp.FindPkg(Arch);
    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);
    Dynamic<pkgCache::PkgIterator> DynPkg(Pkg);
    if (Pkg.end() == true) {
    if (Pkg.end() == true) {
       if (unlikely(Owner->NewPackage(Pkg, PackageName, Arch) == false))
       if (unlikely(Owner->NewPackage(Pkg, PackageName, Arch) == false))

+ 7 - 0
debian/changelog

@@ -5,6 +5,10 @@ apt (0.9.7.5) UNRELEASED; urgency=low
   * Portuguese (Américo Monteiro) (Closes: #686975)
   * Portuguese (Américo Monteiro) (Closes: #686975)
 
 
   [ David Kalnischkies ]
   [ 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:
   * apt-pkg/cdrom.cc:
     - copy only configured translation files from a CD-ROM and not all
     - copy only configured translation files from a CD-ROM and not all
       available translation files preventing new installs with d-i from
       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
     - 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
       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
       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
  -- David Kalnischkies <kalnischkies@gmail.com>  Sun, 26 Aug 2012 10:49:17 +0200
 
 

+ 6 - 6
test/integration/framework

@@ -468,7 +468,7 @@ insertpackage() {
 	local PRIORITY="${6:-optional}"
 	local PRIORITY="${6:-optional}"
 	local ARCHS=""
 	local ARCHS=""
 	for arch in $(echo "$ARCH" | sed -e 's#,#\n#g' | sed -e "s#^native\$#$(getarchitecture 'native')#"); do
 	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)"
 			ARCHS="$(getarchitectures)"
 		else
 		else
 			ARCHS="$arch"
 			ARCHS="$arch"
@@ -482,9 +482,9 @@ insertpackage() {
 Priority: $PRIORITY
 Priority: $PRIORITY
 Section: other
 Section: other
 Installed-Size: 42
 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
 Filename: pool/main/${NAME}/${NAME}_${VERSION}_${arch}.deb" >> $FILE
 			test -z "$DEPENDENCIES" || echo "$DEPENDENCIES" >> $FILE
 			test -z "$DEPENDENCIES" || echo "$DEPENDENCIES" >> $FILE
 			echo "Description: an autogenerated dummy ${NAME}=${VERSION}/${RELEASE}
 			echo "Description: an autogenerated dummy ${NAME}=${VERSION}/${RELEASE}
@@ -534,8 +534,8 @@ Priority: $PRIORITY
 Section: other
 Section: other
 Installed-Size: 42
 Installed-Size: 42
 Maintainer: Joe Sixpack <joe@example.org>
 Maintainer: Joe Sixpack <joe@example.org>
-Architecture: $arch
 Version: $VERSION" >> $FILE
 Version: $VERSION" >> $FILE
+		test "$arch" = 'none' || echo "Architecture: $arch" >> $FILE
 		test -z "$DEPENDENCIES" || echo "$DEPENDENCIES" >> $FILE
 		test -z "$DEPENDENCIES" || echo "$DEPENDENCIES" >> $FILE
 		echo "Description: an autogenerated dummy ${NAME}=${VERSION}/installed
 		echo "Description: an autogenerated dummy ${NAME}=${VERSION}/installed
  If you find such a package installed on your system,
  If you find such a package installed on your system,
@@ -818,7 +818,7 @@ testnopackage() {
 
 
 testdpkginstalled() {
 testdpkginstalled() {
 	msgtest "Test for correctly installed package(s) with" "dpkg -l $*"
 	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
 	if [ "$PKGS" != $# ]; then
 		echo $PKGS
 		echo $PKGS
 		dpkg -l $* | grep '^[a-z]'
 		dpkg -l $* | grep '^[a-z]'

+ 87 - 0
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