Quellcode durchsuchen

just-in-time creation for (implicit) Provides

Expecting the worst is easy to code, but has its disadvantages e.g.
by creating package structures which otherwise would have never
existed. By creating the provides instead at the time a package
structure is added we are well prepared for the introduction of partial
architectures, massive amounts of M-A:foreign (and :allowed) and co as
far as provides are concerned at least. We have something relatively
similar for dependencies already.

Many tests are added for both M-A states and the code cleaned to
properly support implicit provides for foreign architectures and
architectures we 'just' happen to parse.

Git-Dch: Ignore
David Kalnischkies vor 11 Jahren
Ursprung
Commit
ecc138f858

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

@@ -861,7 +861,7 @@ bool debListParser::ParseProvides(pkgCache::VerIterator &Ver)
 	    if (NewProvides(Ver, Package, OtherArch, Version, pkgCache::Flag::ArchSpecific) == false)
 	    if (NewProvides(Ver, Package, OtherArch, Version, pkgCache::Flag::ArchSpecific) == false)
 	       return false;
 	       return false;
 	 } else if ((Ver->MultiArch & pkgCache::Version::Foreign) == pkgCache::Version::Foreign) {
 	 } else if ((Ver->MultiArch & pkgCache::Version::Foreign) == pkgCache::Version::Foreign) {
-	    if (NewProvidesAllArch(Ver, Package, Version) == false)
+	    if (NewProvidesAllArch(Ver, Package, Version, 0) == false)
 	       return false;
 	       return false;
 	 } else {
 	 } else {
 	    if (NewProvides(Ver, Package, Arch, Version, 0) == false)
 	    if (NewProvides(Ver, Package, Arch, Version, 0) == false)
@@ -876,26 +876,14 @@ bool debListParser::ParseProvides(pkgCache::VerIterator &Ver)
    if ((Ver->MultiArch & pkgCache::Version::Allowed) == pkgCache::Version::Allowed)
    if ((Ver->MultiArch & pkgCache::Version::Allowed) == pkgCache::Version::Allowed)
    {
    {
       string const Package = string(Ver.ParentPkg().Name()).append(":").append("any");
       string const Package = string(Ver.ParentPkg().Name()).append(":").append("any");
-      return NewProvidesAllArch(Ver, Package, Ver.VerStr());
+      return NewProvidesAllArch(Ver, Package, Ver.VerStr(), pkgCache::Flag::MultiArchImplicit);
    }
    }
    else if ((Ver->MultiArch & pkgCache::Version::Foreign) == pkgCache::Version::Foreign)
    else if ((Ver->MultiArch & pkgCache::Version::Foreign) == pkgCache::Version::Foreign)
-      return NewProvidesAllArch(Ver, Ver.ParentPkg().Name(), Ver.VerStr());
+      return NewProvidesAllArch(Ver, Ver.ParentPkg().Name(), Ver.VerStr(), pkgCache::Flag::MultiArchImplicit);
 
 
    return true;
    return true;
 }
 }
 									/*}}}*/
 									/*}}}*/
-// ListParser::NewProvides - add provides for all architectures		/*{{{*/
-bool debListParser::NewProvidesAllArch(pkgCache::VerIterator &Ver, string const &Package,
-				string const &Version) {
-   for (std::vector<string>::const_iterator a = Architectures.begin();
-	a != Architectures.end(); ++a)
-   {
-      if (NewProvides(Ver, Package, *a, Version, pkgCache::Flag::MultiArchImplicit) == false)
-	 return false;
-   }
-   return true;
-}
-									/*}}}*/
 // ListParser::GrabWord - Matches a word and returns			/*{{{*/
 // ListParser::GrabWord - Matches a word and returns			/*{{{*/
 // ---------------------------------------------------------------------
 // ---------------------------------------------------------------------
 /* Looks for a word in a list of words - for ParseStatus */
 /* Looks for a word in a list of words - for ParseStatus */
@@ -991,7 +979,7 @@ bool debDebFileParser::UsePackage(pkgCache::PkgIterator &Pkg,
    bool res = debListParser::UsePackage(Pkg, Ver);
    bool res = debListParser::UsePackage(Pkg, Ver);
    // we use the full file path as a provides so that the file is found
    // we use the full file path as a provides so that the file is found
    // by its name
    // by its name
-   if(NewProvidesAllArch(Ver, DebFile, Ver.VerStr()) == false)
+   if(NewProvidesAllArch(Ver, DebFile, Ver.VerStr(), 0) == false)
       return false;
       return false;
    return res;
    return res;
 }
 }

+ 0 - 1
apt-pkg/deb/deblistparser.h

@@ -53,7 +53,6 @@ class APT_HIDDEN debListParser : public pkgCacheGenerator::ListParser
    bool ParseDepends(pkgCache::VerIterator &Ver,const char *Tag,
    bool ParseDepends(pkgCache::VerIterator &Ver,const char *Tag,
 		     unsigned int Type);
 		     unsigned int Type);
    bool ParseProvides(pkgCache::VerIterator &Ver);
    bool ParseProvides(pkgCache::VerIterator &Ver);
-   bool NewProvidesAllArch(pkgCache::VerIterator &Ver, std::string const &Package, std::string const &Version);
    static bool GrabWord(std::string Word,WordList *List,unsigned char &Out);
    static bool GrabWord(std::string Word,WordList *List,unsigned char &Out);
    APT_HIDDEN unsigned char ParseMultiArch(bool const showErrors);
    APT_HIDDEN unsigned char ParseMultiArch(bool const showErrors);
 
 

+ 92 - 31
apt-pkg/pkgcachegen.cc

@@ -648,6 +648,16 @@ bool pkgCacheGenerator::NewPackage(pkgCache::PkgIterator &Pkg,const string &Name
       return false;
       return false;
    Pkg = pkgCache::PkgIterator(Cache,Cache.PkgP + Package);
    Pkg = pkgCache::PkgIterator(Cache,Cache.PkgP + Package);
 
 
+   // Set the name, arch and the ID
+   APT_IGNORE_DEPRECATED(Pkg->Name = Grp->Name;)
+   Pkg->Group = Grp.Index();
+   // all is mapped to the native architecture
+   map_stringitem_t const idxArch = (Arch == "all") ? Cache.HeaderP->Architecture : StoreString(MIXED, Arch);
+   if (unlikely(idxArch == 0))
+      return false;
+   Pkg->Arch = idxArch;
+   Pkg->ID = Cache.HeaderP->PackageCount++;
+
    // Insert the package into our package list
    // Insert the package into our package list
    if (Grp->FirstPackage == 0) // the group is new
    if (Grp->FirstPackage == 0) // the group is new
    {
    {
@@ -662,23 +672,36 @@ bool pkgCacheGenerator::NewPackage(pkgCache::PkgIterator &Pkg,const string &Name
    }
    }
    else // Group the Packages together
    else // Group the Packages together
    {
    {
+      // but first get implicit provides done
+      if (APT::Configuration::checkArchitecture(Pkg.Arch()) == true)
+      {
+	 pkgCache::PkgIterator const M = Grp.FindPreferredPkg(false); // native or any foreign pkg will do
+	 if (M.end() == false)
+	    for (pkgCache::PrvIterator Prv = M.ProvidesList(); Prv.end() == false; ++Prv)
+	    {
+	       if ((Prv->Flags & pkgCache::Flag::ArchSpecific) != 0)
+		  continue;
+	       pkgCache::VerIterator Ver = Prv.OwnerVer();
+	       if ((Ver->MultiArch & pkgCache::Version::Allowed) == pkgCache::Version::Allowed ||
+	           ((Ver->MultiArch & pkgCache::Version::Foreign) == pkgCache::Version::Foreign &&
+			(Prv->Flags & pkgCache::Flag::MultiArchImplicit) == 0))
+		  if (NewProvides(Ver, Pkg, Prv->ProvideVersion, Prv->Flags) == false)
+		     return false;
+	    }
+
+	 for (pkgCache::PkgIterator P = Grp.PackageList(); P.end() == false;  P = Grp.NextPkg(P))
+	    for (pkgCache::VerIterator Ver = P.VersionList(); Ver.end() == false; ++Ver)
+	       if ((Ver->MultiArch & pkgCache::Version::Foreign) == pkgCache::Version::Foreign)
+		  if (NewProvides(Ver, Pkg, Ver->VerStr, pkgCache::Flag::MultiArchImplicit) == false)
+		     return false;
+      }
+
       // this package is the new last package
       // this package is the new last package
       pkgCache::PkgIterator LastPkg(Cache, Cache.PkgP + Grp->LastPackage);
       pkgCache::PkgIterator LastPkg(Cache, Cache.PkgP + Grp->LastPackage);
       Pkg->NextPackage = LastPkg->NextPackage;
       Pkg->NextPackage = LastPkg->NextPackage;
       LastPkg->NextPackage = Package;
       LastPkg->NextPackage = Package;
    }
    }
    Grp->LastPackage = Package;
    Grp->LastPackage = Package;
-
-   // Set the name, arch and the ID
-   APT_IGNORE_DEPRECATED(Pkg->Name = Grp->Name;)
-   Pkg->Group = Grp.Index();
-   // all is mapped to the native architecture
-   map_stringitem_t const idxArch = (Arch == "all") ? Cache.HeaderP->Architecture : StoreString(MIXED, Arch);
-   if (unlikely(idxArch == 0))
-      return false;
-   Pkg->Arch = idxArch;
-   Pkg->ID = Cache.HeaderP->PackageCount++;
-
    return true;
    return true;
 }
 }
 									/*}}}*/
 									/*}}}*/
@@ -1079,44 +1102,82 @@ bool pkgCacheGenerator::ListParser::NewProvides(pkgCache::VerIterator &Ver,
 						const string &Version,
 						const string &Version,
 						uint8_t const Flags)
 						uint8_t const Flags)
 {
 {
-   pkgCache &Cache = Owner->Cache;
+   pkgCache const &Cache = Owner->Cache;
 
 
    // We do not add self referencing provides
    // We do not add self referencing provides
    if (Ver.ParentPkg().Name() == PkgName && (PkgArch == Ver.ParentPkg().Arch() ||
    if (Ver.ParentPkg().Name() == PkgName && (PkgArch == Ver.ParentPkg().Arch() ||
 	(PkgArch == "all" && strcmp((Cache.StrP + Cache.HeaderP->Architecture), Ver.ParentPkg().Arch()) == 0)))
 	(PkgArch == "all" && strcmp((Cache.StrP + Cache.HeaderP->Architecture), Ver.ParentPkg().Arch()) == 0)))
       return true;
       return true;
-   
+
+   // Locate the target package
+   pkgCache::PkgIterator Pkg;
+   Dynamic<pkgCache::PkgIterator> DynPkg(Pkg);
+   if (unlikely(Owner->NewPackage(Pkg,PkgName, PkgArch) == false))
+      return false;
+
+   map_stringitem_t idxProvideVersion = 0;
+   if (Version.empty() == false) {
+      idxProvideVersion = StoreString(VERSIONNUMBER, Version);
+      if (unlikely(idxProvideVersion == 0))
+	 return false;
+   }
+   return Owner->NewProvides(Ver, Pkg, idxProvideVersion, Flags);
+}
+bool pkgCacheGenerator::NewProvides(pkgCache::VerIterator &Ver,
+				    pkgCache::PkgIterator &Pkg,
+				    map_pointer_t const ProvideVersion,
+				    uint8_t const Flags)
+{
    // Get a structure
    // Get a structure
-   map_pointer_t const Provides = Owner->AllocateInMap(sizeof(pkgCache::Provides));
+   map_pointer_t const Provides = AllocateInMap(sizeof(pkgCache::Provides));
    if (unlikely(Provides == 0))
    if (unlikely(Provides == 0))
       return false;
       return false;
-   Cache.HeaderP->ProvidesCount++;
-   
+   ++Cache.HeaderP->ProvidesCount;
+
    // Fill it in
    // Fill it in
    pkgCache::PrvIterator Prv(Cache,Cache.ProvideP + Provides,Cache.PkgP);
    pkgCache::PrvIterator Prv(Cache,Cache.ProvideP + Provides,Cache.PkgP);
-   Dynamic<pkgCache::PrvIterator> DynPrv(Prv);
    Prv->Version = Ver.Index();
    Prv->Version = Ver.Index();
+   Prv->ProvideVersion = ProvideVersion;
    Prv->Flags = Flags;
    Prv->Flags = Flags;
    Prv->NextPkgProv = Ver->ProvidesList;
    Prv->NextPkgProv = Ver->ProvidesList;
    Ver->ProvidesList = Prv.Index();
    Ver->ProvidesList = Prv.Index();
-   if (Version.empty() == false) {
-      map_stringitem_t const idxProvideVersion = WriteString(Version);
-      Prv->ProvideVersion = idxProvideVersion;
-      if (unlikely(idxProvideVersion == 0))
-	 return false;
-   }
-   
-   // Locate the target package
-   pkgCache::PkgIterator Pkg;
-   Dynamic<pkgCache::PkgIterator> DynPkg(Pkg);
-   if (unlikely(Owner->NewPackage(Pkg,PkgName, PkgArch) == false))
-      return false;
-   
+
    // Link it to the package
    // Link it to the package
    Prv->ParentPkg = Pkg.Index();
    Prv->ParentPkg = Pkg.Index();
    Prv->NextProvides = Pkg->ProvidesList;
    Prv->NextProvides = Pkg->ProvidesList;
    Pkg->ProvidesList = Prv.Index();
    Pkg->ProvidesList = Prv.Index();
-   
+   return true;
+}
+									/*}}}*/
+// ListParser::NewProvidesAllArch - add provides for all architectures	/*{{{*/
+bool pkgCacheGenerator::ListParser::NewProvidesAllArch(pkgCache::VerIterator &Ver, string const &Package,
+				string const &Version, uint8_t const Flags) {
+   pkgCache &Cache = Owner->Cache;
+   pkgCache::GrpIterator const Grp = Cache.FindGrp(Package);
+   if (Grp.end() == true)
+      return NewProvides(Ver, Package, Cache.NativeArch(), Version, Flags);
+   else
+   {
+      map_stringitem_t idxProvideVersion = 0;
+      if (Version.empty() == false) {
+	 idxProvideVersion = StoreString(VERSIONNUMBER, Version);
+	 if (unlikely(idxProvideVersion == 0))
+	    return false;
+      }
+
+      bool const isImplicit = (Flags & pkgCache::Flag::MultiArchImplicit) == pkgCache::Flag::MultiArchImplicit;
+      bool const isArchSpecific = (Flags & pkgCache::Flag::ArchSpecific) == pkgCache::Flag::ArchSpecific;
+      pkgCache::PkgIterator const OwnerPkg = Ver.ParentPkg();
+      for (pkgCache::PkgIterator Pkg = Grp.PackageList(); Pkg.end() == false; Pkg = Grp.NextPkg(Pkg))
+      {
+	 if (isImplicit && OwnerPkg == Pkg)
+	    continue;
+	 if (isArchSpecific == false && APT::Configuration::checkArchitecture(OwnerPkg.Arch()) == false)
+	    continue;
+	 if (Owner->NewProvides(Ver, Pkg, idxProvideVersion, Flags) == false)
+	    return false;
+      }
+   }
    return true;
    return true;
 }
 }
 									/*}}}*/
 									/*}}}*/

+ 4 - 0
apt-pkg/pkgcachegen.h

@@ -93,6 +93,8 @@ class APT_HIDDEN pkgCacheGenerator					/*{{{*/
 			    map_pointer_t const ParentPkg, unsigned short const Hash,
 			    map_pointer_t const ParentPkg, unsigned short const Hash,
 			    map_pointer_t const Next);
 			    map_pointer_t const Next);
    map_pointer_t NewDescription(pkgCache::DescIterator &Desc,const std::string &Lang,const MD5SumValue &md5sum,map_stringitem_t const idxmd5str);
    map_pointer_t NewDescription(pkgCache::DescIterator &Desc,const std::string &Lang,const MD5SumValue &md5sum,map_stringitem_t const idxmd5str);
+   bool NewProvides(pkgCache::VerIterator &Ver, pkgCache::PkgIterator &Pkg,
+		    map_stringitem_t const ProvidesVersion, uint8_t const Flags);
 
 
    public:
    public:
 
 
@@ -167,6 +169,8 @@ class APT_HIDDEN pkgCacheGenerator::ListParser
    bool NewProvides(pkgCache::VerIterator &Ver,const std::string &PkgName,
    bool NewProvides(pkgCache::VerIterator &Ver,const std::string &PkgName,
 		    const std::string &PkgArch, const std::string &Version,
 		    const std::string &PkgArch, const std::string &Version,
 		    uint8_t const Flags);
 		    uint8_t const Flags);
+   bool NewProvidesAllArch(pkgCache::VerIterator &Ver, std::string const &Package,
+			   std::string const &Version, uint8_t const Flags);
    
    
    public:
    public:
    
    

+ 2 - 2
cmdline/apt-cache.cc

@@ -253,12 +253,12 @@ static bool DumpPackage(CommandLine &CmdL)
       {
       {
 	 cout << Cur.VerStr() << " - ";
 	 cout << Cur.VerStr() << " - ";
 	 for (pkgCache::PrvIterator Prv = Cur.ProvidesList(); Prv.end() != true; ++Prv)
 	 for (pkgCache::PrvIterator Prv = Cur.ProvidesList(); Prv.end() != true; ++Prv)
-	    cout << Prv.ParentPkg().FullName(true) << " ";
+	    cout << Prv.ParentPkg().FullName(true) << " (= " << (Prv->ProvideVersion == 0 ? "" : Prv.ProvideVersion()) << ") ";
 	 cout << endl;
 	 cout << endl;
       }
       }
       cout << "Reverse Provides: " << endl;
       cout << "Reverse Provides: " << endl;
       for (pkgCache::PrvIterator Prv = Pkg.ProvidesList(); Prv.end() != true; ++Prv)
       for (pkgCache::PrvIterator Prv = Pkg.ProvidesList(); Prv.end() != true; ++Prv)
-	 cout << Prv.OwnerPkg().FullName(true) << " " << Prv.OwnerVer().VerStr() << endl;
+	 cout << Prv.OwnerPkg().FullName(true) << " " << Prv.OwnerVer().VerStr()  << " (= " << (Prv->ProvideVersion == 0 ? "" : Prv.ProvideVersion()) << ")"<< endl;
    }
    }
 
 
    return true;
    return true;

+ 1 - 1
test/integration/test-bug-723586-any-stripped-in-single-arch

@@ -50,5 +50,5 @@ configarchitecture 'amd64' 'armhf'
 rm rootdir/var/cache/apt/*.bin
 rm rootdir/var/cache/apt/*.bin
 
 
 testsuccessequal "$INSTALLLOG" aptget install python3-gnupg -s
 testsuccessequal "$INSTALLLOG" aptget install python3-gnupg -s
-testsuccessequal "$(sed 's#3.3.2-16 - python3#3.3.2-16 - python3:any:armhf python3#' showpkg.log)" aptcache showpkg python3
+testsuccessequal  "$(cat showpkg.log)" aptcache showpkg python3
 testfailureequal "$FAILLOG" aptget install python-mips -s
 testfailureequal "$FAILLOG" aptget install python-mips -s

+ 84 - 0
test/integration/test-bug-758153-versioned-provides-support

@@ -30,6 +30,18 @@ insertpackage 'unstable' 'baz' 'i386,amd64' '1' 'Depends: bar'
 insertpackage 'experimental' 'baz' 'i386,amd64' '2' 'Depends: bar:i386'
 insertpackage 'experimental' 'baz' 'i386,amd64' '2' 'Depends: bar:i386'
 insertpackage 'experimental' 'baz-broken' 'i386' '2' 'Depends: bar:amd64'
 insertpackage 'experimental' 'baz-broken' 'i386' '2' 'Depends: bar:amd64'
 
 
+insertpackage 'unstable' 'next' 'amd64' '1' 'Multi-Arch: foreign
+Provides: next (= 2)'
+insertpackage 'unstable' 'needsrealnext' 'amd64,i386' '2' 'Depends: next (>= 2)'
+
+insertpackage 'unstable' 'virtualnext2' 'amd64' '1' 'Multi-Arch: foreign
+Provides: next2 (= 2)'
+insertpackage 'unstable' 'needsnext2' 'amd64,i386' '2' 'Depends: next2 (>= 2)'
+
+insertpackage 'unstable' 'virtualnext3' 'amd64' '1' 'Multi-Arch: no
+Provides: next3 (= 2)'
+insertpackage 'unstable' 'needsnext3' 'amd64,i386' '2' 'Depends: next3 (>= 2)'
+
 setupaptarchive
 setupaptarchive
 
 
 testsuccessequal 'Reading package lists...
 testsuccessequal 'Reading package lists...
@@ -204,3 +216,75 @@ The following information may help to resolve the situation:
 The following packages have unmet dependencies:
 The following packages have unmet dependencies:
  baz-broken:i386 : Depends: bar but it is not installable
  baz-broken:i386 : Depends: bar but it is not installable
 E: Unable to correct problems, you have held broken packages.' aptget install baz-broken -s
 E: Unable to correct problems, you have held broken packages.' aptget install baz-broken -s
+
+testsuccessequal 'Reading package lists...
+Building dependency tree...
+The following extra packages will be installed:
+  next
+The following NEW packages will be installed:
+  needsrealnext next
+0 upgraded, 2 newly installed, 0 to remove and 2 not upgraded.
+Inst next (1 unstable [amd64])
+Inst needsrealnext (2 unstable [amd64])
+Conf next (1 unstable [amd64])
+Conf needsrealnext (2 unstable [amd64])' aptget install needsrealnext -s
+
+testsuccessequal 'Reading package lists...
+Building dependency tree...
+The following extra packages will be installed:
+  next
+The following NEW packages will be installed:
+  needsrealnext:i386 next
+0 upgraded, 2 newly installed, 0 to remove and 2 not upgraded.
+Inst next (1 unstable [amd64])
+Inst needsrealnext:i386 (2 unstable [i386])
+Conf next (1 unstable [amd64])
+Conf needsrealnext:i386 (2 unstable [i386])' aptget install needsrealnext:i386 -s
+
+testsuccessequal 'Reading package lists...
+Building dependency tree...
+The following extra packages will be installed:
+  virtualnext2
+The following NEW packages will be installed:
+  needsnext2 virtualnext2
+0 upgraded, 2 newly installed, 0 to remove and 2 not upgraded.
+Inst virtualnext2 (1 unstable [amd64])
+Inst needsnext2 (2 unstable [amd64])
+Conf virtualnext2 (1 unstable [amd64])
+Conf needsnext2 (2 unstable [amd64])' aptget install needsnext2 -s
+
+testsuccessequal 'Reading package lists...
+Building dependency tree...
+The following extra packages will be installed:
+  virtualnext2
+The following NEW packages will be installed:
+  needsnext2:i386 virtualnext2
+0 upgraded, 2 newly installed, 0 to remove and 2 not upgraded.
+Inst virtualnext2 (1 unstable [amd64])
+Inst needsnext2:i386 (2 unstable [i386])
+Conf virtualnext2 (1 unstable [amd64])
+Conf needsnext2:i386 (2 unstable [i386])' aptget install needsnext2:i386 -s
+
+testsuccessequal 'Reading package lists...
+Building dependency tree...
+The following extra packages will be installed:
+  virtualnext3
+The following NEW packages will be installed:
+  needsnext3 virtualnext3
+0 upgraded, 2 newly installed, 0 to remove and 2 not upgraded.
+Inst virtualnext3 (1 unstable [amd64])
+Inst needsnext3 (2 unstable [amd64])
+Conf virtualnext3 (1 unstable [amd64])
+Conf needsnext3 (2 unstable [amd64])' aptget install needsnext3 -s
+
+testfailureequal 'Reading package lists...
+Building dependency tree...
+Some packages could not be installed. This may mean that you have
+requested an impossible situation or if you are using the unstable
+distribution that some required packages have not yet been created
+or been moved out of Incoming.
+The following information may help to resolve the situation:
+
+The following packages have unmet dependencies:
+ needsnext3:i386 : Depends: next3:i386 (>= 2) but it is not installable
+E: Unable to correct problems, you have held broken packages.' aptget install needsnext3:i386 -s

+ 246 - 0
test/integration/test-multiarch-allowed

@@ -0,0 +1,246 @@
+#!/bin/sh
+set -e
+
+TESTDIR=$(readlink -f $(dirname $0))
+. $TESTDIR/framework
+setupenvironment
+configarchitecture 'amd64' 'i386'
+
+insertpackage 'unstable' 'foo' 'amd64,i386' '1' 'Multi-Arch: allowed'
+insertpackage 'unstable' 'needsfoo' 'amd64,i386' '1' 'Depends: foo'
+insertpackage 'unstable' 'needsfooany' 'amd64,i386' '1' 'Depends: foo:any'
+insertpackage 'unstable' 'needsfoover1' 'amd64,i386' '1' 'Depends: foo:any (>= 1)'
+insertpackage 'unstable' 'needsfoover2' 'amd64,i386' '1' 'Depends: foo:any (>= 2)'
+insertpackage 'unstable' 'hatesfoo' 'amd64' '1' 'Conflicts: foo'
+insertpackage 'unstable' 'hatesfooany' 'amd64' '1' 'Conflicts: foo:any' # this makes no sense…
+insertpackage 'unstable' 'hatesfoonative' 'amd64' '1' 'Conflicts: foo:amd64'
+
+insertpackage 'unstable' 'coolfoo' 'amd64' '1' 'Multi-Arch:allowed
+Provides: coolbar'
+insertpackage 'unstable' 'coolfoover' 'amd64' '1' 'Multi-Arch:allowed
+Provides: coolbar (= 2)'
+insertpackage 'unstable' 'needscoolfoo' 'amd64' '1' 'Depends: coolfoo, coolbar'
+insertpackage 'unstable' 'needscoolfooany' 'amd64' '1' 'Depends: coolfoo:any, coolbar:any'
+insertpackage 'unstable' 'needscoolfoover0' 'amd64' '1' 'Depends: coolfoo:any (>= 1), coolbar'
+insertpackage 'unstable' 'needscoolfoover1' 'amd64' '1' 'Depends: coolfoo:any (>= 1), coolbar (>= 1)'
+insertpackage 'unstable' 'needscoolfoover2' 'amd64' '1' 'Depends: coolfoo:any (>= 2), coolbar (>= 1)'
+insertpackage 'unstable' 'needscoolfoover3' 'amd64' '1' 'Depends: coolfoo:any (>= 2), coolbar (>= 3)'
+
+setupaptarchive
+
+BADPREFIX='Reading package lists...
+Building dependency tree...
+Some packages could not be installed. This may mean that you have
+requested an impossible situation or if you are using the unstable
+distribution that some required packages have not yet been created
+or been moved out of Incoming.
+The following information may help to resolve the situation:
+'
+
+solveableinsinglearch0() {
+	testsuccessequal 'Reading package lists...
+Building dependency tree...
+The following extra packages will be installed:
+  foo
+The following NEW packages will be installed:
+  foo needsfoo
+0 upgraded, 2 newly installed, 0 to remove and 0 not upgraded.
+Inst foo (1 unstable [amd64])
+Inst needsfoo (1 unstable [amd64])
+Conf foo (1 unstable [amd64])
+Conf needsfoo (1 unstable [amd64])' aptget install needsfoo -s
+}
+solveableinsinglearch0
+testsuccessequal 'Reading package lists...
+Building dependency tree...
+The following extra packages will be installed:
+  foo:i386
+The following NEW packages will be installed:
+  foo:i386 needsfoo:i386
+0 upgraded, 2 newly installed, 0 to remove and 0 not upgraded.
+Inst foo:i386 (1 unstable [i386])
+Inst needsfoo:i386 (1 unstable [i386])
+Conf foo:i386 (1 unstable [i386])
+Conf needsfoo:i386 (1 unstable [i386])' aptget install needsfoo:i386 -s
+testfailureequal "$BADPREFIX
+The following packages have unmet dependencies:
+ needsfoo:i386 : Depends: foo:i386 but it is not going to be installed
+E: Unable to correct problems, you have held broken packages." aptget install needsfoo:i386 foo:amd64 -s
+testfailureequal "$BADPREFIX
+The following packages have unmet dependencies:
+ needsfoo : Depends: foo but it is not going to be installed
+E: Unable to correct problems, you have held broken packages." aptget install needsfoo foo:i386 -s
+
+solveableinsinglearch1() {
+	testsuccessequal "Reading package lists...
+Building dependency tree...
+The following extra packages will be installed:
+  foo
+The following NEW packages will be installed:
+  foo $1
+0 upgraded, 2 newly installed, 0 to remove and 0 not upgraded.
+Inst foo (1 unstable [amd64])
+Inst $1 (1 unstable [amd64])
+Conf foo (1 unstable [amd64])
+Conf $1 (1 unstable [amd64])" aptget install $1 -s
+}
+
+testneedsfooallgood() {
+	solveableinsinglearch1 $1
+	testsuccessequal "Reading package lists...
+Building dependency tree...
+The following extra packages will be installed:
+  foo
+The following NEW packages will be installed:
+  foo $1:i386
+0 upgraded, 2 newly installed, 0 to remove and 0 not upgraded.
+Inst foo (1 unstable [amd64])
+Inst $1:i386 (1 unstable [i386])
+Conf foo (1 unstable [amd64])
+Conf $1:i386 (1 unstable [i386])" aptget install $1:i386 -s
+	testsuccessequal "Reading package lists...
+Building dependency tree...
+The following NEW packages will be installed:
+  foo:i386 $1:i386
+0 upgraded, 2 newly installed, 0 to remove and 0 not upgraded.
+Inst foo:i386 (1 unstable [i386])
+Inst $1:i386 (1 unstable [i386])
+Conf foo:i386 (1 unstable [i386])
+Conf $1:i386 (1 unstable [i386])" aptget install $1:i386 foo:i386 -s
+	testsuccessequal "Reading package lists...
+Building dependency tree...
+The following NEW packages will be installed:
+  foo:i386 $1
+0 upgraded, 2 newly installed, 0 to remove and 0 not upgraded.
+Inst foo:i386 (1 unstable [i386])
+Inst $1 (1 unstable [amd64])
+Conf foo:i386 (1 unstable [i386])
+Conf $1 (1 unstable [amd64])" aptget install $1 foo:i386 -s
+}
+testneedsfooallgood 'needsfooany'
+testneedsfooallgood 'needsfoover1'
+
+NEEDSFOO2NATIVE="$BADPREFIX
+The following packages have unmet dependencies:
+ needsfoover2 : Depends: foo:any (>= 2)
+E: Unable to correct problems, you have held broken packages."
+NEEDSFOO2FOREIGN="$BADPREFIX
+The following packages have unmet dependencies:
+ needsfoover2:i386 : Depends: foo:any:i386 (>= 2)
+E: Unable to correct problems, you have held broken packages."
+testfailureequal "$NEEDSFOO2NATIVE" aptget install needsfoover2 -s
+testfailureequal "$NEEDSFOO2FOREIGN" aptget install needsfoover2:i386 -s
+testfailureequal "$NEEDSFOO2FOREIGN" aptget install needsfoover2:i386 foo:i386 -s
+testfailureequal "$NEEDSFOO2NATIVE" aptget install needsfoover2 foo:i386 -s
+
+solveableinsinglearch2() {
+	testfailureequal "$BADPREFIX
+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
+	testfailureequal "$BADPREFIX
+The following packages have unmet dependencies:
+ hatesfoonative : Conflicts: foo but 1 is to be installed
+E: Unable to correct problems, you have held broken packages." aptget install foo hatesfoonative -s
+}
+solveableinsinglearch2
+testfailureequal "$BADPREFIX
+The following packages have unmet dependencies:
+ hatesfoo : Conflicts: foo:i386 but 1 is to be installed
+E: Unable to correct problems, you have held broken packages." aptget install foo:i386 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:i386 hatesfooany -s
+testsuccessequal 'Reading package lists...
+Building dependency tree...
+The following NEW packages will be installed:
+  foo:i386 hatesfoonative
+0 upgraded, 2 newly installed, 0 to remove and 0 not upgraded.
+Inst foo:i386 (1 unstable [i386])
+Inst hatesfoonative (1 unstable [amd64])
+Conf foo:i386 (1 unstable [i386])
+Conf hatesfoonative (1 unstable [amd64])' aptget install foo:i386 hatesfoonative -s
+
+solveableinsinglearch3() {
+	testsuccessequal "Reading package lists...
+Building dependency tree...
+The following extra packages will be installed:
+  coolfoo
+The following NEW packages will be installed:
+  coolfoo needscoolfoo
+0 upgraded, 2 newly installed, 0 to remove and 0 not upgraded.
+Inst coolfoo (1 unstable [amd64])
+Inst needscoolfoo (1 unstable [amd64])
+Conf coolfoo (1 unstable [amd64])
+Conf needscoolfoo (1 unstable [amd64])" aptget install needscoolfoo -s
+	testsuccessequal "Reading package lists...
+Building dependency tree...
+The following extra packages will be installed:
+  coolfoo
+The following NEW packages will be installed:
+  coolfoo coolfoover needscoolfoo
+0 upgraded, 3 newly installed, 0 to remove and 0 not upgraded.
+Inst coolfoo (1 unstable [amd64])
+Inst coolfoover (1 unstable [amd64])
+Inst needscoolfoo (1 unstable [amd64])
+Conf coolfoo (1 unstable [amd64])
+Conf coolfoover (1 unstable [amd64])
+Conf needscoolfoo (1 unstable [amd64])" aptget install needscoolfoo coolfoover -s
+	testfailureequal "$BADPREFIX
+The following packages have unmet dependencies:
+ needscoolfooany : Depends: coolbar:any but it is not installable
+E: Unable to correct problems, you have held broken packages." aptget install needscoolfooany -s
+	testsuccessequal 'Reading package lists...
+Building dependency tree...
+The following extra packages will be installed:
+  coolfoo
+The following NEW packages will be installed:
+  coolfoo needscoolfoover0
+0 upgraded, 2 newly installed, 0 to remove and 0 not upgraded.
+Inst coolfoo (1 unstable [amd64])
+Inst needscoolfoover0 (1 unstable [amd64])
+Conf coolfoo (1 unstable [amd64])
+Conf needscoolfoover0 (1 unstable [amd64])' aptget install needscoolfoover0 -s
+	testsuccessequal 'Reading package lists...
+Building dependency tree...
+The following extra packages will be installed:
+  coolfoo coolfoover
+The following NEW packages will be installed:
+  coolfoo coolfoover needscoolfoover1
+0 upgraded, 3 newly installed, 0 to remove and 0 not upgraded.
+Inst coolfoo (1 unstable [amd64])
+Inst coolfoover (1 unstable [amd64])
+Inst needscoolfoover1 (1 unstable [amd64])
+Conf coolfoo (1 unstable [amd64])
+Conf coolfoover (1 unstable [amd64])
+Conf needscoolfoover1 (1 unstable [amd64])' aptget install needscoolfoover1 -s
+	testfailureequal "$BADPREFIX
+The following packages have unmet dependencies:
+ needscoolfoover2 : Depends: coolfoo:any (>= 2)
+E: Unable to correct problems, you have held broken packages." aptget install needscoolfoover2 -s
+	testfailureequal "$BADPREFIX
+The following packages have unmet dependencies:
+ needscoolfoover3 : Depends: coolfoo:any (>= 2)
+                    Depends: coolbar (>= 3)
+E: Unable to correct problems, you have held broken packages." aptget install needscoolfoover3 -s
+}
+solveableinsinglearch3
+
+msgmsg 'switch to single architecture'
+configarchitecture 'amd64'
+
+solveableinsinglearch0
+testfailureequal 'Reading package lists...
+Building dependency tree...
+E: Unable to locate package needsfoo' aptget install needsfoo:i386 -s
+
+solveableinsinglearch1 'needsfooany'
+solveableinsinglearch1 'needsfoover1'
+testfailureequal "$NEEDSFOO2NATIVE" aptget install needsfoover2 -s
+solveableinsinglearch2
+solveableinsinglearch3

+ 33 - 0
test/integration/test-multiarch-foreign

@@ -9,11 +9,17 @@ configarchitecture 'amd64' 'i386' 'armel'
 insertpackage 'unstable' 'cool-foo' 'amd64,i386' '1.0' 'Depends: foo'
 insertpackage 'unstable' 'cool-foo' 'amd64,i386' '1.0' 'Depends: foo'
 insertpackage 'unstable' 'cool-foo-x64' 'amd64' '1.0' 'Depends: foo:amd64'
 insertpackage 'unstable' 'cool-foo-x64' 'amd64' '1.0' 'Depends: foo:amd64'
 insertpackage 'unstable' 'cool-foo-x32' 'amd64' '1.0' 'Depends: foo:i386'
 insertpackage 'unstable' 'cool-foo-x32' 'amd64' '1.0' 'Depends: foo:i386'
+insertpackage 'unstable' 'hates-foo' 'amd64,i386' '1.0' 'Conflicts: foo'
+insertpackage 'unstable' 'hates-foo-x64' 'amd64' '1.0' 'Conflicts: foo:amd64'
+insertpackage 'unstable' 'hates-foo-x32' 'amd64' '1.0' 'Conflicts: foo:i386'
 insertpackage 'unstable' 'foo' 'amd64,i386,armel' '1.0' 'Multi-Arch: foreign'
 insertpackage 'unstable' 'foo' 'amd64,i386,armel' '1.0' 'Multi-Arch: foreign'
 
 
 insertpackage 'unstable' 'cool-bar' 'amd64,i386' '1.0' 'Depends: bar-provider'
 insertpackage 'unstable' 'cool-bar' 'amd64,i386' '1.0' 'Depends: bar-provider'
 insertpackage 'unstable' 'cool-bar-x64' 'amd64' '1.0' 'Depends: bar-provider:amd64'
 insertpackage 'unstable' 'cool-bar-x64' 'amd64' '1.0' 'Depends: bar-provider:amd64'
 insertpackage 'unstable' 'cool-bar-x32' 'amd64' '1.0' 'Depends: bar-provider:i386'
 insertpackage 'unstable' 'cool-bar-x32' 'amd64' '1.0' 'Depends: bar-provider:i386'
+insertpackage 'unstable' 'hates-bar' 'amd64,i386' '1.0' 'Conflicts: bar-provider'
+insertpackage 'unstable' 'hates-bar-x64' 'amd64' '1.0' 'Conflicts: bar-provider:amd64'
+insertpackage 'unstable' 'hates-bar-x32' 'amd64' '1.0' 'Conflicts: bar-provider:i386'
 insertpackage 'unstable' 'bar' 'amd64,i386,armel' '1.0' 'Provides: bar-provider
 insertpackage 'unstable' 'bar' 'amd64,i386,armel' '1.0' 'Provides: bar-provider
 Multi-Arch: foreign'
 Multi-Arch: foreign'
 
 
@@ -163,6 +169,33 @@ Conf foo (1.0 unstable [amd64])
 Conf cool-foo-x64 (1.0 unstable [amd64])' aptget install cool-foo-x64 -s
 Conf cool-foo-x64 (1.0 unstable [amd64])' aptget install cool-foo-x64 -s
 }
 }
 
 
+hatersgonnahate() {
+	BADPREFIX='Reading package lists...
+Building dependency tree...
+Some packages could not be installed. This may mean that you have
+requested an impossible situation or if you are using the unstable
+distribution that some required packages have not yet been created
+or been moved out of Incoming.
+The following information may help to resolve the situation:
+'
+	testfailureequal "$BADPREFIX
+The following packages have unmet dependencies:
+ hates-foo : Conflicts: foo
+             Conflicts: foo:i386
+             Conflicts: foo:armel
+E: Unable to correct problems, you have held broken packages." aptget install $1 hates-foo -s
+	testfailureequal "$BADPREFIX
+The following packages have unmet dependencies:
+ hates-foo-x64 : Conflicts: foo
+E: Unable to correct problems, you have held broken packages." aptget install $1 hates-foo-x64 -s
+	testfailureequal "$BADPREFIX
+The following packages have unmet dependencies:
+ hates-foo-x32 : Conflicts: foo:i386
+E: Unable to correct problems, you have held broken packages." aptget install $1 hates-foo-x32 -s
+}
+hatersgonnahate 'foo'
+hatersgonnahate 'foo:i386'
+
 #FIXME: do not work in single-arch as i386 isn't known at cache generation time
 #FIXME: do not work in single-arch as i386 isn't known at cache generation time
 	testsuccessequal 'Reading package lists...
 	testsuccessequal 'Reading package lists...
 Building dependency tree...
 Building dependency tree...