X-Git-Url: https://git.saurik.com/apt.git/blobdiff_plain/dca1e241d1160635329c87ec987c47717bfce4a8..fff4b7f30be7fece23ecf8cead675fad9f830eb1:/cmdline/apt-get.cc diff --git a/cmdline/apt-get.cc b/cmdline/apt-get.cc index 0706d1c74..05d408f42 100644 --- a/cmdline/apt-get.cc +++ b/cmdline/apt-get.cc @@ -1,6 +1,6 @@ // -*- mode: cpp; mode: fold -*- // Description /*{{{*/ -// $Id: apt-get.cc,v 1.86 1999/10/27 05:00:25 jgg Exp $ +// $Id: apt-get.cc,v 1.126 2003/02/12 16:14:08 doogie Exp $ /* ###################################################################### apt-get - Cover for dpkg @@ -32,22 +32,25 @@ #include #include #include -#include #include #include #include #include #include - +#include +#include + #include +#include #include "acqprogress.h" -#include +#include +#include #include #include #include -#include +#include #include #include #include @@ -56,9 +59,11 @@ #include /*}}}*/ -ostream c0out; -ostream c1out; -ostream c2out; +using namespace std; + +ostream c0out(0); +ostream c1out(0); +ostream c2out(0); ofstream devnull("/dev/null"); unsigned int ScreenWidth = 80; @@ -75,14 +80,29 @@ class CacheFile : public pkgCacheFile void Sort(); bool CheckDeps(bool AllowBroken = false); + bool BuildCaches(bool WithLock = true) + { + OpTextProgress Prog(*_config); + if (pkgCacheFile::BuildCaches(Prog,WithLock) == false) + return false; + return true; + } bool Open(bool WithLock = true) { OpTextProgress Prog(*_config); if (pkgCacheFile::Open(Prog,WithLock) == false) return false; Sort(); + return true; }; + bool OpenForInstall() + { + if (_config->FindB("APT::Get::Print-URIs") == true) + return Open(false); + else + return Open(true); + } CacheFile() : List(0) {}; }; /*}}}*/ @@ -92,18 +112,24 @@ class CacheFile : public pkgCacheFile /* Returns true on a Yes.*/ bool YnPrompt() { + // This needs to be a capital + const char *Yes = _("Y"); + if (_config->FindB("APT::Get::Assume-Yes",false) == true) { - c1out << 'Y' << endl; + c1out << Yes << 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 (read(STDIN_FILENO,&C,1) != 1) + return false; + while (C != '\n' && Jnk != '\n') + if (read(STDIN_FILENO,&Jnk,1) != 1) + return false; - if (!(C == 'Y' || C == 'y' || C == '\n' || C == '\r')) + if (!(toupper(C) == *Yes || C == '\n' || C == '\r')) return false; return true; } @@ -122,12 +148,20 @@ bool AnalPrompt(const char *Text) /*}}}*/ // ShowList - Show a list /*{{{*/ // --------------------------------------------------------------------- -/* This prints out a string of space seperated words with a title and +/* This prints out a string of space separated words with a title and a two space indent line wraped to the current screen width. */ bool ShowList(ostream &out,string Title,string List) { if (List.empty() == true) return true; + // trim trailing space + int NonSpace = List.find_last_not_of(' '); + if (NonSpace != -1) + { + List = List.erase(NonSpace + 1); + if (List.empty() == true) + return true; + } // Acount for the leading space int ScreenWidth = ::ScreenWidth - 3; @@ -154,38 +188,70 @@ bool ShowList(ostream &out,string Title,string List) // --------------------------------------------------------------------- /* This prints out the names of all the packages that are broken along with the name of each each broken dependency and a quite version - description. */ + description. + + The output looks like: + The following packages have unmet dependencies: + exim: Depends: libc6 (>= 2.1.94) but 2.1.3-10 is to be installed + Depends: libldap2 (>= 2.0.2-2) but it is not going to be installed + Depends: libsasl7 but it is not going to be installed + */ void ShowBroken(ostream &out,CacheFile &Cache,bool Now) { - out << "Sorry, but the following packages have unmet dependencies:" << endl; + out << _("The following packages have unmet dependencies:") << endl; for (unsigned J = 0; J < Cache->Head().PackageCount; J++) { pkgCache::PkgIterator I(Cache,Cache.List[J]); - if (Cache[I].InstBroken() == false) - continue; - + if (Now == true) + { + if (Cache[I].NowBroken() == false) + continue; + } + else + { + if (Cache[I].InstBroken() == false) + continue; + } + // Print out each package and the failed dependencies out <<" " << I.Name() << ":"; unsigned Indent = strlen(I.Name()) + 3; bool First = true; - if (Cache[I].InstVerIter(Cache).end() == true) + pkgCache::VerIterator Ver; + + if (Now == true) + Ver = I.CurrentVer(); + else + Ver = Cache[I].InstVerIter(Cache); + + if (Ver.end() == true) { - cout << endl; + out << endl; continue; } - for (pkgCache::DepIterator D = Cache[I].InstVerIter(Cache).DependsList(); D.end() == false;) + for (pkgCache::DepIterator D = Ver.DependsList(); D.end() == false;) { // 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) + if (Cache->IsImportantDep(End) == false) continue; - + + if (Now == true) + { + if ((Cache[End] & pkgDepCache::DepGNow) == pkgDepCache::DepGNow) + continue; + } + else + { + if ((Cache[End] & pkgDepCache::DepGInstall) == pkgDepCache::DepGInstall) + continue; + } + bool FirstOr = true; while (1) { @@ -207,34 +273,41 @@ void ShowBroken(ostream &out,CacheFile &Cache,bool Now) // Show a quick summary of the version requirements if (Start.TargetVer() != 0) - out << " (" << Start.CompType() << " " << Start.TargetVer() << - ")"; + out << " (" << Start.CompType() << " " << Start.TargetVer() << ")"; /* Show a summary of the target package if possible. In the case of virtual packages we show nothing */ pkgCache::PkgIterator Targ = Start.TargetPkg(); if (Targ->ProvidesList == 0) { - out << " but "; + out << ' '; pkgCache::VerIterator Ver = Cache[Targ].InstVerIter(Cache); + if (Now == true) + Ver = Targ.CurrentVer(); + if (Ver.end() == false) - out << Ver.VerStr() << (Now?" is installed":" is to be installed"); + { + if (Now == true) + ioprintf(out,_("but %s is installed"),Ver.VerStr()); + else + ioprintf(out,_("but %s is to be installed"),Ver.VerStr()); + } else { if (Cache[Targ].CandidateVerIter(Cache).end() == true) { if (Targ->ProvidesList == 0) - out << "it is not installable"; + out << _("but it is not installable"); else - out << "it is a virtual package"; + out << _("but it is a virtual package"); } else - out << (Now?"it is not installed":"it is not going to be installed"); + out << (Now?_("but it is not installed"):_("but it is not going to be installed")); } } if (Start != End) - cout << " or"; + out << _(" or"); out << endl; if (Start == End) @@ -260,7 +333,7 @@ void ShowNew(ostream &out,CacheFile &Cache) List += string(I.Name()) + " "; } - ShowList(out,"The following NEW packages will be installed:",List); + ShowList(out,_("The following NEW packages will be installed:"),List); } /*}}}*/ // ShowDel - Show packages to delete /*{{{*/ @@ -283,7 +356,7 @@ void ShowDel(ostream &out,CacheFile &Cache) } } - ShowList(out,"The following packages will be REMOVED:",List); + ShowList(out,_("The following packages will be REMOVED:"),List); } /*}}}*/ // ShowKept - Show kept packages /*{{{*/ @@ -303,7 +376,7 @@ void ShowKept(ostream &out,CacheFile &Cache) List += string(I.Name()) + " "; } - ShowList(out,"The following packages have been kept back",List); + ShowList(out,_("The following packages have been kept back"),List); } /*}}}*/ // ShowUpgraded - Show upgraded packages /*{{{*/ @@ -322,7 +395,26 @@ void ShowUpgraded(ostream &out,CacheFile &Cache) List += string(I.Name()) + " "; } - ShowList(out,"The following packages will be upgraded",List); + ShowList(out,_("The following packages will be upgraded"),List); +} + /*}}}*/ +// ShowDowngraded - Show downgraded packages /*{{{*/ +// --------------------------------------------------------------------- +/* */ +bool ShowDowngraded(ostream &out,CacheFile &Cache) +{ + string List; + for (unsigned J = 0; J < Cache->Head().PackageCount; J++) + { + pkgCache::PkgIterator I(Cache,Cache.List[J]); + + // Not interesting + if (Cache[I].Downgrade() == false || Cache[I].NewInstall() == true) + continue; + + List += string(I.Name()) + " "; + } + return ShowList(out,_("The following packages will be DOWNGRADED"),List); } /*}}}*/ // ShowHold - Show held but changed packages /*{{{*/ @@ -339,7 +431,7 @@ bool ShowHold(ostream &out,CacheFile &Cache) List += string(I.Name()) + " "; } - return ShowList(out,"The following held packages will be changed:",List); + return ShowList(out,_("The following held packages will be changed:"),List); } /*}}}*/ // ShowEssential - Show an essential package warning /*{{{*/ @@ -350,14 +442,15 @@ bool ShowHold(ostream &out,CacheFile &Cache) bool ShowEssential(ostream &out,CacheFile &Cache) { string List; - bool *Added = new bool[Cache->HeaderP->PackageCount]; - for (unsigned int I = 0; I != Cache->HeaderP->PackageCount; I++) + bool *Added = new bool[Cache->Head().PackageCount]; + for (unsigned int I = 0; I != Cache->Head().PackageCount; I++) Added[I] = false; for (unsigned J = 0; J < Cache->Head().PackageCount; J++) { pkgCache::PkgIterator I(Cache,Cache.List[J]); - if ((I->Flags & pkgCache::Flag::Essential) != pkgCache::Flag::Essential) + if ((I->Flags & pkgCache::Flag::Essential) != pkgCache::Flag::Essential && + (I->Flags & pkgCache::Flag::Important) != pkgCache::Flag::Important) continue; // The essential package is being removed @@ -374,7 +467,7 @@ bool ShowEssential(ostream &out,CacheFile &Cache) continue; // Print out any essential package depenendents that are to be removed - for (pkgDepCache::DepIterator D = I.CurrentVer().DependsList(); D.end() == false; D++) + for (pkgCache::DepIterator D = I.CurrentVer().DependsList(); D.end() == false; D++) { // Skip everything but depends if (D->Type != pkgCache::Dep::PreDepends && @@ -389,16 +482,15 @@ bool ShowEssential(ostream &out,CacheFile &Cache) Added[P->ID] = true; char S[300]; - sprintf(S,"%s (due to %s) ",P.Name(),I.Name()); + snprintf(S,sizeof(S),_("%s (due to %s) "),P.Name(),I.Name()); List += S; } } } delete [] Added; - if (List.empty() == false) - out << "WARNING: The following essential packages will be removed" << endl; - return ShowList(out,"This should NOT be done unless you know exactly what you are doing!",List); + 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); } /*}}}*/ // Stats - Show some statistics /*{{{*/ @@ -407,6 +499,7 @@ bool ShowEssential(ostream &out,CacheFile &Cache) void Stats(ostream &out,pkgDepCache &Dep) { unsigned long Upgrade = 0; + unsigned long Downgrade = 0; unsigned long Install = 0; unsigned long ReInstall = 0; for (pkgCache::PkgIterator I = Dep.PkgBegin(); I.end() == false; I++) @@ -414,21 +507,32 @@ void Stats(ostream &out,pkgDepCache &Dep) if (Dep[I].NewInstall() == true) Install++; else + { if (Dep[I].Upgrade() == true) Upgrade++; + else + if (Dep[I].Downgrade() == true) + Downgrade++; + } + if (Dep[I].Delete() == false && (Dep[I].iFlags & pkgDepCache::ReInstall) == pkgDepCache::ReInstall) ReInstall++; } - out << Upgrade << " packages upgraded, " << - Install << " newly installed, "; + ioprintf(out,_("%lu packages upgraded, %lu newly installed, "), + Upgrade,Install); + if (ReInstall != 0) - out << ReInstall << " reinstalled, "; - out << Dep.DelCount() << " to remove and " << - Dep.KeepCount() << " not upgraded." << endl; + ioprintf(out,_("%lu reinstalled, "),ReInstall); + if (Downgrade != 0) + ioprintf(out,_("%lu downgraded, "),Downgrade); + ioprintf(out,_("%lu to remove and %lu not upgraded.\n"), + Dep.DelCount(),Dep.KeepCount()); + if (Dep.BadCount() != 0) - out << Dep.BadCount() << " packages not fully installed or removed." << endl; + ioprintf(out,_("%lu packages not fully installed or removed.\n"), + Dep.BadCount()); } /*}}}*/ @@ -463,7 +567,7 @@ void CacheFile::Sort() qsort(List,Cache->Head().PackageCount,sizeof(*List),NameComp); } /*}}}*/ -// CacheFile::Open - Open the cache file /*{{{*/ +// CacheFile::CheckDeps - Open the cache file /*{{{*/ // --------------------------------------------------------------------- /* This routine generates the caches and then opens the dependency cache and verifies that the system is OK. */ @@ -473,39 +577,39 @@ bool CacheFile::CheckDeps(bool AllowBroken) return false; // Check that the system is OK - if (Cache->DelCount() != 0 || Cache->InstCount() != 0) + if (DCache->DelCount() != 0 || DCache->InstCount() != 0) return _error->Error("Internal Error, non-zero counts"); // Apply corrections for half-installed packages - if (pkgApplyStatus(*Cache) == false) + if (pkgApplyStatus(*DCache) == false) return false; // Nothing is broken - if (Cache->BrokenCount() == 0 || AllowBroken == true) + if (DCache->BrokenCount() == 0 || AllowBroken == true) return true; // Attempt to fix broken things if (_config->FindB("APT::Get::Fix-Broken",false) == true) { - c1out << "Correcting dependencies..." << flush; - if (pkgFixBroken(*Cache) == false || Cache->BrokenCount() != 0) + c1out << _("Correcting dependencies...") << flush; + if (pkgFixBroken(*DCache) == false || DCache->BrokenCount() != 0) { - c1out << " failed." << endl; + c1out << _(" failed.") << endl; ShowBroken(c1out,*this,true); - return _error->Error("Unable to correct dependencies"); + return _error->Error(_("Unable to correct dependencies")); } - if (pkgMinimizeUpgrade(*Cache) == false) - return _error->Error("Unable to minimize the upgrade set"); + if (pkgMinimizeUpgrade(*DCache) == false) + return _error->Error(_("Unable to minimize the upgrade set")); - c1out << " Done" << endl; + c1out << _(" Done") << endl; } else { - c1out << "You might want to run `apt-get -f install' to correct these." << endl; + c1out << _("You might want to run `apt-get -f install' to correct these.") << endl; ShowBroken(c1out,*this,true); - return _error->Error("Unmet dependencies. Try using -f."); + return _error->Error(_("Unmet dependencies. Try using -f.")); } return true; @@ -516,7 +620,8 @@ bool CacheFile::CheckDeps(bool AllowBroken) // --------------------------------------------------------------------- /* 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 = true,bool Saftey = true) +bool InstallPackages(CacheFile &Cache,bool ShwKept,bool Ask = true, + bool Saftey = true) { if (_config->FindB("APT::Get::Purge",false) == true) { @@ -539,6 +644,7 @@ bool InstallPackages(CacheFile &Cache,bool ShwKept,bool Ask = true,bool Saftey = Fail |= !ShowHold(c1out,Cache); if (_config->FindB("APT::Get::Show-Upgraded",false) == true) ShowUpgraded(c1out,Cache); + Fail |= !ShowDowngraded(c1out,Cache); Essential = !ShowEssential(c1out,Cache); Fail |= Essential; Stats(c1out,Cache); @@ -554,6 +660,10 @@ bool InstallPackages(CacheFile &Cache,bool ShwKept,bool Ask = true,bool Saftey = Cache->BadCount() == 0) return 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.")); + // Run the simulator .. if (_config->FindB("APT::Get::Simulate") == true) { @@ -573,11 +683,12 @@ bool InstallPackages(CacheFile &Cache,bool ShwKept,bool Ask = true,bool Saftey = // Lock the archive directory FileFd Lock; - if (_config->FindB("Debug::NoLocking",false) == false) + if (_config->FindB("Debug::NoLocking",false) == false && + _config->FindB("APT::Get::Print-URIs") == false) { Lock.Fd(GetLock(_config->FindDir("Dir::Cache::Archives") + "lock")); if (_error->PendingError() == true) - return _error->Error("Unable to lock the download directory"); + return _error->Error(_("Unable to lock the download directory")); } // Create the download object @@ -587,18 +698,18 @@ bool InstallPackages(CacheFile &Cache,bool ShwKept,bool Ask = true,bool Saftey = // Read the source list pkgSourceList List; if (List.ReadMainList() == false) - return _error->Error("The list of sources could not be read."); + 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 || + SPtr PM= _system->CreatePM(Cache); + if (PM->GetArchives(&Fetcher,&List,&Recs) == false || _error->PendingError() == true) return false; // Display statistics - unsigned long FetchBytes = Fetcher.FetchNeeded(); - unsigned long FetchPBytes = Fetcher.PartialPresent(); - unsigned long DebBytes = Fetcher.TotalNeeded(); + double FetchBytes = Fetcher.FetchNeeded(); + double FetchPBytes = Fetcher.PartialPresent(); + double DebBytes = Fetcher.TotalNeeded(); if (DebBytes != Cache->DebSize()) { c0out << DebBytes << ',' << Cache->DebSize() << endl; @@ -606,65 +717,80 @@ bool InstallPackages(CacheFile &Cache,bool ShwKept,bool Ask = true,bool Saftey = } // Number of bytes - c1out << "Need to get "; if (DebBytes != FetchBytes) - c1out << SizeToStr(FetchBytes) << "B/" << SizeToStr(DebBytes) << 'B'; + ioprintf(c1out,_("Need to get %sB/%sB of archives.\n"), + SizeToStr(FetchBytes).c_str(),SizeToStr(DebBytes).c_str()); else - c1out << SizeToStr(DebBytes) << 'B'; - - c1out << " of archives. After unpacking "; + ioprintf(c1out,_("Need to get %sB of archives.\n"), + SizeToStr(DebBytes).c_str()); - // Check for enough free space - struct statfs Buf; - string OutputDir = _config->FindDir("Dir::Cache::Archives"); - if (statfs(OutputDir.c_str(),&Buf) != 0) - return _error->Errno("statfs","Couldn't determine free space in %s", - OutputDir.c_str()); - if (unsigned(Buf.f_bfree) < (FetchBytes - FetchPBytes)/Buf.f_bsize) - return _error->Error("Sorry, you don't have enough free space in %s to hold all the .debs.", - OutputDir.c_str()); - // Size delta if (Cache->UsrSize() >= 0) - c1out << SizeToStr(Cache->UsrSize()) << "B will be used." << endl; + ioprintf(c1out,_("After unpacking %sB of additional disk space will be used.\n"), + SizeToStr(Cache->UsrSize()).c_str()); else - c1out << SizeToStr(-1*Cache->UsrSize()) << "B will be freed." << endl; + ioprintf(c1out,_("After unpacking %sB disk space will be freed.\n"), + SizeToStr(-1*Cache->UsrSize()).c_str()); if (_error->PendingError() == true) return false; + /* Check for enough free space, but only if we are actually going to + download */ + if (_config->FindB("APT::Get::Print-URIs") == false && + _config->FindB("APT::Get::Download",true) == 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", + 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."), + OutputDir.c_str()); + } + // Fail safe check if (_config->FindI("quiet",0) >= 2 || _config->FindB("APT::Get::Assume-Yes",false) == true) { if (Fail == true && _config->FindB("APT::Get::Force-Yes",false) == false) - return _error->Error("There are problems and -y was used without --force-yes"); + return _error->Error(_("There are problems and -y was used without --force-yes")); } if (Essential == true && Saftey == true) { - c2out << "You are about to do something potentially harmful" << endl; - c2out << "To continue type in the phrase 'Yes, I understand this may be bad'" << endl; - c2out << " ?] " << flush; - if (AnalPrompt("Yes, I understand this may be bad") == false) + if (_config->FindB("APT::Get::Trivial-Only",false) == true) + return _error->Error(_("Trivial Only specified but this is not a trivial operation.")); + + const char *Prompt = _("Yes, do as I say!"); + ioprintf(c2out, + _("You are about to do something potentially harmful\n" + "To continue type in the phrase '%s'\n" + " ?] "),Prompt); + c2out << flush; + if (AnalPrompt(Prompt) == false) { - c2out << "Abort." << endl; + c2out << _("Abort.") << 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? [Y/n] " << flush; + c2out << _("Do you want to continue? [Y/n] ") << flush; if (YnPrompt() == false) { - c2out << "Abort." << endl; + c2out << _("Abort.") << endl; exit(1); } } @@ -680,18 +806,43 @@ bool InstallPackages(CacheFile &Cache,bool ShwKept,bool Ask = true,bool Saftey = I->Owner->FileSize << ' ' << I->Owner->MD5Sum() << endl; return true; } + + /* Unlock the dpkg lock if we are not going to be doing an install + after. */ + if (_config->FindB("APT::Get::Download-Only",false) == true) + _system->UnLock(); // Run it while (1) { - if (_config->FindB("APT::Get::No-Download",false) == false) - if (Fetcher.Run() == pkgAcquire::Failed) - return false; + 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(); + } + } + + if (Fetcher.Run() == pkgAcquire::Failed) + return false; // Print out errors bool Failed = false; - bool Transient = false; - for (pkgAcquire::Item **I = Fetcher.ItemsBegin(); I != Fetcher.ItemsEnd(); I++) + for (pkgAcquire::ItemIterator I = Fetcher.ItemsBegin(); I != Fetcher.ItemsEnd(); I++) { if ((*I)->Status == pkgAcquire::Item::StatDone && (*I)->Complete == true) @@ -703,17 +854,17 @@ bool InstallPackages(CacheFile &Cache,bool ShwKept,bool Ask = true,bool Saftey = // Failed = true; continue; } - - cerr << "Failed to fetch " << (*I)->DescURI() << endl; - cerr << " " << (*I)->ErrorText << endl; + + fprintf(stderr,_("Failed to fetch %s %s\n"),(*I)->DescURI().c_str(), + (*I)->ErrorText.c_str()); Failed = true; } - /* If we are in no download mode and missing files then there were + /* 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::No-Download",false) == true) + if (Transient == true && + _config->FindB("APT::Get::Download",true) == false) { Transient = false; Failed = true; @@ -722,27 +873,28 @@ bool InstallPackages(CacheFile &Cache,bool ShwKept,bool Ask = true,bool Saftey = if (_config->FindB("APT::Get::Download-Only",false) == true) { if (Failed == true && _config->FindB("APT::Get::Fix-Missing",false) == false) - return _error->Error("Some files failed to download"); + return _error->Error(_("Some files failed to download")); + c1out << _("Download complete and in download only mode") << endl; return true; } if (Failed == true && _config->FindB("APT::Get::Fix-Missing",false) == false) { - return _error->Error("Unable to fetch some archives, maybe try with --fix-missing?"); + 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"); + 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) + if (Failed == true && PM->FixMissing() == false) { - cerr << "Unable to correct missing packages." << endl; - return _error->Error("Aborting Install."); + cerr << _("Unable to correct missing packages.") << endl; + return _error->Error(_("Aborting Install.")); } - - Cache.ReleaseLock(); - pkgPackageManager::OrderResult Res = PM.DoInstall(); + + _system->UnLock(); + pkgPackageManager::OrderResult Res = PM->DoInstall(); if (Res == pkgPackageManager::Failed || _error->PendingError() == true) return false; if (Res == pkgPackageManager::Completed) @@ -750,8 +902,10 @@ bool InstallPackages(CacheFile &Cache,bool ShwKept,bool Ask = true,bool Saftey = // Reload the fetcher object and loop again for media swapping Fetcher.Shutdown(); - if (PM.GetArchives(&Fetcher,&List,&Recs) == false) + if (PM->GetArchives(&Fetcher,&List,&Recs) == false) return false; + + _system->Lock(); } } /*}}}*/ @@ -769,29 +923,47 @@ bool TryToInstall(pkgCache::PkgIterator Pkg,pkgDepCache &Cache, Pkg.ProvidesList()->NextProvides == 0) { pkgCache::PkgIterator Tmp = Pkg.ProvidesList().OwnerPkg(); - c1out << "Note, installing " << Tmp.Name() << " instead of " << Pkg.Name() << endl; + ioprintf(c1out,_("Note, selecting %s instead of %s\n"), + Tmp.Name(),Pkg.Name()); Pkg = Tmp; } // Handle the no-upgrade case - if (_config->FindB("APT::Get::no-upgrade",false) == true && + if (_config->FindB("APT::Get::upgrade",true) == false && Pkg->CurrentVer != 0) { if (AllowFail == true) - c1out << "Skipping " << Pkg.Name() << ", it is already installed and no-upgrade is set." << endl; + ioprintf(c1out,_("Skipping %s, it is already installed and upgrade is not set.\n"), + Pkg.Name()); return true; } // Check if there is something at all to install pkgDepCache::StateCache &State = Cache[Pkg]; - if (State.CandidateVer == 0) + if (Remove == true && Pkg->CurrentVer == 0) + { + Fix.Clear(Pkg); + Fix.Protect(Pkg); + Fix.Remove(Pkg); + + /* We want to continue searching for regex hits, so we return false here + otherwise this is not really an error. */ + if (AllowFail == false) + return false; + + ioprintf(c1out,_("Package %s is not installed, so not removed\n"),Pkg.Name()); + return true; + } + + if (State.CandidateVer == 0 && Remove == false) { if (AllowFail == false) return false; if (Pkg->ProvidesList != 0) { - c1out << "Package " << Pkg.Name() << " is a virtual package provided by:" << endl; + ioprintf(c1out,_("Package %s is a virtual package provided by:\n"), + Pkg.Name()); pkgCache::PrvIterator I = Pkg.ProvidesList(); for (; I.end() == false; I++) @@ -802,37 +974,43 @@ bool TryToInstall(pkgCache::PkgIterator Pkg,pkgDepCache &Cache, { if (Cache[Pkg].Install() == true && Cache[Pkg].NewInstall() == false) c1out << " " << Pkg.Name() << " " << I.OwnerVer().VerStr() << - " [Installed]"<< endl; + _(" [Installed]") << endl; else c1out << " " << Pkg.Name() << " " << I.OwnerVer().VerStr() << endl; } } - c1out << "You should explicitly select one to install." << endl; + c1out << _("You should explicitly select one to install.") << endl; } else { - c1out << "Package " << Pkg.Name() << " 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, has been obsoleted or is not available with the contents " << endl; - c1out << "of sources.list" << endl; + ioprintf(c1out, + _("Package %s has no available version, but exists in the database.\n" + "This typically means that the package was mentioned in a dependency and\n" + "never uploaded, has been obsoleted or is not available with the contents\n" + "of sources.list\n"),Pkg.Name()); string List; + SPtrArray Seen = new bool[Cache.Head().PackageCount]; + memset(Seen,0,Cache.Head().PackageCount*sizeof(*Seen)); pkgCache::DepIterator Dep = Pkg.RevDependsList(); for (; Dep.end() == false; Dep++) { if (Dep->Type != pkgCache::Dep::Replaces) continue; + if (Seen[Dep.ParentPkg()->ID] == true) + continue; + Seen[Dep.ParentPkg()->ID] = true; List += string(Dep.ParentPkg().Name()) + " "; } - ShowList(c1out,"However the following packages replace it:",List); + ShowList(c1out,_("However the following packages replace it:"),List); } - _error->Error("Package %s has no installation candidate",Pkg.Name()); + _error->Error(_("Package %s has no installation candidate"),Pkg.Name()); return false; } Fix.Clear(Pkg); - Fix.Protect(Pkg); + Fix.Protect(Pkg); if (Remove == true) { Fix.Remove(Pkg); @@ -847,14 +1025,16 @@ bool TryToInstall(pkgCache::PkgIterator Pkg,pkgDepCache &Cache, if (_config->FindB("APT::Get::ReInstall",false) == true) { if (Pkg->CurrentVer == 0 || Pkg.CurrentVer().Downloadable() == false) - c1out << "Sorry, re-installation of " << Pkg.Name() << " is not possible, it cannot be downloaded" << endl; + ioprintf(c1out,_("Reinstallation of %s is not possible, it cannot be downloaded.\n"), + Pkg.Name()); else Cache.SetReInstall(Pkg,true); } else { if (AllowFail == true) - c1out << "Sorry, " << Pkg.Name() << " is already the newest version" << endl; + ioprintf(c1out,_("%s is already the newest version.\n"), + Pkg.Name()); } } else @@ -866,12 +1046,140 @@ bool TryToInstall(pkgCache::PkgIterator Pkg,pkgDepCache &Cache, return true; } /*}}}*/ +// TryToChangeVer - Try to change a candidate version /*{{{*/ +// --------------------------------------------------------------------- +/* */ +bool TryToChangeVer(pkgCache::PkgIterator Pkg,pkgDepCache &Cache, + const char *VerTag,bool IsRel) +{ + pkgVersionMatch Match(VerTag,(IsRel == true?pkgVersionMatch::Release : + pkgVersionMatch::Version)); + + pkgCache::VerIterator Ver = Match.Find(Pkg); + + if (Ver.end() == true) + { + if (IsRel == true) + return _error->Error(_("Release '%s' for '%s' was not found"), + VerTag,Pkg.Name()); + return _error->Error(_("Version '%s' for '%s' was not found"), + VerTag,Pkg.Name()); + } + + if (strcmp(VerTag,Ver.VerStr()) != 0) + { + ioprintf(c1out,_("Selected version %s (%s) for %s\n"), + Ver.VerStr(),Ver.RelStr().c_str(),Pkg.Name()); + } + + Cache.SetCandidateVersion(Ver); + return true; +} + /*}}}*/ +// FindSrc - Find a source record /*{{{*/ +// --------------------------------------------------------------------- +/* */ +pkgSrcRecords::Parser *FindSrc(const char *Name,pkgRecords &Recs, + pkgSrcRecords &SrcRecs,string &Src, + pkgDepCache &Cache) +{ + // We want to pull the version off the package specification.. + string VerTag; + string TmpSrc = Name; + string::size_type Slash = TmpSrc.rfind('='); + if (Slash != string::npos) + { + VerTag = string(TmpSrc.begin() + Slash + 1,TmpSrc.end()); + TmpSrc = string(TmpSrc.begin(),TmpSrc.begin() + Slash); + } + + /* 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) + { + pkgCache::PkgIterator Pkg = Cache.FindPkg(TmpSrc); + if (Pkg.end() == false) + { + pkgCache::VerIterator Ver = Cache.GetCandidateVer(Pkg); + if (Ver.end() == false) + { + pkgRecords::Parser &Parse = Recs.Lookup(Ver.FileList()); + Src = Parse.SourcePkg(); + } + } + } + + // No source package name.. + if (Src.empty() == true) + Src = TmpSrc; + + // The best hit + pkgSrcRecords::Parser *Last = 0; + unsigned long Offset = 0; + string Version; + bool IsMatch = false; + + // If we are matching by version then we need exact matches to be happy + if (VerTag.empty() == false) + IsMatch = true; + + /* Iterate over all of the hits, which includes the resulting + binary packages in the search */ + pkgSrcRecords::Parser *Parse; + SrcRecs.Restart(); + while ((Parse = SrcRecs.Find(Src.c_str(),false)) != 0) + { + string Ver = Parse->Version(); + + // Skip name mismatches + if (IsMatch == true && Parse->Package() != Src) + continue; + + if (VerTag.empty() == false) + { + /* Don't want to fall through because we are doing exact version + matching. */ + if (Cache.VS().CmpVersion(VerTag,Ver) != 0) + continue; + + Last = Parse; + Offset = Parse->Offset(); + break; + } + + // Newer version or an exact match + if (Last == 0 || Cache.VS().CmpVersion(Version,Ver) < 0 || + (Parse->Package() == Src && IsMatch == false)) + { + IsMatch = Parse->Package() == Src; + Last = Parse; + Offset = Parse->Offset(); + Version = Ver; + } + } + + if (Last == 0) + return 0; + + if (Last->Jump(Offset) == false) + return 0; + + return Last; +} + /*}}}*/ // DoUpdate - Update the package lists /*{{{*/ // --------------------------------------------------------------------- /* */ -bool DoUpdate(CommandLine &) +bool DoUpdate(CommandLine &CmdL) { + if (CmdL.FileSize() != 1) + return _error->Error(_("The update command takes no arguments")); + // Get the source list pkgSourceList List; if (List.ReadMainList() == false) @@ -883,20 +1191,25 @@ bool DoUpdate(CommandLine &) { Lock.Fd(GetLock(_config->FindDir("Dir::State::Lists") + "lock")); if (_error->PendingError() == true) - return _error->Error("Unable to lock the list directory"); + 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) + if (List.GetIndexes(&Fetcher) == false) 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++) + cout << '\'' << I->URI << "' " << flNotDir(I->Owner->DestFile) << ' ' << + I->Owner->FileSize << ' ' << I->Owner->MD5Sum() << endl; + return true; } // Run it @@ -904,20 +1217,20 @@ bool DoUpdate(CommandLine &) return false; bool Failed = false; - for (pkgAcquire::Item **I = Fetcher.ItemsBegin(); I != Fetcher.ItemsEnd(); I++) + for (pkgAcquire::ItemIterator I = Fetcher.ItemsBegin(); I != Fetcher.ItemsEnd(); I++) { if ((*I)->Status == pkgAcquire::Item::StatDone) continue; (*I)->Finished(); - cerr << "Failed to fetch " << (*I)->DescURI() << endl; - cerr << " " << (*I)->ErrorText << endl; + fprintf(stderr,_("Failed to fetch %s %s\n"),(*I)->DescURI().c_str(), + (*I)->ErrorText.c_str()); Failed = true; } // Clean out any old list files - if (_config->FindB("APT::Get::List-Cleanup",false) == false) + if (_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) @@ -926,11 +1239,12 @@ bool DoUpdate(CommandLine &) // Prepare the cache. CacheFile Cache; - if (Cache.Open() == false) + if (Cache.BuildCaches() == false) return false; if (Failed == true) - return _error->Error("Some index files failed to download, they have been ignored, or old ones used instead."); + return _error->Error(_("Some index files failed to download, they have been ignored, or old ones used instead.")); + return true; } /*}}}*/ @@ -941,14 +1255,14 @@ bool DoUpdate(CommandLine &) bool DoUpgrade(CommandLine &CmdL) { CacheFile Cache; - if (Cache.Open() == false || Cache.CheckDeps() == false) + if (Cache.OpenForInstall() == false || Cache.CheckDeps() == false) return false; // Do the upgrade 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); @@ -960,7 +1274,8 @@ bool DoUpgrade(CommandLine &CmdL) bool DoInstall(CommandLine &CmdL) { CacheFile Cache; - if (Cache.Open() == false || Cache.CheckDeps(CmdL.FileSize() != 1) == false) + if (Cache.OpenForInstall() == false || + Cache.CheckDeps(CmdL.FileSize() != 1) == false) return false; // Enter the special broken fixing mode if the user specified arguments @@ -975,7 +1290,7 @@ bool DoInstall(CommandLine &CmdL) 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 @@ -985,8 +1300,10 @@ bool DoInstall(CommandLine &CmdL) continue; strcpy(S,*I); - // See if we are removing the package + // See if we are removing and special indicators.. bool Remove = DefRemove; + char *VerTag = 0; + bool VerIsRel = false; while (Cache->FindPkg(S).end() == true) { // Handle an optional end tag indicating what to do @@ -1003,6 +1320,23 @@ bool DoInstall(CommandLine &CmdL) S[--Length] = 0; continue; } + + char *Slash = strchr(S,'='); + if (Slash != 0) + { + VerIsRel = false; + *Slash = 0; + VerTag = Slash + 1; + } + + Slash = strchr(S,'/'); + if (Slash != 0) + { + VerIsRel = true; + *Slash = 0; + VerTag = Slash + 1; + } + break; } @@ -1014,19 +1348,25 @@ bool DoInstall(CommandLine &CmdL) // Check if the name is a regex const char *I; for (I = S; *I != 0; I++) - if (*I == '.' || *I == '?' || *I == '*') + if (*I == '?' || *I == '*' || *I == '|' || + *I == '[' || *I == '^' || *I == '$') break; if (*I == 0) - return _error->Error("Couldn't find package %s",S); + return _error->Error(_("Couldn't find package %s"),S); // Regexs must always be confirmed ExpectedInst += 1000; // Compile the regex pattern regex_t Pattern; - if (regcomp(&Pattern,S,REG_EXTENDED | REG_ICASE | - REG_NOSUB) != 0) - return _error->Error("Regex compilation error"); + 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; @@ -1035,16 +1375,26 @@ bool DoInstall(CommandLine &CmdL) if (regexec(&Pattern,Pkg.Name(),0,0,0) != 0) continue; + 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); + return _error->Error(_("Couldn't find package %s"),S); } else { + if (VerTag != 0) + if (TryToChangeVer(Pkg,Cache,VerTag,VerIsRel) == false) + return false; if (TryToInstall(Pkg,Cache,Fix,Remove,BrokenFix,ExpectedInst) == false) return false; } @@ -1055,10 +1405,10 @@ bool DoInstall(CommandLine &CmdL) packages */ if (BrokenFix == true && Cache->BrokenCount() != 0) { - c1out << "You might want to run `apt-get -f install' to correct these:" << endl; + 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 @@ -1069,22 +1419,24 @@ bool DoInstall(CommandLine &CmdL) // 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; + 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) { 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 << + _("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 << _("The following information may help to resolve the situation:") << endl; c1out << endl; ShowBroken(c1out,Cache,false); - return _error->Error("Sorry, broken packages"); + return _error->Error(_("Broken packages")); } /* Print out a list of packages that are going to be installed extra @@ -1107,7 +1459,7 @@ bool DoInstall(CommandLine &CmdL) List += string(I.Name()) + " "; } - ShowList(c1out,"The following extra packages will be installed:",List); + ShowList(c1out,_("The following extra packages will be installed:"),List); } // See if we need to prompt @@ -1123,18 +1475,18 @@ bool DoInstall(CommandLine &CmdL) bool DoDistUpgrade(CommandLine &CmdL) { CacheFile Cache; - if (Cache.Open() == false || Cache.CheckDeps() == false) + if (Cache.OpenForInstall() == false || Cache.CheckDeps() == false) return false; - c0out << "Calculating Upgrade... " << flush; + c0out << _("Calculating Upgrade... ") << flush; if (pkgDistUpgrade(*Cache) == false) { - c0out << "Failed" << endl; + c0out << _("Failed") << endl; ShowBroken(c1out,Cache,false); return false; } - c0out << "Done" << endl; + c0out << _("Done") << endl; return InstallPackages(Cache,true); } @@ -1145,7 +1497,7 @@ bool DoDistUpgrade(CommandLine &CmdL) bool DoDSelectUpgrade(CommandLine &CmdL) { CacheFile Cache; - if (Cache.Open() == false || Cache.CheckDeps() == false) + if (Cache.OpenForInstall() == false || Cache.CheckDeps() == false) return false; // Install everything with the install flag set @@ -1184,7 +1536,7 @@ bool DoDSelectUpgrade(CommandLine &CmdL) pkgProblemResolver Fix(Cache); // Hold back held packages. - if (_config->FindB("APT::Ingore-Hold",false) == false) + if (_config->FindB("APT::Ignore-Hold",false) == false) { for (pkgCache::PkgIterator I = Cache->PkgBegin(); I.end() == false; I++) { @@ -1218,13 +1570,20 @@ bool DoDSelectUpgrade(CommandLine &CmdL) /* */ bool DoClean(CommandLine &CmdL) { + if (_config->FindB("APT::Get::Simulate") == true) + { + cout << "Del " << _config->FindDir("Dir::Cache::archives") << "* " << + _config->FindDir("Dir::Cache::archives") << "partial/*" << endl; + return true; + } + // Lock the archive directory FileFd Lock; if (_config->FindB("Debug::NoLocking",false) == false) { Lock.Fd(GetLock(_config->FindDir("Dir::Cache::Archives") + "lock")); if (_error->PendingError() == true) - return _error->Error("Unable to lock the download directory"); + return _error->Error(_("Unable to lock the download directory")); } pkgAcquire Fetcher; @@ -1242,7 +1601,7 @@ class LogCleaner : public pkgArchiveCleaner protected: virtual void Erase(const char *File,string Pkg,string Ver,struct stat &St) { - cout << "Del " << Pkg << " " << Ver << " [" << SizeToStr(St.st_size) << "B]" << endl; + c1out << "Del " << Pkg << " " << Ver << " [" << SizeToStr(St.st_size) << "B]" << endl; if (_config->FindB("APT::Get::Simulate") == false) unlink(File); @@ -1257,7 +1616,7 @@ bool DoAutoClean(CommandLine &CmdL) { Lock.Fd(GetLock(_config->FindDir("Dir::Cache::Archives") + "lock")); if (_error->PendingError() == true) - return _error->Error("Unable to lock the download directory"); + return _error->Error(_("Unable to lock the download directory")); } CacheFile Cache; @@ -1300,12 +1659,12 @@ bool DoSource(CommandLine &CmdL) return false; if (CmdL.FileSize() <= 1) - return _error->Error("Must specify at least one package to fetch source for"); + return _error->Error(_("Must specify at least one package to fetch source for")); // Read the source list pkgSourceList List; if (List.ReadMainList() == false) - return _error->Error("The list of sources could not be read."); + return _error->Error(_("The list of sources could not be read.")); // Create the text record parsers pkgRecords Recs(Cache); @@ -1324,61 +1683,14 @@ bool DoSource(CommandLine &CmdL) for (const char **I = CmdL.FileList + 1; *I != 0; I++, J++) { string Src; - - /* 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. */ - pkgCache::PkgIterator Pkg = Cache->FindPkg(*I); - if (Pkg.end() == false) - { - pkgCache::VerIterator Ver = Cache->GetCandidateVer(Pkg); - if (Ver.end() == false) - { - pkgRecords::Parser &Parse = Recs.Lookup(Ver.FileList()); - Src = Parse.SourcePkg(); - } - } - - // No source package name.. - if (Src.empty() == true) - Src = *I; - - // The best hit - pkgSrcRecords::Parser *Last = 0; - unsigned long Offset = 0; - string Version; - bool IsMatch = false; - - // Iterate over all of the hits - pkgSrcRecords::Parser *Parse; - SrcRecs.Restart(); - while ((Parse = SrcRecs.Find(Src.c_str(),false)) != 0) - { - string Ver = Parse->Version(); - - // Skip name mismatches - if (IsMatch == true && Parse->Package() != Src) - continue; - - // Newer version or an exact match - if (Last == 0 || pkgVersionCompare(Version,Ver) < 0 || - (Parse->Package() == Src && IsMatch == false)) - { - IsMatch = Parse->Package() == Src; - Last = Parse; - Offset = Parse->Offset(); - Version = Ver; - } - } + pkgSrcRecords::Parser *Last = FindSrc(*I,Recs,SrcRecs,Src,*Cache); if (Last == 0) - return _error->Error("Unable to find a source package for %s",Src.c_str()); + return _error->Error(_("Unable to find a source package for %s"),Src.c_str()); // Back track vector Lst; - if (Last->Jump(Offset) == false || Last->Files(Lst) == false) + if (Last->Files(Lst) == false) return false; // Load them into the fetcher @@ -1386,63 +1698,56 @@ bool DoSource(CommandLine &CmdL) I != Lst.end(); I++) { // Try to guess what sort of file it is we are getting. - string Comp; - if (I->Path.find(".dsc") != string::npos) + if (I->Type == "dsc") { - Comp = "dsc"; Dsc[J].Package = Last->Package(); Dsc[J].Version = Last->Version(); Dsc[J].Dsc = flNotDir(I->Path); } - if (I->Path.find(".tar.gz") != string::npos) - Comp = "tar"; - if (I->Path.find(".diff.gz") != string::npos) - Comp = "diff"; - // Diff only mode only fetches .diff files if (_config->FindB("APT::Get::Diff-Only",false) == true && - Comp != "diff") + I->Type != "diff") continue; // Tar only mode only fetches .tar files if (_config->FindB("APT::Get::Tar-Only",false) == true && - Comp != "tar") + I->Type != "tar") continue; - new pkgAcqFile(&Fetcher,Last->Source()->ArchiveURI(I->Path), - I->MD5Hash,I->Size,Last->Source()->SourceInfo(Src, - Last->Version(),Comp),Src); + new pkgAcqFile(&Fetcher,Last->Index().ArchiveURI(I->Path), + I->MD5Hash,I->Size, + Last->Index().SourceInfo(*Last,*I),Src); } } // Display statistics - unsigned long FetchBytes = Fetcher.FetchNeeded(); - unsigned long FetchPBytes = Fetcher.PartialPresent(); - unsigned long DebBytes = Fetcher.TotalNeeded(); + double FetchBytes = Fetcher.FetchNeeded(); + double FetchPBytes = Fetcher.PartialPresent(); + double DebBytes = Fetcher.TotalNeeded(); // Check for enough free space - struct statfs Buf; + struct statvfs Buf; string OutputDir = "."; - if (statfs(OutputDir.c_str(),&Buf) != 0) - return _error->Errno("statfs","Couldn't determine free space in %s", + if (statvfs(OutputDir.c_str(),&Buf) != 0) + 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("Sorry, you don't have enough free space in %s", + return _error->Error(_("You don't have enough free space in %s"), OutputDir.c_str()); // Number of bytes - c1out << "Need to get "; if (DebBytes != FetchBytes) - c1out << SizeToStr(FetchBytes) << "B/" << SizeToStr(DebBytes) << 'B'; + ioprintf(c1out,_("Need to get %sB/%sB of source archives.\n"), + SizeToStr(FetchBytes).c_str(),SizeToStr(DebBytes).c_str()); else - c1out << SizeToStr(DebBytes) << 'B'; - c1out << " of source archives." << endl; - + ioprintf(c1out,_("Need to get %sB of source archives.\n"), + SizeToStr(DebBytes).c_str()); + if (_config->FindB("APT::Get::Simulate",false) == true) { for (unsigned I = 0; I != J; I++) - cout << "Fetch Source " << Dsc[I].Package << endl; + ioprintf(cout,_("Fetch Source %s\n"),Dsc[I].Package.c_str()); return true; } @@ -1462,22 +1767,25 @@ bool DoSource(CommandLine &CmdL) // Print error messages bool Failed = false; - for (pkgAcquire::Item **I = Fetcher.ItemsBegin(); I != Fetcher.ItemsEnd(); I++) + for (pkgAcquire::ItemIterator I = Fetcher.ItemsBegin(); I != Fetcher.ItemsEnd(); I++) { if ((*I)->Status == pkgAcquire::Item::StatDone && (*I)->Complete == true) continue; - cerr << "Failed to fetch " << (*I)->DescURI() << endl; - cerr << " " << (*I)->ErrorText << endl; + fprintf(stderr,_("Failed to fetch %s %s\n"),(*I)->DescURI().c_str(), + (*I)->ErrorText.c_str()); Failed = true; } if (Failed == true) - return _error->Error("Failed to fetch some archives."); + return _error->Error(_("Failed to fetch some archives.")); if (_config->FindB("APT::Get::Download-only",false) == true) + { + c1out << _("Download complete and in download only mode") << endl; return true; - + } + // Unpack the sources pid_t Process = ExecFork(); @@ -1485,19 +1793,21 @@ bool DoSource(CommandLine &CmdL) { for (unsigned I = 0; I != J; I++) { - string Dir = Dsc[I].Package + '-' + pkgBaseVersion(Dsc[I].Version.c_str()); + string Dir = Dsc[I].Package + '-' + Cache->VS().UpstreamVersion(Dsc[I].Version.c_str()); // Diff only mode only fetches .diff files if (_config->FindB("APT::Get::Diff-Only",false) == true || - _config->FindB("APT::Get::Tar-Only",false) == true) + _config->FindB("APT::Get::Tar-Only",false) == true || + Dsc[I].Dsc.empty() == true) continue; - + // See if the package is already unpacked struct stat Stat; if (stat(Dir.c_str(),&Stat) == 0 && S_ISDIR(Stat.st_mode) != 0) { - c0out << "Skipping unpack of already unpacked source in " << Dir << endl; + ioprintf(c0out ,_("Skipping unpack of already unpacked source in %s\n"), + Dir.c_str()); } else { @@ -1508,7 +1818,7 @@ bool DoSource(CommandLine &CmdL) Dsc[I].Dsc.c_str()); if (system(S) != 0) { - cerr << "Unpack command '" << S << "' failed." << endl; + fprintf(stderr,_("Unpack command '%s' failed.\n"),S); _exit(1); } } @@ -1525,7 +1835,7 @@ bool DoSource(CommandLine &CmdL) if (system(S) != 0) { - cerr << "Build command '" << S << "' failed." << endl; + fprintf(stderr,_("Build command '%s' failed.\n"),S); _exit(1); } } @@ -1544,57 +1854,290 @@ bool DoSource(CommandLine &CmdL) } if (WIFEXITED(Status) == 0 || WEXITSTATUS(Status) != 0) - return _error->Error("Child process failed"); + return _error->Error(_("Child process failed")); + + return true; +} + /*}}}*/ +// DoBuildDep - Install/removes packages to satisfy build dependencies /*{{{*/ +// --------------------------------------------------------------------- +/* This function will look at the build depends list of the given source + package and install the necessary packages to make it true, or fail. */ +bool DoBuildDep(CommandLine &CmdL) +{ + CacheFile Cache; + if (Cache.Open(true) == false) + return false; + + if (CmdL.FileSize() <= 1) + return _error->Error(_("Must specify at least one package to check builddeps for")); + // Read the source list + pkgSourceList List; + if (List.ReadMainList() == false) + return _error->Error(_("The list of sources could not be read.")); + + // Create the text record parsers + pkgRecords Recs(Cache); + pkgSrcRecords SrcRecs(List); + if (_error->PendingError() == true) + return false; + + // Create the download object + AcqTextStatus Stat(ScreenWidth,_config->FindI("quiet",0)); + pkgAcquire Fetcher(&Stat); + + unsigned J = 0; + for (const char **I = CmdL.FileList + 1; *I != 0; I++, J++) + { + string Src; + pkgSrcRecords::Parser *Last = FindSrc(*I,Recs,SrcRecs,Src,*Cache); + if (Last == 0) + return _error->Error(_("Unable to find a source package for %s"),Src.c_str()); + + // Process the build-dependencies + vector BuildDeps; + if (Last->BuildDepends(BuildDeps, _config->FindB("APT::Get::Arch-Only",false)) == false) + return _error->Error(_("Unable to get build-dependency information for %s"),Src.c_str()); + + // Also ensure that build-essential packages are present + Configuration::Item const *Opts = _config->Tree("APT::Build-Essential"); + if (Opts) + Opts = Opts->Child; + for (; Opts; Opts = Opts->Next) + { + if (Opts->Value.empty() == true) + continue; + + pkgSrcRecords::Parser::BuildDepRec rec; + rec.Package = Opts->Value; + rec.Type = pkgSrcRecords::Parser::BuildDependIndep; + rec.Op = 0; + BuildDeps.insert(BuildDeps.begin(), rec); + } + + if (BuildDeps.size() == 0) + { + ioprintf(c1out,_("%s has no build depends.\n"),Src.c_str()); + continue; + } + + // Install the requested packages + unsigned int ExpectedInst = 0; + vector ::iterator D; + pkgProblemResolver Fix(Cache); + for (D = BuildDeps.begin(); D != BuildDeps.end(); D++) + { + if ((*D).Type == pkgSrcRecords::Parser::BuildConflict || + (*D).Type == pkgSrcRecords::Parser::BuildConflictIndep) + { + pkgCache::PkgIterator Pkg = Cache->FindPkg((*D).Package); + // Build-conflicts on unknown packages are silently ignored + if (Pkg.end() == true) + continue; + + pkgCache::VerIterator IV = (*Cache)[Pkg].InstVerIter(*Cache); + + /* + * Remove if we have an installed version that satisfies the + * version criteria + */ + if (IV.end() == false && + Cache->VS().CheckDep(IV.VerStr(),(*D).Op,(*D).Version.c_str()) == true) + TryToInstall(Pkg,Cache,Fix,true,false,ExpectedInst); + } + else // BuildDep || BuildDepIndep + { + pkgCache::PkgIterator Pkg = Cache->FindPkg((*D).Package); + if (Pkg.end() == true) + { + // Check if there are any alternatives + if (((*D).Op & pkgCache::Dep::Or) != pkgCache::Dep::Or) + return _error->Error(_("%s dependency for %s cannot be satisfied " + "because the package %s cannot be found"), + Last->BuildDepType((*D).Type),Src.c_str(), + (*D).Package.c_str()); + // Try the next alternative + continue; + } + + /* + * if there are alternatives, we've already picked one, so skip + * the rest + * + * TODO: this means that if there's a build-dep on A|B and B is + * installed, we'll still try to install A; more importantly, + * if A is currently broken, we cannot go back and try B. To fix + * this would require we do a Resolve cycle for each package we + * add to the install list. Ugh + */ + while (D != BuildDeps.end() && + (((*D).Op & pkgCache::Dep::Or) == pkgCache::Dep::Or)) + 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 + */ + pkgCache::PrvIterator Prv = Pkg.ProvidesList(); + for (; Prv.end() != true; Prv++) + if ((*Cache)[Prv.OwnerPkg()].InstVerIter(*Cache).end() == false) + break; + + // Get installed version and version we are going to install + pkgCache::VerIterator IV = (*Cache)[Pkg].InstVerIter(*Cache); + pkgCache::VerIterator CV = (*Cache)[Pkg].CandidateVerIter(*Cache); + + for (; CV.end() != true; CV++) + { + if (Cache->VS().CheckDep(CV.VerStr(),(*D).Op,(*D).Version.c_str()) == true) + break; + } + if (CV.end() == true) + return _error->Error(_("%s dependency for %s cannot be satisfied " + "because no available versions of package %s " + "can satisfy version requirements"), + Last->BuildDepType((*D).Type),Src.c_str(), + (*D).Package.c_str()); + + /* + * TODO: if we depend on a version lower than what we already have + * installed it is not clear what should be done; in practice + * this case should be rare, and right now nothing is + * done about it :-( + */ + if (Prv.end() == true && // Nothing provides it; and + (IV.end() == true || // It is not installed, or + Cache->VS().CheckDep(IV.VerStr(),(*D).Op,(*D).Version.c_str()) == false)) + // the version installed doesn't + // satisfy constraints + TryToInstall(Pkg,Cache,Fix,false,false,ExpectedInst); + } + } + + Fix.InstallProtect(); + if (Fix.Resolve(true) == false) + _error->Discard(); + + // Now we check the state of the packages, + if (Cache->BrokenCount() != 0) + return _error->Error(_("Some broken packages were found while trying to process build-dependencies.\n" + "You might want to run `apt-get -f install' to correct these.")); + } + + if (InstallPackages(Cache, false, true) == false) + return _error->Error(_("Failed to process build dependencies")); return true; } /*}}}*/ +// DoMoo - Never Ask, Never Tell /*{{{*/ +// --------------------------------------------------------------------- +/* */ +bool DoMoo(CommandLine &CmdL) +{ + cout << + " (__) \n" + " (oo) \n" + " /------\\/ \n" + " / | || \n" + " * /\\---/\\ \n" + " ~~ ~~ \n" + "....\"Have you mooed today?\"...\n"; + + return true; +} + /*}}}*/ // ShowHelp - Show a help screen /*{{{*/ // --------------------------------------------------------------------- /* */ bool ShowHelp(CommandLine &CmdL) { - cout << PACKAGE << ' ' << VERSION << " for " << ARCHITECTURE << - " compiled on " << __DATE__ << " " << __TIME__ << endl; + ioprintf(cout,_("%s %s for %s %s compiled on %s %s\n"),PACKAGE,VERSION, + COMMON_OS,COMMON_CPU,__DATE__,__TIME__); + if (_config->FindB("version") == true) - return 100; - - cout << "Usage: apt-get [options] command" << endl; - cout << " apt-get [options] install pkg1 [pkg2 ...]" << endl; - cout << endl; - cout << "apt-get is a simple command line interface for downloading and" << endl; - cout << "installing packages. The most frequently used commands are update" << endl; - cout << "and install." << endl; - cout << endl; - cout << "Commands:" << endl; - 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 << " source - Download source archives" << 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 << " autoclean - Erase old 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 << " -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; - cout << " -y Assume Yes to all queries and do not prompt" << endl; - cout << " -f Attempt to continue if the integrity check fails" << endl; - cout << " -m Attempt to continue if archives are unlocatable" << endl; - cout << " -u Show a list of upgraded packages as well" << endl; - cout << " -b Build the source package after fetching it" << endl; - cout << " -c=? Read this configuration file" << endl; - cout << " -o=? Set an arbitary configuration option, eg -o dir::cache=/tmp" << endl; - cout << "See the apt-get(8), sources.list(5) and apt.conf(5) manual" << endl; - cout << "pages for more information and options." << endl; - return 100; + { + cout << _("Supported Modules:") << endl; + + for (unsigned I = 0; I != pkgVersioningSystem::GlobalListLen; I++) + { + pkgVersioningSystem *VS = pkgVersioningSystem::GlobalList[I]; + if (_system != 0 && _system->VS == VS) + cout << '*'; + else + cout << ' '; + cout << "Ver: " << VS->Label << endl; + + /* Print out all the packaging systems that will work with + this VS */ + for (unsigned J = 0; J != pkgSystem::GlobalListLen; J++) + { + pkgSystem *Sys = pkgSystem::GlobalList[J]; + if (_system == Sys) + cout << '*'; + else + cout << ' '; + if (Sys->VS->TestCompatibility(*VS) == true) + cout << "Pkg: " << Sys->Label << " (Priority " << Sys->Score(*_config) << ")" << endl; + } + } + + for (unsigned I = 0; I != pkgSourceList::Type::GlobalListLen; I++) + { + pkgSourceList::Type *Type = pkgSourceList::Type::GlobalList[I]; + cout << " S.L: '" << Type->Name << "' " << Type->Label << endl; + } + + for (unsigned I = 0; I != pkgIndexFile::Type::GlobalListLen; I++) + { + pkgIndexFile::Type *Type = pkgIndexFile::Type::GlobalList[I]; + cout << " Idx: " << Type->Label << endl; + } + + return true; + } + + cout << + _("Usage: apt-get [options] command\n" + " apt-get [options] install|remove pkg1 [pkg2 ...]\n" + " apt-get [options] source pkg1 [pkg2 ...]\n" + "\n" + "apt-get is a simple command line interface for downloading and\n" + "installing packages. The most frequently used commands are update\n" + "and install.\n" + "\n" + "Commands:\n" + " update - Retrieve new lists of packages\n" + " upgrade - Perform an upgrade\n" + " install - Install new packages (pkg is libc6 not libc6.deb)\n" + " remove - Remove 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" + " dselect-upgrade - Follow dselect selections\n" + " clean - Erase downloaded archive files\n" + " autoclean - Erase old downloaded archive files\n" + " check - Verify that there are no broken dependencies\n" + "\n" + "Options:\n" + " -h This help text.\n" + " -q Loggable output - no progress indicator\n" + " -qq No output except for errors\n" + " -d Download only - do NOT install or unpack archives\n" + " -s No-act. Perform ordering simulation\n" + " -y Assume Yes to all queries and do not prompt\n" + " -f Attempt to continue if the integrity check fails\n" + " -m Attempt to continue if archives are unlocatable\n" + " -u Show a list of upgraded packages as well\n" + " -b Build the source package after fetching it\n" + " -c=? Read this configuration file\n" + " -o=? Set an arbitary configuration option, eg -o dir::cache=/tmp\n" + "See the apt-get(8), sources.list(5) and apt.conf(5) manual\n" + "pages for more information and options.\n" + " This APT has Super Cow Powers.\n"); + return true; } /*}}}*/ // GetInitialize - Initialize things for apt-get /*{{{*/ @@ -1637,19 +2180,22 @@ int main(int argc,const char *argv[]) {'d',"download-only","APT::Get::Download-Only",0}, {'b',"compile","APT::Get::Compile",0}, {'b',"build","APT::Get::Compile",0}, - {'s',"simulate","APT::Get::Simulate",0}, - {'s',"just-print","APT::Get::Simulate",0}, - {'s',"recon","APT::Get::Simulate",0}, - {'s',"no-act","APT::Get::Simulate",0}, - {'y',"yes","APT::Get::Assume-Yes",0}, + {'s',"simulate","APT::Get::Simulate",0}, + {'s',"just-print","APT::Get::Simulate",0}, + {'s',"recon","APT::Get::Simulate",0}, + {'s',"dry-run","APT::Get::Simulate",0}, + {'s',"no-act","APT::Get::Simulate",0}, + {'y',"yes","APT::Get::Assume-Yes",0}, {'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-Missing",0}, - {0,"no-download","APT::Get::No-Download",0}, + {'t',"target-release","APT::Default-Release",CommandLine::HasArg}, + {'t',"default-release","APT::Default-Release",CommandLine::HasArg}, + {0,"download","APT::Get::Download",0}, {0,"fix-missing","APT::Get::Fix-Missing",0}, - {0,"ignore-hold","APT::Ingore-Hold",0}, - {0,"no-upgrade","APT::Get::no-upgrade",0}, + {0,"ignore-hold","APT::Ignore-Hold",0}, + {0,"upgrade","APT::Get::upgrade",0}, {0,"force-yes","APT::Get::force-yes",0}, {0,"print-uris","APT::Get::Print-URIs",0}, {0,"diff-only","APT::Get::Diff-Only",0}, @@ -1657,6 +2203,10 @@ int main(int argc,const char *argv[]) {0,"purge","APT::Get::Purge",0}, {0,"list-cleanup","APT::Get::List-Cleanup",0}, {0,"reinstall","APT::Get::ReInstall",0}, + {0,"trivial-only","APT::Get::Trivial-Only",0}, + {0,"remove","APT::Get::Remove",0}, + {0,"only-source","APT::Get::Only-Source",0}, + {0,"arch-only","APT::Get::Arch-Only",0}, {'c',"config-file",0,CommandLine::ConfigFile}, {'o',"option",0,CommandLine::ArbItem}, {0,0,0,0}}; @@ -1666,18 +2216,28 @@ int main(int argc,const char *argv[]) {"remove",&DoInstall}, {"dist-upgrade",&DoDistUpgrade}, {"dselect-upgrade",&DoDSelectUpgrade}, + {"build-dep",&DoBuildDep}, {"clean",&DoClean}, {"autoclean",&DoAutoClean}, {"check",&DoCheck}, - {"source",&DoSource}, - {"help",&ShowHelp}, + {"source",&DoSource}, + {"moo",&DoMoo}, + {"help",&ShowHelp}, {0,0}}; - + + // Set up gettext support + setlocale(LC_ALL,""); + textdomain(PACKAGE); + // Parse the command line and initialize the package library CommandLine CmdL(Args,_config); - if (pkgInitialize(*_config) == false || - CmdL.Parse(argc,argv) == false) + if (pkgInitConfig(*_config) == false || + CmdL.Parse(argc,argv) == false || + pkgInitSystem(*_config,_system) == false) { + if (_config->FindB("version") == true) + ShowHelp(CmdL); + _error->DumpErrors(); return 100; } @@ -1686,12 +2246,15 @@ int main(int argc,const char *argv[]) if (_config->FindB("help") == true || _config->FindB("version") == true || CmdL.FileSize() == 0) - return ShowHelp(CmdL); - + { + ShowHelp(CmdL); + return 0; + } + // Deal with stdout not being a tty if (ttyname(STDOUT_FILENO) == 0 && _config->FindI("quiet",0) < 1) _config->Set("quiet","1"); - + // Setup the output streams c0out.rdbuf(cout.rdbuf()); c1out.rdbuf(cout.rdbuf()); @@ -1705,7 +2268,7 @@ int main(int argc,const char *argv[]) signal(SIGPIPE,SIG_IGN); signal(SIGWINCH,SigWinch); SigWinch(0); - + // Match the operation CmdL.DispatchArg(Cmds);