]> git.saurik.com Git - apt.git/blobdiff - cmdline/apt-get.cc
Small tweaks to no install candidate warning
[apt.git] / cmdline / apt-get.cc
index f3dd4205a17a152e189e3d35baf5665c73dfec55..42ef548ec9a5e0d4eeec4db6e71274180aaec44f 100644 (file)
@@ -1,6 +1,6 @@
 // -*- mode: cpp; mode: fold -*-
 // Description                                                         /*{{{*/
-// $Id: apt-get.cc,v 1.1 1998/10/02 04:39:56 jgg Exp $
+// $Id: apt-get.cc,v 1.19 1998/11/24 02:35:32 jgg Exp $
 /* ######################################################################
    
    apt-get - Cover for dpkg
 #include <apt-pkg/sourcelist.h>
 #include <apt-pkg/pkgcachegen.h>
 #include <apt-pkg/algorithms.h>
+#include <apt-pkg/acquire-item.h>
+#include <apt-pkg/dpkgpm.h>
+#include <apt-pkg/dpkginit.h>
+#include <strutl.h>
 
 #include <config.h>
 
+#include "acqprogress.h"
+
 #include <fstream.h>
+#include <termios.h>
+#include <sys/ioctl.h>
+#include <signal.h>
+#include <stdio.h>
                                                                        /*}}}*/
 
 ostream c0out;
@@ -44,6 +54,27 @@ ostream c2out;
 ofstream devnull("/dev/null");
 unsigned int ScreenWidth = 80;
 
+// YnPrompt - Yes No Prompt.                                           /*{{{*/
+// ---------------------------------------------------------------------
+/* Returns true on a Yes.*/
+bool YnPrompt()
+{
+   if (_config->FindB("APT::Get::Assume-Yes",false) == true)
+   {
+      c2out << 'Y' << endl;
+      return true;
+   }
+   
+   char C = 0;
+   char Jnk = 0;
+   read(STDIN_FILENO,&C,1);
+   while (C != '\n' && Jnk != '\n') read(STDIN_FILENO,&Jnk,1);
+   
+   if (!(C == 'Y' || C == 'y' || C == '\n' || C == '\r'))
+      return false;
+   return true;
+}
+                                                                       /*}}}*/
 // ShowList - Show a list                                              /*{{{*/
 // ---------------------------------------------------------------------
 /* This prints out a string of space seperated words with a title and 
@@ -80,41 +111,72 @@ void ShowList(ostream &out,string Title,string List)
    description. */
 void ShowBroken(ostream &out,pkgDepCache &Cache)
 {
-   out << "Sorry, but the following packages are broken - this means they have unmet" << endl;
-   out << "dependencies:" << endl;
+   out << "Sorry, but the following packages have unmet dependencies:" << endl;
    pkgCache::PkgIterator I = Cache.PkgBegin();
    for (;I.end() != true; I++)
    {
-      if (Cache[I].InstBroken() == true)
+      if (Cache[I].InstBroken() == false)
+         continue;
+         
+      // Print out each package and the failed dependencies
+      out <<"  " <<  I.Name() << ":";
+      int Indent = strlen(I.Name()) + 3;
+      bool First = true;
+      if (Cache[I].InstVerIter(Cache).end() == true)
+      {
+        cout << endl;
+        continue;
+      }
+      
+      for (pkgCache::DepIterator D = Cache[I].InstVerIter(Cache).DependsList(); D.end() == false;)
       {
-        // Print out each package and the failed dependencies
-        out <<"  " <<  I.Name() << ":";
-        int Indent = strlen(I.Name()) + 3;
-        bool First = true;
-        for (pkgCache::DepIterator D = Cache[I].InstVerIter(Cache).DependsList(); D.end() == false; D++)
+        // Compute a single dependency element (glob or)
+        pkgCache::DepIterator Start;
+        pkgCache::DepIterator End;
+        D.GlobOr(Start,End);
+        
+        if (Cache.IsImportantDep(End) == false || 
+            (Cache[End] & pkgDepCache::DepGInstall) == pkgDepCache::DepGInstall)
+           continue;
+        
+        if (First == false)
+           for (int J = 0; J != Indent; J++)
+              out << ' ';
+        First = false;
+
+        cout << ' ' << End.DepType() << ": " << End.TargetPkg().Name();
+        
+        // Show a quick summary of the version requirements
+        if (End.TargetVer() != 0)
+           out << " (" << End.CompType() << " " << End.TargetVer() << 
+           ")";
+        
+        /* Show a summary of the target package if possible. In the case
+         of virtual packages we show nothing */
+        
+        pkgCache::PkgIterator Targ = End.TargetPkg();
+        if (Targ->ProvidesList == 0)
         {
-           if (Cache.IsImportantDep(D) == false || (Cache[D] &
-                                                    pkgDepCache::DepInstall) != 0)
-              continue;
-           
-           if (First == false)
-              for (int J = 0; J != Indent; J++)
-                 out << ' ';
-           First = false;
-           
-           if (D->Type == pkgCache::Dep::Conflicts)
-              out << " Conflicts:" << D.TargetPkg().Name();
-           else
-              out << " Depends:" << D.TargetPkg().Name();
-           
-           // Show a quick summary of the version requirements
-           if (D.TargetVer() != 0)
-              out << " (" << D.CompType() << " " << D.TargetVer() << 
-                  ")" << endl;
+           out << " but ";
+           pkgCache::VerIterator Ver = Cache[Targ].InstVerIter(Cache);
+           if (Ver.end() == false)
+              out << Ver.VerStr() << " is installed";
            else
-              out << endl;
-        }          
-      }   
+           {
+              if (Cache[Targ].CandidateVerIter(Cache).end() == true)
+              {
+                 if (Targ->ProvidesList == 0)
+                    out << "it is not installable";
+                 else
+                    out << "it is a virtual package";
+              }                  
+              else
+                 out << "it is not installed";
+           }          
+        }
+        
+        out << endl;
+      }            
    }   
 }
                                                                        /*}}}*/
@@ -212,7 +274,7 @@ void ShowEssential(ostream &out,pkgDepCache &Dep)
    pkgCache::PkgIterator I = Dep.PkgBegin();
    string List;
    bool *Added = new bool[Dep.HeaderP->PackageCount];
-   for (int I = 0; I != Dep.HeaderP->PackageCount; I++)
+   for (unsigned int I = 0; I != Dep.HeaderP->PackageCount; I++)
       Added[I] = false;
    
    for (;I.end() != true; I++)
@@ -236,13 +298,21 @@ void ShowEssential(ostream &out,pkgDepCache &Dep)
       // Print out any essential package depenendents that are to be removed
       for (pkgDepCache::DepIterator D = I.CurrentVer().DependsList(); D.end() == false; D++)
       {
+        // Skip everything but depends
+        if (D->Type != pkgCache::Dep::PreDepends &&
+            D->Type != pkgCache::Dep::Depends)
+           continue;
+        
         pkgCache::PkgIterator P = D.SmartTargetPkg();
         if (Dep[P].Delete() == true)
         {
            if (Added[P->ID] == true)
               continue;
            Added[P->ID] = true;
-           List += string(P.Name()) + " ";
+           
+           char S[300];
+           sprintf(S,"%s (due to %s) ",P.Name(),I.Name());
+           List += S;
         }       
       }      
    }
@@ -290,6 +360,7 @@ class CacheFile
    FileFd *File;
    MMap *Map;
    pkgDepCache *Cache;
+   pkgDpkgLock Lock;
    
    inline operator pkgDepCache &() {return *Cache;};
    inline pkgDepCache *operator ->() {return Cache;};
@@ -311,6 +382,9 @@ class CacheFile
    and verifies that the system is OK. */
 bool CacheFile::Open()
 {
+   if (_error->PendingError() == true)
+      return false;
+   
    // Create a progress class
    OpTextProgress Progress(*_config);
       
@@ -327,7 +401,7 @@ bool CacheFile::Open()
    Progress.Done();
    
    // Open the cache file
-   File = new FileFd(_config->FindDir("Dir::Cache::pkgcache"),FileFd::ReadOnly);
+   File = new FileFd(_config->FindFile("Dir::Cache::pkgcache"),FileFd::ReadOnly);
    if (_error->PendingError() == true)
       return false;
    
@@ -364,6 +438,8 @@ bool CacheFile::Open()
 
         return _error->Error("Unable to correct dependencies");
       }
+      if (pkgMinimizeUpgrade(*Cache) == false)
+        return _error->Error("Unable to minimize the upgrade set");
       
       c1out << " Done" << endl;
    }
@@ -383,8 +459,9 @@ bool CacheFile::Open()
 // ---------------------------------------------------------------------
 /* This displays the informative messages describing what is going to 
    happen and then calls the download routines */
-bool InstallPackages(pkgDepCache &Cache,bool ShwKept)
+bool InstallPackages(CacheFile &Cache,bool ShwKept,bool Ask = true)
 {
+   // Show all the various warning indicators
    ShowDel(c1out,Cache);
    ShowNew(c1out,Cache);
    if (ShwKept == true)
@@ -396,25 +473,163 @@ bool InstallPackages(pkgDepCache &Cache,bool ShwKept)
    Stats(c1out,Cache);
    
    // Sanity check
-   if (Cache.BrokenCount() != 0)
+   if (Cache->BrokenCount() != 0)
    {
       ShowBroken(c1out,Cache);
       return _error->Error("Internal Error, InstallPackages was called with broken packages!");
    }
 
-   if (Cache.DelCount() == 0 && Cache.InstCount() == 0 && 
-       Cache.BadCount() == 0)
+   if (Cache->DelCount() == 0 && Cache->InstCount() == 0 && 
+       Cache->BadCount() == 0)
       return true;   
+
+   // Run the simulator ..
+   if (_config->FindB("APT::Get::Simulate") == true)
+   {
+      pkgSimulate PM(Cache);
+      return PM.DoInstall();
+   }
+   
+   // Create the text record parser
+   pkgRecords Recs(Cache);
+
+   // Lock the archive directory
+   if (_config->FindB("Debug::NoLocking",false) == false)
+   {
+      FileFd Lock(GetLock(_config->FindDir("Dir::Cache::Archives") + "lock"));
+      if (_error->PendingError() == true)
+        return _error->Error("Unable to lock the download directory");
+   }
+   
+   // Create the download object
+   AcqTextStatus Stat(ScreenWidth,_config->FindI("quiet",0));   
+   pkgAcquire Fetcher(&Stat);
+
+   // Read the source list
+   pkgSourceList List;
+   if (List.ReadMainList() == false)
+      return _error->Error("The list of sources could not be read.");
+   
+   // Create the package manager and prepare to download
+   pkgDPkgPM PM(Cache);
+   if (PM.GetArchives(&Fetcher,&List,&Recs) == false)
+      return false;
+
+   // Display statistics
+   unsigned long FetchBytes = Fetcher.FetchNeeded();
+   unsigned long DebBytes = Fetcher.TotalNeeded();
+   if (DebBytes != Cache->DebSize())
+   {
+      c0out << DebBytes << ',' << Cache->DebSize() << endl;
+      c0out << "How odd.. The sizes didn't match, email apt@packages.debian.org" << endl;
+   }
       
-   return true;
+   // Number of bytes
+   c1out << "Need to get ";
+   if (DebBytes != FetchBytes)
+      c1out << SizeToStr(FetchBytes) << '/' << SizeToStr(DebBytes);
+   else
+      c1out << SizeToStr(DebBytes);
+      
+   c1out << " of archives. After unpacking ";
+   
+   // Size delta
+   if (Cache->UsrSize() >= 0)
+      c1out << SizeToStr(Cache->UsrSize()) << " will be used." << endl;
+   else
+      c1out << SizeToStr(-1*Cache->UsrSize()) << " will be freed." << endl;
+
+   if (_error->PendingError() == true)
+      return false;
+
+   // Prompt to continue
+   if (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;
+      if (YnPrompt() == false)
+        exit(1);
+   }      
+
+   // Run it
+   if (Fetcher.Run() == false)
+      return false;
+
+   // Print out errors
+   bool Failed = false;
+   for (pkgAcquire::Item **I = Fetcher.ItemsBegin(); I != Fetcher.ItemsEnd(); I++)
+   {
+      if ((*I)->Status == pkgAcquire::Item::StatDone &&
+         (*I)->Complete == true)
+        continue;
+      
+      cerr << "Failed to fetch " << (*I)->Describe() << endl;
+      cerr << "  " << (*I)->ErrorText << endl;
+      Failed = true;
+   }
+   
+   if (Failed == true && _config->FindB("APT::Fix-Missing",false) == false)
+      return _error->Error("Unable to fetch some archives, maybe try with --fix-missing?");
+
+   // Try to deal with missing package files
+   if (PM.FixMissing() == false)
+   {
+      cerr << "Unable to correct missing packages." << endl;
+      return _error->Error("Aborting Install.");
+   }
+   
+   Cache.Lock.Close();
+   return PM.DoInstall();
 }
                                                                        /*}}}*/
 
 // DoUpdate - Update the package lists                                 /*{{{*/
 // ---------------------------------------------------------------------
 /* */
-bool DoUpdate(CommandLine &CmdL)
+bool DoUpdate(CommandLine &)
 {
+   // Get the source list
+   pkgSourceList List;
+   if (List.ReadMainList() == false)
+      return false;
+
+   // Lock the list directory
+   if (_config->FindB("Debug::NoLocking",false) == false)
+   {
+      FileFd Lock(GetLock(_config->FindDir("Dir::State::Lists") + "lock"));
+      if (_error->PendingError() == true)
+        return _error->Error("Unable to lock the list directory");
+   }
+   
+   // Create the download object
+   AcqTextStatus Stat(ScreenWidth,_config->FindI("quiet",0));
+   pkgAcquire Fetcher(&Stat);
+   
+   // Populate it with the source selection
+   pkgSourceList::const_iterator I;
+   for (I = List.begin(); I != List.end(); I++)
+   {
+      new pkgAcqIndex(&Fetcher,I);
+      if (_error->PendingError() == true)
+        return false;
+   }
+   
+   // Run it
+   if (Fetcher.Run() == false)
+      return false;
+
+   // Clean out any old list files
+   if (Fetcher.Clean(_config->FindDir("Dir::State::lists")) == false ||
+       Fetcher.Clean(_config->FindDir("Dir::State::lists") + "partial/") == false)
+      return false;
+   
+   // Prepare the cache.   
+   CacheFile Cache;
+   if (Cache.Open() == false)
+      return false;
+   
+   return true;
 }
                                                                        /*}}}*/
 // DoUpgrade - Upgrade all packages                                    /*{{{*/
@@ -428,7 +643,6 @@ bool DoUpgrade(CommandLine &CmdL)
       return false;
 
    // Do the upgrade
-   pkgProblemResolver Resolve(Cache);
    if (pkgAllUpgrade(Cache) == false)
    {
       ShowBroken(c1out,Cache);
@@ -447,9 +661,14 @@ bool DoInstall(CommandLine &CmdL)
    if (Cache.Open() == false)
       return false;
    
-   int ExpectedInst = 0;
+   unsigned int ExpectedInst = 0;
+   unsigned int Packages = 0;
    pkgProblemResolver Fix(Cache);
    
+   bool DefRemove = false;
+   if (strcasecmp(CmdL.FileList[0],"remove") == 0)
+      DefRemove = true;
+   
    for (const char **I = CmdL.FileList + 1; *I != 0; I++)
    {
       // Duplicate the string
@@ -460,26 +679,82 @@ bool DoInstall(CommandLine &CmdL)
       strcpy(S,*I);
       
       // See if we are removing the package
-      bool Remove = false;
-      if (S[Length - 1] == '-')
+      bool Remove = DefRemove;
+      if (Cache->FindPkg(S).end() == true)
       {
-        Remove = true;
-        S[--Length] = 0;
+        // Handle an optional end tag indicating what to do
+        if (S[Length - 1] == '-')
+        {
+           Remove = true;
+           S[--Length] = 0;
+        }
+        if (S[Length - 1] == '+')
+        {
+           Remove = false;
+           S[--Length] = 0;
+        }
       }
       
       // Locate the package
       pkgCache::PkgIterator Pkg = Cache->FindPkg(S);
+      Packages++;
       if (Pkg.end() == true)
         return _error->Error("Couldn't find package %s",S);
       
+      // Handle the no-upgrade case
+      if (_config->FindB("APT::Get::no-upgrade",false) == true &&
+         Pkg->CurrentVer != 0)
+      {
+        c1out << "Skipping " << Pkg.Name() << ", it is already installed and no-upgrade is set." << endl;
+        continue;
+      }
+      
       // Check if there is something new to install
       pkgDepCache::StateCache &State = (*Cache)[Pkg];
       if (State.CandidateVer == 0)
+      {
+        if (Pkg->ProvidesList != 0)
+        {
+           c1out << "Package " << S << " is a virtual package provided by:" << endl;
+
+           pkgCache::PrvIterator I = Pkg.ProvidesList();
+           for (; I.end() == false; I++)
+           {
+              pkgCache::PkgIterator Pkg = I.OwnerPkg();
+              
+              if ((*Cache)[Pkg].CandidateVerIter(*Cache) == I.OwnerVer())
+                 c1out << "  " << Pkg.Name() << " " << I.OwnerVer().VerStr() << endl;
+
+              if ((*Cache)[Pkg].InstVerIter(*Cache) == I.OwnerVer())
+                 c1out << "  " << Pkg.Name() << " " << I.OwnerVer().VerStr() <<
+                   " [Installed]"<< endl;
+           }
+           c1out << "You should explicly select one to install." << endl;
+        }
+        else
+        {
+           c1out << "Package " << S << " has no available version, but exists in the database." << endl;
+           c1out << "This typically means that the package was mentioned in a dependency and " << endl;
+           c1out << "never uploaded, or that it is an obsolete package." << endl;
+           
+           string List;
+           pkgCache::DepIterator Dep = Pkg.RevDependsList();
+           for (; Dep.end() == false; Dep++)
+           {
+              if (Dep->Type != pkgCache::Dep::Replaces)
+                 continue;
+              List += string(Dep.ParentPkg().Name()) + " ";
+           }       
+           ShowList(c1out,"However the following packages replace it:",List);
+        }
+        
         return _error->Error("Package %s has no installation candidate",S);
+      }
       
       Fix.Protect(Pkg);
       if (Remove == true)
       {
+        Fix.Remove(Pkg);
         Cache->MarkDelete(Pkg);
         continue;
       }
@@ -497,12 +772,27 @@ bool DoInstall(CommandLine &CmdL)
    }
 
    // 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" << endl;
+      c1out << "requested an impossible situation or if you are using the unstable" << endl;
+      c1out << "distribution that some required packages have not yet been created" << endl;
+      c1out << "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" << endl;
+        c1out << "the package is simply not installable and a bug report against" << endl;
+        c1out << "that package should be filed." << endl;
+      }
+
+      c1out << "The following information may help to resolve the situation:" << endl;
+      c1out << endl;
       ShowBroken(c1out,Cache);
       return _error->Error("Sorry, broken packages");
    }   
@@ -530,7 +820,11 @@ bool DoInstall(CommandLine &CmdL)
       ShowList(c1out,"The following extra packages will be installed:",List);
    }
 
-   return InstallPackages(Cache,false);
+   // See if we need to prompt
+   if (Cache->InstCount() == ExpectedInst && Cache->DelCount() == 0)
+      return InstallPackages(Cache,false,false);
+   
+   return InstallPackages(Cache,false);   
 }
                                                                        /*}}}*/
 // DoDistUpgrade - Automatic smart upgrader                            /*{{{*/
@@ -609,6 +903,9 @@ bool DoDSelectUpgrade(CommandLine &CmdL)
 /* */
 bool DoClean(CommandLine &CmdL)
 {
+   pkgAcquire Fetcher;
+   Fetcher.Clean(_config->FindDir("Dir::Cache::archives"));
+   Fetcher.Clean(_config->FindDir("Dir::Cache::archives") + "partial/");
    return true;
 }
                                                                        /*}}}*/
@@ -644,14 +941,15 @@ int ShowHelp()
    cout << "   update - Retrieve new lists of packages" << endl;
    cout << "   upgrade - Perform an upgrade" << endl;
    cout << "   install - Install new packages (pkg is libc6 not libc6.deb)" << endl;
+   cout << "   remove - Remove packages" << endl;
    cout << "   dist-upgrade - Distribution upgrade, see apt-get(8)" << endl;
    cout << "   dselect-upgrade - Follow dselect selections" << endl;
    cout << "   clean - Erase downloaded archive files" << endl;
    cout << "   check - Verify that there are no broken dependencies" << endl;
    cout << endl;
    cout << "Options:" << endl;
-   cout << "  -h   This help text." << endl;
-   cout << "  -q   Loggable output - no progress indicator" << endl;
+   cout << "  -h  This help text." << endl;
+   cout << "  -q  Loggable output - no progress indicator" << endl;
    cout << "  -qq No output except for errors" << endl;
    cout << "  -d  Download only - do NOT install or unpack archives" << endl;
    cout << "  -s  No-act. Perform ordering simulation" << endl;
@@ -679,6 +977,20 @@ void GetInitialize()
    _config->Set("APT::Get::Fix-Broken",false);
 }
                                                                        /*}}}*/
+// SigWinch - Window size change signal handler                                /*{{{*/
+// ---------------------------------------------------------------------
+/* */
+void SigWinch(int)
+{
+   // Riped from GNU ls
+#ifdef TIOCGWINSZ
+   struct winsize ws;
+  
+   if (ioctl(1, TIOCGWINSZ, &ws) != -1 && ws.ws_col >= 5)
+      ScreenWidth = ws.ws_col - 1;
+#endif
+}
+                                                                       /*}}}*/
 
 int main(int argc,const char *argv[])
 {
@@ -695,7 +1007,10 @@ int main(int argc,const char *argv[])
       {'y',"assume-yes","APT::Get::Assume-Yes",0},      
       {'f',"fix-broken","APT::Get::Fix-Broken",0},
       {'u',"show-upgraded","APT::Get::Show-Upgraded",0},
-      {'m',"ignore-missing","APT::Get::Fix-Broken",0},      
+      {'m',"ignore-missing","APT::Get::Fix-Missing",0},
+      {0,"fix-missing","APT::Get::Fix-Missing",0},
+      {0,"ignore-hold","APT::Ingore-Hold",0},      
+      {0,"no-upgrade","APT::Get::no-upgrade",0},      
       {'c',"config-file",0,CommandLine::ConfigFile},
       {'o',"option",0,CommandLine::ArbItem},
       {0,0,0,0}};
@@ -722,6 +1037,11 @@ int main(int argc,const char *argv[])
       c0out.rdbuf(devnull.rdbuf());
    if (_config->FindI("quiet",0) > 1)
       c1out.rdbuf(devnull.rdbuf());
+
+   // Setup the signals
+   signal(SIGPIPE,SIG_IGN);
+   signal(SIGWINCH,SigWinch);
+   SigWinch(0);
    
    // Match the operation
    struct 
@@ -731,6 +1051,7 @@ int main(int argc,const char *argv[])
    } Map[] = {{"update",&DoUpdate},
               {"upgrade",&DoUpgrade},
               {"install",&DoInstall},
+              {"remove",&DoInstall},
               {"dist-upgrade",&DoDistUpgrade},
               {"dselect-upgrade",&DoDSelectUpgrade},
               {"clean",&DoClean},
@@ -741,7 +1062,8 @@ int main(int argc,const char *argv[])
    {
       if (strcmp(CmdL.FileList[0],Map[I].Match) == 0)
       {
-        Map[I].Handler(CmdL);
+        if (Map[I].Handler(CmdL) == false && _error->PendingError() == false)
+           _error->Error("Handler silently failed");
         break;
       }
    }