Quellcode durchsuchen

Merge remote-tracking branch 'upstream/debian/sid' into debian/experimental

Conflicts:
	test/integration/test-bug-747261-arch-specific-conflicts
Michael Vogt vor 12 Jahren
Ursprung
Commit
1f46d14620

+ 1 - 1
apt-pkg/deb/debindexfile.cc

@@ -526,7 +526,7 @@ bool debTranslationsIndex::Merge(pkgCacheGenerator &Gen,OpProgress *Prog) const
    if (FileExists(TranslationFile))
    {
      FileFd Trans(TranslationFile,FileFd::ReadOnly, FileFd::Extension);
-     debListParser TransParser(&Trans);
+     debTranslationsParser TransParser(&Trans);
      if (_error->PendingError() == true)
        return false;
      

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

@@ -115,4 +115,15 @@ class debDebFileParser : public debListParser
 			   pkgCache::VerIterator &Ver);
 };
 
+class debTranslationsParser : public debListParser
+{
+ public:
+   // a translation can never be a real package
+   virtual std::string Architecture() { return ""; }
+   virtual std::string Version() { return ""; }
+
+   debTranslationsParser(FileFd *File, std::string const &Arch = "")
+      : debListParser(File, Arch) {};
+};
+
 #endif

+ 166 - 188
apt-pkg/packagemanager.cc

@@ -262,7 +262,7 @@ bool pkgPackageManager::CheckRConflicts(PkgIterator Pkg,DepIterator D,
       if (Cache.VS().CheckDep(Ver,D->CompareOp,D.TargetVer()) == false)
 	 continue;
 
-      if (EarlyRemove(D.ParentPkg()) == false)
+      if (EarlyRemove(D.ParentPkg(), &D) == false)
 	 return _error->Error("Reverse conflicts early remove for package '%s' failed",
 			      Pkg.FullName().c_str());
    }
@@ -314,18 +314,41 @@ bool pkgPackageManager::ConfigureAll()
    return true;
 }
 									/*}}}*/
+// PM::NonLoopingSmart - helper to avoid loops while calling Smart methods /*{{{*/
+// -----------------------------------------------------------------------
+/* ensures that a loop of the form A depends B, B depends A (and similar)
+   is not leading us down into infinite recursion segfault land */
+bool pkgPackageManager::NonLoopingSmart(SmartAction const action, pkgCache::PkgIterator &Pkg,
+      pkgCache::PkgIterator DepPkg, int const Depth, bool const PkgLoop,
+      bool * const Bad, bool * const Changed)
+{
+   if (PkgLoop == false)
+      List->Flag(Pkg,pkgOrderList::Loop);
+   bool success = false;
+   switch(action)
+   {
+      case UNPACK_IMMEDIATE: success = SmartUnPack(DepPkg, true, Depth + 1); break;
+      case UNPACK: success = SmartUnPack(DepPkg, false, Depth + 1); break;
+      case CONFIGURE: success = SmartConfigure(DepPkg, Depth + 1); break;
+   }
+   if (PkgLoop == false)
+      List->RmFlag(Pkg,pkgOrderList::Loop);
+
+   if (success == false)
+      return false;
+
+   if (Bad != NULL)
+      *Bad = false;
+   if (Changed != NULL && List->IsFlag(DepPkg,pkgOrderList::Loop) == false)
+      *Changed = true;
+   return true;
+}
+									/*}}}*/
 // PM::SmartConfigure - Perform immediate configuration of the pkg	/*{{{*/
 // ---------------------------------------------------------------------
 /* This function tries to put the system in a state where Pkg can be configured.
-   This involves checking each of Pkg's dependanies and unpacking and 
-   configuring packages where needed. 
-   
-   Note on failure: This method can fail, without causing any problems. 
-   This can happen when using Immediate-Configure-All, SmartUnPack may call
-   SmartConfigure, it may fail because of a complex dependency situation, but
-   a error will only be reported if ConfigureAll fails. This is why some of the
-   messages this function reports on failure (return false;) as just warnings
-   only shown when debuging*/
+   This involves checking each of Pkg's dependencies and unpacking and
+   configuring packages where needed. */
 bool pkgPackageManager::SmartConfigure(PkgIterator Pkg, int const Depth)
 {
    // If this is true, only check and correct and dependencies without the Loop flag
@@ -340,9 +363,9 @@ bool pkgPackageManager::SmartConfigure(PkgIterator Pkg, int const Depth)
    }
 
    VerIterator const instVer = Cache[Pkg].InstVerIter(Cache);
-      
-   /* Because of the ordered list, most dependencies should be unpacked, 
-      however if there is a loop (A depends on B, B depends on A) this will not 
+
+   /* Because of the ordered list, most dependencies should be unpacked,
+      however if there is a loop (A depends on B, B depends on A) this will not
       be the case, so check for dependencies before configuring. */
    bool Bad = false, Changed = false;
    const unsigned int max_loops = _config->FindI("APT::pkgPackageManager::MaxLoopCount", 5000);
@@ -389,25 +412,15 @@ bool pkgPackageManager::SmartConfigure(PkgIterator Pkg, int const Depth)
 		  if (Debug)
 		     std::clog << OutputInDepth(Depth) << "Package " << Pkg << " loops in SmartConfigure" << std::endl;
 	          Bad = false;
-		  break;
 	       }
 	       else
 	       {
 		  if (Debug)
 		     clog << OutputInDepth(Depth) << "Unpacking " << DepPkg.FullName() << " to avoid loop " << Cur << endl;
-		  if (PkgLoop == false)
-		     List->Flag(Pkg,pkgOrderList::Loop);
-		  if (SmartUnPack(DepPkg, true, Depth + 1) == true)
-		  {
-		     Bad = false;
-		     if (List->IsFlag(DepPkg,pkgOrderList::Loop) == false)
-		        Changed = true;
-		  }
-		  if (PkgLoop == false)
-		     List->RmFlag(Pkg,pkgOrderList::Loop);
-		  if (Bad == false)
-		     break;
+		  if (NonLoopingSmart(UNPACK_IMMEDIATE, Pkg, DepPkg, Depth, PkgLoop, &Bad, &Changed) == false)
+		     return false;
 	       }
+	       break;
 	    }
 
 	    if (Cur == End || Bad == false)
@@ -462,25 +475,12 @@ bool pkgPackageManager::SmartConfigure(PkgIterator Pkg, int const Depth)
 		    Bad = false;
 		    break;
 		  }
-		  /* Check for a loop to prevent one forming
-		       If A depends on B and B depends on A, SmartConfigure will
-		       just hop between them if this is not checked. Dont remove the
-		       loop flag after finishing however as loop is already set.
-		       This means that there is another SmartConfigure call for this
-		       package and it will remove the loop flag */
-		  if (PkgLoop == false)
-		     List->Flag(Pkg,pkgOrderList::Loop);
-		  if (SmartConfigure(DepPkg, Depth + 1) == true)
-		  {
-		     Bad = false;
-		     if (List->IsFlag(DepPkg,pkgOrderList::Loop) == false)
-			Changed = true;
-		  }
-		  if (PkgLoop == false)
-		    List->RmFlag(Pkg,pkgOrderList::Loop);
-		  // If SmartConfigure was succesfull, Bad is false, so break
-		  if (Bad == false)
-		     break;
+		  if (Debug)
+		     std::clog << OutputInDepth(Depth) << "Configure already unpacked " << DepPkg << std::endl;
+		  if (NonLoopingSmart(CONFIGURE, Pkg, DepPkg, Depth, PkgLoop, &Bad, &Changed) == false)
+		     return false;
+		  break;
+
 	       }
 	       else if (List->IsFlag(DepPkg,pkgOrderList::Configured))
 	       {
@@ -499,19 +499,16 @@ bool pkgPackageManager::SmartConfigure(PkgIterator Pkg, int const Depth)
       if (i++ > max_loops)
          return _error->Error("Internal error: MaxLoopCount reached in SmartUnPack (2) for %s, aborting", Pkg.FullName().c_str());
    } while (Changed == true);
-   
-   if (Bad) {
-      if (Debug)
-         _error->Warning(_("Could not configure '%s'. "),Pkg.FullName().c_str());
-      return false;
-   }
-   
+
+   if (Bad == true)
+      return _error->Error(_("Could not configure '%s'. "),Pkg.FullName().c_str());
+
    if (PkgLoop) return true;
 
    static std::string const conf = _config->Find("PackageManager::Configure","all");
    static bool const ConfigurePkgs = (conf == "all" || conf == "smart");
 
-   if (List->IsFlag(Pkg,pkgOrderList::Configured)) 
+   if (List->IsFlag(Pkg,pkgOrderList::Configured))
       return _error->Error("Internal configure error on '%s'.", Pkg.FullName().c_str());
 
    if (ConfigurePkgs == true && Configure(Pkg) == false)
@@ -528,7 +525,8 @@ bool pkgPackageManager::SmartConfigure(PkgIterator Pkg, int const Depth)
 	     Cache[P].InstallVer == 0 || (P.CurrentVer() == Cache[P].InstallVer &&
 	      (Cache[Pkg].iFlags & pkgDepCache::ReInstall) != pkgDepCache::ReInstall))
 	    continue;
-	 SmartConfigure(P, (Depth +1));
+	 if (SmartConfigure(P, (Depth +1)) == false)
+	    return false;
       }
 
    // Sanity Check
@@ -542,29 +540,37 @@ bool pkgPackageManager::SmartConfigure(PkgIterator Pkg, int const Depth)
 // ---------------------------------------------------------------------
 /* This is called to deal with conflicts arising from unpacking */
 bool pkgPackageManager::EarlyRemove(PkgIterator Pkg)
+{
+   return EarlyRemove(Pkg, NULL);
+}
+bool pkgPackageManager::EarlyRemove(PkgIterator Pkg, DepIterator const * const Dep)
 {
    if (List->IsNow(Pkg) == false)
       return true;
-	 
+
    // Already removed it
    if (List->IsFlag(Pkg,pkgOrderList::Removed) == true)
       return true;
-   
+
    // Woops, it will not be re-installed!
    if (List->IsFlag(Pkg,pkgOrderList::InList) == false)
       return false;
 
+   // these breaks on M-A:same packages can be dealt with. They 'loop' by design
+   if (Dep != NULL && (*Dep)->Type == pkgCache::Dep::DpkgBreaks && Dep->IsMultiArchImplicit() == true)
+      return true;
+
    // Essential packages get special treatment
    bool IsEssential = false;
    if ((Pkg->Flags & pkgCache::Flag::Essential) != 0 ||
        (Pkg->Flags & pkgCache::Flag::Important) != 0)
       IsEssential = true;
 
-   /* Check for packages that are the dependents of essential packages and 
+   /* Check for packages that are the dependents of essential packages and
       promote them too */
    if (Pkg->CurrentVer != 0)
    {
-      for (DepIterator D = Pkg.RevDependsList(); D.end() == false &&
+      for (pkgCache::DepIterator D = Pkg.RevDependsList(); D.end() == false &&
 	   IsEssential == false; ++D)
 	 if (D->Type == pkgCache::Dep::Depends || D->Type == pkgCache::Dep::PreDepends)
 	    if ((D.ParentPkg()->Flags & pkgCache::Flag::Essential) != 0 ||
@@ -581,11 +587,14 @@ bool pkgPackageManager::EarlyRemove(PkgIterator Pkg)
 				"but if you really want to do it, activate the "
 				"APT::Force-LoopBreak option."),Pkg.FullName().c_str());
    }
-   
+   // dpkg will auto-deconfigure it, no need for the big remove hammer
+   else if (Dep != NULL && (*Dep)->Type == pkgCache::Dep::DpkgBreaks)
+      return true;
+
    bool Res = SmartRemove(Pkg);
    if (Cache[Pkg].Delete() == false)
       List->Flag(Pkg,pkgOrderList::Removed,pkgOrderList::States);
-   
+
    return Res;
 }
 									/*}}}*/
@@ -630,13 +639,14 @@ bool pkgPackageManager::SmartUnPack(PkgIterator Pkg, bool const Immediate, int c
 
    VerIterator const instVer = Cache[Pkg].InstVerIter(Cache);
 
-   /* PreUnpack Checks: This loop checks and attempts to rectify and problems that would prevent the package being unpacked.
+   /* PreUnpack Checks: This loop checks and attempts to rectify any problems that would prevent the package being unpacked.
       It addresses: PreDepends, Conflicts, Obsoletes and Breaks (DpkgBreaks). Any resolutions that do not require it should
       avoid configuration (calling SmartUnpack with Immediate=true), this is because when unpacking some packages with
-      complex dependency structures, trying to configure some packages while breaking the loops can complicate things .
+      complex dependency structures, trying to configure some packages while breaking the loops can complicate things.
       This will be either dealt with if the package is configured as a dependency of Pkg (if and when Pkg is configured),
       or by the ConfigureAll call at the end of the for loop in OrderInstall. */
-   bool Changed = false;
+   bool SomethingBad = false, Changed = false;
+   bool couldBeTemporaryRemoved = Depth != 0 && List->IsFlag(Pkg,pkgOrderList::Removed) == false;
    const unsigned int max_loops = _config->FindI("APT::pkgPackageManager::MaxLoopCount", 5000);
    unsigned int i = 0;
    do 
@@ -684,184 +694,142 @@ bool pkgPackageManager::SmartUnPack(PkgIterator Pkg, bool const Immediate, int c
 	       for (Version **I = VList; *I != 0; ++I)
 	       {
 		  VerIterator Ver(Cache,*I);
-		  PkgIterator Pkg = Ver.ParentPkg();
+		  PkgIterator DepPkg = Ver.ParentPkg();
 
 		  // Not the install version
-		  if (Cache[Pkg].InstallVer != *I ||
-		      (Cache[Pkg].Keep() == true && Pkg.State() == PkgIterator::NeedsNothing))
+		  if (Cache[DepPkg].InstallVer != *I ||
+		      (Cache[DepPkg].Keep() == true && DepPkg.State() == PkgIterator::NeedsNothing))
 		     continue;
 
-		  if (List->IsFlag(Pkg,pkgOrderList::Configured))
+		  if (List->IsFlag(DepPkg,pkgOrderList::Configured))
 		  {
 		     Bad = false;
 		     break;
 		  }
 
 		  // check if it needs unpack or if if configure is enough
-		  if (List->IsFlag(Pkg,pkgOrderList::UnPacked) == false)
+		  if (List->IsFlag(DepPkg,pkgOrderList::UnPacked) == false)
 		  {
 		     if (Debug)
-			clog << OutputInDepth(Depth) << "Trying to SmartUnpack " << Pkg.FullName() << endl;
-		     // SmartUnpack with the ImmediateFlag to ensure its really ready
-		     if (SmartUnPack(Pkg, true, Depth + 1) == true)
-		     {
-			Bad = false;
-			if (List->IsFlag(Pkg,pkgOrderList::Loop) == false)
-			   Changed = true;
-			break;
-		     }
+			clog << OutputInDepth(Depth) << "Trying to SmartUnpack " << DepPkg.FullName() << endl;
+		     if (NonLoopingSmart(UNPACK_IMMEDIATE, Pkg, DepPkg, Depth, PkgLoop, &Bad, &Changed) == false)
+			return false;
 		  }
 		  else
 		  {
 		     if (Debug)
-			clog << OutputInDepth(Depth) << "Trying to SmartConfigure " << Pkg.FullName() << endl;
-		     if (SmartConfigure(Pkg, Depth + 1) == true)
-		     {
-			Bad = false;
-			if (List->IsFlag(Pkg,pkgOrderList::Loop) == false)
-			   Changed = true;
-			break;
-		     }
+			clog << OutputInDepth(Depth) << "Trying to SmartConfigure " << DepPkg.FullName() << endl;
+		     if (NonLoopingSmart(CONFIGURE, Pkg, DepPkg, Depth, PkgLoop, &Bad, &Changed) == false)
+			return false;
 		  }
+		  break;
 	       }
 	    }
 
 	    if (Bad == true)
-	    {
-	       if (Start == End)
-		  return _error->Error("Couldn't configure pre-depend %s for %s, "
-					"probably a dependency cycle.",
-					End.TargetPkg().FullName().c_str(),Pkg.FullName().c_str());
-	    }
-	    else
-	       continue;
+	       SomethingBad = true;
 	 }
 	 else if (End->Type == pkgCache::Dep::Conflicts ||
-		  End->Type == pkgCache::Dep::Obsoletes)
+		  End->Type == pkgCache::Dep::Obsoletes ||
+		  End->Type == pkgCache::Dep::DpkgBreaks)
 	 {
-	    /* Look for conflicts. Two packages that are both in the install
-	       state cannot conflict so we don't check.. */
 	    SPtrArray<Version *> VList = End.AllTargets();
-	    for (Version **I = VList; *I != 0; I++)
+	    for (Version **I = VList; *I != 0; ++I)
 	    {
 	       VerIterator Ver(Cache,*I);
 	       PkgIterator ConflictPkg = Ver.ParentPkg();
-	       VerIterator InstallVer(Cache,Cache[ConflictPkg].InstallVer);
+	       if (ConflictPkg.CurrentVer() != Ver)
+	       {
+		  if (Debug)
+		     std::clog << OutputInDepth(Depth) << "Ignore not-installed version " << Ver.VerStr() << " of " << ConflictPkg.FullName() << " for " << End << std::endl;
+		  continue;
+	       }
 
-	       // See if the current version is conflicting
-	       if (ConflictPkg.CurrentVer() == Ver && List->IsNow(ConflictPkg))
+	       if (List->IsNow(ConflictPkg) == false)
 	       {
 		  if (Debug)
-		     clog << OutputInDepth(Depth) << Pkg.FullName() << " conflicts with " << ConflictPkg.FullName() << endl;
-		  /* If a loop is not present or has not yet been detected, attempt to unpack packages
-		     to resolve this conflict. If there is a loop present, remove packages to resolve this conflict */
-		  if (List->IsFlag(ConflictPkg,pkgOrderList::Loop) == false)
-		  {
-		     if (Cache[ConflictPkg].Keep() == 0 && Cache[ConflictPkg].InstallVer != 0)
-		     {
-			if (Debug)
-			   clog << OutputInDepth(Depth) << OutputInDepth(Depth) << "Unpacking " << ConflictPkg.FullName() << " to prevent conflict" << endl;
-			List->Flag(Pkg,pkgOrderList::Loop);
-			if (SmartUnPack(ConflictPkg,false, Depth + 1) == true)
-			   if (List->IsFlag(ConflictPkg,pkgOrderList::Loop) == false)
-			      Changed = true;
-			// Remove loop to allow it to be used later if needed
-			List->RmFlag(Pkg,pkgOrderList::Loop);
-		     }
-		     else if (EarlyRemove(ConflictPkg) == false)
-			return _error->Error("Internal Error, Could not early remove %s (1)",ConflictPkg.FullName().c_str());
-		  }
-		  else if (List->IsFlag(ConflictPkg,pkgOrderList::Removed) == false)
+		     std::clog << OutputInDepth(Depth) << "Ignore already dealt-with version " << Ver.VerStr() << " of " << ConflictPkg.FullName() << " for " << End << std::endl;
+		  continue;
+	       }
+
+	       if (List->IsFlag(ConflictPkg,pkgOrderList::Removed) == true)
+	       {
+		  if (Debug)
+		     clog << OutputInDepth(Depth) << "Ignoring " << End << " as " << ConflictPkg.FullName() << "was temporarily removed" << endl;
+		  continue;
+	       }
+
+	       if (List->IsFlag(ConflictPkg,pkgOrderList::Loop) && PkgLoop)
+	       {
+		  if (End->Type == pkgCache::Dep::DpkgBreaks && End.IsMultiArchImplicit() == true)
 		  {
 		     if (Debug)
-			clog << OutputInDepth(Depth) << "Because of conficts knot, removing " << ConflictPkg.FullName() << " to conflict violation" << endl;
-		     if (EarlyRemove(ConflictPkg) == false)
-			return _error->Error("Internal Error, Could not early remove %s (2)",ConflictPkg.FullName().c_str());
+			clog << OutputInDepth(Depth) << "Because dependency is MultiArchImplicit we ignored looping on: " << ConflictPkg << endl;
+		     continue;
 		  }
-	       }
-	    }
-	 }
-	 else if (End->Type == pkgCache::Dep::DpkgBreaks)
-	 {
-	    SPtrArray<Version *> VList = End.AllTargets();
-	    for (Version **I = VList; *I != 0; ++I)
-	    {
-	       VerIterator Ver(Cache,*I);
-	       PkgIterator BrokenPkg = Ver.ParentPkg();
-	       if (BrokenPkg.CurrentVer() != Ver)
-	       {
 		  if (Debug)
-		     std::clog << OutputInDepth(Depth) << "  Ignore not-installed version " << Ver.VerStr() << " of " << Pkg.FullName() << " for " << End << std::endl;
+		  {
+		     if (End->Type == pkgCache::Dep::DpkgBreaks)
+			clog << OutputInDepth(Depth) << "Because of breaks knot, deconfigure " << ConflictPkg.FullName() << " temporarily" << endl;
+		     else
+			clog << OutputInDepth(Depth) << "Because of conflict knot, removing " << ConflictPkg.FullName() << " temporarily" << endl;
+		  }
+		  if (EarlyRemove(ConflictPkg, &End) == false)
+		     return _error->Error("Internal Error, Could not early remove %s (2)",ConflictPkg.FullName().c_str());
+		  SomethingBad = true;
 		  continue;
 	       }
 
-	       // Check if it needs to be unpacked
-	       if (List->IsFlag(BrokenPkg,pkgOrderList::InList) && Cache[BrokenPkg].Delete() == false &&
-		   List->IsNow(BrokenPkg))
+	       if (Cache[ConflictPkg].Delete() == false)
 	       {
-		  if (List->IsFlag(BrokenPkg,pkgOrderList::Loop) && PkgLoop)
+		  if (Debug)
 		  {
-		     // This dependency has already been dealt with by another SmartUnPack on Pkg
-		     break;
+		     clog << OutputInDepth(Depth) << "Unpacking " << ConflictPkg.FullName() << " to avoid " << End;
+		     if (PkgLoop == true)
+			clog << " (Looping)";
+		     clog << std::endl;
 		  }
-		  else
+		  // we would like to avoid temporary removals and all that at best via a simple unpack
+		  _error->PushToStack();
+		  if (NonLoopingSmart(UNPACK, Pkg, ConflictPkg, Depth, PkgLoop, NULL, &Changed) == false)
 		  {
-		     // Found a break, so see if we can unpack the package to avoid it
-		     // but do not set loop if another SmartUnPack already deals with it
-		     // Also, avoid it if the package we would unpack pre-depends on this one
-		     VerIterator InstallVer(Cache,Cache[BrokenPkg].InstallVer);
-		     bool circle = false;
-		     for (pkgCache::DepIterator D = InstallVer.DependsList(); D.end() == false; ++D)
+		     // but if it fails ignore this failure and look for alternative ways of solving
+		     if (Debug)
+		     {
+			clog << OutputInDepth(Depth) << "Avoidance unpack of " << ConflictPkg.FullName() << " failed for " << End << std::endl;
+			_error->DumpErrors(std::clog);
+		     }
+		     _error->RevertToStack();
+		     // ignorance can only happen if a) one of the offenders is already gone
+		     if (List->IsFlag(ConflictPkg,pkgOrderList::Removed) == true)
 		     {
-			if (D->Type != pkgCache::Dep::PreDepends)
-			   continue;
-			SPtrArray<Version *> VL = D.AllTargets();
-			for (Version **I = VL; *I != 0; ++I)
-			{
-			   VerIterator V(Cache,*I);
-			   PkgIterator P = V.ParentPkg();
-			   // we are checking for installation as an easy 'protection' against or-groups and (unchosen) providers
-			   if (P != Pkg || (P.CurrentVer() != V && Cache[P].InstallVer != V))
-			      continue;
-			   circle = true;
-			   break;
-			}
-			if (circle == true)
-			   break;
+			if (Debug)
+			   clog << OutputInDepth(Depth) << "But " << ConflictPkg.FullName() << " was temporarily removed in the meantime to satisfy " << End << endl;
 		     }
-		     if (circle == true)
+		     else if (List->IsFlag(Pkg,pkgOrderList::Removed) == true)
 		     {
 			if (Debug)
-			   clog << OutputInDepth(Depth) << "  Avoiding " << End << " avoided as " << BrokenPkg.FullName() << " has a pre-depends on " << Pkg.FullName() << std::endl;
-			continue;
+			   clog << OutputInDepth(Depth) << "But " << Pkg.FullName() << " was temporarily removed in the meantime to satisfy " << End << endl;
 		     }
+		     // or b) we can make one go (removal or dpkg auto-deconfigure)
 		     else
 		     {
 			if (Debug)
-			{
-			   clog << OutputInDepth(Depth) << "  Unpacking " << BrokenPkg.FullName() << " to avoid " << End;
-			   if (PkgLoop == true)
-			      clog << " (Looping)";
-			   clog << std::endl;
-			}
-			if (PkgLoop == false)
-			   List->Flag(Pkg,pkgOrderList::Loop);
-			if (SmartUnPack(BrokenPkg, false, Depth + 1) == true)
-			{
-			   if (List->IsFlag(BrokenPkg,pkgOrderList::Loop) == false)
-			      Changed = true;
-			}
-			if (PkgLoop == false)
-			   List->RmFlag(Pkg,pkgOrderList::Loop);
+			   clog << OutputInDepth(Depth) << "So temprorary remove/deconfigure " << ConflictPkg.FullName() << " to satisfy " << End << endl;
+			if (EarlyRemove(ConflictPkg, &End) == false)
+			   return _error->Error("Internal Error, Could not early remove %s (2)",ConflictPkg.FullName().c_str());
 		     }
 		  }
+		  else
+		     _error->MergeWithStack();
 	       }
-	       // Check if a package needs to be removed
-	       else if (Cache[BrokenPkg].Delete() == true && List->IsFlag(BrokenPkg,pkgOrderList::Configured) == false)
+	       else
 	       {
 		  if (Debug)
-		     clog << OutputInDepth(Depth) << "  Removing " << BrokenPkg.FullName() << " to avoid " << End << endl;
-		  SmartRemove(BrokenPkg);
+		     clog << OutputInDepth(Depth) << "Removing " << ConflictPkg.FullName() << " now to avoid " << End << endl;
+		  // no earlyremove() here as user has already agreed to the permanent removal
+		  if (SmartRemove(Pkg) == false)
+		     return _error->Error("Internal Error, Could not early remove %s (1)",ConflictPkg.FullName().c_str());
 	       }
 	    }
 	 }
@@ -869,7 +837,17 @@ bool pkgPackageManager::SmartUnPack(PkgIterator Pkg, bool const Immediate, int c
       if (i++ > max_loops)
          return _error->Error("Internal error: APT::pkgPackageManager::MaxLoopCount reached in SmartConfigure for %s, aborting", Pkg.FullName().c_str());
    } while (Changed == true);
-   
+
+   if (SomethingBad == true)
+      return _error->Error("Couldn't configure %s, probably a dependency cycle.", Pkg.FullName().c_str());
+
+   if (couldBeTemporaryRemoved == true && List->IsFlag(Pkg,pkgOrderList::Removed) == true)
+   {
+      if (Debug)
+	 std::clog << OutputInDepth(Depth) << "Prevent unpack as " << Pkg << " is currently temporarily removed" << std::endl;
+      return true;
+   }
+
    // Check for reverse conflicts.
    if (CheckRConflicts(Pkg,Pkg.RevDependsList(),
 		   instVer.VerStr()) == false)
@@ -930,7 +908,7 @@ bool pkgPackageManager::SmartUnPack(PkgIterator Pkg, bool const Immediate, int c
    if (Immediate == true) {
       // Perform immedate configuration of the package. 
          if (SmartConfigure(Pkg, Depth + 1) == false)
-            _error->Warning(_("Could not perform immediate configuration on '%s'. "
+            _error->Error(_("Could not perform immediate configuration on '%s'. "
                "Please see man 5 apt.conf under APT::Immediate-Configure for details. (%d)"),Pkg.FullName().c_str(),2);
    }
    

+ 13 - 6
apt-pkg/packagemanager.h

@@ -84,13 +84,14 @@ class pkgPackageManager : protected pkgCache::Namespace
    
    // Install helpers
    bool ConfigureAll();
-   bool SmartConfigure(PkgIterator Pkg, int const Depth);
+   bool SmartConfigure(PkgIterator Pkg, int const Depth) APT_MUSTCHECK;
    //FIXME: merge on abi break
-   bool SmartUnPack(PkgIterator Pkg);
-   bool SmartUnPack(PkgIterator Pkg, bool const Immediate, int const Depth);
-   bool SmartRemove(PkgIterator Pkg);
-   bool EarlyRemove(PkgIterator Pkg);  
-   
+   bool SmartUnPack(PkgIterator Pkg) APT_MUSTCHECK;
+   bool SmartUnPack(PkgIterator Pkg, bool const Immediate, int const Depth) APT_MUSTCHECK;
+   bool SmartRemove(PkgIterator Pkg) APT_MUSTCHECK;
+   bool EarlyRemove(PkgIterator Pkg, DepIterator const * const Dep) APT_MUSTCHECK;
+   APT_DEPRECATED bool EarlyRemove(PkgIterator Pkg) APT_MUSTCHECK;
+
    // The Actual installation implementation
    virtual bool Install(PkgIterator /*Pkg*/,std::string /*File*/) {return false;};
    virtual bool Configure(PkgIterator /*Pkg*/) {return false;};
@@ -144,6 +145,12 @@ class pkgPackageManager : protected pkgCache::Namespace
 
    pkgPackageManager(pkgDepCache *Cache);
    virtual ~pkgPackageManager();
+
+   private:
+   enum APT_HIDDEN SmartAction { UNPACK_IMMEDIATE, UNPACK, CONFIGURE };
+   APT_HIDDEN bool NonLoopingSmart(SmartAction const action, pkgCache::PkgIterator &Pkg,
+      pkgCache::PkgIterator DepPkg, int const Depth, bool const PkgLoop,
+      bool * const Bad, bool * const Changed) APT_MUSTCHECK;
 };
 
 #endif

+ 1 - 0
apt-private/private-output.cc

@@ -23,6 +23,7 @@
 #include <langinfo.h>
 #include <unistd.h>
 #include <signal.h>
+#include <sys/ioctl.h>
 
 #include <apti18n.h>
 									/*}}}*/

+ 0 - 1
cmdline/apt-get.cc

@@ -76,7 +76,6 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
-#include <sys/ioctl.h>
 #include <sys/stat.h>
 #include <sys/statfs.h>
 #include <sys/statvfs.h>

Datei-Diff unterdrückt, da er zu groß ist
+ 1365 - 943
doc/Doxyfile.in


+ 41 - 0
test/integration/test-apt-translation-has-no-packages

@@ -0,0 +1,41 @@
+#!/bin/sh
+#
+# Due to corruption (local or network) a user might end up with a
+# Translation-$lang file on disk that is actually a Packages file. In this
+# case apt used to generate invalid package versions out of the
+# Translation-$lang file (i.e. apt-cache policy foo) would show a version
+# comming out of a Translation file. Downloading this versions fails as
+# there is no acquire method available for the package
+#
+set -e
+
+TESTDIR=$(readlink -f $(dirname $0))
+. $TESTDIR/framework
+
+setupenvironment
+configarchitecture "amd64"
+
+if [ ! -x ${BUILDDIRECTORY}/apt ]; then
+    msgmsg "No ${BUILDDIRECTORY}/apt"
+    msgskip 
+    exit 0
+fi
+
+buildsimplenativepackage 'foo' 'all' '1.0'
+setupaptarchive
+
+APTARCHIVE=$(readlink -f ./aptarchive)
+
+# corrupt the Translation-en file to look like a regular Packages file
+rm rootdir/var/cache/apt/*.bin
+cp $APTARCHIVE/dists/unstable/main/binary-amd64/Packages \
+   rootdir/var/lib/apt/lists/*Translation-en
+
+# ensure that there is no Version for the package foo generated out of
+# the corrupted Translation-en file
+testequal "foo:
+  Installed: (none)
+  Candidate: 1.0
+  Version table:
+     1.0 0
+        500 file:$APTARCHIVE/ unstable/main amd64 Packages" aptcache policy foo

+ 10 - 9
test/integration/test-bug-618288-multiarch-same-lockstep

@@ -16,22 +16,23 @@ buildsimplenativepackage 'apt' 'i386' '2' 'unstable' 'Depends: libsame (= 2)' ''
 buildsimplenativepackage 'apt2' 'amd64' '2' 'unstable' 'Depends: libsame (= 2)' '' 'required'
 
 setupaptarchive
-aptget dist-upgrade -s >output.apt 2>&1
+testsuccess aptget dist-upgrade -s -o Debug::pkgPackageManager=1
 
 # order in switch libsame:{amd64,i386} are unpacked is irrelevant, as both are installed - but we need to do it together
-LS_U_AMD="$(grep -o -n '^Inst libsame ' output.apt | cut -d: -f1)"
-LS_U_INT="$(grep -o -n '^Inst libsame:i386 ' output.apt | cut -d: -f1)"
-LS_C_AMD="$(grep -o -n '^Conf libsame ' output.apt | cut -d: -f1)"
-LS_C_INT="$(grep -o -n '^Conf libsame:i386 ' output.apt | cut -d: -f1)"
+OUTPUT=rootdir/tmp/testsuccess.output
+LS_U_AMD="$(grep -o -n '^Inst libsame ' $OUTPUT | cut -d: -f1)"
+LS_U_INT="$(grep -o -n '^Inst libsame:i386 ' $OUTPUT | cut -d: -f1)"
+LS_C_AMD="$(grep -o -n '^Conf libsame ' $OUTPUT | cut -d: -f1)"
+LS_C_INT="$(grep -o -n '^Conf libsame:i386 ' $OUTPUT | cut -d: -f1)"
 
-msgtest 'Test if libsame:amd64 unpack before configure'
+msgtest 'Test if' 'libsame:amd64 unpack before configure'
 test "$LS_U_AMD" -lt "$LS_C_AMD" && msgpass || msgfail
 
-msgtest 'Test if libsame:i386 unpack before configure'
+msgtest 'Test if' 'libsame:i386 unpack before configure'
 test "$LS_U_INT" -lt "$LS_C_INT" && msgpass || msgfail
 
-msgtest 'Test if libsame:amd64 unpack is before libsame:i386 configure'
+msgtest 'Test if' 'libsame:amd64 unpack is before libsame:i386 configure'
 test "$LS_U_AMD" -lt "$LS_C_INT" && msgpass || msgfail
 
-msgtest 'Test if libsame:i386 unpack is before libsame:amd64 configure'
+msgtest 'Test if' 'libsame:i386 unpack is before libsame:amd64 configure'
 test "$LS_U_INT" -lt "$LS_C_AMD" && msgpass || msgfail

+ 21 - 7
test/integration/test-bug-673536-pre-depends-breaks-loop

@@ -6,18 +6,32 @@ TESTDIR=$(readlink -f $(dirname $0))
 setupenvironment
 configarchitecture 'native'
 
-buildsimplenativepackage 'basic' 'native' '1' 'stable'
+buildsimplenativepackage 'advanced' 'native' '1' 'stable'
+buildsimplenativepackage 'advanced' 'native' '2' 'unstable' 'Pre-Depends: basic'
 buildsimplenativepackage 'basic' 'native' '2' 'unstable' 'Pre-Depends: common'
-buildsimplenativepackage 'common' 'native' '2' 'unstable' 'Breaks: basic (<= 1)'
+
+buildsimplenativepackage 'common' 'native' '2~conflict' 'unstable-conflict' 'Conflicts: advanced (<= 1)'
+buildsimplenativepackage 'common' 'native' '2~break' 'unstable-break' 'Conflicts: advanced (<= 1)'
 
 setupaptarchive
 
 # we check with 'real' packages here as the simulation reports a 'Conf broken'
 # which is technical correct for the simulation, but testing errormsg is ugly
 
-testsuccess aptget install basic=1 -y
-testdpkginstalled basic
-testdpkgnotinstalled common
+cp -a rootdir/var/lib/dpkg/status dpkg.status.backup
+
+testloopbreak() {
+	cp -a dpkg.status.backup rootdir/var/lib/dpkg/status
+	rm -f rootdir/var/lib/apt/extended_states
+
+
+	testsuccess aptget install advanced=1 -y -t "$1" -o Debug::pkgPackageManager=1
+	testdpkginstalled advanced
+	testdpkgnotinstalled basic common
+
+	testsuccess aptget dist-upgrade -y -t "$1" -o Debug::pkgPackageManager=1
+	testdpkginstalled advanced basic common
+}
 
-testsuccess aptget dist-upgrade -y
-testdpkginstalled basic common
+testloopbreak 'unstable-break'
+testloopbreak 'unstable-conflict'

+ 4 - 2
test/integration/test-conflicts-loop

@@ -20,11 +20,13 @@ Building dependency tree...
 The following packages will be upgraded:
   openjdk-6-jre openjdk-6-jre-headless openjdk-6-jre-lib
 3 upgraded, 0 newly installed, 0 to remove and 0 not upgraded.
-Remv openjdk-6-jre [6b16-1.8-0ubuntu1]
+Remv openjdk-6-jre-headless [6b16-1.8-0ubuntu1]
 Remv openjdk-6-jre-lib [6b16-1.8-0ubuntu1]
-Inst openjdk-6-jre-headless [6b16-1.8-0ubuntu1] (6b20-1.9.8-0ubuntu1~10.04.1 unstable [i386])
 Inst openjdk-6-jre [6b16-1.8-0ubuntu1] (6b20-1.9.8-0ubuntu1~10.04.1 unstable [i386])
 Inst openjdk-6-jre-lib [6b16-1.8-0ubuntu1] (6b20-1.9.8-0ubuntu1~10.04.1 unstable [i386])
 Conf openjdk-6-jre-lib (6b20-1.9.8-0ubuntu1~10.04.1 unstable [i386])
 Conf openjdk-6-jre (6b20-1.9.8-0ubuntu1~10.04.1 unstable [i386])
+Inst openjdk-6-jre-headless [6b16-1.8-0ubuntu1] (6b20-1.9.8-0ubuntu1~10.04.1 unstable [i386])
 Conf openjdk-6-jre-headless (6b20-1.9.8-0ubuntu1~10.04.1 unstable [i386])' aptget dist-upgrade -s -o APT::Immediate-Configure-All=true
+
+testsuccess aptget dist-upgrade -s -o Debug::pkgPackageManager=1

+ 51 - 0
test/integration/test-essential-force-loopbreak

@@ -0,0 +1,51 @@
+#!/bin/sh
+set -e
+
+TESTDIR=$(readlink -f $(dirname $0))
+. $TESTDIR/framework
+
+setupenvironment
+configarchitecture 'amd64'
+
+insertinstalledpackage 'sysvinit' 'amd64' '1' 'Essential: yes'
+
+buildsimplenativepackage 'sysvinit' 'amd64' '2' 'sid' 'Pre-Depends: sysvinit-core | systemd-sysv
+Essential: yes'
+buildsimplenativepackage 'sysvinit-core' 'amd64' '2' 'sid'
+
+buildsimplenativepackage 'systemd-sysv' 'amd64' '2~conflict' 'sid-conflict' 'Conflicts: sysvinit (<< 2)
+Breaks: sysvinit-core'
+
+buildsimplenativepackage 'systemd-sysv' 'amd64' '2~break' 'sid-break' 'Breaks: sysvinit (<< 2), sysvinit-core'
+
+setupaptarchive
+
+cp -a rootdir/var/lib/dpkg/status dpkg.status.backup
+
+testforcebreak() {
+	cp -a dpkg.status.backup rootdir/var/lib/dpkg/status
+	rm -f rootdir/var/lib/apt/extended_states
+	testequal 'Reading package lists...
+Building dependency tree...
+The following extra packages will be installed:
+  sysvinit
+The following NEW packages will be installed:
+  systemd-sysv
+The following packages will be upgraded:
+  sysvinit
+1 upgraded, 1 newly installed, 0 to remove and 0 not upgraded.
+E: This installation run will require temporarily removing the essential package sysvinit:amd64 due to a Conflicts/Pre-Depends loop. This is often bad, but if you really want to do it, activate the APT::Force-LoopBreak option.
+E: Internal Error, Could not early remove sysvinit:amd64 (2)' aptget install systemd-sysv -t "$1" -s
+	# ensure that really nothing happens
+	testfailure aptget install systemd-sysv -y -t "$1" -o Debug::pkgPackageManager=1
+	testdpkginstalled 'sysvinit'
+	testdpkgnotinstalled 'systemd-sysv'
+
+	# with enough force however …
+	cp -a dpkg.status.backup rootdir/var/lib/dpkg/status
+	testsuccess aptget install systemd-sysv -y -t "$1" -o Debug::pkgPackageManager=1 -o APT::Force-LoopBreak=1
+	testdpkginstalled 'sysvinit' 'systemd-sysv'
+}
+
+testforcebreak 'sid-conflict'
+testforcebreak 'sid-break'