* cmdline/apt-get.cc:
[ntk/apt.git] / cmdline / apt-get.cc
index 30d0464..9b6e36e 100644 (file)
@@ -1392,31 +1392,47 @@ bool DoUpdate(CommandLine &CmdL)
 /* Remove unused automatic packages */
 bool DoAutomaticRemove(CacheFile &Cache)
 {
-   if(_config->FindI("Debug::pkgAutoRemove",false))
-      std::cout << "DoAutomaticRemove()" << std::endl;
+   bool Debug = _config->FindI("Debug::pkgAutoRemove",false);
+   bool doAutoRemove = _config->FindB("APT::Get::AutomaticRemove", false);
+   pkgDepCache::ActionGroup group(*Cache);
+   
 
-   if (_config->FindB("APT::Get::Remove",true) == false)
-      return _error->Error(_("We are not supposed to delete stuff, can't "
-                            "start AutoRemover"));
+   if(Debug)
+      std::cout << "DoAutomaticRemove()" << std::endl;
 
+   if (_config->FindB("APT::Get::Remove",true) == false &&
+       doAutoRemove == true)
    {
-     pkgDepCache::ActionGroup group(*Cache);
-
-     // look over the cache to see what can be removed
-     for (pkgCache::PkgIterator Pkg = Cache->PkgBegin(); ! Pkg.end(); ++Pkg)
-       {
-        if (Cache[Pkg].Garbage)
-          {
-            if(Pkg.CurrentVer() != 0 || Cache[Pkg].Install())
-              fprintf(stdout,"We could delete %s\n", Pkg.Name());
+      c1out << _("We are not supposed to delete stuff, can't start "
+                "AutoRemover") << std::endl;
+      doAutoRemove = false;
+   }
 
-            if(Pkg.CurrentVer() != 0 && Pkg->CurrentState != pkgCache::State::ConfigFiles)
+   string autoremovelist, autoremoveversions;
+   // look over the cache to see what can be removed
+   for (pkgCache::PkgIterator Pkg = Cache->PkgBegin(); ! Pkg.end(); ++Pkg)
+   {
+      if (Cache[Pkg].Garbage)
+      {
+        if(Pkg.CurrentVer() != 0 || Cache[Pkg].Install())
+           if(Debug)
+              std::cout << "We could delete %s" <<  Pkg.Name() << std::endl;
+          
+        autoremovelist += string(Pkg.Name()) + " ";
+        autoremoveversions += string(Cache[Pkg].CandVersion) + " ";
+        if (doAutoRemove)
+        {
+           if(Pkg.CurrentVer() != 0 && 
+              Pkg->CurrentState != pkgCache::State::ConfigFiles)
               Cache->MarkDelete(Pkg, _config->FindB("APT::Get::Purge", false));
-            else
+           else
               Cache->MarkKeep(Pkg, false, false);
-          }
-       }
+        }
+      }
    }
+   ShowList(c1out, _("The following packages were automatically installed and are no longer required:"), autoremovelist, autoremoveversions);
+   if (!doAutoRemove && autoremovelist.size() > 0)
+      c1out << _("Use 'apt-get autoremove' to remove them.") << std::endl;
 
    // Now see if we destroyed anything
    if (Cache->BrokenCount() != 0)
@@ -1476,163 +1492,164 @@ bool DoInstall(CommandLine &CmdL)
    if (strcasecmp(CmdL.FileList[0],"remove") == 0)
       DefRemove = true;
    else if (strcasecmp(CmdL.FileList[0], "autoremove") == 0)
-     {
-       _config->Set("APT::Get::AutomaticRemove", "true");
-       DefRemove = true;
-     }
+   {
+      _config->Set("APT::Get::AutomaticRemove", "true");
+      DefRemove = true;
+   }
 
-   for (const char **I = CmdL.FileList + 1; *I != 0; I++)
+   // new scope for the ActionGroup
    {
-      // Duplicate the string
-      unsigned int Length = strlen(*I);
-      char S[300];
-      if (Length >= sizeof(S))
-        continue;
-      strcpy(S,*I);
-      
-      // See if we are removing and special indicators..
-      bool Remove = DefRemove;
-      char *VerTag = 0;
-      bool VerIsRel = false;
-      while (Cache->FindPkg(S).end() == true)
+      pkgDepCache::ActionGroup group(Cache);
+      for (const char **I = CmdL.FileList + 1; *I != 0; I++)
       {
-        // Handle an optional end tag indicating what to do
-        if (Length >= 1 && S[Length - 1] == '-')
-        {
-           Remove = true;
-           S[--Length] = 0;
+        // Duplicate the string
+        unsigned int Length = strlen(*I);
+        char S[300];
+        if (Length >= sizeof(S))
            continue;
-        }
-        
-        if (Length >= 1 && S[Length - 1] == '+')
+        strcpy(S,*I);
+      
+        // See if we are removing and special indicators..
+        bool Remove = DefRemove;
+        char *VerTag = 0;
+        bool VerIsRel = false;
+        while (Cache->FindPkg(S).end() == true)
         {
-           Remove = false;
-           S[--Length] = 0;
-           continue;
-        }
+           // Handle an optional end tag indicating what to do
+           if (Length >= 1 && S[Length - 1] == '-')
+           {
+              Remove = true;
+              S[--Length] = 0;
+              continue;
+           }
         
-        char *Slash = strchr(S,'=');
-        if (Slash != 0)
-        {
-           VerIsRel = false;
-           *Slash = 0;
-           VerTag = Slash + 1;
-        }
+           if (Length >= 1 && S[Length - 1] == '+')
+           {
+              Remove = false;
+              S[--Length] = 0;
+              continue;
+           }
         
-        Slash = strchr(S,'/');
-        if (Slash != 0)
-        {
-           VerIsRel = true;
-           *Slash = 0;
-           VerTag = Slash + 1;
-        }
+           char *Slash = strchr(S,'=');
+           if (Slash != 0)
+           {
+              VerIsRel = false;
+              *Slash = 0;
+              VerTag = Slash + 1;
+           }
         
-        break;
-      }
-      
-      // Locate the package
-      pkgCache::PkgIterator Pkg = Cache->FindPkg(S);
-      Packages++;
-      if (Pkg.end() == true)
-      {
-        // Check if the name is a regex
-        const char *I;
-        for (I = S; *I != 0; I++)
-           if (*I == '?' || *I == '*' || *I == '|' ||
-               *I == '[' || *I == '^' || *I == '$')
-              break;
-        if (*I == 0)
-           return _error->Error(_("Couldn't find package %s"),S);
-
-        // Regexs must always be confirmed
-        ExpectedInst += 1000;
+           Slash = strchr(S,'/');
+           if (Slash != 0)
+           {
+              VerIsRel = true;
+              *Slash = 0;
+              VerTag = Slash + 1;
+           }
         
-        // Compile the regex pattern
-        regex_t Pattern;
-        int Res;
-        if ((Res = regcomp(&Pattern,S,REG_EXTENDED | REG_ICASE |
-                    REG_NOSUB)) != 0)
-        {
-           char Error[300];        
-           regerror(Res,&Pattern,Error,sizeof(Error));
-           return _error->Error(_("Regex compilation error - %s"),Error);
+           break;
         }
-        
-        // Run over the matches
-        bool Hit = false;
-        for (Pkg = Cache->PkgBegin(); Pkg.end() == false; Pkg++)
+      
+        // Locate the package
+        pkgCache::PkgIterator Pkg = Cache->FindPkg(S);
+        Packages++;
+        if (Pkg.end() == true)
         {
-           if (regexec(&Pattern,Pkg.Name(),0,0,0) != 0)
-              continue;
+           // Check if the name is a regex
+           const char *I;
+           for (I = S; *I != 0; I++)
+              if (*I == '?' || *I == '*' || *I == '|' ||
+                  *I == '[' || *I == '^' || *I == '$')
+                 break;
+           if (*I == 0)
+              return _error->Error(_("Couldn't find package %s"),S);
+
+           // Regexs must always be confirmed
+           ExpectedInst += 1000;
+        
+           // Compile the regex pattern
+           regex_t Pattern;
+           int Res;
+           if ((Res = regcomp(&Pattern,S,REG_EXTENDED | REG_ICASE |
+                              REG_NOSUB)) != 0)
+           {
+              char Error[300];     
+              regerror(Res,&Pattern,Error,sizeof(Error));
+              return _error->Error(_("Regex compilation error - %s"),Error);
+           }
+        
+           // Run over the matches
+           bool Hit = false;
+           for (Pkg = Cache->PkgBegin(); Pkg.end() == false; Pkg++)
+           {
+              if (regexec(&Pattern,Pkg.Name(),0,0,0) != 0)
+                 continue;
            
-           ioprintf(c1out,_("Note, selecting %s for regex '%s'\n"),
-                    Pkg.Name(),S);
+              ioprintf(c1out,_("Note, selecting %s for regex '%s'\n"),
+                       Pkg.Name(),S);
            
+              if (VerTag != 0)
+                 if (TryToChangeVer(Pkg,Cache,VerTag,VerIsRel) == false)
+                    return false;
+           
+              Hit |= TryToInstall(Pkg,Cache,Fix,Remove,BrokenFix,
+                                  ExpectedInst,false);
+           }
+           regfree(&Pattern);
+        
+           if (Hit == false)
+              return _error->Error(_("Couldn't find package %s"),S);
+        }
+        else
+        {
            if (VerTag != 0)
               if (TryToChangeVer(Pkg,Cache,VerTag,VerIsRel) == false)
                  return false;
-           
-           Hit |= TryToInstall(Pkg,Cache,Fix,Remove,BrokenFix,
-                               ExpectedInst,false);
-        }
-        regfree(&Pattern);
-        
-        if (Hit == false)
-           return _error->Error(_("Couldn't find package %s"),S);
-      }
-      else
-      {
-        if (VerTag != 0)
-           if (TryToChangeVer(Pkg,Cache,VerTag,VerIsRel) == false)
+           if (TryToInstall(Pkg,Cache,Fix,Remove,BrokenFix,ExpectedInst) == false)
               return false;
-        if (TryToInstall(Pkg,Cache,Fix,Remove,BrokenFix,ExpectedInst) == false)
-           return false;
-      }      
-   }
+        }      
+      }
 
-   /* If we are in the Broken fixing mode we do not attempt to fix the
-      problems. This is if the user invoked install without -f and gave
-      packages */
-   if (BrokenFix == true && Cache->BrokenCount() != 0)
-   {
-      c1out << _("You might want to run `apt-get -f install' to correct these:") << endl;
-      ShowBroken(c1out,Cache,false);
+      /* If we are in the Broken fixing mode we do not attempt to fix the
+        problems. This is if the user invoked install without -f and gave
+        packages */
+      if (BrokenFix == true && Cache->BrokenCount() != 0)
+      {
+        c1out << _("You might want to run `apt-get -f install' to correct these:") << endl;
+        ShowBroken(c1out,Cache,false);
 
-      return _error->Error(_("Unmet dependencies. Try 'apt-get -f install' with no packages (or specify a solution)."));
-   }
+        return _error->Error(_("Unmet dependencies. Try 'apt-get -f install' with no packages (or specify a solution)."));
+      }
    
-   // Call the scored problem resolver
-   Fix.InstallProtect();
-   if (Fix.Resolve(true) == false)
-      _error->Discard();
+      // Call the scored problem resolver
+      Fix.InstallProtect();
+      if (Fix.Resolve(true) == false)
+        _error->Discard();
 
-   // Now we check the state of the packages,
-   if (Cache->BrokenCount() != 0)
-   {
-      c1out << 
-       _("Some packages could not be installed. This may mean that you have\n" 
-        "requested an impossible situation or if you are using the unstable\n" 
-        "distribution that some required packages have not yet been created\n"
-        "or been moved out of Incoming.") << endl;
-      if (Packages == 1)
+      // Now we check the state of the packages,
+      if (Cache->BrokenCount() != 0)
       {
-        c1out << endl;
         c1out << 
-         _("Since you only requested a single operation it is extremely likely that\n"
-           "the package is simply not installable and a bug report against\n" 
-           "that package should be filed.") << endl;
-      }
+           _("Some packages could not be installed. This may mean that you have\n" 
+             "requested an impossible situation or if you are using the unstable\n" 
+             "distribution that some required packages have not yet been created\n"
+             "or been moved out of Incoming.") << endl;
+        if (Packages == 1)
+        {
+           c1out << endl;
+           c1out << 
+              _("Since you only requested a single operation it is extremely likely that\n"
+                "the package is simply not installable and a bug report against\n" 
+                "that package should be filed.") << endl;
+        }
 
-      c1out << _("The following information may help to resolve the situation:") << endl;
-      c1out << endl;
-      ShowBroken(c1out,Cache,false);
-      return _error->Error(_("Broken packages"));
-   }   
-   
-   if (_config->FindB("APT::Get::AutomaticRemove")) {
-      if (!DoAutomaticRemove(Cache)) 
-        return false;
+        c1out << _("The following information may help to resolve the situation:") << endl;
+        c1out << endl;
+        ShowBroken(c1out,Cache,false);
+        return _error->Error(_("Broken packages"));
+      }   
    }
+   if (!DoAutomaticRemove(Cache)) 
+        return false;
 
    /* Print out a list of packages that are going to be installed extra
       to what the user asked */
@@ -1666,68 +1683,86 @@ bool DoInstall(CommandLine &CmdL)
       string SuggestsVersions, RecommendsVersions;
       for (unsigned J = 0; J < Cache->Head().PackageCount; J++)
       {
-        pkgCache::PkgIterator I(Cache,Cache.List[J]);
+        pkgCache::PkgIterator Pkg(Cache,Cache.List[J]);
 
         /* Just look at the ones we want to install */
-        if ((*Cache)[I].Install() == false)
+        if ((*Cache)[Pkg].Install() == false)
           continue;
 
-        for (pkgCache::VerIterator V = I.VersionList(); V.end() == false; V++)
-         {
-            for (pkgCache::DepIterator D = V.DependsList(); D.end() == false; )
-             {
-                pkgCache::DepIterator Start;
-                pkgCache::DepIterator End;
-                D.GlobOr(Start,End); // advances D
-
-                /* 
-                 * If this is a virtual package, we need to check the list of
-                 * packages that provide it and see if any of those are
-                 * installed
-                 */
-                
-                bool providedBySomething = false;
-                for (pkgCache::PrvIterator Prv = Start.TargetPkg().ProvidesList();
-                      Prv.end() != true;
-                      Prv++)
-                   if ((*Cache)[Prv.OwnerPkg()].InstVerIter(*Cache).end() == false)
-                    {
-                      providedBySomething = true;
-                      break;
-                   }
-
-                if (providedBySomething) continue;
-            
-                 for(;;)
-                 {
-                     /* Skip if package is  installed already, or is about to be */
-                     string target = string(Start.TargetPkg().Name()) + " ";
-
-                     if ((*Start.TargetPkg()).SelectedState == pkgCache::State::Install
-                         || Cache[Start.TargetPkg()].Install())
-                       break;
-
-                     /* Skip if we already saw it */
-                     if (int(SuggestsList.find(target)) != -1 || int(RecommendsList.find(target)) != -1)
-                       break; 
-
-                    if (Start->Type == pkgCache::Dep::Suggests) {
-                      SuggestsList += target;
-                      SuggestsVersions += string(Cache[Start.TargetPkg()].CandVersion) + "\n";
-                    }
-                    
-                    if (Start->Type == pkgCache::Dep::Recommends) {
-                      RecommendsList += target;
-                      RecommendsVersions += string(Cache[Start.TargetPkg()].CandVersion) + "\n";
-                    }
-
-                     if (Start >= End)
-                        break;
-                     Start++;
-                 }
-             }
-         }
+        // get the recommends/suggests for the candidate ver
+        pkgCache::VerIterator CV = (*Cache)[Pkg].CandidateVerIter(*Cache);
+        for (pkgCache::DepIterator D = CV.DependsList(); D.end() == false; )
+        {
+           pkgCache::DepIterator Start;
+           pkgCache::DepIterator End;
+           D.GlobOr(Start,End); // advances D
+
+           // FIXME: we really should display a or-group as a or-group to the user
+           //        the problem is that ShowList is incapable of doing this
+           string RecommendsOrList,RecommendsOrVersions;
+           string SuggestsOrList,SuggestsOrVersions;
+           bool foundInstalledInOrGroup = false;
+           for(;;)
+           {
+              /* Skip if package is  installed already, or is about to be */
+              string target = string(Start.TargetPkg().Name()) + " ";
+              
+              if ((*Start.TargetPkg()).SelectedState == pkgCache::State::Install
+                  || Cache[Start.TargetPkg()].Install())
+              {
+                 foundInstalledInOrGroup=true;
+                 break;
+              }
+
+              /* Skip if we already saw it */
+              if (int(SuggestsList.find(target)) != -1 || int(RecommendsList.find(target)) != -1)
+              {
+                 foundInstalledInOrGroup=true;
+                 break; 
+              }
+
+              // this is a dep on a virtual pkg, check if any package that provides it
+              // should be installed
+              if(Start.TargetPkg().ProvidesList() != 0)
+              {
+                 pkgCache::PrvIterator I = Start.TargetPkg().ProvidesList();
+                 for (; I.end() == false; I++)
+                 {
+                    pkgCache::PkgIterator Pkg = I.OwnerPkg();
+                    if (Cache[Pkg].CandidateVerIter(Cache) == I.OwnerVer() && 
+                        Pkg.CurrentVer() != 0)
+                       foundInstalledInOrGroup=true;
+                 }
+              }
+
+              if (Start->Type == pkgCache::Dep::Suggests) 
+              {
+                 SuggestsOrList += target;
+                 SuggestsOrVersions += string(Cache[Start.TargetPkg()].CandVersion) + "\n";
+              }
+              
+              if (Start->Type == pkgCache::Dep::Recommends) 
+              {
+                 RecommendsOrList += target;
+                 RecommendsOrVersions += string(Cache[Start.TargetPkg()].CandVersion) + "\n";
+              }
+
+              if (Start >= End)
+                 break;
+              Start++;
+           }
+           
+           if(foundInstalledInOrGroup == false)
+           {
+              RecommendsList += RecommendsOrList;
+              RecommendsVersions += RecommendsOrVersions;
+              SuggestsList += SuggestsOrList;
+              SuggestsVersions += SuggestsOrVersions;
+           }
+              
+        }
       }
+
       ShowList(c1out,_("Suggested packages:"),SuggestsList,SuggestsVersions);
       ShowList(c1out,_("Recommended packages:"),RecommendsList,RecommendsVersions);
 
@@ -1771,6 +1806,8 @@ bool DoDSelectUpgrade(CommandLine &CmdL)
    if (Cache.OpenForInstall() == false || Cache.CheckDeps() == false)
       return false;
    
+   pkgDepCache::ActionGroup group(Cache);
+
    // Install everything with the install flag set
    pkgCache::PkgIterator I = Cache->PkgBegin();
    for (;I.end() != true; I++)
@@ -2523,7 +2560,6 @@ void GetInitialize()
    _config->Set("APT::Get::Fix-Broken",false);
    _config->Set("APT::Get::Force-Yes",false);
    _config->Set("APT::Get::List-Cleanup",true);
-   _config->Set("APT::Get::AutomaticRemove",false);
 }
                                                                        /*}}}*/
 // SigWinch - Window size change signal handler                                /*{{{*/