]> git.saurik.com Git - apt.git/blobdiff - cmdline/apt-get.cc
* add "purge" commandline argument, closes: #133421)
[apt.git] / cmdline / apt-get.cc
index cdefd0034fd98330bda689a7ad7a1e61e28c7f6d..c79c1559e14cf7770060555e4ebad4a6dadae475 100644 (file)
@@ -38,6 +38,7 @@
 #include <apt-pkg/version.h>
 #include <apt-pkg/cachefile.h>
 #include <apt-pkg/sptr.h>
+#include <apt-pkg/md5.h>
 #include <apt-pkg/versionmatch.h>
     
 #include <config.h>
@@ -45,6 +46,7 @@
 
 #include "acqprogress.h"
 
+#include <set>
 #include <locale.h>
 #include <langinfo.h>
 #include <fstream>
@@ -66,7 +68,7 @@ ostream c0out(0);
 ostream c1out(0);
 ostream c2out(0);
 ofstream devnull("/dev/null");
-unsigned int ScreenWidth = 80;
+unsigned int ScreenWidth = 80 - 1; /* - 1 for the cursor */
 
 // class CacheFile - Cover class for some dependency cache functions   /*{{{*/
 // ---------------------------------------------------------------------
@@ -541,7 +543,7 @@ bool ShowEssential(ostream &out,CacheFile &Cache)
    }
    
    delete [] Added;
-   return ShowList(out,_("WARNING: The following essential packages will be removed\n"
+   return ShowList(out,_("WARNING: The following essential packages will be removed.\n"
                         "This should NOT be done unless you know exactly what you are doing!"),List,VersionsList);
 }
 
@@ -631,7 +633,7 @@ bool CacheFile::CheckDeps(bool AllowBroken)
 
    // Check that the system is OK
    if (DCache->DelCount() != 0 || DCache->InstCount() != 0)
-      return _error->Error("Internal Error, non-zero counts");
+      return _error->Error("Internal error, non-zero counts");
    
    // Apply corrections for half-installed packages
    if (pkgApplyStatus(*DCache) == false)
@@ -688,14 +690,14 @@ static bool CheckAuth(pkgAcquire& Fetcher)
 
    if (_config->FindB("APT::Get::AllowUnauthenticated",false) == true)
    {
-      c2out << "Authentication warning overridden.\n";
+      c2out << _("Authentication warning overridden.\n");
       return true;
    }
 
    if (_config->FindI("quiet",0) < 2
        && _config->FindB("APT::Get::Assume-Yes",false) == false)
    {
-      c2out << _("Install these packages without verification? [y/N] ") << flush;
+      c2out << _("Install these packages without verification [y/N]? ") << flush;
       if (!YnPrompt(false))
          return _error->Error(_("Some packages could not be authenticated"));
 
@@ -750,7 +752,7 @@ bool InstallPackages(CacheFile &Cache,bool ShwKept,bool Ask = true,
    if (Cache->BrokenCount() != 0)
    {
       ShowBroken(c1out,Cache,false);
-      return _error->Error("Internal Error, InstallPackages was called with broken packages!");
+      return _error->Error(_("Internal error, InstallPackages was called with broken packages!"));
    }
 
    if (Cache->DelCount() == 0 && Cache->InstCount() == 0 &&
@@ -759,17 +761,18 @@ bool InstallPackages(CacheFile &Cache,bool ShwKept,bool Ask = true,
 
    // No remove flag
    if (Cache->DelCount() != 0 && _config->FindB("APT::Get::Remove",true) == false)
-      return _error->Error(_("Packages need to be removed but Remove is disabled."));
+      return _error->Error(_("Packages need to be removed but remove is disabled."));
        
    // Run the simulator ..
    if (_config->FindB("APT::Get::Simulate") == true)
    {
       pkgSimulate PM(Cache);
-      pkgPackageManager::OrderResult Res = PM.DoInstall();
+      int status_fd = _config->FindI("APT::Status-Fd",-1);
+      pkgPackageManager::OrderResult Res = PM.DoInstall(status_fd);
       if (Res == pkgPackageManager::Failed)
         return false;
       if (Res != pkgPackageManager::Completed)
-        return _error->Error("Internal Error, Ordering didn't finish");
+        return _error->Error(_("Internal error, Ordering didn't finish"));
       return true;
    }
    
@@ -810,7 +813,7 @@ bool InstallPackages(CacheFile &Cache,bool ShwKept,bool Ask = true,
    if (DebBytes != Cache->DebSize())
    {
       c0out << DebBytes << ',' << Cache->DebSize() << endl;
-      c0out << "How odd.. The sizes didn't match, email apt@packages.debian.org" << endl;
+      c0out << _("How odd.. The sizes didn't match, email apt@packages.debian.org") << endl;
    }
    
    // Number of bytes
@@ -840,7 +843,7 @@ bool InstallPackages(CacheFile &Cache,bool ShwKept,bool Ask = true,
       struct statvfs Buf;
       string OutputDir = _config->FindDir("Dir::Cache::Archives");
       if (statvfs(OutputDir.c_str(),&Buf) != 0)
-        return _error->Errno("statvfs","Couldn't determine free space in %s",
+        return _error->Errno("statvfs",_("Couldn't determine free space in %s"),
                              OutputDir.c_str());
       if (unsigned(Buf.f_bfree) < (FetchBytes - FetchPBytes)/Buf.f_bsize)
         return _error->Error(_("You don't have enough free space in %s."),
@@ -862,7 +865,7 @@ bool InstallPackages(CacheFile &Cache,bool ShwKept,bool Ask = true,
       
       const char *Prompt = _("Yes, do as I say!");
       ioprintf(c2out,
-              _("You are about to do something potentially harmful\n"
+              _("You are about to do something potentially harmful.\n"
                 "To continue type in the phrase '%s'\n"
                 " ?] "),Prompt);
       c2out << flush;
@@ -883,7 +886,7 @@ bool InstallPackages(CacheFile &Cache,bool ShwKept,bool Ask = true,
         if (_config->FindI("quiet",0) < 2 &&
             _config->FindB("APT::Get::Assume-Yes",false) == false)
         {
-           c2out << _("Do you want to continue? [Y/n] ") << flush;
+           c2out << _("Do you want to continue [Y/n]? ") << flush;
         
            if (YnPrompt() == false)
            {
@@ -990,11 +993,12 @@ bool InstallPackages(CacheFile &Cache,bool ShwKept,bool Ask = true,
       if (Failed == true && PM->FixMissing() == false)
       {
         cerr << _("Unable to correct missing packages.") << endl;
-        return _error->Error(_("Aborting Install."));
+        return _error->Error(_("Aborting install."));
       }
                 
       _system->UnLock();
-      pkgPackageManager::OrderResult Res = PM->DoInstall();
+      int status_fd = _config->FindI("APT::Status-Fd",-1);
+      pkgPackageManager::OrderResult Res = PM->DoInstall(status_fd);
       if (Res == pkgPackageManager::Failed || _error->PendingError() == true)
         return false;
       if (Res == pkgPackageManager::Completed)
@@ -1188,24 +1192,54 @@ pkgSrcRecords::Parser *FindSrc(const char *Name,pkgRecords &Recs,
    string VerTag;
    string TmpSrc = Name;
    string::size_type Slash = TmpSrc.rfind('=');
+
+   // honor default release
+   string DefRel = _config->Find("APT::Default-Release");
+   pkgCache::PkgIterator Pkg = Cache.FindPkg(TmpSrc);
+
    if (Slash != string::npos)
    {
       VerTag = string(TmpSrc.begin() + Slash + 1,TmpSrc.end());
       TmpSrc = string(TmpSrc.begin(),TmpSrc.begin() + Slash);
+   } 
+   else  if(!Pkg.end() && DefRel.empty() == false)
+   {
+      // we have a default release, try to locate the pkg. we do it like
+      // this because GetCandidateVer() will not "downgrade", that means
+      // "apt-get source -t stable apt" won't work on a unstable system
+      for (pkgCache::VerIterator Ver = Pkg.VersionList(); Ver.end() == false; 
+          Ver++)
+      {
+        for (pkgCache::VerFileIterator VF = Ver.FileList(); VF.end() == false;
+             VF++)
+        {
+           /* If this is the status file, and the current version is not the
+              version in the status file (ie it is not installed, or somesuch)
+              then it is not a candidate for installation, ever. This weeds
+              out bogus entries that may be due to config-file states, or
+              other. */
+           if ((VF.File()->Flags & pkgCache::Flag::NotSource) == 
+               pkgCache::Flag::NotSource && Pkg.CurrentVer() != Ver)
+           continue;
+           
+           //std::cout << VF.File().Archive() << std::endl;
+           if(VF.File().Archive() && (VF.File().Archive() == DefRel)) 
+           {
+              VerTag = Ver.VerStr();
+              break;
+           }
+        }
+      }
    }
-   
+
    /* Lookup the version of the package we would install if we were to
       install a version and determine the source package name, then look
-      in the archive for a source package of the same name. In theory
-      we could stash the version string as well and match that too but
-      today there aren't multi source versions in the archive. */
-   if (_config->FindB("APT::Get::Only-Source") == false && 
-       VerTag.empty() == true)
+      in the archive for a source package of the same name. */
+   if (_config->FindB("APT::Get::Only-Source") == false)
    {
-      pkgCache::PkgIterator Pkg = Cache.FindPkg(TmpSrc);
       if (Pkg.end() == false)
       {
-        pkgCache::VerIterator Ver = Cache.GetCandidateVer(Pkg);      
+        pkgCache::VerIterator Ver = Cache.GetCandidateVer(Pkg);
         if (Ver.end() == false)
         {
            pkgRecords::Parser &Parse = Recs.Lookup(Ver.FileList());
@@ -1263,10 +1297,7 @@ pkgSrcRecords::Parser *FindSrc(const char *Name,pkgRecords &Recs,
       }      
    }
    
-   if (Last == 0)
-      return 0;
-   
-   if (Last->Jump(Offset) == false)
+   if (Last == 0 || Last->Jump(Offset) == false)
       return 0;
    
    return Last;
@@ -1337,7 +1368,7 @@ bool DoUpdate(CommandLine &CmdL)
    }
    
    // Clean out any old list files
-   if (_config->FindB("APT::Get::List-Cleanup",true) == true)
+   if (!Failed && _config->FindB("APT::Get::List-Cleanup",true) == true)
    {
       if (Fetcher.Clean(_config->FindDir("Dir::State::lists")) == false ||
          Fetcher.Clean(_config->FindDir("Dir::State::lists") + "partial/") == false)
@@ -1369,7 +1400,7 @@ bool DoUpgrade(CommandLine &CmdL)
    if (pkgAllUpgrade(Cache) == false)
    {
       ShowBroken(c1out,Cache,false);
-      return _error->Error(_("Internal Error, AllUpgrade broke stuff"));
+      return _error->Error(_("Internal error, AllUpgrade broke stuff"));
    }
    
    return InstallPackages(Cache,true);
@@ -1397,7 +1428,11 @@ bool DoInstall(CommandLine &CmdL)
    bool DefRemove = false;
    if (strcasecmp(CmdL.FileList[0],"remove") == 0)
       DefRemove = true;
-
+   else if (strcasecmp(CmdL.FileList[0], "purge") == 0)
+   {
+      _config->Set("APT::Get::Purge", true);
+      DefRemove = true;
+   }
    for (const char **I = CmdL.FileList + 1; *I != 0; I++)
    {
       // Duplicate the string
@@ -1578,68 +1613,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);
 
@@ -1648,7 +1701,7 @@ bool DoInstall(CommandLine &CmdL)
    // See if we need to prompt
    if (Cache->InstCount() == ExpectedInst && Cache->DelCount() == 0)
       return InstallPackages(Cache,false,false);
-   
+
    return InstallPackages(Cache,false);   
 }
                                                                        /*}}}*/
@@ -1661,7 +1714,7 @@ bool DoDistUpgrade(CommandLine &CmdL)
    if (Cache.OpenForInstall() == false || Cache.CheckDeps() == false)
       return false;
 
-   c0out << _("Calculating Upgrade... ") << flush;
+   c0out << _("Calculating upgrade... ") << flush;
    if (pkgDistUpgrade(*Cache) == false)
    {
       c0out << _("Failed") << endl;
@@ -1734,7 +1787,7 @@ bool DoDSelectUpgrade(CommandLine &CmdL)
       if (Fix.Resolve() == false)
       {
         ShowBroken(c1out,Cache,false);
-        return _error->Error("Internal Error, problem resolver broke stuff");
+        return _error->Error(_("Internal error, problem resolver broke stuff"));
       }
    }
 
@@ -1742,7 +1795,7 @@ bool DoDSelectUpgrade(CommandLine &CmdL)
    if (pkgAllUpgrade(Cache) == false)
    {
       ShowBroken(c1out,Cache,false);
-      return _error->Error("Internal Error, problem resolver broke stuff");
+      return _error->Error(_("Internal error, problem resolver broke stuff"));
    }
    
    return InstallPackages(Cache,false);
@@ -1861,6 +1914,9 @@ bool DoSource(CommandLine &CmdL)
 
    DscFile *Dsc = new DscFile[CmdL.FileSize()];
    
+   // insert all downloaded uris into this set to avoid downloading them
+   // twice
+   set<string> queued;
    // Load the requestd sources into the fetcher
    unsigned J = 0;
    for (const char **I = CmdL.FileList + 1; *I != 0; I++, J++)
@@ -1897,7 +1953,28 @@ bool DoSource(CommandLine &CmdL)
         if (_config->FindB("APT::Get::Tar-Only",false) == true &&
             I->Type != "tar")
            continue;
-        
+
+        // don't download the same uri twice (should this be moved to
+        // the fetcher interface itself?)
+        if(queued.find(Last->Index().ArchiveURI(I->Path)) != queued.end())
+           continue;
+        queued.insert(Last->Index().ArchiveURI(I->Path));
+           
+        // check if we have a file with that md5 sum already localy
+        if(!I->MD5Hash.empty() && FileExists(flNotDir(I->Path)))  
+        {
+           FileFd Fd(flNotDir(I->Path), FileFd::ReadOnly);
+           MD5Summation sum;
+           sum.AddFD(Fd.Fd(), Fd.Size());
+           Fd.Close();
+           if((string)sum.Result() == I->MD5Hash) 
+           {
+              ioprintf(c1out,_("Skipping already downloaded file '%s'\n"),
+                       flNotDir(I->Path).c_str());
+              continue;
+           }
+        }
+
         new pkgAcqFile(&Fetcher,Last->Index().ArchiveURI(I->Path),
                        I->MD5Hash,I->Size,
                        Last->Index().SourceInfo(*Last,*I),Src);
@@ -1913,7 +1990,7 @@ bool DoSource(CommandLine &CmdL)
    struct statvfs Buf;
    string OutputDir = ".";
    if (statvfs(OutputDir.c_str(),&Buf) != 0)
-      return _error->Errno("statvfs","Couldn't determine free space in %s",
+      return _error->Errno("statvfs",_("Couldn't determine free space in %s"),
                           OutputDir.c_str());
    if (unsigned(Buf.f_bfree) < (FetchBytes - FetchPBytes)/Buf.f_bsize)
       return _error->Error(_("You don't have enough free space in %s"),
@@ -1930,7 +2007,7 @@ bool DoSource(CommandLine &CmdL)
    if (_config->FindB("APT::Get::Simulate",false) == true)
    {
       for (unsigned I = 0; I != J; I++)
-        ioprintf(cout,_("Fetch Source %s\n"),Dsc[I].Package.c_str());
+        ioprintf(cout,_("Fetch source %s\n"),Dsc[I].Package.c_str());
       return true;
    }
    
@@ -2002,6 +2079,7 @@ bool DoSource(CommandLine &CmdL)
            if (system(S) != 0)
            {
               fprintf(stderr,_("Unpack command '%s' failed.\n"),S);
+              fprintf(stderr,_("Check if the 'dpkg-dev' package is installed.\n"));
               _exit(1);
            }       
         }
@@ -2315,7 +2393,7 @@ bool ShowHelp(CommandLine &CmdL)
            
    if (_config->FindB("version") == true)
    {
-      cout << _("Supported Modules:") << endl;
+      cout << _("Supported modules:") << endl;
       
       for (unsigned I = 0; I != pkgVersioningSystem::GlobalListLen; I++)
       {
@@ -2369,6 +2447,7 @@ bool ShowHelp(CommandLine &CmdL)
       "   upgrade - Perform an upgrade\n"
       "   install - Install new packages (pkg is libc6 not libc6.deb)\n"
       "   remove - Remove packages\n"
+      "   purge - Remove and purge packages\n"
       "   source - Download source archives\n"
       "   build-dep - Configure build-dependencies for source packages\n"
       "   dist-upgrade - Distribution upgrade, see apt-get(8)\n"