]> git.saurik.com Git - apt.git/blobdiff - apt-pkg/algorithms.cc
* apt-pkg/init.cc:
[apt.git] / apt-pkg / algorithms.cc
index 62727a852fd01504e7cd27820913b153449f6231..6ac69032b88697046a131c862db0e1915afa874e 100644 (file)
@@ -19,7 +19,7 @@
 #include <apt-pkg/configuration.h>
 #include <apt-pkg/version.h>
 #include <apt-pkg/sptr.h>
-
+#include <apt-pkg/acquire-item.h>
     
 #include <apti18n.h>
 #include <sys/types.h>
@@ -37,7 +37,8 @@ pkgProblemResolver *pkgProblemResolver::This = 0;
    this is not necessary since the pkgCaches are fully shared now. */
 pkgSimulate::pkgSimulate(pkgDepCache *Cache) : pkgPackageManager(Cache),
                            iPolicy(Cache),
-                            Sim(&Cache->GetCache(),&iPolicy)
+                           Sim(&Cache->GetCache(),&iPolicy),
+                           group(Sim)
 {
    Sim.Init(0);
    Flags = new unsigned char[Cache->Head().PackageCount];
@@ -57,7 +58,7 @@ void pkgSimulate::Describe(PkgIterator Pkg,ostream &out,bool Current,bool Candid
 {
    VerIterator Ver(Sim);
  
-   out << Pkg.Name();
+   out << Pkg.FullName(true);
 
    if (Current == true)
    {
@@ -82,15 +83,15 @@ void pkgSimulate::Describe(PkgIterator Pkg,ostream &out,bool Current,bool Candid
 bool pkgSimulate::Install(PkgIterator iPkg,string /*File*/)
 {
    // Adapt the iterator
-   PkgIterator Pkg = Sim.FindPkg(iPkg.Name());
+   PkgIterator Pkg = Sim.FindPkg(iPkg.Name(), iPkg.Arch());
    Flags[Pkg->ID] = 1;
    
    cout << "Inst ";
    Describe(Pkg,cout,true,true);
    Sim.MarkInstall(Pkg,false);
-   
+
    // Look for broken conflicts+predepends.
-   for (PkgIterator I = Sim.PkgBegin(); I.end() == false; I++)
+   for (PkgIterator I = Sim.PkgBegin(); I.end() == false; ++I)
    {
       if (Sim[I].InstallVer == 0)
         continue;
@@ -100,16 +101,14 @@ bool pkgSimulate::Install(PkgIterator iPkg,string /*File*/)
         DepIterator Start;
         DepIterator End;
         D.GlobOr(Start,End);
-        if (Start->Type == pkgCache::Dep::Conflicts ||
-            Start->Type == pkgCache::Dep::DpkgBreaks ||
-            Start->Type == pkgCache::Dep::Obsoletes ||
+        if (Start.IsNegative() == true ||
             End->Type == pkgCache::Dep::PreDepends)
          {
            if ((Sim[End] & pkgDepCache::DepGInstall) == 0)
            {
-              cout << " [" << I.Name() << " on " << Start.TargetPkg().Name() << ']';
+              cout << " [" << I.FullName(false) << " on " << Start.TargetPkg().FullName(false) << ']';
               if (Start->Type == pkgCache::Dep::Conflicts)
-                 _error->Error("Fatal, conflicts violated %s",I.Name());
+                 _error->Error("Fatal, conflicts violated %s",I.FullName(false).c_str());
            }       
         }
       }      
@@ -130,35 +129,35 @@ bool pkgSimulate::Install(PkgIterator iPkg,string /*File*/)
 bool pkgSimulate::Configure(PkgIterator iPkg)
 {
    // Adapt the iterator
-   PkgIterator Pkg = Sim.FindPkg(iPkg.Name());
+   PkgIterator Pkg = Sim.FindPkg(iPkg.Name(), iPkg.Arch());
    
    Flags[Pkg->ID] = 2;
-//   Sim.MarkInstall(Pkg,false);
+
    if (Sim[Pkg].InstBroken() == true)
    {
-      cout << "Conf " << Pkg.Name() << " broken" << endl;
+      cout << "Conf " << Pkg.FullName(false) << " broken" << endl;
 
       Sim.Update();
       
       // Print out each package and the failed dependencies
-      for (pkgCache::DepIterator D = Sim[Pkg].InstVerIter(Sim).DependsList(); D.end() == false; D++)
+      for (pkgCache::DepIterator D = Sim[Pkg].InstVerIter(Sim).DependsList(); D.end() == false; ++D)
       {
         if (Sim.IsImportantDep(D) == false || 
             (Sim[D] & pkgDepCache::DepInstall) != 0)
            continue;
         
         if (D->Type == pkgCache::Dep::Obsoletes)
-           cout << " Obsoletes:" << D.TargetPkg().Name();
+           cout << " Obsoletes:" << D.TargetPkg().FullName(false);
         else if (D->Type == pkgCache::Dep::Conflicts)
-           cout << " Conflicts:" << D.TargetPkg().Name();
+           cout << " Conflicts:" << D.TargetPkg().FullName(false);
         else if (D->Type == pkgCache::Dep::DpkgBreaks)
-           cout << " Breaks:" << D.TargetPkg().Name();
+           cout << " Breaks:" << D.TargetPkg().FullName(false);
         else
-           cout << " Depends:" << D.TargetPkg().Name();
+           cout << " Depends:" << D.TargetPkg().FullName(false);
       }            
       cout << endl;
 
-      _error->Error("Conf Broken %s",Pkg.Name());
+      _error->Error("Conf Broken %s",Pkg.FullName(false).c_str());
    }   
    else
    {
@@ -180,10 +179,11 @@ bool pkgSimulate::Configure(PkgIterator iPkg)
 bool pkgSimulate::Remove(PkgIterator iPkg,bool Purge)
 {
    // Adapt the iterator
-   PkgIterator Pkg = Sim.FindPkg(iPkg.Name());
+   PkgIterator Pkg = Sim.FindPkg(iPkg.Name(), iPkg.Arch());
 
    Flags[Pkg->ID] = 3;
    Sim.MarkDelete(Pkg);
+
    if (Purge == true)
       cout << "Purg ";
    else
@@ -204,12 +204,12 @@ bool pkgSimulate::Remove(PkgIterator iPkg,bool Purge)
 void pkgSimulate::ShortBreaks()
 {
    cout << " [";
-   for (PkgIterator I = Sim.PkgBegin(); I.end() == false; I++)
+   for (PkgIterator I = Sim.PkgBegin(); I.end() == false; ++I)
    {
       if (Sim[I].InstBroken() == true)
       {
         if (Flags[I->ID] == 0)
-           cout << I.Name() << ' ';
+           cout << I.FullName(false) << ' ';
 /*      else
            cout << I.Name() << "! ";*/
       }      
@@ -226,7 +226,7 @@ bool pkgApplyStatus(pkgDepCache &Cache)
 {
    pkgDepCache::ActionGroup group(Cache);
 
-   for (pkgCache::PkgIterator I = Cache.PkgBegin(); I.end() == false; I++)
+   for (pkgCache::PkgIterator I = Cache.PkgBegin(); I.end() == false; ++I)
    {
       if (I->VersionList == 0)
         continue;
@@ -245,7 +245,7 @@ bool pkgApplyStatus(pkgDepCache &Cache)
               Cache.MarkInstall(I, false, 0, false);
            else
               return _error->Error(_("The package %s needs to be reinstalled, "
-                                   "but I can't find an archive for it."),I.Name());
+                                   "but I can't find an archive for it."),I.FullName(true).c_str());
         }
         
         continue;
@@ -280,7 +280,7 @@ bool pkgApplyStatus(pkgDepCache &Cache)
         default:
         if (I->InstState != pkgCache::State::Ok)
            return _error->Error("The package %s is not ok and I "
-                                "don't know how to fix it!",I.Name());
+                                "don't know how to fix it!",I.FullName(false).c_str());
       }
    }
    return true;
@@ -295,13 +295,13 @@ bool pkgFixBroken(pkgDepCache &Cache)
    pkgDepCache::ActionGroup group(Cache);
 
    // Auto upgrade all broken packages
-   for (pkgCache::PkgIterator I = Cache.PkgBegin(); I.end() == false; I++)
+   for (pkgCache::PkgIterator I = Cache.PkgBegin(); I.end() == false; ++I)
       if (Cache[I].NowBroken() == true)
         Cache.MarkInstall(I, true, 0, false);
    
    /* Fix packages that are in a NeedArchive state but don't have a
       downloadable install version */
-   for (pkgCache::PkgIterator I = Cache.PkgBegin(); I.end() == false; I++)
+   for (pkgCache::PkgIterator I = Cache.PkgBegin(); I.end() == false; ++I)
    {
       if (I.State() != pkgCache::PkgIterator::NeedsUnpack ||
          Cache[I].Delete() == true)
@@ -329,21 +329,28 @@ bool pkgDistUpgrade(pkgDepCache &Cache)
 {
    pkgDepCache::ActionGroup group(Cache);
 
+   /* Upgrade all installed packages first without autoinst to help the resolver
+      in versioned or-groups to upgrade the old solver instead of installing
+      a new one (if the old solver is not the first one [anymore]) */
+   for (pkgCache::PkgIterator I = Cache.PkgBegin(); I.end() == false; ++I)
+      if (I->CurrentVer != 0)
+        Cache.MarkInstall(I, false, 0, false);
+
    /* Auto upgrade all installed packages, this provides the basis 
       for the installation */
-   for (pkgCache::PkgIterator I = Cache.PkgBegin(); I.end() == false; I++)
+   for (pkgCache::PkgIterator I = Cache.PkgBegin(); I.end() == false; ++I)
       if (I->CurrentVer != 0)
         Cache.MarkInstall(I, true, 0, false);
 
    /* Now, auto upgrade all essential packages - this ensures that
       the essential packages are present and working */
-   for (pkgCache::PkgIterator I = Cache.PkgBegin(); I.end() == false; I++)
+   for (pkgCache::PkgIterator I = Cache.PkgBegin(); I.end() == false; ++I)
       if ((I->Flags & pkgCache::Flag::Essential) == pkgCache::Flag::Essential)
         Cache.MarkInstall(I, true, 0, false);
    
    /* We do it again over all previously installed packages to force 
       conflict resolution on them all. */
-   for (pkgCache::PkgIterator I = Cache.PkgBegin(); I.end() == false; I++)
+   for (pkgCache::PkgIterator I = Cache.PkgBegin(); I.end() == false; ++I)
       if (I->CurrentVer != 0)
         Cache.MarkInstall(I, false, 0, false);
 
@@ -352,7 +359,7 @@ bool pkgDistUpgrade(pkgDepCache &Cache)
    // Hold back held packages.
    if (_config->FindB("APT::Ignore-Hold",false) == false)
    {
-      for (pkgCache::PkgIterator I = Cache.PkgBegin(); I.end() == false; I++)
+      for (pkgCache::PkgIterator I = Cache.PkgBegin(); I.end() == false; ++I)
       {
         if (I->SelectedState == pkgCache::State::Hold)
         {
@@ -380,7 +387,7 @@ bool pkgAllUpgrade(pkgDepCache &Cache)
       return false;
    
    // Upgrade all installed packages
-   for (pkgCache::PkgIterator I = Cache.PkgBegin(); I.end() == false; I++)
+   for (pkgCache::PkgIterator I = Cache.PkgBegin(); I.end() == false; ++I)
    {
       if (Cache[I].Install() == true)
         Fix.Protect(I);
@@ -414,7 +421,7 @@ bool pkgMinimizeUpgrade(pkgDepCache &Cache)
    do
    {
       Change = false;
-      for (pkgCache::PkgIterator I = Cache.PkgBegin(); I.end() == false; I++)
+      for (pkgCache::PkgIterator I = Cache.PkgBegin(); I.end() == false; ++I)
       {
         // Not interesting
         if (Cache[I].Upgrade() == false || Cache[I].NewInstall() == true)
@@ -431,7 +438,7 @@ bool pkgMinimizeUpgrade(pkgDepCache &Cache)
               Change = true;
         }       
       }      
-      Count++;
+      ++Count;
    }
    while (Change == true && Count < 10);
 
@@ -441,7 +448,6 @@ bool pkgMinimizeUpgrade(pkgDepCache &Cache)
    return true;
 }
                                                                        /*}}}*/
-
 // ProblemResolver::pkgProblemResolver - Constructor                   /*{{{*/
 // ---------------------------------------------------------------------
 /* */
@@ -488,24 +494,52 @@ void pkgProblemResolver::MakeScores()
    unsigned long Size = Cache.Head().PackageCount;
    memset(Scores,0,sizeof(*Scores)*Size);
 
+   // Important Required Standard Optional Extra
+   signed short PrioMap[] = {
+      0,
+      (signed short) _config->FindI("pkgProblemResolver::Scores::Important",3),
+      (signed short) _config->FindI("pkgProblemResolver::Scores::Required",2),
+      (signed short) _config->FindI("pkgProblemResolver::Scores::Standard",1),
+      (signed short) _config->FindI("pkgProblemResolver::Scores::Optional",-1),
+      (signed short) _config->FindI("pkgProblemResolver::Scores::Extra",-2)
+   };
+   signed short PrioEssentials = _config->FindI("pkgProblemResolver::Scores::Essentials",100);
+   signed short PrioInstalledAndNotObsolete = _config->FindI("pkgProblemResolver::Scores::NotObsolete",1);
+   signed short PrioDepends = _config->FindI("pkgProblemResolver::Scores::Depends",1);
+   signed short PrioRecommends = _config->FindI("pkgProblemResolver::Scores::Recommends",1);
+   signed short AddProtected = _config->FindI("pkgProblemResolver::Scores::AddProtected",10000);
+   signed short AddEssential = _config->FindI("pkgProblemResolver::Scores::AddEssential",5000);
+
+   if (_config->FindB("Debug::pkgProblemResolver::ShowScores",false) == true)
+      clog << "Settings used to calculate pkgProblemResolver::Scores::" << endl
+         << "  Important => " << PrioMap[1] << endl
+         << "  Required => " << PrioMap[2] << endl
+         << "  Standard => " << PrioMap[3] << endl
+         << "  Optional => " << PrioMap[4] << endl
+         << "  Extra => " << PrioMap[5] << endl
+         << "  Essentials => " << PrioEssentials << endl
+         << "  InstalledAndNotObsolete => " << PrioInstalledAndNotObsolete << endl
+         << "  Depends => " << PrioDepends << endl
+         << "  Recommends => " << PrioRecommends << endl
+         << "  AddProtected => " << AddProtected << endl
+         << "  AddEssential => " << AddEssential << endl;
+
    // Generate the base scores for a package based on its properties
-   for (pkgCache::PkgIterator I = Cache.PkgBegin(); I.end() == false; I++)
+   for (pkgCache::PkgIterator I = Cache.PkgBegin(); I.end() == false; ++I)
    {
       if (Cache[I].InstallVer == 0)
         continue;
       
       signed short &Score = Scores[I->ID];
       
-      /* This is arbitary, it should be high enough to elevate an
+      /* This is arbitrary, it should be high enough to elevate an
          essantial package above most other packages but low enough
         to allow an obsolete essential packages to be removed by
         a conflicts on a powerfull normal package (ie libc6) */
       if ((I->Flags & pkgCache::Flag::Essential) == pkgCache::Flag::Essential)
-        Score += 100;
+        Score += PrioEssentials;
 
       // We transform the priority
-      // Important Required Standard Optional Extra
-      signed short PrioMap[] = {0,3,2,1,-1,-2};
       if (Cache[I].InstVerIter(Cache)->Priority <= 5)
         Score += PrioMap[Cache[I].InstVerIter(Cache)->Priority];
       
@@ -514,19 +548,22 @@ void pkgProblemResolver::MakeScores()
         if those are not obsolete
       */
       if (I->CurrentVer != 0 && Cache[I].CandidateVer != 0 && Cache[I].CandidateVerIter(Cache).Downloadable())
-        Score += 1;
+        Score += PrioInstalledAndNotObsolete;
    }
 
    // Now that we have the base scores we go and propogate dependencies
-   for (pkgCache::PkgIterator I = Cache.PkgBegin(); I.end() == false; I++)
+   for (pkgCache::PkgIterator I = Cache.PkgBegin(); I.end() == false; ++I)
    {
       if (Cache[I].InstallVer == 0)
         continue;
       
-      for (pkgCache::DepIterator D = Cache[I].InstVerIter(Cache).DependsList(); D.end() == false; D++)
+      for (pkgCache::DepIterator D = Cache[I].InstVerIter(Cache).DependsList(); D.end() == false; ++D)
       {
-        if (D->Type == pkgCache::Dep::Depends || D->Type == pkgCache::Dep::PreDepends)
-           Scores[D.TargetPkg()->ID]++;
+        if (D->Type == pkgCache::Dep::Depends || 
+            D->Type == pkgCache::Dep::PreDepends)
+           Scores[D.TargetPkg()->ID] += PrioDepends;
+        else if (D->Type == pkgCache::Dep::Recommends)
+           Scores[D.TargetPkg()->ID] += PrioRecommends;
       }
    }   
    
@@ -537,16 +574,18 @@ void pkgProblemResolver::MakeScores()
    /* Now we cause 1 level of dependency inheritance, that is we add the 
       score of the packages that depend on the target Package. This 
       fortifies high scoring packages */
-   for (pkgCache::PkgIterator I = Cache.PkgBegin(); I.end() == false; I++)
+   for (pkgCache::PkgIterator I = Cache.PkgBegin(); I.end() == false; ++I)
    {
       if (Cache[I].InstallVer == 0)
         continue;
       
-      for (pkgCache::DepIterator D = I.RevDependsList(); D.end() == false; D++)
+      for (pkgCache::DepIterator D = I.RevDependsList(); D.end() == false; ++D)
       {
         // Only do it for the install version
         if ((pkgCache::Version *)D.ParentVer() != Cache[D.ParentPkg()].InstallVer ||
-            (D->Type != pkgCache::Dep::Depends && D->Type != pkgCache::Dep::PreDepends))
+            (D->Type != pkgCache::Dep::Depends && 
+             D->Type != pkgCache::Dep::PreDepends &&
+             D->Type != pkgCache::Dep::Recommends))
            continue;    
         
         Scores[I->ID] += abs(OldScores[D.ParentPkg()->ID]);
@@ -555,9 +594,9 @@ void pkgProblemResolver::MakeScores()
 
    /* Now we propogate along provides. This makes the packages that 
       provide important packages extremely important */
-   for (pkgCache::PkgIterator I = Cache.PkgBegin(); I.end() == false; I++)
+   for (pkgCache::PkgIterator I = Cache.PkgBegin(); I.end() == false; ++I)
    {
-      for (pkgCache::PrvIterator P = I.ProvidesList(); P.end() == false; P++)
+      for (pkgCache::PrvIterator P = I.ProvidesList(); P.end() == false; ++P)
       {
         // Only do it once per package
         if ((pkgCache::Version *)P.OwnerVer() != Cache[P.OwnerPkg()].InstallVer)
@@ -568,13 +607,13 @@ void pkgProblemResolver::MakeScores()
 
    /* Protected things are pushed really high up. This number should put them
       ahead of everything */
-   for (pkgCache::PkgIterator I = Cache.PkgBegin(); I.end() == false; I++)
+   for (pkgCache::PkgIterator I = Cache.PkgBegin(); I.end() == false; ++I)
    {
       if ((Flags[I->ID] & Protected) != 0)
-        Scores[I->ID] += 10000;
+        Scores[I->ID] += AddProtected;
       if ((I->Flags & pkgCache::Flag::Essential) == pkgCache::Flag::Essential)
-        Scores[I->ID] += 5000;
-   }   
+        Scores[I->ID] += AddEssential;
+   }
 }
                                                                        /*}}}*/
 // ProblemResolver::DoUpgrade - Attempt to upgrade this package                /*{{{*/
@@ -606,12 +645,10 @@ bool pkgProblemResolver::DoUpgrade(pkgCache::PkgIterator Pkg)
       // Compute a single dependency element (glob or)
       pkgCache::DepIterator Start = D;
       pkgCache::DepIterator End = D;
-      unsigned char State = 0;
       for (bool LastOR = true; D.end() == false && LastOR == true;)
       {
-        State |= Cache[D];
         LastOR = (D->CompareOp & pkgCache::Dep::Or) == pkgCache::Dep::Or;
-        D++;
+        ++D;
         if (LastOR == true)
            End = D;
       }
@@ -632,7 +669,7 @@ bool pkgProblemResolver::DoUpgrade(pkgCache::PkgIterator Pkg)
         if ((Flags[P->ID] & Protected) == Protected)
         {
            if (Debug == true)
-              clog << "    Reinst Failed because of protected " << P.Name() << endl;
+              clog << "    Reinst Failed because of protected " << P.FullName(false) << endl;
            Fail = true;
         }      
         else
@@ -643,7 +680,7 @@ bool pkgProblemResolver::DoUpgrade(pkgCache::PkgIterator Pkg)
               if (DoUpgrade(P) == false)
               {
                  if (Debug == true)
-                    clog << "    Reinst Failed because of " << P.Name() << endl;
+                    clog << "    Reinst Failed because of " << P.FullName(false) << endl;
                  Fail = true;
               }
               else
@@ -656,20 +693,18 @@ bool pkgProblemResolver::DoUpgrade(pkgCache::PkgIterator Pkg)
            {
               /* We let the algorithm deal with conflicts on its next iteration,
                it is much smarter than us */
-              if (Start->Type == pkgCache::Dep::Conflicts || 
-                  Start->Type == pkgCache::Dep::DpkgBreaks || 
-                  Start->Type == pkgCache::Dep::Obsoletes)
+              if (Start.IsNegative() == true)
                   break;
               
               if (Debug == true)
-                 clog << "    Reinst Failed early because of " << Start.TargetPkg().Name() << endl;
+                 clog << "    Reinst Failed early because of " << Start.TargetPkg().FullName(false) << endl;
               Fail = true;
            }     
         }
         
         if (Start == End)
            break;
-        Start++;
+        ++Start;
       }
       if (Fail == true)
         break;
@@ -686,7 +721,7 @@ bool pkgProblemResolver::DoUpgrade(pkgCache::PkgIterator Pkg)
    }    
    
    if (Debug == true)
-      clog << "  Re-Instated " << Pkg.Name() << endl;
+      clog << "  Re-Instated " << Pkg.FullName(false) << endl;
    return true;
 }
                                                                        /*}}}*/
@@ -715,7 +750,7 @@ bool pkgProblemResolver::Resolve(bool BrokenFix)
    do
    {
       Again = false;
-      for (pkgCache::PkgIterator I = Cache.PkgBegin(); I.end() == false; I++)
+      for (pkgCache::PkgIterator I = Cache.PkgBegin(); I.end() == false; ++I)
       {
         if (Cache[I].Install() == true)
            Flags[I->ID] |= PreInstalled;
@@ -746,28 +781,31 @@ bool pkgProblemResolver::Resolve(bool BrokenFix)
       would cause the removal of even lower score packages. */
    SPtrArray<pkgCache::Package *> PList = new pkgCache::Package *[Size];
    pkgCache::Package **PEnd = PList;
-   for (pkgCache::PkgIterator I = Cache.PkgBegin(); I.end() == false; I++)
+   for (pkgCache::PkgIterator I = Cache.PkgBegin(); I.end() == false; ++I)
       *PEnd++ = I;
    This = this;
    qsort(PList,PEnd - PList,sizeof(*PList),&ScoreSort);
-   
-/* for (pkgCache::Package **K = PList; K != PEnd; K++)
-      if (Scores[(*K)->ID] != 0)
-      {
-        pkgCache::PkgIterator Pkg(Cache,*K);
-        clog << Scores[(*K)->ID] << ' ' << Pkg.Name() <<
-           ' ' << (pkgCache::Version *)Pkg.CurrentVer() << ' ' << 
-           Cache[Pkg].InstallVer << ' ' << Cache[Pkg].CandidateVer << endl;
-      } */
+
+   if (_config->FindB("Debug::pkgProblemResolver::ShowScores",false) == true)
+   {
+      clog << "Show Scores" << endl;
+      for (pkgCache::Package **K = PList; K != PEnd; K++)
+         if (Scores[(*K)->ID] != 0)
+         {
+           pkgCache::PkgIterator Pkg(Cache,*K);
+           clog << Scores[(*K)->ID] << ' ' << Pkg << std::endl;
+         }
+   }
 
    if (Debug == true)
       clog << "Starting 2" << endl;
-   
+
    /* Now consider all broken packages. For each broken package we either
       remove the package or fix it's problem. We do this once, it should
       not be possible for a loop to form (that is a < b < c and fixing b by
       changing a breaks c) */
    bool Change = true;
+   bool const TryFixByInstall = _config->FindB("pkgProblemResolver::FixByInstall", true);
    for (int Counter = 0; Counter != 10 && Change == true; Counter++)
    {
       Change = false;
@@ -784,7 +822,7 @@ bool pkgProblemResolver::Resolve(bool BrokenFix)
             (Flags[I->ID] & ReInstateTried) == 0)
         {
            if (Debug == true)
-              clog << " Try to Re-Instate " << I.Name() << endl;
+              clog << " Try to Re-Instate (" << Counter << ") " << I.FullName(false) << endl;
            unsigned long OldBreaks = Cache.BrokenCount();
            pkgCache::Version *OldVer = Cache[I].InstallVer;
            Flags[I->ID] &= ReInstateTried;
@@ -800,14 +838,14 @@ bool pkgProblemResolver::Resolve(bool BrokenFix)
            }       
            else
               if (Debug == true)
-                 clog << "Re-Instated " << I.Name() << " (" << OldBreaks << " vs " << Cache.BrokenCount() << ')' << endl;
+                 clog << "Re-Instated " << I.FullName(false) << " (" << OldBreaks << " vs " << Cache.BrokenCount() << ')' << endl;
         }
            
         if (Cache[I].InstallVer == 0 || Cache[I].InstBroken() == false)
            continue;
         
         if (Debug == true)
-           clog << "Investigating " << I.Name() << endl;
+           clog << "Investigating (" << Counter << ") " << I << endl;
         
         // Isolate the problem dependency
         PackageKill KillList[100];
@@ -825,22 +863,22 @@ bool pkgProblemResolver::Resolve(bool BrokenFix)
            if (Start == End)
            {
               // Decide what to do
-              if (InOr == true)
+              if (InOr == true && OldEnd == LEnd)
               {
-                 if (OldEnd == LEnd && OrOp == OrRemove)
+                 if (OrOp == OrRemove)
                  {
                     if ((Flags[I->ID] & Protected) != Protected)
                     {
                        if (Debug == true)
-                          clog << "  Or group remove for " << I.Name() << endl;
+                          clog << "  Or group remove for " << I.FullName(false) << endl;
                        Cache.MarkDelete(I);
                        Change = true;
-                    }               
-                 }               
-                 if (OldEnd == LEnd && OrOp == OrKeep)
+                    }
+                 }
+                 else if (OrOp == OrKeep)
                  {
                     if (Debug == true)
-                       clog << "  Or group keep for " << I.Name() << endl;
+                       clog << "  Or group keep for " << I.FullName(false) << endl;
                     Cache.MarkKeep(I, false, false);
                     Change = true;
                  }
@@ -863,7 +901,7 @@ bool pkgProblemResolver::Resolve(bool BrokenFix)
            }
            else
             {
-              Start++;
+              ++Start;
               // We only worry about critical deps.
               if (Start.IsCritical() != true)
                   continue;
@@ -877,16 +915,14 @@ bool pkgProblemResolver::Resolve(bool BrokenFix)
            }
            
            if (Debug == true)
-              clog << "Package " << I.Name() << " has broken dep on " << Start.TargetPkg().Name() << endl;
+              clog << "Broken " << Start << endl;
 
            /* Look across the version list. If there are no possible
               targets then we keep the package and bail. This is necessary
               if a package has a dep on another package that cant be found */
            SPtrArray<pkgCache::Version *> VList = Start.AllTargets();
            if (*VList == 0 && (Flags[I->ID] & Protected) != Protected &&
-               Start->Type != pkgCache::Dep::Conflicts &&
-               Start->Type != pkgCache::Dep::DpkgBreaks &&
-               Start->Type != pkgCache::Dep::Obsoletes &&
+               Start.IsNegative() == false &&
                Cache[I].NowBroken() == false)
            {          
               if (InOr == true)
@@ -907,17 +943,29 @@ bool pkgProblemResolver::Resolve(bool BrokenFix)
               pkgCache::VerIterator Ver(Cache,*V);
               pkgCache::PkgIterator Pkg = Ver.ParentPkg();
 
+               /* This is a conflicts, and the version we are looking
+                  at is not the currently selected version of the 
+                  package, which means it is not necessary to 
+                  remove/keep */
+               if (Cache[Pkg].InstallVer != Ver && Start.IsNegative() == true)
+               {
+                  if (Debug) 
+                     clog << "  Conflicts//Breaks against version " 
+                          << Ver.VerStr() << " for " << Pkg.Name() 
+                          << " but that is not InstVer, ignoring"
+                          << endl;
+                  continue;
+               }
+
               if (Debug == true)
-                 clog << "  Considering " << Pkg.Name() << ' ' << (int)Scores[Pkg->ID] <<
-                 " as a solution to " << I.Name() << ' ' << (int)Scores[I->ID] << endl;
+                 clog << "  Considering " << Pkg.FullName(false) << ' ' << (int)Scores[Pkg->ID] <<
+                 " as a solution to " << I.FullName(false) << ' ' << (int)Scores[I->ID] << endl;
 
               /* Try to fix the package under consideration rather than
                  fiddle with the VList package */
               if (Scores[I->ID] <= Scores[Pkg->ID] ||
                   ((Cache[Start] & pkgDepCache::DepNow) == 0 &&
-                   End->Type != pkgCache::Dep::Conflicts &&
-                   End->Type != pkgCache::Dep::DpkgBreaks &&
-                   End->Type != pkgCache::Dep::Obsoletes))
+                   End.IsNegative() == false))
               {
                  // Try a little harder to fix protected packages..
                  if ((Flags[I->ID] & Protected) == Protected)
@@ -947,24 +995,40 @@ bool pkgProblemResolver::Resolve(bool BrokenFix)
                        Cache.MarkInstall(I, false, 0, false);
                     
                     if (Debug == true)
-                       clog << "  Holding Back " << I.Name() << " rather than change " << Start.TargetPkg().Name() << endl;
+                       clog << "  Holding Back " << I.FullName(false) << " rather than change " << Start.TargetPkg().FullName(false) << endl;
                  }               
                  else
                  {                  
                     if (BrokenFix == false || DoUpgrade(I) == false)
                     {
                        // Consider other options
-                       if (InOr == false)
+                       if (InOr == false || Cache[I].Garbage == true)
                        {
                           if (Debug == true)
-                             clog << "  Removing " << I.Name() << " rather than change " << Start.TargetPkg().Name() << endl;
+                             clog << "  Removing " << I.FullName(false) << " rather than change " << Start.TargetPkg().FullName(false) << endl;
                           Cache.MarkDelete(I);
-                          if (Counter > 1)
-                          {
-                             if (Scores[Pkg->ID] > Scores[I->ID])
-                                Scores[I->ID] = Scores[Pkg->ID];
-                          }                       
-                       }                       
+                          if (Counter > 1 && Scores[Pkg->ID] > Scores[I->ID])
+                             Scores[I->ID] = Scores[Pkg->ID];
+                       }
+                       else if (TryFixByInstall == true &&
+                                Start.TargetPkg()->CurrentVer == 0 &&
+                                Cache[Start.TargetPkg()].Delete() == false &&
+                                (Flags[Start.TargetPkg()->ID] & ToRemove) != ToRemove &&
+                                Cache.GetCandidateVer(Start.TargetPkg()).end() == false)
+                       {
+                          /* Before removing or keeping the package with the broken dependency
+                             try instead to install the first not previously installed package
+                             solving this dependency. This helps every time a previous solver
+                             is removed by the resolver because of a conflict or alike but it is
+                             dangerous as it could trigger new breaks/conflicts… */
+                          if (Debug == true)
+                             clog << "  Try Installing " << Start.TargetPkg() << " before changing " << I.FullName(false) << std::endl;
+                          unsigned long const OldBroken = Cache.BrokenCount();
+                          Cache.MarkInstall(Start.TargetPkg(), true, 1, false);
+                          // FIXME: we should undo the complete MarkInstall process here
+                          if (Cache[Start.TargetPkg()].InstBroken() == true || Cache.BrokenCount() > OldBroken)
+                             Cache.MarkDelete(Start.TargetPkg(), false, 1, false);
+                       }
                     }
                  }
                                  
@@ -974,28 +1038,20 @@ bool pkgProblemResolver::Resolve(bool BrokenFix)
               }
               else
               {
-                 /* This is a conflicts, and the version we are looking
-                    at is not the currently selected version of the 
-                    package, which means it is not necessary to 
-                    remove/keep */
-                 if (Cache[Pkg].InstallVer != Ver &&
-                     (Start->Type == pkgCache::Dep::Conflicts ||
-                      Start->Type == pkgCache::Dep::Obsoletes))
-                    continue;
-
                  if (Start->Type == pkgCache::Dep::DpkgBreaks)
                  {
-                    /* Would it help if we upgraded? */
-                    if (Cache[End] & pkgDepCache::DepGCVer) {
+                    // first, try upgradring the package, if that
+                    // does not help, the breaks goes onto the
+                    // kill list
+                     //
+                    // FIXME: use DoUpgrade(Pkg) instead?
+                    if (Cache[End] & pkgDepCache::DepGCVer)
+                    {
                        if (Debug)
-                          clog << "  Upgrading " << Pkg.Name() << " due to Breaks field in " << I.Name() << endl;
+                          clog << "  Upgrading " << Pkg.FullName(false) << " due to Breaks field in " << I.FullName(false) << endl;
                        Cache.MarkInstall(Pkg, false, 0, false);
                        continue;
                     }
-                    if (Debug)
-                       clog << "  Will not break " << Pkg.Name() << " as stated in Breaks field in " << I.Name() <<endl;
-                    Cache.MarkKeep(I, false, false);
-                    continue;
                  }
 
                  // Skip adding to the kill list if it is protected
@@ -1003,7 +1059,7 @@ bool pkgProblemResolver::Resolve(bool BrokenFix)
                     continue;
                
                  if (Debug == true)
-                    clog << "  Added " << Pkg.Name() << " to the remove list" << endl;
+                    clog << "  Added " << Pkg.FullName(false) << " to the remove list" << endl;
                  
                  LEnd->Pkg = Pkg;
                  LEnd->Dep = End;
@@ -1016,10 +1072,8 @@ bool pkgProblemResolver::Resolve(bool BrokenFix)
            }
 
            // Hm, nothing can possibly satisify this dep. Nuke it.
-           if (VList[0] == 0 && 
-               Start->Type != pkgCache::Dep::Conflicts &&
-               Start->Type != pkgCache::Dep::DpkgBreaks &&
-               Start->Type != pkgCache::Dep::Obsoletes &&
+           if (VList[0] == 0 &&
+               Start.IsNegative() == false &&
                (Flags[I->ID] & Protected) != Protected)
            {
               bool Installed = Cache[I].Install();
@@ -1035,12 +1089,12 @@ bool pkgProblemResolver::Resolve(bool BrokenFix)
                     Cache.MarkInstall(I, false, 0, false);
                  
                  if (Debug == true)
-                    clog << "  Holding Back " << I.Name() << " because I can't find " << Start.TargetPkg().Name() << endl;
+                    clog << "  Holding Back " << I.FullName(false) << " because I can't find " << Start.TargetPkg().FullName(false) << endl;
               }               
               else
               {
                  if (Debug == true)
-                    clog << "  Removing " << I.Name() << " because I can't find " << Start.TargetPkg().Name() << endl;
+                    clog << "  Removing " << I.FullName(false) << " because I can't find " << Start.TargetPkg().FullName(false) << endl;
                  if (InOr == false)
                     Cache.MarkDelete(I);
               }
@@ -1065,18 +1119,17 @@ bool pkgProblemResolver::Resolve(bool BrokenFix)
               Change = true;
               if ((Cache[J->Dep] & pkgDepCache::DepGNow) == 0)
               {
-                 if (J->Dep->Type == pkgCache::Dep::Conflicts || 
-                     J->Dep->Type == pkgCache::Dep::Obsoletes)
+                 if (J->Dep.IsNegative() == true)
                  {
                     if (Debug == true)
-                       clog << "  Fixing " << I.Name() << " via remove of " << J->Pkg.Name() << endl;
+                       clog << "  Fixing " << I.FullName(false) << " via remove of " << J->Pkg.FullName(false) << endl;
                     Cache.MarkDelete(J->Pkg);
                  }
               }
               else
               {
                  if (Debug == true)
-                    clog << "  Fixing " << I.Name() << " via keep of " << J->Pkg.Name() << endl;
+                    clog << "  Fixing " << I.FullName(false) << " via keep of " << J->Pkg.FullName(false) << endl;
                  Cache.MarkKeep(J->Pkg, false, false);
               }
 
@@ -1097,7 +1150,7 @@ bool pkgProblemResolver::Resolve(bool BrokenFix)
    {
       // See if this is the result of a hold
       pkgCache::PkgIterator I = Cache.PkgBegin();
-      for (;I.end() != true; I++)
+      for (;I.end() != true; ++I)
       {
         if (Cache[I].InstBroken() == false)
            continue;
@@ -1107,13 +1160,12 @@ bool pkgProblemResolver::Resolve(bool BrokenFix)
       return _error->Error(_("Unable to correct problems, you have held broken packages."));
    }
    
-   // set the auto-flags (mvo: I'm not sure if we _really_ need this, but
-   // I didn't managed 
+   // set the auto-flags (mvo: I'm not sure if we _really_ need this)
    pkgCache::PkgIterator I = Cache.PkgBegin();
-   for (;I.end() != true; I++) {
+   for (;I.end() != true; ++I) {
       if (Cache[I].NewInstall() && !(Flags[I->ID] & PreInstalled)) {
         if(_config->FindI("Debug::pkgAutoRemove",false)) {
-           std::clog << "Resolve installed new pkg: " << I.Name(
+           std::clog << "Resolve installed new pkg: " << I.FullName(false
                      << " (now marking it as auto)" << std::endl;
         }
         Cache[I].Flags |= pkgCache::Flag::Auto;
@@ -1124,6 +1176,31 @@ bool pkgProblemResolver::Resolve(bool BrokenFix)
    return true;
 }
                                                                        /*}}}*/
+
+// ProblemResolver::BreaksInstOrPolicy - Check if the given pkg is broken/*{{{*/
+// ---------------------------------------------------------------------
+/* This checks if the given package is broken either by a hard dependency
+   (InstBroken()) or by introducing a new policy breakage e.g. new
+   unsatisfied recommends for a package that was in "policy-good" state
+
+   Note that this is not perfect as it will ignore further breakage
+   for already broken policy (recommends)
+*/
+bool pkgProblemResolver::InstOrNewPolicyBroken(pkgCache::PkgIterator I)
+{
+   
+   // a broken install is always a problem
+   if (Cache[I].InstBroken() == true)
+      return true;
+
+   // a newly broken policy (recommends/suggests) is a problem
+   if (Cache[I].NowPolicyBroken() == false &&
+       Cache[I].InstPolicyBroken() == true)
+      return true;
+       
+   return false;
+}
+
 // ProblemResolver::ResolveByKeep - Resolve problems using keep                /*{{{*/
 // ---------------------------------------------------------------------
 /* This is the work horse of the soft upgrade routine. It is very gental 
@@ -1135,9 +1212,6 @@ bool pkgProblemResolver::ResolveByKeep()
 
    unsigned long Size = Cache.Head().PackageCount;
 
-   if (Debug == true)      
-      clog << "Entering ResolveByKeep" << endl;
-   
    MakeScores();
    
    /* We have to order the packages so that the broken fixing pass 
@@ -1146,28 +1220,45 @@ bool pkgProblemResolver::ResolveByKeep()
       would cause the removal of even lower score packages. */
    pkgCache::Package **PList = new pkgCache::Package *[Size];
    pkgCache::Package **PEnd = PList;
-   for (pkgCache::PkgIterator I = Cache.PkgBegin(); I.end() == false; I++)
+   for (pkgCache::PkgIterator I = Cache.PkgBegin(); I.end() == false; ++I)
       *PEnd++ = I;
    This = this;
    qsort(PList,PEnd - PList,sizeof(*PList),&ScoreSort);
-   
+
+   if (_config->FindB("Debug::pkgProblemResolver::ShowScores",false) == true)
+   {
+      clog << "Show Scores" << endl;
+      for (pkgCache::Package **K = PList; K != PEnd; K++)
+         if (Scores[(*K)->ID] != 0)
+         {
+           pkgCache::PkgIterator Pkg(Cache,*K);
+           clog << Scores[(*K)->ID] << ' ' << Pkg << std::endl;
+         }
+   }
+
+   if (Debug == true)
+      clog << "Entering ResolveByKeep" << endl;
+
    // Consider each broken package 
    pkgCache::Package **LastStop = 0;
    for (pkgCache::Package **K = PList; K != PEnd; K++)
    {
       pkgCache::PkgIterator I(Cache,*K);
 
-      if (Cache[I].InstallVer == 0 || Cache[I].InstBroken() == false)
+      if (Cache[I].InstallVer == 0)
         continue;
 
+      if (InstOrNewPolicyBroken(I) == false)
+         continue;
+
       /* Keep the package. If this works then great, otherwise we have
                 to be significantly more agressive and manipulate its dependencies */
       if ((Flags[I->ID] & Protected) == 0)
       {
         if (Debug == true)
-           clog << "Keeping package " << I.Name() << endl;
+           clog << "Keeping package " << I.FullName(false) << endl;
         Cache.MarkKeep(I, false, false);
-        if (Cache[I].InstBroken() == false)
+        if (InstOrNewPolicyBroken(I) == false)
         {
            K = PList - 1;
            continue;
@@ -1196,8 +1287,8 @@ bool pkgProblemResolver::ResolveByKeep()
         while (true)
         {
            if (Debug == true)
-              clog << "Package " << I.Name() << " has broken dep on " << Start.TargetPkg().Name() << endl;
-           
+              clog << "Package " << I.FullName(false) << " " << Start << endl;
+
            // Look at all the possible provides on this package
            SPtrArray<pkgCache::Version *> VList = Start.AllTargets();
            for (pkgCache::Version **V = VList; *V != 0; V++)
@@ -1213,32 +1304,32 @@ bool pkgProblemResolver::ResolveByKeep()
               if ((Flags[I->ID] & Protected) == 0)
               {
                  if (Debug == true)
-                    clog << "  Keeping Package " << Pkg.Name() << " due to dep" << endl;
+                    clog << "  Keeping Package " << Pkg.FullName(false) << " due to " << Start.DepType() << endl;
                  Cache.MarkKeep(Pkg, false, false);
               }
               
-              if (Cache[I].InstBroken() == false)
+              if (InstOrNewPolicyBroken(I) == false)
                  break;
            }
            
-           if (Cache[I].InstBroken() == false)
+           if (InstOrNewPolicyBroken(I) == false)
               break;
 
            if (Start == End)
               break;
-           Start++;
+           ++Start;
         }
              
-        if (Cache[I].InstBroken() == false)
+        if (InstOrNewPolicyBroken(I) == false)
            break;
       }
 
-      if (Cache[I].InstBroken() == true)
+      if (InstOrNewPolicyBroken(I) == true)
         continue;
       
       // Restart again.
       if (K == LastStop)
-        return _error->Error("Internal Error, pkgProblemResolver::ResolveByKeep is looping on package %s.",I.Name());
+        return _error->Error("Internal Error, pkgProblemResolver::ResolveByKeep is looping on package %s.",I.FullName(false).c_str());
       LastStop = K;
       K = PList - 1;
    }   
@@ -1253,7 +1344,7 @@ void pkgProblemResolver::InstallProtect()
 {
    pkgDepCache::ActionGroup group(Cache);
 
-   for (pkgCache::PkgIterator I = Cache.PkgBegin(); I.end() == false; I++)
+   for (pkgCache::PkgIterator I = Cache.PkgBegin(); I.end() == false; ++I)
    {
       if ((Flags[I->ID] & Protected) == Protected)
       {
@@ -1261,8 +1352,8 @@ void pkgProblemResolver::InstallProtect()
            Cache.MarkDelete(I);
         else 
         {
-           // preserver the information if the package was auto
-           // or manual installed
+           // preserve the information whether the package was auto
+           // or manually installed
            bool autoInst = (Cache[I].Flags & pkgCache::Flag::Auto);
            Cache.MarkInstall(I, false, 0, !autoInst);
         }
@@ -1270,7 +1361,6 @@ void pkgProblemResolver::InstallProtect()
    }   
 }
                                                                        /*}}}*/
-
 // PrioSortList - Sort a list of versions by priority                  /*{{{*/
 // ---------------------------------------------------------------------
 /* This is ment to be used in conjunction with AllTargets to get a list 
@@ -1301,4 +1391,87 @@ void pkgPrioSortList(pkgCache &Cache,pkgCache::Version **List)
    qsort(List,Count,sizeof(*List),PrioComp);
 }
                                                                        /*}}}*/
+// CacheFile::ListUpdate - update the cache files                      /*{{{*/
+// ---------------------------------------------------------------------
+/* This is a simple wrapper to update the cache. it will fetch stuff
+ * from the network (or any other sources defined in sources.list)
+ */
+bool ListUpdate(pkgAcquireStatus &Stat, 
+               pkgSourceList &List, 
+               int PulseInterval)
+{
+   pkgAcquire::RunResult res;
+   pkgAcquire Fetcher;
+   if (Fetcher.Setup(&Stat, _config->FindDir("Dir::State::Lists")) == false)
+      return false;
+
+   // Populate it with the source selection
+   if (List.GetIndexes(&Fetcher) == false)
+        return false;
+
+   // Run scripts
+   RunScripts("APT::Update::Pre-Invoke");
+   
+   // check arguments
+   if(PulseInterval>0)
+      res = Fetcher.Run(PulseInterval);
+   else
+      res = Fetcher.Run();
+
+   if (res == pkgAcquire::Failed)
+      return false;
+
+   bool Failed = false;
+   bool TransientNetworkFailure = false;
+   for (pkgAcquire::ItemIterator I = Fetcher.ItemsBegin(); 
+       I != Fetcher.ItemsEnd(); ++I)
+   {
+      if ((*I)->Status == pkgAcquire::Item::StatDone)
+        continue;
+
+      (*I)->Finished();
+
+      ::URI uri((*I)->DescURI());
+      uri.User.clear();
+      uri.Password.clear();
+      string descUri = string(uri);
+      _error->Warning(_("Failed to fetch %s  %s\n"), descUri.c_str(),
+             (*I)->ErrorText.c_str());
+
+      if ((*I)->Status == pkgAcquire::Item::StatTransientNetworkError) 
+      {
+        TransientNetworkFailure = true;
+        continue;
+      }
 
+      Failed = true;
+   }
+   
+   // Clean out any old list files
+   // Keep "APT::Get::List-Cleanup" name for compatibility, but
+   // this is really a global option for the APT library now
+   if (!TransientNetworkFailure && !Failed &&
+       (_config->FindB("APT::Get::List-Cleanup",true) == true &&
+       _config->FindB("APT::List-Cleanup",true) == true))
+   {
+      if (Fetcher.Clean(_config->FindDir("Dir::State::lists")) == false ||
+         Fetcher.Clean(_config->FindDir("Dir::State::lists") + "partial/") == false)
+        // something went wrong with the clean
+        return false;
+   }
+   
+   if (TransientNetworkFailure == true)
+      _error->Warning(_("Some index files failed to download. They have been ignored, or old ones used instead."));
+   else if (Failed == true)
+      return _error->Error(_("Some index files failed to download. They have been ignored, or old ones used instead."));
+
+
+   // Run the success scripts if all was fine
+   if(!TransientNetworkFailure && !Failed)
+      RunScripts("APT::Update::Post-Invoke-Success");
+
+   // Run the other scripts
+   RunScripts("APT::Update::Post-Invoke");
+   return true;
+}
+                                                                       /*}}}*/