]> git.saurik.com Git - apt.git/blobdiff - apt-pkg/depcache.cc
move regex magic from apt-get to new FromRegEx method
[apt.git] / apt-pkg / depcache.cc
index 2c7cdd5c2835aa29e00454985c5e254d41009cd4..6c73b9cfdc429ee3bab8d6af23f84c399c435aa5 100644 (file)
@@ -165,7 +165,7 @@ bool pkgDepCache::Init(OpProgress *Prog)
 bool pkgDepCache::readStateFile(OpProgress *Prog)                      /*{{{*/
 {
    FileFd state_file;
-   string const state = _config->FindDir("Dir::State") + "extended_states";
+   string const state = _config->FindFile("Dir::State::extended_states");
    if(FileExists(state)) {
       state_file.Open(state, FileFd::ReadOnly);
       int const file_size = state_file.Size();
@@ -222,7 +222,7 @@ bool pkgDepCache::writeStateFile(OpProgress *prog, bool InstalledOnly)      /*{{{*/
       std::clog << "pkgDepCache::writeStateFile()" << std::endl;
 
    FileFd StateFile;
-   string const state = _config->FindDir("Dir::State") + "extended_states";
+   string const state = _config->FindFile("Dir::State::extended_states");
 
    // if it does not exist, create a empty one
    if(!FileExists(state)) 
@@ -804,17 +804,18 @@ void pkgDepCache::Update(OpProgress *Prog)
       /* FIXME: recheck breaks proper progress reporting as we don't know
                how many packages we need to recheck. To lower the effect
                a bit we increase with a kill, but we should do something more clever… */
-      for(std::set<unsigned long>::const_iterator p = recheck.begin();
-         p != recheck.end(); ++p) {
-        if (Prog != 0 && Done%20 == 0)
-           Prog->Progress(Done);
-        PkgIterator P = PkgIterator(*Cache, Cache->PkgP + *p);
-        if (RemovePseudoInstalledPkg(P, recheck) == true) {
-           ++killed;
-           ++Done;
+      while(recheck.empty() == false)
+        for (std::set<unsigned long>::const_iterator p = recheck.begin();
+            p != recheck.end();) {
+           if (Prog != 0 && Done%20 == 0)
+              Prog->Progress(Done);
+           PkgIterator P = PkgIterator(*Cache, Cache->PkgP + *p);
+           if (RemovePseudoInstalledPkg(P, recheck) == true) {
+              ++killed;
+              ++Done;
+           }
+           recheck.erase(p++);
         }
-        recheck.erase(p);
-      }
 
       /* Okay, we have killed a great amount of pseudopackages -
         we have killed so many that we have now arch "all" packages
@@ -841,42 +842,15 @@ void pkgDepCache::Update(OpProgress *Prog)
         if (installed == false)
            recheck.insert(G.Index());
       }
-      std::vector<std::string> Archs = APT::Configuration::getArchitectures();
-      bool checkChanged = false;
-      do {
-        for(std::set<unsigned long>::const_iterator g = recheck.begin();
-            g != recheck.end(); ++g) {
-           GrpIterator G = GrpIterator(*Cache, Cache->GrpP + *g);
-           VerIterator allV = G.FindPkg("all").CurrentVer();
-           for (std::vector<std::string>::const_iterator a = Archs.begin();
-                a != Archs.end(); ++a)
-           {
-              PkgIterator P = G.FindPkg(*a);
-              if (P.end() == true) continue;
-              for (VerIterator V = P.VersionList(); V.end() != true; ++V)
-              {
-                 // FIXME: String comparison isn't a save indicator!
-                 if (strcmp(allV.VerStr(),V.VerStr()) != 0)
-                    continue;
-                 unsigned char const CurDepState = VersionState(V.DependsList(),DepInstall,DepInstMin,DepInstPolicy);
-                 if ((CurDepState & DepInstMin) != DepInstMin)
-                    break; // we found the correct version, but it is broken. Better try another arch or later again
-                 P->CurrentVer = V.Index();
-                 AddStates(P);
-                 Update(P);
-                 AddSizes(P);
-                 checkChanged = true;
-                 break;
-              }
-           }
-           recheck.erase(g);
-        }
-      } while (checkChanged == true && recheck.empty() == false);
 
-      if (_config->FindB("Debug::MultiArchKiller", false) == true)
-        for(std::set<unsigned long>::const_iterator g = recheck.begin();
-            g != recheck.end(); ++g)
-           std::cout << "No pseudo package for »" << GrpIterator(*Cache, Cache->GrpP + *g).Name() << "« installed" << std::endl;
+      while (recheck.empty() != true)
+      {
+        std::set<unsigned long>::const_iterator g = recheck.begin();
+        unsigned long const G = *g;
+        recheck.erase(g);
+        if (unlikely(ReInstallPseudoForGroup(G, recheck) == false))
+           _error->Warning(_("Internal error, group '%s' has no installable pseudo package"), GrpIterator(*Cache, Cache->GrpP + G).Name());
+      }
    }
 
    if (Prog != 0)
@@ -885,6 +859,80 @@ void pkgDepCache::Update(OpProgress *Prog)
    readStateFile(Prog);
 }
                                                                        /*}}}*/
+// DepCache::ReInstallPseudoForGroup - MultiArch helper for Update()   /*{{{*/
+// ---------------------------------------------------------------------
+/* RemovePseudoInstalledPkg() is very successful. It even kills packages
+   to an amount that no pseudo package is left, but we need a pseudo package
+   for upgrading senarios so we need to reinstall one pseudopackage which
+   doesn't break everything. Thankfully we can't have architecture depending
+   negative dependencies so this problem is already eliminated */
+bool pkgDepCache::ReInstallPseudoForGroup(pkgCache::PkgIterator const &P, std::set<unsigned long> &recheck)
+{
+   if (P->CurrentVer != 0)
+      return true;
+   // recursive call for packages which provide this package
+   for (pkgCache::PrvIterator Prv = P.ProvidesList(); Prv.end() != true; ++Prv)
+      ReInstallPseudoForGroup(Prv.OwnerPkg(), recheck);
+   // check if we actually need to look at this group
+   unsigned long const G = P->Group;
+   std::set<unsigned long>::const_iterator Pi = recheck.find(G);
+   if (Pi == recheck.end())
+      return true;
+   recheck.erase(Pi); // remove here, so we can't fall into an endless loop
+   if (unlikely(ReInstallPseudoForGroup(G, recheck) == false))
+   {
+      recheck.insert(G);
+      return false;
+   }
+   return true;
+}
+bool pkgDepCache::ReInstallPseudoForGroup(unsigned long const &G, std::set<unsigned long> &recheck)
+{
+   std::vector<std::string> static const Archs = APT::Configuration::getArchitectures();
+   pkgCache::GrpIterator Grp(*Cache, Cache->GrpP + G);
+   if (unlikely(Grp.end() == true))
+      return false;
+   for (std::vector<std::string>::const_iterator a = Archs.begin();
+        a != Archs.end(); ++a)
+   {
+      pkgCache::PkgIterator P = Grp.FindPkg(*a);
+      if (P.end() == true)
+        continue;
+      pkgCache::VerIterator allV = Grp.FindPkg("all").CurrentVer();
+      for (VerIterator V = P.VersionList(); V.end() != true; ++V)
+      {
+        // search for the same version as the all package
+        if (allV->Hash != V->Hash || strcmp(allV.VerStr(),V.VerStr()) != 0)
+           continue;
+        unsigned char const CurDepState = VersionState(V.DependsList(),DepInstall,DepInstMin,DepInstPolicy);
+        // If it is broken, try to install dependencies first before retry
+        if ((CurDepState & DepInstMin) != DepInstMin)
+        {
+           for (pkgCache::DepIterator D = V.DependsList(); D.end() != true; ++D)
+           {
+              if (D->Type != pkgCache::Dep::PreDepends && D->Type != pkgCache::Dep::Depends)
+                 continue;
+              ReInstallPseudoForGroup(D.TargetPkg(), recheck);
+           }
+           unsigned char const CurDepState = VersionState(V.DependsList(),DepInstall,DepInstMin,DepInstPolicy);
+           // if package ist still broken… try another arch
+           if ((CurDepState & DepInstMin) != DepInstMin)
+              break;
+        }
+        // dependencies satisfied: reinstall the package
+        RemoveSizes(P);
+        RemoveStates(P);
+        P->CurrentVer = V.Index();
+        PkgState[P->ID].InstallVer = V;
+        AddStates(P);
+        Update(P);
+        AddSizes(P);
+        return true;
+      }
+   }
+   return false;
+}
+                                                                       /*}}}*/
 // DepCache::Update - Update the deps list of a package                        /*{{{*/
 // ---------------------------------------------------------------------
 /* This is a helper for update that only does the dep portion of the scan. 
@@ -1590,8 +1638,11 @@ bool pkgDepCache::MarkRequired(InRootSetFunc &userFunc)
    {
       if(!(PkgState[p->ID].Flags & Flag::Auto) ||
          (p->Flags & Flag::Essential) ||
-         userFunc.InRootSet(p))
-          
+         userFunc.InRootSet(p) ||
+         // be nice even then a required package violates the policy (#583517)
+         // and do the full mark process also for required packages
+         (p.CurrentVer().end() != true &&
+          p.CurrentVer()->Priority == pkgCache::State::Required))
       {
         // the package is installed (and set to keep)
         if(PkgState[p->ID].Keep() && !p.CurrentVer().end())
@@ -1668,10 +1719,6 @@ void pkgDepCache::MarkPackage(const pkgCache::PkgIterator &pkg,
 
    // If the version belongs to a Multi-Arch all package
    // we will mark all others in this Group with this version also
-   // Beware: We compare versions here the lazy way: string comparision
-   // this is bad if multiple repositories provide different versions
-   // of the package with an identical version number - but even in this
-   // case the dependencies are likely the same.
    if (ver->MultiArch == pkgCache::Version::All &&
        strcmp(ver.Arch(true), "all") == 0)
    {
@@ -1683,7 +1730,8 @@ void pkgDepCache::MarkPackage(const pkgCache::PkgIterator &pkg,
         for (VerIterator V = P.VersionList();
              V.end() != true; ++V)
         {
-           if (strcmp(VerStr, V.VerStr()) != 0)
+           if (ver->Hash != V->Hash ||
+               strcmp(VerStr, V.VerStr()) != 0)
               continue;
            MarkPackage(P, V, follow_recommends, follow_suggests);
            break;