Prechádzať zdrojové kódy

just-in-time creation for (explicit) negative deps

Now that we deal with provides in a more dynamic fashion the last
remaining problem is explicit dependencies like 'Conflicts: foo' which
have to apply to all architectures, but creating them all at the same
time requires us to know all architectures ending up in the cache which
isn't needed to be the same set as all foreign architectures.

The effect is visible already now through as this prevents the creation
of a bunch of virtual packages for arch:all packages and as such also
many dependencies, just not very visible if you don't look at the stats…

Git-Dch Ignore
David Kalnischkies 11 rokov pred
rodič
commit
bb0f6a34c4

+ 5 - 25
apt-pkg/deb/deblistparser.cc

@@ -790,43 +790,23 @@ bool debListParser::ParseDepends(pkgCache::VerIterator &Ver,
 	 return _error->Error("Problem parsing dependency %s",Tag);
       size_t const found = Package.rfind(':');
 
-      // If negative is unspecific it needs to apply on all architectures
-      if (MultiArchEnabled == true && found == string::npos &&
-	  (Type == pkgCache::Dep::Conflicts ||
-	   Type == pkgCache::Dep::DpkgBreaks ||
-	   Type == pkgCache::Dep::Replaces))
+      if (found == string::npos || strcmp(Package.c_str() + found, ":any") == 0)
       {
-	 for (std::vector<std::string>::const_iterator a = Architectures.begin();
-	      a != Architectures.end(); ++a)
-	    if (NewDepends(Ver,Package,*a,Version,Op,Type) == false)
-	       return false;
-	 if (NewDepends(Ver,Package,"none",Version,Op,Type) == false)
+	 if (NewDepends(Ver,Package,pkgArch,Version,Op,Type) == false)
 	    return false;
       }
-      else if (found != string::npos &&
-	       strcmp(Package.c_str() + found, ":any") != 0)
+      else
       {
 	 string Arch = Package.substr(found+1, string::npos);
 	 Package = Package.substr(0, found);
 	 // Such dependencies are not supposed to be accepted …
-	 // … but this is probably the best thing to do.
+	 // … but this is probably the best thing to do anyway
 	 if (Arch == "native")
 	    Arch = _config->Find("APT::Architecture");
 	 if (NewDepends(Ver,Package,Arch,Version,Op | pkgCache::Dep::ArchSpecific,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;
    }

+ 69 - 43
apt-pkg/pkgcachegen.cc

@@ -695,6 +695,23 @@ bool pkgCacheGenerator::NewPackage(pkgCache::PkgIterator &Pkg,const string &Name
 		  if (NewProvides(Ver, Pkg, Ver->VerStr, pkgCache::Flag::MultiArchImplicit) == false)
 		     return false;
       }
+      // and negative dependencies, don't forget negative dependencies
+      {
+	 pkgCache::PkgIterator const M = Grp.FindPreferredPkg(false);
+	 if (M.end() == false)
+	    for (pkgCache::DepIterator Dep = M.RevDependsList(); Dep.end() == false; ++Dep)
+	    {
+	       if ((Dep->CompareOp & (pkgCache::Dep::ArchSpecific | pkgCache::Dep::MultiArchImplicit)) != 0)
+		  continue;
+	       if (Dep->Type != pkgCache::Dep::DpkgBreaks && Dep->Type != pkgCache::Dep::Conflicts &&
+		     Dep->Type != pkgCache::Dep::Replaces)
+		  continue;
+	       pkgCache::VerIterator Ver = Dep.ParentVer();
+	       map_pointer_t * unused = NULL;
+	       if (NewDepends(Pkg, Ver, Dep->Version, Dep->CompareOp, Dep->Type, unused) == false)
+		  return false;
+	    }
+      }
 
       // this package is the new last package
       pkgCache::PkgIterator LastPkg(Cache, Cache.PkgP + Grp->LastPackage);
@@ -933,33 +950,6 @@ map_pointer_t pkgCacheGenerator::NewDescription(pkgCache::DescIterator &Desc,
 // ---------------------------------------------------------------------
 /* This creates a dependency element in the tree. It is linked to the
    version and to the package that it is pointing to. */
-bool pkgCacheGenerator::NewDepends(pkgCache::PkgIterator &Pkg,
-				   pkgCache::VerIterator &Ver,
-				   string const &Version,
-				   uint8_t const Op,
-				   uint8_t const Type,
-				   map_stringitem_t* &OldDepLast)
-{
-   map_stringitem_t index = 0;
-   if (Version.empty() == false)
-   {
-      int const CmpOp = Op & 0x0F;
-      // =-deps are used (79:1) for lockstep on same-source packages (e.g. data-packages)
-      if (CmpOp == pkgCache::Dep::Equals && strcmp(Version.c_str(), Ver.VerStr()) == 0)
-	 index = Ver->VerStr;
-
-      if (index == 0)
-      {
-	 void const * const oldMap = Map.Data();
-	 index = StoreString(VERSIONNUMBER, Version);
-	 if (unlikely(index == 0))
-	    return false;
-	 if (OldDepLast != 0 && oldMap != Map.Data())
-	    OldDepLast += (map_pointer_t const * const) Map.Data() - (map_pointer_t const * const) oldMap;
-      }
-   }
-   return NewDepends(Pkg, Ver, index, Op, Type, OldDepLast);
-}
 bool pkgCacheGenerator::NewDepends(pkgCache::PkgIterator &Pkg,
 				   pkgCache::VerIterator &Ver,
 				   map_pointer_t const Version,
@@ -1071,28 +1061,64 @@ bool pkgCacheGenerator::ListParser::NewDepends(pkgCache::VerIterator &Ver,
    if (unlikely(Owner->NewGroup(Grp, PackageName) == false))
       return false;
 
-   // 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" && strcmp(Ver.ParentPkg().Arch(), "none") != 0)
-      return true;
-   Dynamic<pkgCache::PkgIterator> DynPkg(Pkg);
-   if (Pkg.end() == true) {
-      if (unlikely(Owner->NewPackage(Pkg, PackageName, Arch) == false))
-	 return false;
-   }
-
    // Is it a file dependency?
    if (unlikely(PackageName[0] == '/'))
       FoundFileDeps = true;
 
-   /* Caching the old end point speeds up generation substantially */
-   if (OldDepVer != Ver) {
-      OldDepLast = NULL;
-      OldDepVer = Ver;
+   map_stringitem_t idxVersion = 0;
+   if (Version.empty() == false)
+   {
+      int const CmpOp = Op & 0x0F;
+      // =-deps are used (79:1) for lockstep on same-source packages (e.g. data-packages)
+      if (CmpOp == pkgCache::Dep::Equals && strcmp(Version.c_str(), Ver.VerStr()) == 0)
+	 idxVersion = Ver->VerStr;
+
+      if (idxVersion == 0)
+      {
+	 idxVersion = StoreString(VERSIONNUMBER, Version);
+	 if (unlikely(idxVersion == 0))
+	    return false;
+      }
+   }
+
+   bool const isNegative = (Type == pkgCache::Dep::DpkgBreaks ||
+	 Type == pkgCache::Dep::Conflicts ||
+	 Type == pkgCache::Dep::Replaces);
+
+   pkgCache::PkgIterator Pkg;
+   Dynamic<pkgCache::PkgIterator> DynPkg(Pkg);
+   if (isNegative == false || (Op & pkgCache::Dep::ArchSpecific) == pkgCache::Dep::ArchSpecific || Grp->FirstPackage == 0)
+   {
+      // Locate the target package
+      Pkg = Grp.FindPkg(Arch);
+      if (Pkg.end() == true) {
+	 if (unlikely(Owner->NewPackage(Pkg, PackageName, Arch) == false))
+	    return false;
+      }
+
+      /* Caching the old end point speeds up generation substantially */
+      if (OldDepVer != Ver) {
+	 OldDepLast = NULL;
+	 OldDepVer = Ver;
+      }
+
+      return Owner->NewDepends(Pkg, Ver, idxVersion, Op, Type, OldDepLast);
    }
+   else
+   {
+      /* Caching the old end point speeds up generation substantially */
+      if (OldDepVer != Ver) {
+	 OldDepLast = NULL;
+	 OldDepVer = Ver;
+      }
 
-   return Owner->NewDepends(Pkg, Ver, Version, Op, Type, OldDepLast);
+      for (Pkg = Grp.PackageList(); Pkg.end() == false; Pkg = Grp.NextPkg(Pkg))
+      {
+	 if (Owner->NewDepends(Pkg, Ver, idxVersion, Op, Type, OldDepLast) == false)
+	       return false;
+      }
+   }
+   return true;
 }
 									/*}}}*/
 // ListParser::NewProvides - Create a Provides element			/*{{{*/

+ 1 - 4
apt-pkg/pkgcachegen.h

@@ -76,14 +76,11 @@ class APT_HIDDEN pkgCacheGenerator					/*{{{*/
 
    // Flag file dependencies
    bool FoundFileDeps;
-   
+
    bool NewGroup(pkgCache::GrpIterator &Grp,const std::string &Name);
    bool NewPackage(pkgCache::PkgIterator &Pkg,const std::string &Name, const std::string &Arch);
    bool NewFileVer(pkgCache::VerIterator &Ver,ListParser &List);
    bool NewFileDesc(pkgCache::DescIterator &Desc,ListParser &List);
-   bool NewDepends(pkgCache::PkgIterator &Pkg, pkgCache::VerIterator &Ver,
-		   std::string const &Version, uint8_t const Op,
-		   uint8_t const Type, map_pointer_t* &OldDepLast);
    bool NewDepends(pkgCache::PkgIterator &Pkg, pkgCache::VerIterator &Ver,
 		   map_pointer_t const Version, uint8_t const Op,
 		   uint8_t const Type, map_pointer_t* &OldDepLast);

+ 4 - 11
test/integration/test-apt-cache

@@ -66,7 +66,6 @@ testsuccessequal 'foo
 testsuccessequal 'foo
   Depends: bar
   Conflicts: <foobar>
-  Conflicts: <foobar:i386>
  |Recommends: <cool>
   Recommends: <cooler>' aptcache depends foo --implicit
 testsuccessequal 'foo
@@ -76,7 +75,6 @@ testsuccessequal 'foo
 testsuccessequal 'foo
   Depends: bar
   Conflicts: <foobar>
-  Conflicts: <foobar:i386>
   Recommends: <cool>' aptcache depends foo -o APT::Cache::ShowOnlyFirstOr=1 --implicit
 testsuccessequal 'foo
   Depends: bar
@@ -86,7 +84,6 @@ testsuccessequal 'foo
 testsuccessequal 'foo
   Depends: bar
   Conflicts: <foobar>
-  Conflicts: <foobar:i386>
  |Recommends: <cool> (>= 2)
   Recommends: <cooler> (<< 5)' aptcache depends foo -o APT::Cache::ShowVersion=1 --implicit
 testsuccessequal 'foo
@@ -94,15 +91,13 @@ testsuccessequal 'foo
   Conflicts: <foobar>' aptcache depends foo --no-recommends
 testsuccessequal 'foo
   Depends: bar
-  Conflicts: <foobar>
-  Conflicts: <foobar:i386>' aptcache depends foo --no-recommends --implicit
+  Conflicts: <foobar>' aptcache depends foo --no-recommends --implicit
 testsuccessequal 'foo
   Depends: bar' aptcache depends foo --important --implicit
 testsuccessequal 'foo
   Conflicts: <foobar>' aptcache depends foo --important --no-depends --conflicts
 testsuccessequal 'foo
-  Conflicts: <foobar>
-  Conflicts: <foobar:i386>' aptcache depends foo --important --no-depends --conflicts --implicit
+  Conflicts: <foobar>' aptcache depends foo --important --no-depends --conflicts --implicit
 testsuccessequal 'foo
   Depends: bar
   Conflicts: <foobar>
@@ -118,17 +113,15 @@ bar
 testsuccessequal 'foo
   Depends: bar
   Conflicts: <foobar>
-  Conflicts: <foobar:i386>
  |Recommends: <cool>
   Recommends: <cooler>
 bar
   Depends: bar
   Breaks: foo
-  Breaks: <foo:i386>
   Replaces: foo
+  Breaks: <foo:i386>
   Replaces: <foo:i386>
 <foobar>
-<foobar:i386>
 <cool>
 <cooler>
 <foo:i386>' aptcache depends foo --recurse --implicit
@@ -151,8 +144,8 @@ testsuccessequal 'bar
 testsuccessequal 'bar
   Depends: bar
   Breaks: foo
-  Breaks: <foo:i386>
   Replaces: foo
+  Breaks: <foo:i386>
   Replaces: <foo:i386>' aptcache depends bar --implicit
 testsuccessequal 'specific
   Depends: <bar:i386>

+ 1 - 1
test/integration/test-bug-590041-prefer-non-virtual-packages

@@ -45,7 +45,7 @@ EOF
 
 setupaptarchive
 
-testshowvirtual libc6:i386
+testnopackage libc6:i386
 testsuccessequal "$pkglibc6" aptcache show libc6:armel
 testsuccessequal "$pkglibc6" aptcache show libc6
 testsuccessequal "$pkglibdb1" aptcache show libdb1:i386

+ 3 - 4
test/integration/test-multiarch-allowed

@@ -138,10 +138,8 @@ solveableinsinglearch2() {
 The following packages have unmet dependencies:
  hatesfoo : Conflicts: foo but 1 is to be installed
 E: Unable to correct problems, you have held broken packages." aptget install foo hatesfoo -s
-	testfailureequal "$BADPREFIX
-The following packages have unmet dependencies:
- hatesfooany : Conflicts: foo:any
-E: Unable to correct problems, you have held broken packages." aptget install foo hatesfooany -s
+	# the message differs slightly between single and multiarch
+	testfailuremsg 'E: Unable to correct problems, you have held broken packages.' aptget install foo hatesfooany -s
 	testfailureequal "$BADPREFIX
 The following packages have unmet dependencies:
  hatesfoonative : Conflicts: foo but 1 is to be installed
@@ -155,6 +153,7 @@ E: Unable to correct problems, you have held broken packages." aptget install fo
 testfailureequal "$BADPREFIX
 The following packages have unmet dependencies:
  hatesfooany : Conflicts: foo:any
+               Conflicts: foo:any:i386
 E: Unable to correct problems, you have held broken packages." aptget install foo:i386 hatesfooany -s
 testsuccessequal 'Reading package lists...
 Building dependency tree...