]> git.saurik.com Git - apt.git/blobdiff - apt-private/private-install.cc
support "install ./foo.changes"
[apt.git] / apt-private / private-install.cc
index 28b8d9a7b7abe5dff374fb5a64c2a2a8a3b4fee1..aa28780da7b802333bf14622536e3208f23f51d8 100644 (file)
@@ -21,7 +21,7 @@
 #include <apt-pkg/pkgcache.h>
 #include <apt-pkg/upgrade.h>
 #include <apt-pkg/install-progress.h>
-#include <apt-pkg/debindexfile.h>
+#include <apt-pkg/prettyprinters.h>
 
 #include <stdlib.h>
 #include <string.h>
                                                                        /*}}}*/
 class pkgSourceList;
 
+bool CheckNothingBroken(CacheFile &Cache)                              /*{{{*/
+{
+   // Now we check the state of the packages,
+   if (Cache->BrokenCount() == 0)
+      return true;
+
+   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.") << std::endl;
+   /*
+   if (Packages == 1)
+   {
+      c1out << std::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.") << std::endl;
+   }
+   */
+
+   c1out << _("The following information may help to resolve the situation:") << std::endl;
+   c1out << std::endl;
+   ShowBroken(c1out,Cache,false);
+   if (_error->PendingError() == true)
+      return false;
+   else
+      return _error->Error(_("Broken packages"));
+}
+                                                                       /*}}}*/
 // InstallPackages - Actually download and install the packages                /*{{{*/
 // ---------------------------------------------------------------------
 /* This displays the informative messages describing what is going to 
    happen and then calls the download routines */
-bool InstallPackages(CacheFile &Cache,bool ShwKept,bool Ask, bool Safety)
+static void RemoveDownloadNeedingItemsFromFetcher(pkgAcquire &Fetcher, bool &Transient)
 {
-   if (_config->FindB("APT::Get::Purge",false) == true)
+   for (pkgAcquire::ItemIterator I = Fetcher.ItemsBegin(); I < Fetcher.ItemsEnd();)
    {
-      pkgCache::PkgIterator I = Cache->PkgBegin();
-      for (; I.end() == false; ++I)
+      if ((*I)->Local == true)
       {
-        if (I.Purge() == false && Cache[I].Mode == pkgDepCache::ModeDelete)
-           Cache->MarkDelete(I,true);
+        ++I;
+        continue;
       }
+
+      // Close the item and check if it was found in cache
+      (*I)->Finished();
+      if ((*I)->Complete == false)
+        Transient = true;
+
+      // Clear it out of the fetch list
+      delete *I;
+      I = Fetcher.ItemsBegin();
    }
-   
-   bool Hold = false;
-   bool Downgrade = false;
-   bool Essential = false;
-   
+}
+bool InstallPackages(CacheFile &Cache,bool ShwKept,bool Ask, bool Safety)
+{
+   if (_config->FindB("APT::Get::Purge", false) == true)
+      for (pkgCache::PkgIterator I = Cache->PkgBegin(); I.end() == false; ++I)
+        if (Cache[I].Delete() == true && Cache[I].Purge() == false)
+           Cache->MarkDelete(I,true);
+
+   // Create the download object
+   aptAcquireWithTextStatus Fetcher;
+   if (_config->FindB("APT::Get::Print-URIs", false) == true)
+   {
+      // force a hashsum for compatibility reasons
+      _config->CndSet("Acquire::ForceHash", "md5sum");
+   }
+   else if (_config->FindB("APT::Get::Simulate") == true)
+      ;
+   else if (Fetcher.GetLock(_config->FindDir("Dir::Cache::Archives")) == false)
+      return false;
+
+   // Read the source list
+   if (Cache.BuildSourceList() == false)
+      return false;
+   pkgSourceList * const List = Cache.GetSourceList();
+
+   // Create the text record parser
+   pkgRecords Recs(Cache);
+   if (_error->PendingError() == true)
+      return false;
+
+   // Create the package manager and prepare to download
+   std::unique_ptr<pkgPackageManager> PM(_system->CreatePM(Cache));
+   if (PM->GetArchives(&Fetcher,List,&Recs) == false || 
+       _error->PendingError() == true)
+      return false;
+
+   if (_config->FindB("APT::Get::Fix-Missing",false) == true &&
+        _config->FindB("APT::Get::Download",true) == false)
+   {
+      bool Missing = false;
+      RemoveDownloadNeedingItemsFromFetcher(Fetcher, Missing);
+      if (Missing)
+        PM->FixMissing();
+      Fetcher.Shutdown();
+      if (PM->GetArchives(&Fetcher,List,&Recs) == false ||
+           _error->PendingError() == true)
+        return false;
+   }
+
    // Show all the various warning indicators
    ShowDel(c1out,Cache);
    ShowNew(c1out,Cache);
    if (ShwKept == true)
       ShowKept(c1out,Cache);
-   Hold = !ShowHold(c1out,Cache);
+   bool const Hold = !ShowHold(c1out,Cache);
    if (_config->FindB("APT::Get::Show-Upgraded",true) == true)
       ShowUpgraded(c1out,Cache);
-   Downgrade = !ShowDowngraded(c1out,Cache);
+   bool const Downgrade = !ShowDowngraded(c1out,Cache);
 
+   bool Essential = false;
    if (_config->FindB("APT::Get::Download-Only",false) == false)
         Essential = !ShowEssential(c1out,Cache);
 
-   // All kinds of failures
-   bool Fail = (Essential || Downgrade || Hold);
-
    Stats(c1out,Cache);
 
    // Sanity check
@@ -96,6 +177,7 @@ bool InstallPackages(CacheFile &Cache,bool ShwKept,bool Ask, bool Safety)
       return _error->Error(_("Packages need to be removed but remove is disabled."));
 
    // Fail safe check
+   bool const Fail = (Essential || Downgrade || Hold);
    if (_config->FindI("quiet",0) >= 2 ||
        _config->FindB("APT::Get::Assume-Yes",false) == true)
    {
@@ -128,38 +210,11 @@ bool InstallPackages(CacheFile &Cache,bool ShwKept,bool Ask, bool Safety)
         return _error->Error(_("Internal error, Ordering didn't finish"));
       return true;
    }
-   
-   // Create the text record parser
-   pkgRecords Recs(Cache);
-   if (_error->PendingError() == true)
-      return false;
-
-   // Create the download object
-   AcqTextStatus Stat(std::cout, ScreenWidth,_config->FindI("quiet",0));
-   pkgAcquire Fetcher(&Stat);
-   if (_config->FindB("APT::Get::Print-URIs", false) == true)
-   {
-      // force a hashsum for compatibility reasons
-      _config->CndSet("Acquire::ForceHash", "md5sum");
-   }
-   else if (Fetcher.GetLock(_config->FindDir("Dir::Cache::Archives")) == false)
-      return false;
-
-   // Read the source list
-   if (Cache.BuildSourceList() == false)
-      return false;
-   pkgSourceList *List = Cache.GetSourceList();
-   
-   // Create the package manager and prepare to download
-   std::unique_ptr<pkgPackageManager> PM(_system->CreatePM(Cache));
-   if (PM->GetArchives(&Fetcher,List,&Recs) == false || 
-       _error->PendingError() == true)
-      return false;
 
    // Display statistics
-   unsigned long long FetchBytes = Fetcher.FetchNeeded();
-   unsigned long long FetchPBytes = Fetcher.PartialPresent();
-   unsigned long long DebBytes = Fetcher.TotalNeeded();
+   auto const FetchBytes = Fetcher.FetchNeeded();
+   auto const FetchPBytes = Fetcher.PartialPresent();
+   auto const DebBytes = Fetcher.TotalNeeded();
    if (DebBytes != Cache->DebSize())
    {
       c0out << DebBytes << ',' << Cache->DebSize() << std::endl;
@@ -190,12 +245,22 @@ bool InstallPackages(CacheFile &Cache,bool ShwKept,bool Ask, bool Safety)
       ioprintf(c1out,_("After this operation, %sB disk space will be freed.\n"),
               SizeToStr(-1*Cache->UsrSize()).c_str());
 
-   if (_error->PendingError() == true)
+   if (CheckFreeSpaceBeforeDownload(_config->FindDir("Dir::Cache::Archives"), (FetchBytes - FetchPBytes)) == false)
       return false;
 
-   if (CheckFreeSpaceBeforeDownload(_config->FindDir("Dir::Cache::Archives"), (FetchBytes - FetchPBytes)) == false)
+   if (_error->PendingError() == true)
       return false;
 
+   // Just print out the uris an exit if the --print-uris flag was used
+   if (_config->FindB("APT::Get::Print-URIs") == true)
+   {
+      pkgAcquire::UriIterator I = Fetcher.UriBegin();
+      for (; I != Fetcher.UriEnd(); ++I)
+        std::cout << '\'' << I->URI << "' " << flNotDir(I->Owner->DestFile) << ' ' <<
+              std::to_string(I->Owner->FileSize) << ' ' << I->Owner->HashSum() << std::endl;
+      return true;
+   }
+
    if (Essential == true && Safety == true && _config->FindB("APT::Get::allow-remove-essential", false) == false)
    {
       if (_config->FindB("APT::Get::Trivial-Only",false) == true)
@@ -204,46 +269,35 @@ bool InstallPackages(CacheFile &Cache,bool ShwKept,bool Ask, bool Safety)
       // TRANSLATOR: This string needs to be typed by the user as a confirmation, so be
       //             careful with hard to type or special characters (like non-breaking spaces)
       const char *Prompt = _("Yes, do as I say!");
-      ioprintf(c2out,
+      std::string question;
+      strprintf(question,
               _("You are about to do something potentially harmful.\n"
                 "To continue type in the phrase '%s'\n"
                 " ?] "),Prompt);
-      c2out << std::flush;
-      if (AnalPrompt(Prompt) == false)
+      if (AnalPrompt(question, Prompt) == false)
       {
         c2out << _("Abort.") << std::endl;
         exit(1);
-      }     
+      }
    }
    else
-   {      
+   {
       // Prompt to continue
       if (Ask == true || Fail == true)
-      {            
+      {
         if (_config->FindB("APT::Get::Trivial-Only",false) == true)
            return _error->Error(_("Trivial Only specified but this is not a trivial operation."));
-        
+
         if (_config->FindI("quiet",0) < 2 &&
             _config->FindB("APT::Get::Assume-Yes",false) == false)
         {
-            c2out << _("Do you want to continue?") << std::flush;
-           if (YnPrompt() == false)
+           if (YnPrompt(_("Do you want to continue?")) == false)
            {
               c2out << _("Abort.") << std::endl;
               exit(1);
-           }     
-        }       
-      }      
-   }
-   
-   // Just print out the uris an exit if the --print-uris flag was used
-   if (_config->FindB("APT::Get::Print-URIs") == true)
-   {
-      pkgAcquire::UriIterator I = Fetcher.UriBegin();
-      for (; I != Fetcher.UriEnd(); ++I)
-        std::cout << '\'' << I->URI << "' " << flNotDir(I->Owner->DestFile) << ' ' <<
-              I->Owner->FileSize << ' ' << I->Owner->HashSum() << std::endl;
-      return true;
+           }
+        }
+      }
    }
 
    if (!CheckAuth(Fetcher, true))
@@ -253,46 +307,15 @@ bool InstallPackages(CacheFile &Cache,bool ShwKept,bool Ask, bool Safety)
       after. */
    if (_config->FindB("APT::Get::Download-Only",false) == true)
       _system->UnLock();
-   
+
    // Run it
+   bool Failed = false;
    while (1)
    {
       bool Transient = false;
-      if (_config->FindB("APT::Get::Download",true) == false)
-      {
-        for (pkgAcquire::ItemIterator I = Fetcher.ItemsBegin(); I < Fetcher.ItemsEnd();)
-        {
-           if ((*I)->Local == true)
-           {
-              ++I;
-              continue;
-           }
-
-           // Close the item and check if it was found in cache
-           (*I)->Finished();
-           if ((*I)->Complete == false)
-              Transient = true;
-           
-           // Clear it out of the fetch list
-           delete *I;
-           I = Fetcher.ItemsBegin();
-        }       
-      }
-
-      bool Failed = false;
       if (AcquireRun(Fetcher, 0, &Failed, &Transient) == false)
         return false;
 
-      /* If we are in no download mode and missing files and there were
-         'failures' then the user must specify -m. Furthermore, there 
-         is no such thing as a transient error in no-download mode! */
-      if (Transient == true &&
-         _config->FindB("APT::Get::Download",true) == false)
-      {
-        Transient = false;
-        Failed = true;
-      }
-      
       if (_config->FindB("APT::Get::Download-Only",false) == true)
       {
         if (Failed == true && _config->FindB("APT::Get::Fix-Missing",false) == false)
@@ -300,15 +323,13 @@ bool InstallPackages(CacheFile &Cache,bool ShwKept,bool Ask, bool Safety)
         c1out << _("Download complete and in download only mode") << std::endl;
         return true;
       }
-      
+
       if (Failed == true && _config->FindB("APT::Get::Fix-Missing",false) == false)
-      {
         return _error->Error(_("Unable to fetch some archives, maybe run apt-get update or try with --fix-missing?"));
-      }
-      
+
       if (Transient == true && Failed == true)
         return _error->Error(_("--fix-missing and media swapping is not currently supported"));
-      
+
       // Try to deal with missing package files
       if (Failed == true && PM->FixMissing() == false)
       {
@@ -316,23 +337,26 @@ bool InstallPackages(CacheFile &Cache,bool ShwKept,bool Ask, bool Safety)
         return _error->Error(_("Aborting install."));
       }
 
+      auto const progress = APT::Progress::PackageManagerProgressFactory();
       _system->UnLock();
-
-      APT::Progress::PackageManager *progress = APT::Progress::PackageManagerProgressFactory();
-      pkgPackageManager::OrderResult Res = PM->DoInstall(progress);
+      pkgPackageManager::OrderResult const Res = PM->DoInstall(progress);
       delete progress;
 
       if (Res == pkgPackageManager::Failed || _error->PendingError() == true)
         return false;
       if (Res == pkgPackageManager::Completed)
         break;
-      
+
+      _system->Lock();
+
       // Reload the fetcher object and loop again for media swapping
       Fetcher.Shutdown();
       if (PM->GetArchives(&Fetcher,List,&Recs) == false)
         return false;
-      
-      _system->Lock();
+
+      Failed = false;
+      if (_config->FindB("APT::Get::Download",true) == false)
+        RemoveDownloadNeedingItemsFromFetcher(Fetcher, Failed);
    }
 
    std::set<std::string> const disappearedPkgs = PM->GetDisappearedPackages();
@@ -348,13 +372,25 @@ bool InstallPackages(CacheFile &Cache,bool ShwKept,bool Ask, bool Safety)
       c0out << _("Note: This is done automatically and on purpose by dpkg.") << std::endl;
    }
 
+   // cleanup downloaded debs
+   if (_config->FindB("APT::Keep-Downloaded-Packages", true) == false)
+   {
+      std::string const archivedir = _config->FindDir("Dir::Cache::archives");
+      for (auto I = Fetcher.ItemsBegin(); I != Fetcher.ItemsEnd(); ++I)
+      {
+        if (flNotFile((*I)->DestFile) != archivedir || (*I)->Local)
+           continue;
+         RemoveFile("Keep-Downloaded-Packages=false", (*I)->DestFile);
+      }
+   }
+
    return true;
 }
                                                                        /*}}}*/
 // DoAutomaticRemove - Remove all automatic unused packages            /*{{{*/
 // ---------------------------------------------------------------------
 /* Remove unused automatic packages */
-static bool DoAutomaticRemove(CacheFile &Cache)
+bool DoAutomaticRemove(CacheFile &Cache)
 {
    bool Debug = _config->FindI("Debug::pkgAutoRemove",false);
    bool doAutoRemove = _config->FindB("APT::Get::AutomaticRemove", false);
@@ -402,8 +438,7 @@ static bool DoAutomaticRemove(CacheFile &Cache)
            // install it in the first place, so nuke it instead of show it
            if (Cache[Pkg].Install() == true && Pkg.CurrentVer() == 0)
            {
-              if (Pkg.CandVersion() != 0)
-                 tooMuch.insert(Pkg);
+              tooMuch.insert(Pkg);
               Cache->MarkDelete(Pkg, false, 0, false);
            }
            // only show stuff in the list that is not yet marked for removal
@@ -440,7 +475,7 @@ static bool DoAutomaticRemove(CacheFile &Cache)
                 if (N.end() == true || (N->CurrentVer == 0 && (*Cache)[N].Install() == false))
                    continue;
                 if (Debug == true)
-                   std::clog << "Save " << Pkg << " as another installed garbage package depends on it" << std::endl;
+                   std::clog << "Save " << APT::PrettyPkg(Cache, Pkg) << " as another installed garbage package depends on it" << std::endl;
                 Cache->MarkInstall(Pkg, false, 0, false);
                 if (hideAutoRemove == false)
                    ++autoRemoveCount;
@@ -485,7 +520,16 @@ static bool DoAutomaticRemove(CacheFile &Cache)
       else
         ioprintf(c1out, P_("%lu package was automatically installed and is no longer required.\n",
                  "%lu packages were automatically installed and are no longer required.\n", autoRemoveCount), autoRemoveCount);
-      c1out << P_("Use 'apt-get autoremove' to remove it.", "Use 'apt-get autoremove' to remove them.", autoRemoveCount) << std::endl;
+      std::string autocmd = "apt autoremove";
+      if (getenv("SUDO_USER") != nullptr)
+      {
+        auto const envsudocmd = getenv("SUDO_COMMAND");
+        auto const envshell = getenv("SHELL");
+        if (envsudocmd == nullptr || envshell == nullptr || strcmp(envsudocmd, envshell) != 0)
+           autocmd = "sudo " + autocmd;
+      }
+      ioprintf(c1out, P_("Use '%s' to remove it.", "Use '%s' to remove them.", autoRemoveCount), autocmd.c_str());
+      c1out << std::endl;
    }
    return true;
 }
@@ -495,11 +539,16 @@ static const unsigned short MOD_REMOVE = 1;
 static const unsigned short MOD_INSTALL = 2;
 
 bool DoCacheManipulationFromCommandLine(CommandLine &CmdL, CacheFile &Cache, int UpgradeMode)
+{
+   std::vector<std::string> VolatileCmdL;
+   return DoCacheManipulationFromCommandLine(CmdL, VolatileCmdL, Cache, UpgradeMode);
+}
+bool DoCacheManipulationFromCommandLine(CommandLine &CmdL, std::vector<std::string> &VolatileCmdL, CacheFile &Cache, int UpgradeMode)
 {
    std::map<unsigned short, APT::VersionSet> verset;
-   return DoCacheManipulationFromCommandLine(CmdL, Cache, verset, UpgradeMode);
+   return DoCacheManipulationFromCommandLine(CmdL, VolatileCmdL, Cache, verset, UpgradeMode);
 }
-bool DoCacheManipulationFromCommandLine(CommandLine &CmdL, CacheFile &Cache,
+bool DoCacheManipulationFromCommandLine(CommandLine &CmdL, std::vector<std::string> &VolatileCmdL, CacheFile &Cache,
                                         std::map<unsigned short, APT::VersionSet> &verset, int UpgradeMode)
 {
    // Enter the special broken fixing mode if the user specified arguments
@@ -535,6 +584,20 @@ bool DoCacheManipulationFromCommandLine(CommandLine &CmdL, CacheFile &Cache,
    verset = APT::VersionSet::GroupedFromCommandLine(Cache,
                CmdL.FileList + 1, mods, fallback, helper);
 
+   for (auto const &I: VolatileCmdL)
+   {
+      pkgCache::PkgIterator const P = Cache->FindPkg(I);
+      if (P.end())
+        continue;
+
+      // Set any version providing the .deb as the candidate.
+      for (auto Prv = P.ProvidesList(); Prv.end() == false; Prv++)
+        Cache.GetDepCache()->SetCandidateVersion(Prv.OwnerVer());
+
+      // via cacheset to have our usual virtual handling
+      APT::VersionContainerInterface::FromPackage(&(verset[MOD_INSTALL]), Cache, P, APT::CacheSetHelper::CANDIDATE, helper);
+   }
+
    if (_error->PendingError() == true)
    {
       helper.showVirtualPackageErrors(Cache);
@@ -595,33 +658,8 @@ bool DoCacheManipulationFromCommandLine(CommandLine &CmdL, CacheFile &Cache,
            return false;
       }
 
-      // 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.") << std::endl;
-        /*
-        if (Packages == 1)
-        {
-           c1out << std::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.") << std::endl;
-        }
-        */
-
-        c1out << _("The following information may help to resolve the situation:") << std::endl;
-        c1out << std::endl;
-        ShowBroken(c1out,Cache,false);
-        if (_error->PendingError() == true)
-           return false;
-        else
-           return _error->Error(_("Broken packages"));
-      }
+      if (CheckNothingBroken(Cache) == false)
+        return false;
    }
    if (!DoAutomaticRemove(Cache)) 
       return false;
@@ -645,7 +683,7 @@ struct PkgIsExtraInstalled {
    pkgCacheFile * const Cache;
    APT::VersionSet const * const verset;
    PkgIsExtraInstalled(pkgCacheFile * const Cache, APT::VersionSet const * const Container) : Cache(Cache), verset(Container) {}
-   bool operator() (pkgCache::PkgIterator const Pkg)
+   bool operator() (pkgCache::PkgIterator const &Pkg)
    {
         if ((*Cache)[Pkg].Install() == false)
            return false;
@@ -656,33 +694,16 @@ struct PkgIsExtraInstalled {
 bool DoInstall(CommandLine &CmdL)
 {
    CacheFile Cache;
-   // first check for local pkgs and add them to the cache
-   for (const char **I = CmdL.FileList; *I != 0; I++)
-   {
-      if(FileExists(*I) && flExtension(*I) == "deb")
-        Cache.GetSourceList()->AddVolatileFile(new debDebPkgFileIndex(*I));
-   }
+   std::vector<std::string> VolatileCmdL;
+   Cache.GetSourceList()->AddVolatileFiles(CmdL, &VolatileCmdL);
 
    // then open the cache
    if (Cache.OpenForInstall() == false || 
        Cache.CheckDeps(CmdL.FileSize() != 1) == false)
       return false;
-   
-   std::map<unsigned short, APT::VersionSet> verset;
-
-   for (const char **I = CmdL.FileList; *I != 0; I++) {
-      // Check for local pkgs like in the loop above.
-      if(!FileExists(*I) || flExtension(*I) != "deb")
-        continue;
-
-      pkgCache::PkgIterator pkg = Cache->FindPkg(*I);
-
-      // Set any version providing the .deb as the candidate.
-      for (auto Prv = pkg.ProvidesList(); Prv.end() == false; Prv++)
-        Cache.GetDepCache()->SetCandidateVersion(Prv.OwnerVer());
-   }
 
-   if(!DoCacheManipulationFromCommandLine(CmdL, Cache, verset, 0))
+   std::map<unsigned short, APT::VersionSet> verset;
+   if(!DoCacheManipulationFromCommandLine(CmdL, VolatileCmdL, Cache, verset, 0))
       return false;
 
    /* Print out a list of packages that are going to be installed extra
@@ -795,7 +816,17 @@ bool DoInstall(CommandLine &CmdL)
 
 // TryToInstall - Mark a package for installation                      /*{{{*/
 void TryToInstall::operator() (pkgCache::VerIterator const &Ver) {
+   if (unlikely(Ver.end()))
+   {
+      _error->Fatal("The given version to TryToInstall is invalid!");
+      return;
+   }
    pkgCache::PkgIterator Pkg = Ver.ParentPkg();
+   if (unlikely(Pkg.end()))
+   {
+      _error->Fatal("The given version to TryToInstall has an invalid parent package!");
+      return;
+   }
 
    Cache->GetDepCache()->SetCandidateVersion(Ver);
    pkgDepCache::StateCache &State = (*Cache)[Pkg];