diff options
Diffstat (limited to 'apt-private')
-rw-r--r-- | apt-private/acqprogress.cc | 218 | ||||
-rw-r--r-- | apt-private/acqprogress.h | 8 | ||||
-rw-r--r-- | apt-private/private-cachefile.cc | 4 | ||||
-rw-r--r-- | apt-private/private-cachefile.h | 23 | ||||
-rw-r--r-- | apt-private/private-cacheset.cc | 89 | ||||
-rw-r--r-- | apt-private/private-cacheset.h | 37 | ||||
-rw-r--r-- | apt-private/private-cmndline.cc | 47 | ||||
-rw-r--r-- | apt-private/private-cmndline.h | 6 | ||||
-rw-r--r-- | apt-private/private-download.cc | 99 | ||||
-rw-r--r-- | apt-private/private-download.h | 12 | ||||
-rw-r--r-- | apt-private/private-install.cc | 240 | ||||
-rw-r--r-- | apt-private/private-install.h | 162 | ||||
-rw-r--r-- | apt-private/private-list.cc | 53 | ||||
-rw-r--r-- | apt-private/private-output.cc | 386 | ||||
-rw-r--r-- | apt-private/private-output.h | 10 | ||||
-rw-r--r-- | apt-private/private-search.cc | 82 | ||||
-rw-r--r-- | apt-private/private-show.cc | 54 | ||||
-rw-r--r-- | apt-private/private-update.cc | 38 | ||||
-rw-r--r-- | apt-private/private-upgrade.cc | 16 | ||||
-rw-r--r-- | apt-private/private-utils.cc | 58 | ||||
-rw-r--r-- | apt-private/private-utils.h | 4 |
21 files changed, 967 insertions, 679 deletions
diff --git a/apt-private/acqprogress.cc b/apt-private/acqprogress.cc index 0f5b53e50..0c606e48e 100644 --- a/apt-private/acqprogress.cc +++ b/apt-private/acqprogress.cc @@ -1,10 +1,9 @@ // -*- mode: cpp; mode: fold -*- // Description /*{{{*/ -// $Id: acqprogress.cc,v 1.24 2003/04/27 01:56:48 doogie Exp $ /* ###################################################################### - Acquire Progress - Command line progress meter - + Acquire Progress - Command line progress meter + ##################################################################### */ /*}}}*/ // Include files /*{{{*/ @@ -23,20 +22,18 @@ #include <stdio.h> #include <signal.h> #include <iostream> +#include <sstream> #include <unistd.h> #include <apti18n.h> /*}}}*/ -using namespace std; - // AcqTextStatus::AcqTextStatus - Constructor /*{{{*/ // --------------------------------------------------------------------- /* */ -AcqTextStatus::AcqTextStatus(unsigned int &ScreenWidth,unsigned int const Quiet) : - pkgAcquireStatus(), ScreenWidth(ScreenWidth), ID(0), Quiet(Quiet) +AcqTextStatus::AcqTextStatus(std::ostream &out, unsigned int &ScreenWidth,unsigned int const Quiet) : + pkgAcquireStatus(), out(out), ScreenWidth(ScreenWidth), LastLineLength(0), ID(0), Quiet(Quiet) { - BlankLine[0] = 0; // testcases use it to disable pulses without disabling other user messages if (Quiet == 0 && _config->FindB("quiet::NoUpdate", false) == true) this->Quiet = 1; @@ -48,7 +45,7 @@ AcqTextStatus::AcqTextStatus(unsigned int &ScreenWidth,unsigned int const Quiet) void AcqTextStatus::Start() { pkgAcquireStatus::Start(); - BlankLine[0] = 0; + LastLineLength = 0; ID = 1; } /*}}}*/ @@ -60,13 +57,10 @@ void AcqTextStatus::IMSHit(pkgAcquire::ItemDesc &Itm) if (Quiet > 1) return; - if (Quiet <= 0) - cout << '\r' << BlankLine << '\r'; + clearLastLine(); - cout << _("Hit ") << Itm.Description; - if (Itm.Owner->FileSize != 0) - cout << " [" << SizeToStr(Itm.Owner->FileSize) << "B]"; - cout << endl; + out << _("Hit ") << Itm.Description; + out << std::endl; Update = true; } /*}}}*/ @@ -84,13 +78,12 @@ void AcqTextStatus::Fetch(pkgAcquire::ItemDesc &Itm) if (Quiet > 1) return; - if (Quiet <= 0) - cout << '\r' << BlankLine << '\r'; + clearLastLine(); - cout << _("Get:") << Itm.Owner->ID << ' ' << Itm.Description; + out << _("Get:") << Itm.Owner->ID << ' ' << Itm.Description; if (Itm.Owner->FileSize != 0) - cout << " [" << SizeToStr(Itm.Owner->FileSize) << "B]"; - cout << endl; + out << " [" << SizeToStr(Itm.Owner->FileSize) << "B]"; + out << std::endl; } /*}}}*/ // AcqTextStatus::Done - Completed a download /*{{{*/ @@ -113,17 +106,19 @@ void AcqTextStatus::Fail(pkgAcquire::ItemDesc &Itm) if (Itm.Owner->Status == pkgAcquire::Item::StatIdle) return; - if (Quiet <= 0) - cout << '\r' << BlankLine << '\r'; + clearLastLine(); if (Itm.Owner->Status == pkgAcquire::Item::StatDone) { - cout << _("Ign ") << Itm.Description << endl; + out << _("Ign ") << Itm.Description << std::endl; + if (Itm.Owner->ErrorText.empty() == false && + _config->FindB("Acquire::Progress::Ignore::ShowErrorText", false) == true) + out << " " << Itm.Owner->ErrorText << std::endl; } else { - cout << _("Err ") << Itm.Description << endl; - cout << " " << Itm.Owner->ErrorText << endl; + out << _("Err ") << Itm.Description << std::endl; + out << " " << Itm.Owner->ErrorText << std::endl; } Update = true; @@ -139,11 +134,13 @@ void AcqTextStatus::Stop() if (Quiet > 1) return; - if (Quiet <= 0) - cout << '\r' << BlankLine << '\r' << flush; + clearLastLine(); + + if (_config->FindB("quiet::NoStatistic", false) == true) + return; if (FetchedBytes != 0 && _error->PendingError() == false) - ioprintf(cout,_("Fetched %sB in %s (%sB/s)\n"), + ioprintf(out,_("Fetched %sB in %s (%sB/s)\n"), SizeToStr(FetchedBytes).c_str(), TimeToStr(ElapsedTime).c_str(), SizeToStr(CurrentCPS).c_str()); @@ -152,7 +149,7 @@ void AcqTextStatus::Stop() // AcqTextStatus::Pulse - Regular event pulse /*{{{*/ // --------------------------------------------------------------------- /* This draws the current progress. Each line has an overall percent - meter and a per active item status meter along with an overall + meter and a per active item status meter along with an overall bandwidth and ETA indicator. */ bool AcqTextStatus::Pulse(pkgAcquire *Owner) { @@ -163,77 +160,66 @@ bool AcqTextStatus::Pulse(pkgAcquire *Owner) enum {Long = 0,Medium,Short} Mode = Medium; - char Buffer[sizeof(BlankLine)]; - char *End = Buffer + sizeof(Buffer); - char *S = Buffer; - if (ScreenWidth >= sizeof(Buffer)) - ScreenWidth = sizeof(Buffer)-1; - - // Put in the percent done - sprintf(S,"%.0f%%",((CurrentBytes + CurrentItems)*100.0)/(TotalBytes+TotalItems)); - - bool Shown = false; - for (pkgAcquire::Worker *I = Owner->WorkersBegin(); I != 0; - I = Owner->WorkerStep(I)) + std::string Line; { - S += strlen(S); - - // There is no item running - if (I->CurrentItem == 0) + std::stringstream S; + for (pkgAcquire::Worker *I = Owner->WorkersBegin(); I != 0; + I = Owner->WorkerStep(I)) { - if (I->Status.empty() == false) + // There is no item running + if (I->CurrentItem == 0) { - snprintf(S,End-S," [%s]",I->Status.c_str()); - Shown = true; - } - - continue; - } + if (I->Status.empty() == false) + S << " [" << I->Status << "]"; - Shown = true; + continue; + } - // Add in the short description - if (I->CurrentItem->Owner->ID != 0) - snprintf(S,End-S," [%lu %s",I->CurrentItem->Owner->ID, - I->CurrentItem->ShortDesc.c_str()); - else - snprintf(S,End-S," [%s",I->CurrentItem->ShortDesc.c_str()); - S += strlen(S); + // Add in the short description + S << " ["; + if (I->CurrentItem->Owner->ID != 0) + S << I->CurrentItem->Owner->ID << " "; + S << I->CurrentItem->ShortDesc; - // Show the short mode string - if (I->CurrentItem->Owner->Mode != 0) - { - snprintf(S,End-S," %s",I->CurrentItem->Owner->Mode); - S += strlen(S); - } - - // Add the current progress - if (Mode == Long) - snprintf(S,End-S," %llu",I->CurrentSize); - else - { - if (Mode == Medium || I->TotalSize == 0) - snprintf(S,End-S," %sB",SizeToStr(I->CurrentSize).c_str()); - } - S += strlen(S); + // Show the short mode string + if (I->CurrentItem->Owner->ActiveSubprocess.empty() == false) + S << " " << I->CurrentItem->Owner->ActiveSubprocess; - // Add the total size and percent - if (I->TotalSize > 0 && I->CurrentItem->Owner->Complete == false) - { - if (Mode == Short) - snprintf(S,End-S," %.0f%%", - (I->CurrentSize*100.0)/I->TotalSize); + // Add the current progress + if (Mode == Long) + S << " " << I->CurrentSize; else - snprintf(S,End-S,"/%sB %.0f%%",SizeToStr(I->TotalSize).c_str(), + { + if (Mode == Medium || I->TotalSize == 0) + S << " " << SizeToStr(I->CurrentSize) << "B"; + } + + // Add the total size and percent + if (I->TotalSize > 0 && I->CurrentItem->Owner->Complete == false) + { + if (Mode == Short) + ioprintf(S, " %.0f%%", (I->CurrentSize*100.0)/I->TotalSize); + else + ioprintf(S, "/%sB %.0f%%", SizeToStr(I->TotalSize).c_str(), (I->CurrentSize*100.0)/I->TotalSize); + } + S << "]"; } - S += strlen(S); - snprintf(S,End-S,"]"); - } - // Show something.. - if (Shown == false) - snprintf(S,End-S,_(" [Working]")); + // Show at least something + Line = S.str(); + S.clear(); + if (Line.empty() == true) + Line = _(" [Working]"); + } + // Put in the percent done + { + std::stringstream S; + ioprintf(S, "%.0f%%", Percent); + S << Line; + Line = S.str(); + S.clear(); + } /* Put in the ETA and cps meter, block off signals to prevent strangeness during resizing */ @@ -244,34 +230,33 @@ bool AcqTextStatus::Pulse(pkgAcquire *Owner) if (CurrentCPS != 0) { - char Tmp[300]; unsigned long long ETA = (TotalBytes - CurrentBytes)/CurrentCPS; - sprintf(Tmp," %sB/s %s",SizeToStr(CurrentCPS).c_str(),TimeToStr(ETA).c_str()); - unsigned int Len = strlen(Buffer); - unsigned int LenT = strlen(Tmp); - if (Len + LenT < ScreenWidth) + std::string Tmp = " " + SizeToStr(CurrentCPS) + "B/s " + TimeToStr(ETA); + size_t alignment = Line.length() + Tmp.length(); + if (alignment < ScreenWidth) { - memset(Buffer + Len,' ',ScreenWidth - Len); - strcpy(Buffer + ScreenWidth - LenT,Tmp); + alignment = ScreenWidth - alignment; + for (size_t i = 0; i < alignment; ++i) + Line.append(" "); + Line.append(Tmp); } } - Buffer[ScreenWidth] = 0; - BlankLine[ScreenWidth] = 0; + if (Line.length() > ScreenWidth) + Line.erase(ScreenWidth); sigprocmask(SIG_SETMASK,&OldSigs,0); // Draw the current status if (_config->FindB("Apt::Color", false) == true) - cout << _config->Find("APT::Color::Yellow"); - if (strlen(Buffer) == strlen(BlankLine)) - cout << '\r' << Buffer << flush; + out << _config->Find("APT::Color::Yellow"); + if (LastLineLength > Line.length()) + clearLastLine(); else - cout << '\r' << BlankLine << '\r' << Buffer << flush; + out << '\r'; + out << Line << std::flush; if (_config->FindB("Apt::Color", false) == true) - cout << _config->Find("APT::Color::Neutral") << flush; - - memset(BlankLine,' ',strlen(Buffer)); - BlankLine[strlen(Buffer)] = 0; + out << _config->Find("APT::Color::Neutral") << std::flush; + LastLineLength = Line.length(); Update = false; return true; @@ -280,7 +265,7 @@ bool AcqTextStatus::Pulse(pkgAcquire *Owner) // AcqTextStatus::MediaChange - Media need to be swapped /*{{{*/ // --------------------------------------------------------------------- /* Prompt for a media swap */ -bool AcqTextStatus::MediaChange(string Media,string Drive) +bool AcqTextStatus::MediaChange(std::string Media, std::string Drive) { // If we do not output on a terminal and one of the options to avoid user // interaction is given, we assume that no user is present who could react @@ -292,9 +277,8 @@ bool AcqTextStatus::MediaChange(string Media,string Drive) return false; - if (Quiet <= 0) - cout << '\r' << BlankLine << '\r'; - ioprintf(cout,_("Media change: please insert the disc labeled\n" + clearLastLine(); + ioprintf(out,_("Media change: please insert the disc labeled\n" " '%s'\n" "in the drive '%s' and press enter\n"), Media.c_str(),Drive.c_str()); @@ -313,3 +297,17 @@ bool AcqTextStatus::MediaChange(string Media,string Drive) return bStatus; } /*}}}*/ +void AcqTextStatus::clearLastLine() { /*{{{*/ + if (Quiet > 0 || LastLineLength == 0) + return; + + // do not try to clear more than the (now smaller) screen + if (LastLineLength > ScreenWidth) + LastLineLength = ScreenWidth; + + out << '\r'; + for (size_t i = 0; i < LastLineLength; ++i) + out << ' '; + out << '\r' << std::flush; +} + /*}}}*/ diff --git a/apt-private/acqprogress.h b/apt-private/acqprogress.h index 71a10d78a..7cf990c65 100644 --- a/apt-private/acqprogress.h +++ b/apt-private/acqprogress.h @@ -13,14 +13,18 @@ #include <apt-pkg/macros.h> #include <string> +#include <iostream> class APT_PUBLIC AcqTextStatus : public pkgAcquireStatus { + std::ostream &out; unsigned int &ScreenWidth; - char BlankLine[1024]; + size_t LastLineLength; unsigned long ID; unsigned long Quiet; + void clearLastLine(); + public: virtual bool MediaChange(std::string Media,std::string Drive); @@ -33,7 +37,7 @@ class APT_PUBLIC AcqTextStatus : public pkgAcquireStatus bool Pulse(pkgAcquire *Owner); - AcqTextStatus(unsigned int &ScreenWidth,unsigned int const Quiet); + AcqTextStatus(std::ostream &out, unsigned int &ScreenWidth,unsigned int const Quiet); }; #endif diff --git a/apt-private/private-cachefile.cc b/apt-private/private-cachefile.cc index 5e955ac39..29e665245 100644 --- a/apt-private/private-cachefile.cc +++ b/apt-private/private-cachefile.cc @@ -32,8 +32,10 @@ int CacheFile::NameComp(const void *a,const void *b) const pkgCache::Package &A = **(pkgCache::Package **)a; const pkgCache::Package &B = **(pkgCache::Package **)b; + const pkgCache::Group * const GA = SortCache->GrpP + A.Group; + const pkgCache::Group * const GB = SortCache->GrpP + B.Group; - return strcmp(SortCache->StrP + A.Name,SortCache->StrP + B.Name); + return strcmp(SortCache->StrP + GA->Name,SortCache->StrP + GB->Name); } /*}}}*/ // CacheFile::Sort - Sort by name /*{{{*/ diff --git a/apt-private/private-cachefile.h b/apt-private/private-cachefile.h index dce7e0a3a..1fddabfbd 100644 --- a/apt-private/private-cachefile.h +++ b/apt-private/private-cachefile.h @@ -6,7 +6,20 @@ #include <apt-pkg/configuration.h> #include <apt-pkg/pkgcache.h> #include <apt-pkg/macros.h> +#include <apt-pkg/sourcelist.h> +#include <apti18n.h> +// FIXME: we need to find a way to export this +class APT_PUBLIC SourceList : public pkgSourceList +{ + + public: + // Add custom metaIndex (e.g. local files) + void AddMetaIndex(metaIndex *mi) { + SrcList.push_back(mi); + } + +}; // class CacheFile - Cover class for some dependency cache functions /*{{{*/ // --------------------------------------------------------------------- @@ -28,6 +41,16 @@ class APT_PUBLIC CacheFile : public pkgCacheFile return false; return true; } + // FIXME: this can go once the "libapt-pkg" pkgSourceList has a way + // to add custom metaIndexes (or custom local files or so) + bool BuildSourceList(OpProgress */*Progress*/ = NULL) { + if (SrcList != NULL) + return true; + SrcList = new SourceList(); + if (SrcList->ReadMainList() == false) + return _error->Error(_("The list of sources could not be read.")); + return true; + } bool Open(bool WithLock = true) { OpTextProgress Prog(*_config); diff --git a/apt-private/private-cacheset.cc b/apt-private/private-cacheset.cc index e37e7b227..cb68024db 100644 --- a/apt-private/private-cacheset.cc +++ b/apt-private/private-cacheset.cc @@ -14,74 +14,77 @@ #include <apti18n.h> -bool GetLocalitySortedVersionSet(pkgCacheFile &CacheFile, - LocalitySortedVersionSet &output_set, - OpProgress &progress) +bool GetLocalitySortedVersionSet(pkgCacheFile &CacheFile, + APT::VersionContainerInterface * const vci, + OpProgress * const progress) { Matcher null_matcher = Matcher(); - return GetLocalitySortedVersionSet(CacheFile, output_set, + return GetLocalitySortedVersionSet(CacheFile, vci, null_matcher, progress); } -bool GetLocalitySortedVersionSet(pkgCacheFile &CacheFile, - LocalitySortedVersionSet &output_set, +bool GetLocalitySortedVersionSet(pkgCacheFile &CacheFile, + APT::VersionContainerInterface * const vci, Matcher &matcher, - OpProgress &progress) + OpProgress * const progress) { pkgCache *Cache = CacheFile.GetPkgCache(); pkgDepCache *DepCache = CacheFile.GetDepCache(); + APT::CacheSetHelper helper(false); int Done=0; - progress.SubProgress(Cache->Head().PackageCount, _("Sorting")); + if (progress != NULL) + progress->SubProgress(Cache->Head().PackageCount, _("Sorting")); + + bool const insertCurrentVer = _config->FindB("APT::Cmd::Installed", false); + bool const insertUpgradable = _config->FindB("APT::Cmd::Upgradable", false); + bool const insertManualInstalled = _config->FindB("APT::Cmd::Manual-Installed", false); + for (pkgCache::PkgIterator P = Cache->PkgBegin(); P.end() == false; ++P) { - if (Done%500 == 0) - progress.Progress(Done); - Done++; + if (progress != NULL) + { + if (Done % 500 == 0) + progress->Progress(Done); + ++Done; + } + + // exclude virtual pkgs + if (P->VersionList == 0) + continue; if ((matcher)(P) == false) - continue; + continue; - // exclude virtual pkgs - if (P.VersionList() == 0) - continue; pkgDepCache::StateCache &state = (*DepCache)[P]; - if (_config->FindB("APT::Cmd::Installed") == true) + if (insertCurrentVer == true) { - if (P.CurrentVer() != NULL) - { - output_set.insert(P.CurrentVer()); - } + if (P->CurrentVer != 0) + vci->FromPackage(vci, CacheFile, P, APT::CacheSetHelper::INSTALLED, helper); } - else if (_config->FindB("APT::Cmd::Upgradable") == true) + else if (insertUpgradable == true) { - if(P.CurrentVer() && state.Upgradable()) - { - pkgPolicy *policy = CacheFile.GetPolicy(); - output_set.insert(policy->GetCandidateVer(P)); - } + if(P.CurrentVer() && state.Upgradable()) + vci->FromPackage(vci, CacheFile, P, APT::CacheSetHelper::CANDIDATE, helper); } - else if (_config->FindB("APT::Cmd::Manual-Installed") == true) + else if (insertManualInstalled == true) { - if (P.CurrentVer() && - ((*DepCache)[P].Flags & pkgCache::Flag::Auto) == false) - { - pkgPolicy *policy = CacheFile.GetPolicy(); - output_set.insert(policy->GetCandidateVer(P)); - } + if (P.CurrentVer() && + ((*DepCache)[P].Flags & pkgCache::Flag::Auto) == false) + vci->FromPackage(vci, CacheFile, P, APT::CacheSetHelper::CANDIDATE, helper); } - else + else { - pkgPolicy *policy = CacheFile.GetPolicy(); - if (policy->GetCandidateVer(P).IsGood()) - output_set.insert(policy->GetCandidateVer(P)); - else - // no candidate, this may happen for packages in - // dpkg "deinstall ok config-file" state - we pick the first ver - // (which should be the only one) - output_set.insert(P.VersionList()); + if (vci->FromPackage(vci, CacheFile, P, APT::CacheSetHelper::CANDIDATE, helper) == false) + { + // no candidate, this may happen for packages in + // dpkg "deinstall ok config-file" state - we pick the first ver + // (which should be the only one) + vci->insert(P.VersionList()); + } } } - progress.Done(); + if (progress != NULL) + progress->Done(); return true; } diff --git a/apt-private/private-cacheset.h b/apt-private/private-cacheset.h index 854d16922..059c7637e 100644 --- a/apt-private/private-cacheset.h +++ b/apt-private/private-cacheset.h @@ -62,13 +62,13 @@ public: }; // FIXME: add default argument for OpProgress (or overloaded function) -bool GetLocalitySortedVersionSet(pkgCacheFile &CacheFile, - LocalitySortedVersionSet &output_set, +bool GetLocalitySortedVersionSet(pkgCacheFile &CacheFile, + APT::VersionContainerInterface * const vci, Matcher &matcher, - OpProgress &progress); -bool GetLocalitySortedVersionSet(pkgCacheFile &CacheFile, - LocalitySortedVersionSet &output_set, - OpProgress &progress); + OpProgress * const progress); +bool GetLocalitySortedVersionSet(pkgCacheFile &CacheFile, + APT::VersionContainerInterface * const vci, + OpProgress * const progress); // CacheSetHelper saving virtual packages /*{{{*/ @@ -76,19 +76,16 @@ class CacheSetHelperVirtuals: public APT::CacheSetHelper { public: APT::PackageSet virtualPkgs; - virtual pkgCache::VerIterator canNotFindCandidateVer(pkgCacheFile &Cache, pkgCache::PkgIterator const &Pkg) { - virtualPkgs.insert(Pkg); - return CacheSetHelper::canNotFindCandidateVer(Cache, Pkg); + virtual pkgCache::VerIterator canNotGetVersion(enum CacheSetHelper::VerSelector const select, pkgCacheFile &Cache, pkgCache::PkgIterator const &Pkg) { + if (select == NEWEST || select == CANDIDATE || select == ALL) + virtualPkgs.insert(Pkg); + return CacheSetHelper::canNotGetVersion(select, Cache, Pkg); } - virtual pkgCache::VerIterator canNotFindNewestVer(pkgCacheFile &Cache, pkgCache::PkgIterator const &Pkg) { - virtualPkgs.insert(Pkg); - return CacheSetHelper::canNotFindNewestVer(Cache, Pkg); - } - - virtual void canNotFindAllVer(APT::VersionContainerInterface * vci, pkgCacheFile &Cache, pkgCache::PkgIterator const &Pkg) { - virtualPkgs.insert(Pkg); - CacheSetHelper::canNotFindAllVer(vci, Cache, Pkg); + virtual void canNotFindVersion(enum CacheSetHelper::VerSelector const select, APT::VersionContainerInterface * vci, pkgCacheFile &Cache, pkgCache::PkgIterator const &Pkg) { + if (select == NEWEST || select == CANDIDATE || select == ALL) + virtualPkgs.insert(Pkg); + return CacheSetHelper::canNotFindVersion(select, vci, Cache, Pkg); } CacheSetHelperVirtuals(bool const ShowErrors = true, GlobalError::MsgType const &ErrorType = GlobalError::NOTICE) : CacheSetHelper(ShowErrors, ErrorType) {} @@ -190,7 +187,7 @@ public: } virtual pkgCache::VerIterator canNotFindCandidateVer(pkgCacheFile &Cache, pkgCache::PkgIterator const &Pkg) { - APT::VersionSet const verset = tryVirtualPackage(Cache, Pkg, APT::VersionSet::CANDIDATE); + APT::VersionSet const verset = tryVirtualPackage(Cache, Pkg, CacheSetHelper::CANDIDATE); if (verset.empty() == false) return *(verset.begin()); else if (ShowError == true) { @@ -203,7 +200,7 @@ public: virtual pkgCache::VerIterator canNotFindNewestVer(pkgCacheFile &Cache, pkgCache::PkgIterator const &Pkg) { if (Pkg->ProvidesList != 0) { - APT::VersionSet const verset = tryVirtualPackage(Cache, Pkg, APT::VersionSet::NEWEST); + APT::VersionSet const verset = tryVirtualPackage(Cache, Pkg, CacheSetHelper::NEWEST); if (verset.empty() == false) return *(verset.begin()); if (ShowError == true) @@ -231,7 +228,7 @@ public: } APT::VersionSet tryVirtualPackage(pkgCacheFile &Cache, pkgCache::PkgIterator const &Pkg, - APT::VersionSet::Version const &select) { + CacheSetHelper::VerSelector const select) { /* This is a pure virtual package and there is a single available candidate providing it. */ if (unlikely(Cache[Pkg].CandidateVer != 0) || Pkg->ProvidesList == 0) diff --git a/apt-private/private-cmndline.cc b/apt-private/private-cmndline.cc index a21a9dc8c..41aab81f6 100644 --- a/apt-private/private-cmndline.cc +++ b/apt-private/private-cmndline.cc @@ -2,12 +2,17 @@ #include <config.h> #include <apt-pkg/cmndline.h> +#include <apt-pkg/configuration.h> +#include <apt-pkg/pkgsystem.h> +#include <apt-pkg/init.h> +#include <apt-pkg/error.h> #include <apt-private/private-cmndline.h> #include <vector> #include <stdarg.h> #include <string.h> +#include <stdlib.h> #include <apti18n.h> /*}}}*/ @@ -70,6 +75,8 @@ static bool addArgumentsAPTCache(std::vector<CommandLine::Args> &Args, char cons else return false; + bool const found_something = Args.empty() == false; + // FIXME: move to the correct command(s) addArg('g', "generate", "APT::Cache::Generate", 0); addArg('t', "target-release", "APT::Default-Release", CommandLine::HasArg); @@ -77,7 +84,8 @@ static bool addArgumentsAPTCache(std::vector<CommandLine::Args> &Args, char cons addArg('p', "pkg-cache", "Dir::Cache::pkgcache", CommandLine::HasArg); addArg('s', "src-cache", "Dir::Cache::srcpkgcache", CommandLine::HasArg); - return true; + + return found_something; } /*}}}*/ static bool addArgumentsAPTCDROM(std::vector<CommandLine::Args> &Args, char const * const Cmd)/*{{{*/ @@ -162,8 +170,8 @@ static bool addArgumentsAPTGet(std::vector<CommandLine::Args> &Args, char const addArg(0, "color", "APT::Moo::Color", 0); if (CmdMatches("install", "remove", "purge", "upgrade", "dist-upgrade", - "deselect-upgrade", "autoremove", "clean", "autoclean", "check", - "build-dep", "full-upgrade")) + "dselect-upgrade", "autoremove", "clean", "autoclean", "check", + "build-dep", "full-upgrade", "source")) { addArg('s', "simulate", "APT::Get::Simulate", 0); addArg('s', "just-print", "APT::Get::Simulate", 0); @@ -172,6 +180,8 @@ static bool addArgumentsAPTGet(std::vector<CommandLine::Args> &Args, char const addArg('s', "no-act", "APT::Get::Simulate", 0); } + bool const found_something = Args.empty() == false; + // FIXME: move to the correct command(s) addArg('d',"download-only","APT::Get::Download-Only",0); addArg('y',"yes","APT::Get::Assume-Yes",0); @@ -193,11 +203,12 @@ static bool addArgumentsAPTGet(std::vector<CommandLine::Args> &Args, char const addArg(0,"only-source","APT::Get::Only-Source",0); addArg(0,"arch-only","APT::Get::Arch-Only",0); addArg(0,"allow-unauthenticated","APT::Get::AllowUnauthenticated",0); + addArg(0,"allow-insecure-repositories","Acquire::AllowInsecureRepositories",0); addArg(0,"install-recommends","APT::Install-Recommends",CommandLine::Boolean); addArg(0,"install-suggests","APT::Install-Suggests",CommandLine::Boolean); addArg(0,"fix-policy","APT::Get::Fix-Policy-Broken",0); - return true; + return found_something; } /*}}}*/ static bool addArgumentsAPTMark(std::vector<CommandLine::Args> &Args, char const * const Cmd)/*{{{*/ @@ -281,3 +292,31 @@ std::vector<CommandLine::Args> getCommandArgs(char const * const Program, char c /*}}}*/ #undef CmdMatches #undef addArg +void ParseCommandLine(CommandLine &CmdL, CommandLine::Dispatch * const Cmds, CommandLine::Args * const Args,/*{{{*/ + Configuration * const * const Cnf, pkgSystem ** const Sys, int const argc, const char *argv[], bool(*ShowHelp)(CommandLine &CmdL)) +{ + CmdL = CommandLine(Args,_config); + if ((Cnf != NULL && pkgInitConfig(**Cnf) == false) || + CmdL.Parse(argc,argv) == false || + (Sys != NULL && pkgInitSystem(*_config, *Sys) == false)) + { + if (_config->FindB("version") == true) + ShowHelp(CmdL); + + _error->DumpErrors(); + exit(100); + } + + // See if the help should be shown + if (_config->FindB("help") == true || _config->FindB("version") == true) + { + ShowHelp(CmdL); + exit(0); + } + if (Cmds != NULL && CmdL.FileSize() == 0) + { + ShowHelp(CmdL); + exit(1); + } +} + /*}}}*/ diff --git a/apt-private/private-cmndline.h b/apt-private/private-cmndline.h index d0af16782..7b468456b 100644 --- a/apt-private/private-cmndline.h +++ b/apt-private/private-cmndline.h @@ -6,6 +6,12 @@ #include <vector> +class Configuration; +class pkgSystem; + APT_PUBLIC std::vector<CommandLine::Args> getCommandArgs(char const * const Program, char const * const Cmd); +APT_PUBLIC void ParseCommandLine(CommandLine &CmdL, CommandLine::Dispatch * const Cmds, CommandLine::Args * const Args, + Configuration * const * const Cnf, pkgSystem ** const Sys, int const argc, const char * argv[], + bool(*ShowHelp)(CommandLine &CmdL)); #endif diff --git a/apt-private/private-download.cc b/apt-private/private-download.cc index a095f0c67..37fae18e9 100644 --- a/apt-private/private-download.cc +++ b/apt-private/private-download.cc @@ -5,6 +5,7 @@ #include <apt-pkg/acquire-item.h> #include <apt-pkg/configuration.h> #include <apt-pkg/error.h> +#include <apt-pkg/fileutl.h> #include <apt-pkg/strutl.h> #include <apt-private/private-output.h> @@ -14,9 +15,66 @@ #include <string> #include <vector> +#include <unistd.h> +#include <sys/types.h> +#include <pwd.h> +#include <fcntl.h> +#include <sys/vfs.h> +#include <sys/statvfs.h> +#include <errno.h> + #include <apti18n.h> /*}}}*/ +bool CheckDropPrivsMustBeDisabled(pkgAcquire &Fetcher) /*{{{*/ +{ + // no need/possibility to drop privs + if(getuid() != 0) + return true; + + // the user does not want to drop privs + std::string SandboxUser = _config->Find("APT::Sandbox::User"); + if (SandboxUser.empty()) + return true; + + struct passwd const * const pw = getpwnam(SandboxUser.c_str()); + if (pw == NULL) + return true; + + if (seteuid(pw->pw_uid) != 0) + return _error->Errno("seteuid", "seteuid %u failed", pw->pw_uid); + + bool res = true; + // check if we can write to destfile + for (pkgAcquire::ItemIterator I = Fetcher.ItemsBegin(); + I != Fetcher.ItemsEnd() && res == true; ++I) + { + if ((*I)->DestFile.empty()) + continue; + // we assume that an existing (partial) file means that we have sufficient rights + if (RealFileExists((*I)->DestFile)) + continue; + int fd = open((*I)->DestFile.c_str(), O_CREAT | O_EXCL | O_RDWR, 0600); + if (fd < 0) + { + res = false; + std::string msg; + strprintf(msg, _("Can't drop privileges for downloading as file '%s' couldn't be accessed by user '%s'."), + (*I)->DestFile.c_str(), SandboxUser.c_str()); + std::cerr << "W: " << msg << std::endl; + _config->Set("APT::Sandbox::User", ""); + break; + } + unlink((*I)->DestFile.c_str()); + close(fd); + } + + if (seteuid(0) != 0) + return _error->Errno("seteuid", "seteuid %u failed", 0); + + return res; +} + /*}}}*/ // CheckAuth - check if each download comes form a trusted source /*{{{*/ bool CheckAuth(pkgAcquire& Fetcher, bool const PromptUser) { @@ -28,6 +86,11 @@ bool CheckAuth(pkgAcquire& Fetcher, bool const PromptUser) if (UntrustedList == "") return true; + return AuthPrompt(UntrustedList, PromptUser); +} + +bool AuthPrompt(std::string const &UntrustedList, bool const PromptUser) +{ ShowList(c2out,_("WARNING: The following packages cannot be authenticated!"),UntrustedList,""); if (_config->FindB("APT::Get::AllowUnauthenticated",false) == true) @@ -93,3 +156,39 @@ bool AcquireRun(pkgAcquire &Fetcher, int const PulseInterval, bool * const Failu return true; } /*}}}*/ +bool CheckFreeSpaceBeforeDownload(std::string const &Dir, unsigned long long FetchBytes)/*{{{*/ +{ + uint32_t const RAMFS_MAGIC = 0x858458f6; + /* Check for enough free space, but only if we are actually going to + download */ + if (_config->FindB("APT::Get::Print-URIs", false) == true || + _config->FindB("APT::Get::Download", true) == false) + return true; + + struct statvfs Buf; + if (statvfs(Dir.c_str(),&Buf) != 0) { + if (errno == EOVERFLOW) + return _error->WarningE("statvfs",_("Couldn't determine free space in %s"), + Dir.c_str()); + else + return _error->Errno("statvfs",_("Couldn't determine free space in %s"), + Dir.c_str()); + } + else + { + unsigned long long const FreeBlocks = _config->Find("APT::Sandbox::User").empty() ? Buf.f_bfree : Buf.f_bavail; + if (FreeBlocks < (FetchBytes / Buf.f_bsize)) + { + struct statfs Stat; + if (statfs(Dir.c_str(),&Stat) != 0 +#if HAVE_STRUCT_STATFS_F_TYPE + || Stat.f_type != RAMFS_MAGIC +#endif + ) + return _error->Error(_("You don't have enough free space in %s."), + Dir.c_str()); + } + } + return true; +} + /*}}}*/ diff --git a/apt-private/private-download.h b/apt-private/private-download.h index a108aa531..0a0ac6b95 100644 --- a/apt-private/private-download.h +++ b/apt-private/private-download.h @@ -3,9 +3,21 @@ #include <apt-pkg/macros.h> +#include <string> + class pkgAcquire; +APT_PUBLIC bool CheckDropPrivsMustBeDisabled(pkgAcquire &Fetcher); + +// Check if all files in the fetcher are authenticated APT_PUBLIC bool CheckAuth(pkgAcquire& Fetcher, bool const PromptUser); + +// show a authentication warning prompt and return true if the system +// should continue +APT_PUBLIC bool AuthPrompt(std::string const &UntrustedList, bool const PromptUser); + APT_PUBLIC bool AcquireRun(pkgAcquire &Fetcher, int const PulseInterval, bool * const Failure, bool * const TransientNetworkFailure); +APT_PUBLIC bool CheckFreeSpaceBeforeDownload(std::string const &Dir, unsigned long long FetchBytes); + #endif diff --git a/apt-private/private-install.cc b/apt-private/private-install.cc index 107ed398e..acc6d42c2 100644 --- a/apt-private/private-install.cc +++ b/apt-private/private-install.cc @@ -19,16 +19,16 @@ #include <apt-pkg/macros.h> #include <apt-pkg/packagemanager.h> #include <apt-pkg/pkgcache.h> +#include <apt-pkg/upgrade.h> +#include <apt-pkg/install-progress.h> -#include <errno.h> #include <stdlib.h> #include <string.h> -#include <sys/statfs.h> -#include <sys/statvfs.h> #include <algorithm> #include <iostream> #include <set> #include <vector> +#include <map> #include <apt-private/acqprogress.h> #include <apt-private/private-install.h> @@ -94,7 +94,7 @@ bool InstallPackages(CacheFile &Cache,bool ShwKept,bool Ask, bool Safety) { pkgSimulate PM(Cache); -#if (APT_PKG_MAJOR >= 4 && APT_PKG_MINOR >= 13) +#if APT_PKG_ABI >= 413 APT::Progress::PackageManager *progress = APT::Progress::PackageManagerProgressFactory(); pkgPackageManager::OrderResult Res = PM.DoInstall(progress); delete progress; @@ -116,14 +116,14 @@ bool InstallPackages(CacheFile &Cache,bool ShwKept,bool Ask, bool Safety) return false; // Create the download object - pkgAcquire Fetcher; - AcqTextStatus Stat(ScreenWidth,_config->FindI("quiet",0)); + 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.Setup(&Stat, _config->FindDir("Dir::Cache::Archives")) == false) + else if (Fetcher.GetLock(_config->FindDir("Dir::Cache::Archives")) == false) return false; // Read the source list @@ -174,33 +174,9 @@ bool InstallPackages(CacheFile &Cache,bool ShwKept,bool Ask, bool Safety) 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; - std::string OutputDir = _config->FindDir("Dir::Cache::Archives"); - if (statvfs(OutputDir.c_str(),&Buf) != 0) { - if (errno == EOVERFLOW) - return _error->WarningE("statvfs",_("Couldn't determine free space in %s"), - OutputDir.c_str()); - else - return _error->Errno("statvfs",_("Couldn't determine free space in %s"), - OutputDir.c_str()); - } else if (unsigned(Buf.f_bfree) < (FetchBytes - FetchPBytes)/Buf.f_bsize) - { - struct statfs Stat; - if (statfs(OutputDir.c_str(),&Stat) != 0 -#if HAVE_STRUCT_STATFS_F_TYPE - || unsigned(Stat.f_type) != RAMFS_MAGIC -#endif - ) - return _error->Error(_("You don't have enough free space in %s."), - OutputDir.c_str()); - } - } - + if (CheckFreeSpaceBeforeDownload(_config->FindDir("Dir::Cache::Archives"), (FetchBytes - FetchPBytes)) == false) + return false; + // Fail safe check if (_config->FindI("quiet",0) >= 2 || _config->FindB("APT::Get::Assume-Yes",false) == true) @@ -330,8 +306,8 @@ bool InstallPackages(CacheFile &Cache,bool ShwKept,bool Ask, bool Safety) } _system->UnLock(); - -#if (APT_PKG_MAJOR >= 4 && APT_PKG_MINOR >= 13) + +#if APT_PKG_ABI >= 413 APT::Progress::PackageManager *progress = APT::Progress::PackageManagerProgressFactory(); pkgPackageManager::OrderResult Res = PM->DoInstall(progress); delete progress; @@ -524,15 +500,14 @@ static bool DoAutomaticRemove(CacheFile &Cache) static const unsigned short MOD_REMOVE = 1; static const unsigned short MOD_INSTALL = 2; -bool DoCacheManipulationFromCommandLine(CommandLine &CmdL, CacheFile &Cache) +bool DoCacheManipulationFromCommandLine(CommandLine &CmdL, CacheFile &Cache, int UpgradeMode) { std::map<unsigned short, APT::VersionSet> verset; - return DoCacheManipulationFromCommandLine(CmdL, Cache, verset); + return DoCacheManipulationFromCommandLine(CmdL, Cache, verset, UpgradeMode); } bool DoCacheManipulationFromCommandLine(CommandLine &CmdL, CacheFile &Cache, - std::map<unsigned short, APT::VersionSet> &verset) + std::map<unsigned short, APT::VersionSet> &verset, int UpgradeMode) { - // Enter the special broken fixing mode if the user specified arguments bool BrokenFix = false; if (Cache->BrokenCount() != 0) @@ -558,9 +533,9 @@ bool DoCacheManipulationFromCommandLine(CommandLine &CmdL, CacheFile &Cache, std::list<APT::VersionSet::Modifier> mods; mods.push_back(APT::VersionSet::Modifier(MOD_INSTALL, "+", - APT::VersionSet::Modifier::POSTFIX, APT::VersionSet::CANDIDATE)); + APT::VersionSet::Modifier::POSTFIX, APT::CacheSetHelper::CANDIDATE)); mods.push_back(APT::VersionSet::Modifier(MOD_REMOVE, "-", - APT::VersionSet::Modifier::POSTFIX, APT::VersionSet::NEWEST)); + APT::VersionSet::Modifier::POSTFIX, APT::CacheSetHelper::NEWEST)); CacheSetHelperAPTGet helper(c0out); verset = APT::VersionSet::GroupedFromCommandLine(Cache, CmdL.FileList + 1, mods, fallback, helper); @@ -617,7 +592,17 @@ bool DoCacheManipulationFromCommandLine(CommandLine &CmdL, CacheFile &Cache, if (Fix != NULL) { // Call the scored problem resolver - Fix->Resolve(true); + OpTextProgress Progress(*_config); + bool const distUpgradeMode = strcmp(CmdL.FileList[0], "dist-upgrade") == 0 || strcmp(CmdL.FileList[0], "full-upgrade") == 0; + + bool resolver_fail = false; + if (distUpgradeMode == true || UpgradeMode != APT::Upgrade::ALLOW_EVERYTHING) + resolver_fail = APT::Upgrade::Upgrade(Cache, UpgradeMode, &Progress); + else + resolver_fail = Fix->Resolve(true, &Progress); + + if (resolver_fail == false && Cache->BrokenCount() == 0) + return false; } // Now we check the state of the packages, @@ -669,13 +654,37 @@ bool DoCacheManipulationFromCommandLine(CommandLine &CmdL, CacheFile &Cache, 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)) + { + // FIXME: make this more elegant + std::string TypeStr = flExtension(*I) + "-file"; + pkgSourceList::Type *Type = pkgSourceList::Type::GetType(TypeStr.c_str()); + if(Type != 0) + { + std::vector<metaIndex *> List; + std::map<std::string, std::string> Options; + if(Type->CreateItem(List, *I, "", "", Options)) + { + // we have our own CacheFile that gives us a SourceList + // with superpowerz + SourceList *sources = (SourceList*)Cache.GetSourceList(); + sources->AddMetaIndex(List[0]); + } + } + } + } + + // then open the cache if (Cache.OpenForInstall() == false || Cache.CheckDeps(CmdL.FileSize() != 1) == false) return false; - + std::map<unsigned short, APT::VersionSet> verset; - if(!DoCacheManipulationFromCommandLine(CmdL, Cache, verset)) + if(!DoCacheManipulationFromCommandLine(CmdL, Cache, verset, 0)) return false; /* Print out a list of packages that are going to be installed extra @@ -801,3 +810,144 @@ bool DoInstall(CommandLine &CmdL) return InstallPackages(Cache,false); } /*}}}*/ + +// TryToInstall - Mark a package for installation /*{{{*/ +void TryToInstall::operator() (pkgCache::VerIterator const &Ver) { + pkgCache::PkgIterator Pkg = Ver.ParentPkg(); + + Cache->GetDepCache()->SetCandidateVersion(Ver); + pkgDepCache::StateCache &State = (*Cache)[Pkg]; + + // Handle the no-upgrade case + if (_config->FindB("APT::Get::upgrade",true) == false && Pkg->CurrentVer != 0) + ioprintf(c1out,_("Skipping %s, it is already installed and upgrade is not set.\n"), + Pkg.FullName(true).c_str()); + // Ignore request for install if package would be new + else if (_config->FindB("APT::Get::Only-Upgrade", false) == true && Pkg->CurrentVer == 0) + ioprintf(c1out,_("Skipping %s, it is not installed and only upgrades are requested.\n"), + Pkg.FullName(true).c_str()); + else { + if (Fix != NULL) { + Fix->Clear(Pkg); + Fix->Protect(Pkg); + } + Cache->GetDepCache()->MarkInstall(Pkg,false); + + if (State.Install() == false) { + if (_config->FindB("APT::Get::ReInstall",false) == true) { + if (Pkg->CurrentVer == 0 || Pkg.CurrentVer().Downloadable() == false) + ioprintf(c1out,_("Reinstallation of %s is not possible, it cannot be downloaded.\n"), + Pkg.FullName(true).c_str()); + else + Cache->GetDepCache()->SetReInstall(Pkg, true); + } else + ioprintf(c1out,_("%s is already the newest version.\n"), + Pkg.FullName(true).c_str()); + } + + // Install it with autoinstalling enabled (if we not respect the minial + // required deps or the policy) + if (FixBroken == false) + doAutoInstallLater.insert(Pkg); + } + + // see if we need to fix the auto-mark flag + // e.g. apt-get install foo + // where foo is marked automatic + if (State.Install() == false && + (State.Flags & pkgCache::Flag::Auto) && + _config->FindB("APT::Get::ReInstall",false) == false && + _config->FindB("APT::Get::Only-Upgrade",false) == false && + _config->FindB("APT::Get::Download-Only",false) == false) + { + ioprintf(c1out,_("%s set to manually installed.\n"), + Pkg.FullName(true).c_str()); + Cache->GetDepCache()->MarkAuto(Pkg,false); + AutoMarkChanged++; + } +} + /*}}}*/ +bool TryToInstall::propergateReleaseCandiateSwitching(std::list<std::pair<pkgCache::VerIterator, std::string> > const &start, std::ostream &out)/*{{{*/ +{ + for (std::list<std::pair<pkgCache::VerIterator, std::string> >::const_iterator s = start.begin(); + s != start.end(); ++s) + Cache->GetDepCache()->SetCandidateVersion(s->first); + + bool Success = true; + // the Changed list contains: + // first: "new version" + // second: "what-caused the change" + std::list<std::pair<pkgCache::VerIterator, pkgCache::VerIterator> > Changed; + for (std::list<std::pair<pkgCache::VerIterator, std::string> >::const_iterator s = start.begin(); + s != start.end(); ++s) + { + Changed.push_back(std::make_pair(s->first, pkgCache::VerIterator(*Cache))); + // We continue here even if it failed to enhance the ShowBroken output + Success &= Cache->GetDepCache()->SetCandidateRelease(s->first, s->second, Changed); + } + for (std::list<std::pair<pkgCache::VerIterator, pkgCache::VerIterator> >::const_iterator c = Changed.begin(); + c != Changed.end(); ++c) + { + if (c->second.end() == true) + ioprintf(out, _("Selected version '%s' (%s) for '%s'\n"), + c->first.VerStr(), c->first.RelStr().c_str(), c->first.ParentPkg().FullName(true).c_str()); + else if (c->first.ParentPkg()->Group != c->second.ParentPkg()->Group) + { + pkgCache::VerIterator V = (*Cache)[c->first.ParentPkg()].CandidateVerIter(*Cache); + ioprintf(out, _("Selected version '%s' (%s) for '%s' because of '%s'\n"), V.VerStr(), + V.RelStr().c_str(), V.ParentPkg().FullName(true).c_str(), c->second.ParentPkg().FullName(true).c_str()); + } + } + return Success; +} + /*}}}*/ +void TryToInstall::doAutoInstall() { /*{{{*/ + for (APT::PackageSet::const_iterator P = doAutoInstallLater.begin(); + P != doAutoInstallLater.end(); ++P) { + pkgDepCache::StateCache &State = (*Cache)[P]; + if (State.InstBroken() == false && State.InstPolicyBroken() == false) + continue; + Cache->GetDepCache()->MarkInstall(P, true); + } + doAutoInstallLater.clear(); +} + /*}}}*/ +// TryToRemove - Mark a package for removal /*{{{*/ +void TryToRemove::operator() (pkgCache::VerIterator const &Ver) +{ + pkgCache::PkgIterator Pkg = Ver.ParentPkg(); + + if (Fix != NULL) + { + Fix->Clear(Pkg); + Fix->Protect(Pkg); + Fix->Remove(Pkg); + } + + if ((Pkg->CurrentVer == 0 && PurgePkgs == false) || + (PurgePkgs == true && Pkg->CurrentState == pkgCache::State::NotInstalled)) + { + pkgCache::GrpIterator Grp = Pkg.Group(); + pkgCache::PkgIterator P = Grp.PackageList(); + for (; P.end() != true; P = Grp.NextPkg(P)) + { + if (P == Pkg) + continue; + if (P->CurrentVer != 0 || (PurgePkgs == true && P->CurrentState != pkgCache::State::NotInstalled)) + { + // TRANSLATORS: Note, this is not an interactive question + ioprintf(c1out,_("Package '%s' is not installed, so not removed. Did you mean '%s'?\n"), + Pkg.FullName(true).c_str(), P.FullName(true).c_str()); + break; + } + } + if (P.end() == true) + ioprintf(c1out,_("Package '%s' is not installed, so not removed\n"),Pkg.FullName(true).c_str()); + + // MarkInstall refuses to install packages on hold + Pkg->SelectedState = pkgCache::State::Hold; + } + else + Cache->GetDepCache()->MarkDelete(Pkg, PurgePkgs); +} + /*}}}*/ diff --git a/apt-private/private-install.h b/apt-private/private-install.h index 5e18560c5..62276fbff 100644 --- a/apt-private/private-install.h +++ b/apt-private/private-install.h @@ -3,43 +3,31 @@ #include <apt-pkg/cachefile.h> #include <apt-pkg/configuration.h> -#include <apt-pkg/depcache.h> #include <apt-pkg/pkgcache.h> #include <apt-pkg/cacheiterators.h> #include <apt-pkg/cacheset.h> -#include <apt-pkg/strutl.h> -#include <apt-pkg/algorithms.h> #include <apt-pkg/macros.h> -#include <apt-private/private-output.h> - -#include <stddef.h> -#include <iosfwd> #include <list> -#include <map> #include <string> #include <utility> - -#include <apti18n.h> - class CacheFile; class CommandLine; - -#define RAMFS_MAGIC 0x858458f6 +class pkgProblemResolver; APT_PUBLIC bool DoInstall(CommandLine &Cmd); bool DoCacheManipulationFromCommandLine(CommandLine &CmdL, CacheFile &Cache, - std::map<unsigned short, APT::VersionSet> &verset); -bool DoCacheManipulationFromCommandLine(CommandLine &CmdL, CacheFile &Cache); + std::map<unsigned short, APT::VersionSet> &verset, int UpgradeMode); +bool DoCacheManipulationFromCommandLine(CommandLine &CmdL, CacheFile &Cache, int UpgradeMode); APT_PUBLIC bool InstallPackages(CacheFile &Cache,bool ShwKept,bool Ask = true, bool Safety = true); // TryToInstall - Mark a package for installation /*{{{*/ -struct TryToInstall { +struct APT_PUBLIC TryToInstall { pkgCacheFile* Cache; pkgProblemResolver* Fix; bool FixBroken; @@ -49,109 +37,13 @@ struct TryToInstall { TryToInstall(pkgCacheFile &Cache, pkgProblemResolver *PM, bool const FixBroken) : Cache(&Cache), Fix(PM), FixBroken(FixBroken), AutoMarkChanged(0) {}; - void operator() (pkgCache::VerIterator const &Ver) { - pkgCache::PkgIterator Pkg = Ver.ParentPkg(); - - Cache->GetDepCache()->SetCandidateVersion(Ver); - pkgDepCache::StateCache &State = (*Cache)[Pkg]; - - // Handle the no-upgrade case - if (_config->FindB("APT::Get::upgrade",true) == false && Pkg->CurrentVer != 0) - ioprintf(c1out,_("Skipping %s, it is already installed and upgrade is not set.\n"), - Pkg.FullName(true).c_str()); - // Ignore request for install if package would be new - else if (_config->FindB("APT::Get::Only-Upgrade", false) == true && Pkg->CurrentVer == 0) - ioprintf(c1out,_("Skipping %s, it is not installed and only upgrades are requested.\n"), - Pkg.FullName(true).c_str()); - else { - if (Fix != NULL) { - Fix->Clear(Pkg); - Fix->Protect(Pkg); - } - Cache->GetDepCache()->MarkInstall(Pkg,false); - - if (State.Install() == false) { - if (_config->FindB("APT::Get::ReInstall",false) == true) { - if (Pkg->CurrentVer == 0 || Pkg.CurrentVer().Downloadable() == false) - ioprintf(c1out,_("Reinstallation of %s is not possible, it cannot be downloaded.\n"), - Pkg.FullName(true).c_str()); - else - Cache->GetDepCache()->SetReInstall(Pkg, true); - } else - ioprintf(c1out,_("%s is already the newest version.\n"), - Pkg.FullName(true).c_str()); - } - - // Install it with autoinstalling enabled (if we not respect the minial - // required deps or the policy) - if (FixBroken == false) - doAutoInstallLater.insert(Pkg); - } - - // see if we need to fix the auto-mark flag - // e.g. apt-get install foo - // where foo is marked automatic - if (State.Install() == false && - (State.Flags & pkgCache::Flag::Auto) && - _config->FindB("APT::Get::ReInstall",false) == false && - _config->FindB("APT::Get::Only-Upgrade",false) == false && - _config->FindB("APT::Get::Download-Only",false) == false) - { - ioprintf(c1out,_("%s set to manually installed.\n"), - Pkg.FullName(true).c_str()); - Cache->GetDepCache()->MarkAuto(Pkg,false); - AutoMarkChanged++; - } - } - - bool propergateReleaseCandiateSwitching(std::list<std::pair<pkgCache::VerIterator, std::string> > start, std::ostream &out) - { - for (std::list<std::pair<pkgCache::VerIterator, std::string> >::const_iterator s = start.begin(); - s != start.end(); ++s) - Cache->GetDepCache()->SetCandidateVersion(s->first); - - bool Success = true; - // the Changed list contains: - // first: "new version" - // second: "what-caused the change" - std::list<std::pair<pkgCache::VerIterator, pkgCache::VerIterator> > Changed; - for (std::list<std::pair<pkgCache::VerIterator, std::string> >::const_iterator s = start.begin(); - s != start.end(); ++s) - { - Changed.push_back(std::make_pair(s->first, pkgCache::VerIterator(*Cache))); - // We continue here even if it failed to enhance the ShowBroken output - Success &= Cache->GetDepCache()->SetCandidateRelease(s->first, s->second, Changed); - } - for (std::list<std::pair<pkgCache::VerIterator, pkgCache::VerIterator> >::const_iterator c = Changed.begin(); - c != Changed.end(); ++c) - { - if (c->second.end() == true) - ioprintf(out, _("Selected version '%s' (%s) for '%s'\n"), - c->first.VerStr(), c->first.RelStr().c_str(), c->first.ParentPkg().FullName(true).c_str()); - else if (c->first.ParentPkg()->Group != c->second.ParentPkg()->Group) - { - pkgCache::VerIterator V = (*Cache)[c->first.ParentPkg()].CandidateVerIter(*Cache); - ioprintf(out, _("Selected version '%s' (%s) for '%s' because of '%s'\n"), V.VerStr(), - V.RelStr().c_str(), V.ParentPkg().FullName(true).c_str(), c->second.ParentPkg().FullName(true).c_str()); - } - } - return Success; - } - - void doAutoInstall() { - for (APT::PackageSet::const_iterator P = doAutoInstallLater.begin(); - P != doAutoInstallLater.end(); ++P) { - pkgDepCache::StateCache &State = (*Cache)[P]; - if (State.InstBroken() == false && State.InstPolicyBroken() == false) - continue; - Cache->GetDepCache()->MarkInstall(P, true); - } - doAutoInstallLater.clear(); - } + void operator() (pkgCache::VerIterator const &Ver); + bool propergateReleaseCandiateSwitching(std::list<std::pair<pkgCache::VerIterator, std::string> > const &start, std::ostream &out); + void doAutoInstall(); }; /*}}}*/ // TryToRemove - Mark a package for removal /*{{{*/ -struct TryToRemove { +struct APT_PUBLIC TryToRemove { pkgCacheFile* Cache; pkgProblemResolver* Fix; bool PurgePkgs; @@ -159,43 +51,7 @@ struct TryToRemove { TryToRemove(pkgCacheFile &Cache, pkgProblemResolver *PM) : Cache(&Cache), Fix(PM), PurgePkgs(_config->FindB("APT::Get::Purge", false)) {}; - void operator() (pkgCache::VerIterator const &Ver) - { - pkgCache::PkgIterator Pkg = Ver.ParentPkg(); - - if (Fix != NULL) - { - Fix->Clear(Pkg); - Fix->Protect(Pkg); - Fix->Remove(Pkg); - } - - if ((Pkg->CurrentVer == 0 && PurgePkgs == false) || - (PurgePkgs == true && Pkg->CurrentState == pkgCache::State::NotInstalled)) - { - pkgCache::GrpIterator Grp = Pkg.Group(); - pkgCache::PkgIterator P = Grp.PackageList(); - for (; P.end() != true; P = Grp.NextPkg(P)) - { - if (P == Pkg) - continue; - if (P->CurrentVer != 0 || (PurgePkgs == true && P->CurrentState != pkgCache::State::NotInstalled)) - { - // TRANSLATORS: Note, this is not an interactive question - ioprintf(c1out,_("Package '%s' is not installed, so not removed. Did you mean '%s'?\n"), - Pkg.FullName(true).c_str(), P.FullName(true).c_str()); - break; - } - } - if (P.end() == true) - ioprintf(c1out,_("Package '%s' is not installed, so not removed\n"),Pkg.FullName(true).c_str()); - - // MarkInstall refuses to install packages on hold - Pkg->SelectedState = pkgCache::State::Hold; - } - else - Cache->GetDepCache()->MarkDelete(Pkg, PurgePkgs); - } + void operator() (pkgCache::VerIterator const &Ver); }; /*}}}*/ diff --git a/apt-private/private-list.cc b/apt-private/private-list.cc index b69002103..aa3a2c24b 100644 --- a/apt-private/private-list.cc +++ b/apt-private/private-list.cc @@ -37,28 +37,20 @@ struct PackageSortAlphabetic /*{{{*/ return (l_name < r_name); } }; - /*}}}*/ -class PackageNameMatcher : public Matcher /*{{{*/ + +class PackageNameMatcher : public Matcher { -#ifdef PACKAGE_MATCHER_ABI_COMPAT -#define PackageMatcher PackageNameMatchesFnmatch -#endif public: PackageNameMatcher(const char **patterns) { for(int i=0; patterns[i] != NULL; ++i) { std::string pattern = patterns[i]; -#ifdef PACKAGE_MATCHER_ABI_COMPAT - APT::CacheFilter::PackageNameMatchesFnmatch *cachefilter = NULL; - cachefilter = new APT::CacheFilter::PackageNameMatchesFnmatch(pattern); -#else APT::CacheFilter::PackageMatcher *cachefilter = NULL; if(_config->FindB("APT::Cmd::Use-Regexp", false) == true) cachefilter = new APT::CacheFilter::PackageNameMatchesRegEx(pattern); else cachefilter = new APT::CacheFilter::PackageNameMatchesFnmatch(pattern); -#endif filters.push_back(cachefilter); } } @@ -85,15 +77,14 @@ private: }; /*}}}*/ static void ListAllVersions(pkgCacheFile &CacheFile, pkgRecords &records,/*{{{*/ - pkgCache::PkgIterator P, - std::ostream &outs, - bool include_summary=true) + pkgCache::PkgIterator const &P, std::ostream &outs, + std::string const &format) { for (pkgCache::VerIterator Ver = P.VersionList(); Ver.end() == false; ++Ver) { - ListSingleVersion(CacheFile, records, Ver, outs, include_summary); - outs << "\n"; + ListSingleVersion(CacheFile, records, Ver, outs, format); + outs << std::endl; } } /*}}}*/ @@ -117,10 +108,9 @@ bool DoList(CommandLine &Cmd) patterns = Cmd.FileList + 1; } - std::map<std::string, std::string> output_map; - std::map<std::string, std::string>::const_iterator K; - - bool includeSummary = _config->FindB("APT::Cmd::List-Include-Summary"); + std::string format = "${color:highlight}${Package}${color:neutral}/${Origin} ${Version} ${Architecture}${ }${apt:Status}"; + if (_config->FindB("APT::Cmd::List-Include-Summary", false) == true) + format += "\n ${Description}\n"; PackageNameMatcher matcher(patterns); LocalitySortedVersionSet bag; @@ -129,37 +119,34 @@ bool DoList(CommandLine &Cmd) Cache->Head().PackageCount, Cache->Head().PackageCount, _("Listing")); - GetLocalitySortedVersionSet(CacheFile, bag, matcher, progress); - bool ShowAllVersions = _config->FindB("APT::Cmd::All-Versions", false); + GetLocalitySortedVersionSet(CacheFile, &bag, matcher, &progress); + bool const ShowAllVersions = _config->FindB("APT::Cmd::All-Versions", false); + std::map<std::string, std::string> output_map; for (LocalitySortedVersionSet::iterator V = bag.begin(); V != bag.end(); ++V) { std::stringstream outs; if(ShowAllVersions == true) - { - ListAllVersions(CacheFile, records, V.ParentPkg(), outs, includeSummary); - output_map.insert(std::make_pair<std::string, std::string>( - V.ParentPkg().Name(), outs.str())); - } else { - ListSingleVersion(CacheFile, records, V, outs, includeSummary); - output_map.insert(std::make_pair<std::string, std::string>( - V.ParentPkg().Name(), outs.str())); - } + ListAllVersions(CacheFile, records, V.ParentPkg(), outs, format); + else + ListSingleVersion(CacheFile, records, V, outs, format); + output_map.insert(std::make_pair<std::string, std::string>( + V.ParentPkg().Name(), outs.str())); } // FIXME: SORT! and make sorting flexible (alphabetic, by pkg status) // output the sorted map + std::map<std::string, std::string>::const_iterator K; for (K = output_map.begin(); K != output_map.end(); ++K) std::cout << (*K).second << std::endl; - // be nice and tell the user if there is more to see if (bag.size() == 1 && ShowAllVersions == false) { // start with -1 as we already displayed one version int versions = -1; pkgCache::VerIterator Ver = *bag.begin(); - for ( ; Ver.end() == false; Ver++) - versions++; + for ( ; Ver.end() == false; ++Ver) + ++versions; if (versions > 0) _error->Notice(P_("There is %i additional version. Please use the '-a' switch to see it", "There are %i additional versions. Please use the '-a' switch to see them.", versions), versions); } diff --git a/apt-private/private-output.cc b/apt-private/private-output.cc index 7f3eef6c2..4e18030ab 100644 --- a/apt-private/private-output.cc +++ b/apt-private/private-output.cc @@ -23,6 +23,7 @@ #include <langinfo.h> #include <unistd.h> #include <signal.h> +#include <sys/ioctl.h> #include <apti18n.h> /*}}}*/ @@ -51,14 +52,14 @@ static void SigWinch(int) #endif } /*}}}*/ -bool InitOutput() /*{{{*/ +bool InitOutput(std::basic_streambuf<char> * const out) /*{{{*/ { if (!isatty(STDOUT_FILENO) && _config->FindI("quiet", -1) == -1) _config->Set("quiet","1"); - c0out.rdbuf(cout.rdbuf()); - c1out.rdbuf(cout.rdbuf()); - c2out.rdbuf(cout.rdbuf()); + c0out.rdbuf(out); + c1out.rdbuf(out); + c2out.rdbuf(out); if (_config->FindI("quiet",0) > 0) c0out.rdbuf(devnull.rdbuf()); if (_config->FindI("quiet",0) > 1) @@ -93,7 +94,7 @@ bool InitOutput() /*{{{*/ static std::string GetArchiveSuite(pkgCacheFile &/*CacheFile*/, pkgCache::VerIterator ver) /*{{{*/ { std::string suite = ""; - if (ver && ver.FileList() && ver.FileList()) + if (ver && ver.FileList()) { pkgCache::VerFileIterator VF = ver.FileList(); for (; VF.end() == false ; ++VF) @@ -117,7 +118,7 @@ static std::string GetFlagsStr(pkgCacheFile &CacheFile, pkgCache::PkgIterator P) std::string flags_str; if (state.NowBroken()) flags_str = "B"; - if (P.CurrentVer() && state.Upgradable()) + if (P.CurrentVer() && state.Upgradable() && state.CandidateVer != NULL) flags_str = "g"; else if (P.CurrentVer() != NULL) flags_str = "i"; @@ -163,15 +164,26 @@ static std::string GetVersion(pkgCacheFile &/*CacheFile*/, pkgCache::VerIterator /*}}}*/ static std::string GetArchitecture(pkgCacheFile &CacheFile, pkgCache::PkgIterator P)/*{{{*/ { - pkgPolicy *policy = CacheFile.GetPolicy(); - pkgCache::VerIterator inst = P.CurrentVer(); - pkgCache::VerIterator cand = policy->GetCandidateVer(P); - - // this may happen for packages in dpkg "deinstall ok config-file" state - if (inst.IsGood() == false && cand.IsGood() == false) - return P.VersionList().Arch(); - - return inst ? inst.Arch() : cand.Arch(); + if (P->CurrentVer == 0) + { + pkgDepCache * const DepCache = CacheFile.GetDepCache(); + pkgDepCache::StateCache const &state = (*DepCache)[P]; + if (state.CandidateVer != NULL) + { + pkgCache::VerIterator const CandV(CacheFile, state.CandidateVer); + return CandV.Arch(); + } + else + { + pkgCache::VerIterator const V = P.VersionList(); + if (V.end() == false) + return V.Arch(); + else + return P.Arch(); + } + } + else + return P.CurrentVer().Arch(); } /*}}}*/ static std::string GetShortDescription(pkgCacheFile &CacheFile, pkgRecords &records, pkgCache::PkgIterator P)/*{{{*/ @@ -195,80 +207,90 @@ static std::string GetShortDescription(pkgCacheFile &CacheFile, pkgRecords &reco return ShortDescription; } /*}}}*/ -void ListSingleVersion(pkgCacheFile &CacheFile, pkgRecords &records, /*{{{*/ - pkgCache::VerIterator V, std::ostream &out, - bool include_summary) +static std::string GetLongDescription(pkgCacheFile &CacheFile, pkgRecords &records, pkgCache::PkgIterator P)/*{{{*/ { - pkgCache::PkgIterator P = V.ParentPkg(); + pkgPolicy *policy = CacheFile.GetPolicy(); - pkgDepCache *DepCache = CacheFile.GetDepCache(); - pkgDepCache::StateCache &state = (*DepCache)[P]; + pkgCache::VerIterator ver; + if (P->CurrentVer != 0) + ver = P.CurrentVer(); + else + ver = policy->GetCandidateVer(P); - std::string suite = GetArchiveSuite(CacheFile, V); - std::string name_str = P.Name(); + std::string const EmptyDescription = "(none)"; + if(ver.end() == true) + return EmptyDescription; + + pkgCache::DescIterator const Desc = ver.TranslatedDescription(); + pkgRecords::Parser & parser = records.Lookup(Desc.FileList()); + std::string const longdesc = parser.LongDesc(); + if (longdesc.empty() == true) + return EmptyDescription; + return SubstVar(longdesc, "\n ", "\n "); +} + /*}}}*/ +void ListSingleVersion(pkgCacheFile &CacheFile, pkgRecords &records, /*{{{*/ + pkgCache::VerIterator const &V, std::ostream &out, + std::string const &format) +{ + pkgCache::PkgIterator const P = V.ParentPkg(); + pkgDepCache * const DepCache = CacheFile.GetDepCache(); + pkgDepCache::StateCache const &state = (*DepCache)[P]; + std::string output; if (_config->FindB("APT::Cmd::use-format", false)) + output = _config->Find("APT::Cmd::format", "${db::Status-Abbrev} ${Package} ${Version} ${Origin} ${Description}"); + else + output = format; + + // FIXME: some of these names are really icky – and all is nowhere documented + output = SubstVar(output, "${db::Status-Abbrev}", GetFlagsStr(CacheFile, P)); + output = SubstVar(output, "${Package}", P.Name()); + std::string const ArchStr = GetArchitecture(CacheFile, P); + output = SubstVar(output, "${Architecture}", ArchStr); + std::string const InstalledVerStr = GetInstalledVersion(CacheFile, P); + output = SubstVar(output, "${installed:Version}", InstalledVerStr); + std::string const CandidateVerStr = GetCandidateVersion(CacheFile, P); + output = SubstVar(output, "${candidate:Version}", CandidateVerStr); + std::string const VersionStr = GetVersion(CacheFile, V); + output = SubstVar(output, "${Version}", VersionStr); + output = SubstVar(output, "${Origin}", GetArchiveSuite(CacheFile, V)); + + std::string StatusStr = ""; + if (P->CurrentVer != 0) { - std::string format = _config->Find("APT::Cmd::format", "${db::Status-Abbrev} ${Package} ${Version} ${Origin} ${Description}"); - std::string output = format; - - output = SubstVar(output, "${db::Status-Abbrev}", GetFlagsStr(CacheFile, P)); - output = SubstVar(output, "${Package}", name_str); - output = SubstVar(output, "${installed:Version}", GetInstalledVersion(CacheFile, P)); - output = SubstVar(output, "${candidate:Version}", GetCandidateVersion(CacheFile, P)); - output = SubstVar(output, "${Version}", GetVersion(CacheFile, V)); - output = SubstVar(output, "${Description}", GetShortDescription(CacheFile, records, P)); - output = SubstVar(output, "${Origin}", GetArchiveSuite(CacheFile, V)); - out << output << std::endl; - } else { - // raring/linux-kernel version [upradable: new-version] - // description - pkgPolicy *policy = CacheFile.GetPolicy(); - std::string VersionStr = GetVersion(CacheFile, V); - std::string CandidateVerStr = GetCandidateVersion(CacheFile, P); - std::string InstalledVerStr = GetInstalledVersion(CacheFile, P); - std::string StatusStr; - if(P.CurrentVer() == V && state.Upgradable()) { - strprintf(StatusStr, _("[installed,upgradable to: %s]"), - CandidateVerStr.c_str()); - } else if (P.CurrentVer() == V) { - if(!V.Downloadable()) - StatusStr = _("[installed,local]"); - else - if(V.Automatic() && state.Garbage) - StatusStr = _("[installed,auto-removable]"); - else if (state.Flags & pkgCache::Flag::Auto) - StatusStr = _("[installed,automatic]"); - else - StatusStr = _("[installed]"); - } else if (P.CurrentVer() && - policy->GetCandidateVer(P) == V && - state.Upgradable()) { - strprintf(StatusStr, _("[upgradable from: %s]"), - InstalledVerStr.c_str()); - } else { - if (V.ParentPkg()->CurrentState == pkgCache::State::ConfigFiles) - StatusStr = _("[residual-config]"); - else - StatusStr = ""; - } - out << std::setiosflags(std::ios::left) - << _config->Find("APT::Color::Highlight", "") - << name_str - << _config->Find("APT::Color::Neutral", "") - << "/" << suite - << " " - << VersionStr << " " - << GetArchitecture(CacheFile, P); - if (StatusStr != "") - out << " " << StatusStr; - if (include_summary) + if (P.CurrentVer() == V) { - out << std::endl - << " " << GetShortDescription(CacheFile, records, P) - << std::endl; + if (state.Upgradable() && state.CandidateVer != NULL) + strprintf(StatusStr, _("[installed,upgradable to: %s]"), + CandidateVerStr.c_str()); + else if (V.Downloadable() == false) + StatusStr = _("[installed,local]"); + else if(V.Automatic() == true && state.Garbage == true) + StatusStr = _("[installed,auto-removable]"); + else if ((state.Flags & pkgCache::Flag::Auto) == pkgCache::Flag::Auto) + StatusStr = _("[installed,automatic]"); + else + StatusStr = _("[installed]"); } + else if (state.CandidateVer == V && state.Upgradable()) + strprintf(StatusStr, _("[upgradable from: %s]"), + InstalledVerStr.c_str()); } + else if (V.ParentPkg()->CurrentState == pkgCache::State::ConfigFiles) + StatusStr = _("[residual-config]"); + output = SubstVar(output, "${apt:Status}", StatusStr); + output = SubstVar(output, "${color:highlight}", _config->Find("APT::Color::Highlight", "")); + output = SubstVar(output, "${color:neutral}", _config->Find("APT::Color::Neutral", "")); + output = SubstVar(output, "${Description}", GetShortDescription(CacheFile, records, P)); + output = SubstVar(output, "${LongDescription}", GetLongDescription(CacheFile, records, P)); + output = SubstVar(output, "${ }${ }", "${ }"); + output = SubstVar(output, "${ }\n", "\n"); + output = SubstVar(output, "${ }", " "); + if (APT::String::Endswith(output, " ") == true) + output.erase(output.length() - 1); + + out << output; } /*}}}*/ // ShowList - Show a list /*{{{*/ @@ -343,129 +365,141 @@ bool ShowList(ostream &out,string Title,string List,string VersionsList) 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) +static void ShowBrokenPackage(ostream &out, pkgCacheFile * const Cache, pkgCache::PkgIterator const &Pkg, bool const Now) { - if (Cache->BrokenCount() == 0) + if (Now == true) + { + if ((*Cache)[Pkg].NowBroken() == false) + return; + } + else + { + if ((*Cache)[Pkg].InstBroken() == false) + return; + } + + // Print out each package and the failed dependencies + out << " " << Pkg.FullName(true) << " :"; + unsigned const Indent = Pkg.FullName(true).size() + 3; + bool First = true; + pkgCache::VerIterator Ver; + + if (Now == true) + Ver = Pkg.CurrentVer(); + else + Ver = (*Cache)[Pkg].InstVerIter(*Cache); + + if (Ver.end() == true) + { + out << endl; return; + } - out << _("The following packages have unmet dependencies:") << endl; - for (unsigned J = 0; J < Cache->Head().PackageCount; J++) + for (pkgCache::DepIterator D = Ver.DependsList(); D.end() == false;) { - pkgCache::PkgIterator I(Cache,Cache.List[J]); - + // Compute a single dependency element (glob or) + pkgCache::DepIterator Start; + pkgCache::DepIterator End; + D.GlobOr(Start,End); // advances D + + if ((*Cache)->IsImportantDep(End) == false) + continue; + if (Now == true) { - if (Cache[I].NowBroken() == false) + if (((*Cache)[End] & pkgDepCache::DepGNow) == pkgDepCache::DepGNow) continue; } else { - if (Cache[I].InstBroken() == false) + if (((*Cache)[End] & pkgDepCache::DepGInstall) == pkgDepCache::DepGInstall) continue; } - - // Print out each package and the failed dependencies - out << " " << I.FullName(true) << " :"; - unsigned const Indent = I.FullName(true).size() + 3; - bool First = true; - pkgCache::VerIterator Ver; - - if (Now == true) - Ver = I.CurrentVer(); - else - Ver = Cache[I].InstVerIter(Cache); - - if (Ver.end() == true) - { - out << endl; - continue; - } - - for (pkgCache::DepIterator D = Ver.DependsList(); D.end() == false;) + + bool FirstOr = true; + while (1) { - // Compute a single dependency element (glob or) - pkgCache::DepIterator Start; - pkgCache::DepIterator End; - D.GlobOr(Start,End); // advances D + if (First == false) + for (unsigned J = 0; J != Indent; J++) + out << ' '; + First = false; - if (Cache->IsImportantDep(End) == false) - continue; - - if (Now == true) + if (FirstOr == false) { - if ((Cache[End] & pkgDepCache::DepGNow) == pkgDepCache::DepGNow) - continue; + for (unsigned J = 0; J != strlen(End.DepType()) + 3; J++) + out << ' '; } else + out << ' ' << End.DepType() << ": "; + FirstOr = false; + + out << Start.TargetPkg().FullName(true); + + // Show a quick summary of the version requirements + if (Start.TargetVer() != 0) + 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) { - if ((Cache[End] & pkgDepCache::DepGInstall) == pkgDepCache::DepGInstall) - continue; - } - - bool FirstOr = true; - while (1) - { - if (First == false) - for (unsigned J = 0; J != Indent; J++) - out << ' '; - First = false; + out << ' '; + pkgCache::VerIterator Ver = (*Cache)[Targ].InstVerIter(*Cache); + if (Now == true) + Ver = Targ.CurrentVer(); - if (FirstOr == false) + if (Ver.end() == false) { - for (unsigned J = 0; J != strlen(End.DepType()) + 3; J++) - out << ' '; + if (Now == true) + ioprintf(out,_("but %s is installed"),Ver.VerStr()); + else + ioprintf(out,_("but %s is to be installed"),Ver.VerStr()); } else - out << ' ' << End.DepType() << ": "; - FirstOr = false; - - out << Start.TargetPkg().FullName(true); - - // Show a quick summary of the version requirements - if (Start.TargetVer() != 0) - 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 << ' '; - pkgCache::VerIterator Ver = Cache[Targ].InstVerIter(Cache); - if (Now == true) - Ver = Targ.CurrentVer(); - - if (Ver.end() == false) + if ((*Cache)[Targ].CandidateVerIter(*Cache).end() == true) { - if (Now == true) - ioprintf(out,_("but %s is installed"),Ver.VerStr()); + if (Targ->ProvidesList == 0) + out << _("but it is not installable"); else - ioprintf(out,_("but %s is to be installed"),Ver.VerStr()); - } + out << _("but it is a virtual package"); + } else - { - if (Cache[Targ].CandidateVerIter(Cache).end() == true) - { - if (Targ->ProvidesList == 0) - out << _("but it is not installable"); - else - out << _("but it is a virtual package"); - } - else - out << (Now?_("but it is not installed"):_("but 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) - out << _(" or"); - out << endl; - - if (Start == End) - break; - ++Start; - } - } - } + } + + if (Start != End) + out << _(" or"); + out << endl; + + if (Start == End) + break; + ++Start; + } + } +} +void ShowBroken(ostream &out, CacheFile &Cache, bool const Now) +{ + if (Cache->BrokenCount() == 0) + return; + + out << _("The following packages have unmet dependencies:") << endl; + for (unsigned J = 0; J < Cache->Head().PackageCount; J++) + { + pkgCache::PkgIterator const I(Cache,Cache.List[J]); + ShowBrokenPackage(out, &Cache, I, Now); + } +} +void ShowBroken(ostream &out, pkgCacheFile &Cache, bool const Now) +{ + if (Cache->BrokenCount() == 0) + return; + + out << _("The following packages have unmet dependencies:") << endl; + for (pkgCache::PkgIterator Pkg = Cache->PkgBegin(); Pkg.end() == false; ++Pkg) + ShowBrokenPackage(out, &Cache, Pkg, Now); } /*}}}*/ // ShowNew - Show packages to newly install /*{{{*/ diff --git a/apt-private/private-output.h b/apt-private/private-output.h index 9633d0c37..d5b57adec 100644 --- a/apt-private/private-output.h +++ b/apt-private/private-output.h @@ -6,6 +6,7 @@ #include <fstream> #include <string> +#include <iostream> // forward declaration class pkgCacheFile; @@ -20,15 +21,16 @@ APT_PUBLIC extern std::ostream c2out; APT_PUBLIC extern std::ofstream devnull; APT_PUBLIC extern unsigned int ScreenWidth; -APT_PUBLIC bool InitOutput(); +APT_PUBLIC bool InitOutput(std::basic_streambuf<char> * const out = std::cout.rdbuf()); void ListSingleVersion(pkgCacheFile &CacheFile, pkgRecords &records, - pkgCache::VerIterator V, std::ostream &out, - bool include_summary=true); + pkgCache::VerIterator const &V, std::ostream &out, + std::string const &format); // helper to describe global state -APT_PUBLIC void ShowBroken(std::ostream &out,CacheFile &Cache,bool Now); +APT_PUBLIC void ShowBroken(std::ostream &out, CacheFile &Cache, bool const Now); +APT_PUBLIC void ShowBroken(std::ostream &out, pkgCacheFile &Cache, bool const Now); APT_PUBLIC bool ShowList(std::ostream &out, std::string Title, std::string List, std::string VersionsList); diff --git a/apt-private/private-search.cc b/apt-private/private-search.cc index ecd5d7fad..6bce9ffa4 100644 --- a/apt-private/private-search.cc +++ b/apt-private/private-search.cc @@ -32,61 +32,95 @@ bool FullTextSearch(CommandLine &CmdL) /*{{{*/ pkgCacheFile CacheFile; pkgCache *Cache = CacheFile.GetPkgCache(); pkgDepCache::Policy *Plcy = CacheFile.GetPolicy(); - pkgRecords records(CacheFile); if (unlikely(Cache == NULL || Plcy == NULL)) return false; - const char **patterns; - patterns = CmdL.FileList + 1; + // Make sure there is at least one argument + unsigned int const NumPatterns = CmdL.FileSize() -1; + if (NumPatterns < 1) + return _error->Error(_("You must give at least one search pattern")); + +#define APT_FREE_PATTERNS() for (std::vector<regex_t>::iterator P = Patterns.begin(); \ + P != Patterns.end(); ++P) { regfree(&(*P)); } + + // Compile the regex pattern + std::vector<regex_t> Patterns; + for (unsigned int I = 0; I != NumPatterns; ++I) + { + regex_t pattern; + if (regcomp(&pattern, CmdL.FileList[I + 1], REG_EXTENDED | REG_ICASE | REG_NOSUB) != 0) + { + APT_FREE_PATTERNS(); + return _error->Error("Regex compilation error"); + } + Patterns.push_back(pattern); + } + + bool const NamesOnly = _config->FindB("APT::Cache::NamesOnly", false); std::map<std::string, std::string> output_map; - std::map<std::string, std::string>::const_iterator K; LocalitySortedVersionSet bag; OpTextProgress progress(*_config); progress.OverallProgress(0, 100, 50, _("Sorting")); - GetLocalitySortedVersionSet(CacheFile, bag, progress); + GetLocalitySortedVersionSet(CacheFile, &bag, &progress); LocalitySortedVersionSet::iterator V = bag.begin(); progress.OverallProgress(50, 100, 50, _("Full Text Search")); progress.SubProgress(bag.size()); + pkgRecords records(CacheFile); + + std::string format = "${color:highlight}${Package}${color:neutral}/${Origin} ${Version} ${Architecture}${ }${apt:Status}\n"; + if (_config->FindB("APT::Cache::ShowFull",false) == false) + format += " ${Description}\n"; + else + format += " ${LongDescription}\n"; + int Done = 0; + std::vector<bool> PkgsDone(Cache->Head().PackageCount, false); for ( ;V != bag.end(); ++V) { if (Done%500 == 0) progress.Progress(Done); ++Done; - - int i; + + // we want to list each package only once + pkgCache::PkgIterator const P = V.ParentPkg(); + if (PkgsDone[P->ID] == true) + continue; + + char const * const PkgName = P.Name(); pkgCache::DescIterator Desc = V.TranslatedDescription(); pkgRecords::Parser &parser = records.Lookup(Desc.FileList()); - + std::string const LongDesc = parser.LongDesc(); + bool all_found = true; - for(i=0; patterns[i] != NULL; ++i) + for (std::vector<regex_t>::const_iterator pattern = Patterns.begin(); + pattern != Patterns.end(); ++pattern) { - // FIXME: use regexp instead of simple find() - const char *pattern = patterns[i]; - all_found &= ( - strstr(V.ParentPkg().Name(), pattern) != NULL || - strcasestr(parser.ShortDesc().c_str(), pattern) != NULL || - strcasestr(parser.LongDesc().c_str(), pattern) != NULL); - // search patterns are AND by default so we can skip looking further - // on the first mismatch - if(all_found == false) - break; + if (regexec(&(*pattern), PkgName, 0, 0, 0) == 0) + continue; + else if (NamesOnly == false && regexec(&(*pattern), LongDesc.c_str(), 0, 0, 0) == 0) + continue; + // search patterns are AND, so one failing fails all + all_found = false; + break; } - if (all_found) + if (all_found == true) { - std::stringstream outs; - ListSingleVersion(CacheFile, records, V, outs); - output_map.insert(std::make_pair<std::string, std::string>( - V.ParentPkg().Name(), outs.str())); + PkgsDone[P->ID] = true; + std::stringstream outs; + ListSingleVersion(CacheFile, records, V, outs, format); + output_map.insert(std::make_pair<std::string, std::string>( + PkgName, outs.str())); } } + APT_FREE_PATTERNS(); progress.Done(); // FIXME: SORT! and make sorting flexible (alphabetic, by pkg status) // output the sorted map + std::map<std::string, std::string>::const_iterator K; for (K = output_map.begin(); K != output_map.end(); ++K) std::cout << (*K).second << std::endl; diff --git a/apt-private/private-show.cc b/apt-private/private-show.cc index 8ae6a6dac..790bc0092 100644 --- a/apt-private/private-show.cc +++ b/apt-private/private-show.cc @@ -97,28 +97,30 @@ static bool DisplayRecord(pkgCacheFile &CacheFile, pkgCache::VerIterator V, manual_installed = 0; // FIXME: add verbose that does not do the removal of the tags? - TFRewriteData RW[] = { - // delete, apt-cache show has this info and most users do not care - {"MD5sum", NULL, NULL}, - {"SHA1", NULL, NULL}, - {"SHA256", NULL, NULL}, - {"Filename", NULL, NULL}, - {"Multi-Arch", NULL, NULL}, - {"Architecture", NULL, NULL}, - {"Conffiles", NULL, NULL}, - // we use the translated description - {"Description", NULL, NULL}, - {"Description-md5", NULL, NULL}, - // improve - {"Installed-Size", installed_size.c_str(), NULL}, - {"Size", package_size.c_str(), "Download-Size"}, - // add - {"APT-Manual-Installed", manual_installed, NULL}, - {"APT-Sources", source_index_file.c_str(), NULL}, - {NULL, NULL, NULL} - }; - - if(TFRewrite(stdout, Tags, NULL, RW) == false) + std::vector<pkgTagSection::Tag> RW; + // delete, apt-cache show has this info and most users do not care + RW.push_back(pkgTagSection::Tag::Remove("MD5sum")); + RW.push_back(pkgTagSection::Tag::Remove("SHA1")); + RW.push_back(pkgTagSection::Tag::Remove("SHA256")); + RW.push_back(pkgTagSection::Tag::Remove("SHA512")); + RW.push_back(pkgTagSection::Tag::Remove("Filename")); + RW.push_back(pkgTagSection::Tag::Remove("Multi-Arch")); + RW.push_back(pkgTagSection::Tag::Remove("Architecture")); + RW.push_back(pkgTagSection::Tag::Remove("Conffiles")); + // we use the translated description + RW.push_back(pkgTagSection::Tag::Remove("Description")); + RW.push_back(pkgTagSection::Tag::Remove("Description-md5")); + // improve + RW.push_back(pkgTagSection::Tag::Rewrite("Installed-Size", installed_size)); + RW.push_back(pkgTagSection::Tag::Remove("Size")); + RW.push_back(pkgTagSection::Tag::Rewrite("Download-Size", package_size)); + // add + RW.push_back(pkgTagSection::Tag::Rewrite("APT-Manual-Installed", manual_installed)); + RW.push_back(pkgTagSection::Tag::Rewrite("APT-Sources", source_index_file)); + + FileFd stdoutfd; + if (stdoutfd.OpenDescriptor(STDOUT_FILENO, FileFd::WriteOnly, false) == false || + Tags.Write(stdoutfd, TFRewritePackageOrder, RW) == false || stdoutfd.Close() == false) return _error->Error("Internal Error, Unable to parse a package record"); // write the description @@ -141,16 +143,16 @@ bool ShowPackage(CommandLine &CmdL) /*{{{*/ { pkgCacheFile CacheFile; CacheSetHelperVirtuals helper(true, GlobalError::NOTICE); - APT::VersionList::Version const select = _config->FindB("APT::Cache::AllVersions", false) ? - APT::VersionList::ALL : APT::VersionList::CANDIDATE; + APT::CacheSetHelper::VerSelector const select = _config->FindB("APT::Cache::AllVersions", false) ? + APT::CacheSetHelper::ALL : APT::CacheSetHelper::CANDIDATE; APT::VersionList const verset = APT::VersionList::FromCommandLine(CacheFile, CmdL.FileList + 1, select, helper); for (APT::VersionList::const_iterator Ver = verset.begin(); Ver != verset.end(); ++Ver) if (DisplayRecord(CacheFile, Ver, c1out) == false) return false; - if (select == APT::VersionList::CANDIDATE) + if (select == APT::CacheSetHelper::CANDIDATE) { - APT::VersionList const verset_all = APT::VersionList::FromCommandLine(CacheFile, CmdL.FileList + 1, APT::VersionList::ALL, helper); + APT::VersionList const verset_all = APT::VersionList::FromCommandLine(CacheFile, CmdL.FileList + 1, APT::CacheSetHelper::ALL, helper); int const records = verset_all.size() - verset.size(); if (records > 0) _error->Notice(P_("There is %i additional record. Please use the '-a' switch to see it", "There are %i additional records. Please use the '-a' switch to see them.", records), records); diff --git a/apt-private/private-update.cc b/apt-private/private-update.cc index da83d7741..73a82e988 100644 --- a/apt-private/private-update.cc +++ b/apt-private/private-update.cc @@ -38,8 +38,8 @@ bool DoUpdate(CommandLine &CmdL) pkgSourceList *List = Cache.GetSourceList(); // Create the progress - AcqTextStatus Stat(ScreenWidth,_config->FindI("quiet",0)); - + AcqTextStatus Stat(std::cout, ScreenWidth,_config->FindI("quiet",0)); + // Just print out the uris an exit if the --print-uris flag was used if (_config->FindB("APT::Get::Print-URIs") == true) { @@ -47,19 +47,24 @@ bool DoUpdate(CommandLine &CmdL) _config->CndSet("Acquire::ForceHash", "md5sum"); // get a fetcher - pkgAcquire Fetcher; - if (Fetcher.Setup(&Stat) == false) - return false; + pkgAcquire Fetcher(&Stat); // Populate it with the source selection and get all Indexes // (GetAll=true) if (List->GetIndexes(&Fetcher,true) == false) return false; + std::string compExt = APT::Configuration::getCompressionTypes()[0]; pkgAcquire::UriIterator I = Fetcher.UriBegin(); for (; I != Fetcher.UriEnd(); ++I) - c1out << '\'' << I->URI << "' " << flNotDir(I->Owner->DestFile) << ' ' << + { + std::string FileName = flNotDir(I->Owner->DestFile); + if(compExt.empty() == false && + APT::String::Endswith(FileName, compExt)) + FileName = FileName.substr(0, FileName.size() - compExt.size() - 1); + c1out << '\'' << I->URI << "' " << FileName << ' ' << I->Owner->FileSize << ' ' << I->Owner->HashSum() << std::endl; + } return true; } @@ -75,6 +80,27 @@ bool DoUpdate(CommandLine &CmdL) return false; } + // show basic stats (if the user whishes) + if (_config->FindB("APT::Cmd::Show-Update-Stats", false) == true) + { + int upgradable = 0; + Cache.Open(); + for (pkgCache::PkgIterator I = Cache->PkgBegin(); I.end() != true; ++I) + { + pkgDepCache::StateCache &state = Cache[I]; + if (I->CurrentVer != 0 && state.Upgradable() && state.CandidateVer != NULL) + upgradable++; + } + const char *msg = P_( + "%i package can be upgraded. Run 'apt list --upgradable' to see it.\n", + "%i packages can be upgraded. Run 'apt list --upgradable' to see them.\n", + upgradable); + if (upgradable == 0) + c1out << _("All packages are up to date.") << std::endl; + else + ioprintf(c1out, msg, upgradable); + } + return true; } /*}}}*/ diff --git a/apt-private/private-upgrade.cc b/apt-private/private-upgrade.cc index 68b2c5e00..d13a6af49 100644 --- a/apt-private/private-upgrade.cc +++ b/apt-private/private-upgrade.cc @@ -22,19 +22,9 @@ static bool UpgradeHelper(CommandLine &CmdL, int UpgradeFlags) if (Cache.OpenForInstall() == false || Cache.CheckDeps() == false) return false; - c0out << _("Calculating upgrade... ") << std::flush; - if (APT::Upgrade::Upgrade(Cache, UpgradeFlags) == false) - { - c0out << _("Failed") << std::endl; - ShowBroken(c1out,Cache,false); - return _error->Error(_("Internal error, Upgrade broke stuff")); - } - c0out << _("Done") << std::endl; - - // parse additional cmdline pkg manipulation switches - if(!DoCacheManipulationFromCommandLine(CmdL, Cache)) + if(!DoCacheManipulationFromCommandLine(CmdL, Cache, UpgradeFlags)) return false; - + return InstallPackages(Cache,true); } @@ -43,7 +33,7 @@ static bool UpgradeHelper(CommandLine &CmdL, int UpgradeFlags) /* Intelligent upgrader that will install and remove packages at will */ bool DoDistUpgrade(CommandLine &CmdL) { - return UpgradeHelper(CmdL, 0); + return UpgradeHelper(CmdL, APT::Upgrade::ALLOW_EVERYTHING); } /*}}}*/ bool DoUpgrade(CommandLine &CmdL) /*{{{*/ diff --git a/apt-private/private-utils.cc b/apt-private/private-utils.cc index 9547a1b75..34af83c08 100644 --- a/apt-private/private-utils.cc +++ b/apt-private/private-utils.cc @@ -8,45 +8,69 @@ #include <cstdlib> #include <unistd.h> -// DisplayFileInPager - Display File with pager /*{{{*/ -void DisplayFileInPager(std::string filename) +// DisplayFileInPager - Display File with pager /*{{{*/ +void DisplayFileInPager(std::string const &filename) { - std::string pager = _config->Find("Dir::Bin::Pager", - "/usr/bin/sensible-pager"); - pid_t Process = ExecFork(); if (Process == 0) { const char *Args[3]; - Args[0] = pager.c_str(); Args[1] = filename.c_str(); - Args[2] = 0; + Args[2] = NULL; + if (isatty(STDOUT_FILENO) == 1) + { + // likely installed, provided by sensible-utils + std::string const pager = _config->Find("Dir::Bin::Pager", + "sensible-pager"); + Args[0] = pager.c_str(); + execvp(Args[0],(char **)Args); + // lets try some obvious alternatives + Args[0] = getenv("PAGER"); + if (Args[0] != NULL) + execvp(Args[0],(char **)Args); + + Args[0] = "pager"; + execvp(Args[0],(char **)Args); + } + // we could read the file ourselves, but… meh + Args[0] = "cat"; execvp(Args[0],(char **)Args); exit(100); } - + // Wait for the subprocess - ExecWait(Process, "sensible-pager", false); + ExecWait(Process, "pager", false); } /*}}}*/ -// EditFileInSensibleEditor - Edit File with editor /*{{{*/ -void EditFileInSensibleEditor(std::string filename) +// EditFileInSensibleEditor - Edit File with editor /*{{{*/ +void EditFileInSensibleEditor(std::string const &filename) { - std::string editor = _config->Find("Dir::Bin::Editor", - "/usr/bin/sensible-editor"); - pid_t Process = ExecFork(); if (Process == 0) { + // likely installed, provided by sensible-utils + std::string const editor = _config->Find("Dir::Bin::Editor", + "sensible-editor"); const char *Args[3]; Args[0] = editor.c_str(); Args[1] = filename.c_str(); - Args[2] = 0; + Args[2] = NULL; + execvp(Args[0],(char **)Args); + // the usual suspects we can try as an alternative + Args[0] = getenv("VISUAL"); + if (Args[0] != NULL) + execvp(Args[0],(char **)Args); + + Args[0] = getenv("EDITOR"); + if (Args[0] != NULL) + execvp(Args[0],(char **)Args); + + Args[0] = "editor"; execvp(Args[0],(char **)Args); exit(100); } - + // Wait for the subprocess - ExecWait(Process, "sensible-editor", false); + ExecWait(Process, "editor", false); } /*}}}*/ diff --git a/apt-private/private-utils.h b/apt-private/private-utils.h index 432699787..8ba480bd4 100644 --- a/apt-private/private-utils.h +++ b/apt-private/private-utils.h @@ -5,7 +5,7 @@ #include <string> -APT_PUBLIC void DisplayFileInPager(std::string filename); -APT_PUBLIC void EditFileInSensibleEditor(std::string filename); +APT_PUBLIC void DisplayFileInPager(std::string const &filename); +APT_PUBLIC void EditFileInSensibleEditor(std::string const &filename); #endif |