diff options
Diffstat (limited to 'apt-private')
27 files changed, 3784 insertions, 0 deletions
diff --git a/apt-private/acqprogress.cc b/apt-private/acqprogress.cc new file mode 100644 index 000000000..af2d0f461 --- /dev/null +++ b/apt-private/acqprogress.cc @@ -0,0 +1,309 @@ +// -*- 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 + + ##################################################################### */ + /*}}}*/ +// Include files /*{{{*/ +#include<config.h> + +#include <apt-pkg/acquire-item.h> +#include <apt-pkg/acquire-worker.h> +#include <apt-pkg/configuration.h> +#include <apt-pkg/strutl.h> +#include <apt-pkg/error.h> + +#include <stdio.h> +#include <signal.h> +#include <iostream> +#include <unistd.h> + +#include "acqprogress.h" +#include <apti18n.h> + /*}}}*/ + +using namespace std; + +// AcqTextStatus::AcqTextStatus - Constructor /*{{{*/ +// --------------------------------------------------------------------- +/* */ +AcqTextStatus::AcqTextStatus(unsigned int &ScreenWidth,unsigned int Quiet) : + ScreenWidth(ScreenWidth), ID(0), Quiet(Quiet) +{ + BlankLine[0] = 0; +} + /*}}}*/ +// AcqTextStatus::Start - Downloading has started /*{{{*/ +// --------------------------------------------------------------------- +/* */ +void AcqTextStatus::Start() +{ + pkgAcquireStatus::Start(); + BlankLine[0] = 0; + ID = 1; +}; + /*}}}*/ +// AcqTextStatus::IMSHit - Called when an item got a HIT response /*{{{*/ +// --------------------------------------------------------------------- +/* */ +void AcqTextStatus::IMSHit(pkgAcquire::ItemDesc &Itm) +{ + if (Quiet > 1) + return; + + if (Quiet <= 0) + cout << '\r' << BlankLine << '\r'; + + cout << _("Hit ") << Itm.Description; + if (Itm.Owner->FileSize != 0) + cout << " [" << SizeToStr(Itm.Owner->FileSize) << "B]"; + cout << endl; + Update = true; +}; + /*}}}*/ +// AcqTextStatus::Fetch - An item has started to download /*{{{*/ +// --------------------------------------------------------------------- +/* This prints out the short description and the expected size */ +void AcqTextStatus::Fetch(pkgAcquire::ItemDesc &Itm) +{ + Update = true; + if (Itm.Owner->Complete == true) + return; + + Itm.Owner->ID = ID++; + + if (Quiet > 1) + return; + + if (Quiet <= 0) + cout << '\r' << BlankLine << '\r'; + + cout << _("Get:") << Itm.Owner->ID << ' ' << Itm.Description; + if (Itm.Owner->FileSize != 0) + cout << " [" << SizeToStr(Itm.Owner->FileSize) << "B]"; + cout << endl; +}; + /*}}}*/ +// AcqTextStatus::Done - Completed a download /*{{{*/ +// --------------------------------------------------------------------- +/* We don't display anything... */ +void AcqTextStatus::Done(pkgAcquire::ItemDesc &Itm) +{ + Update = true; +}; + /*}}}*/ +// AcqTextStatus::Fail - Called when an item fails to download /*{{{*/ +// --------------------------------------------------------------------- +/* We print out the error text */ +void AcqTextStatus::Fail(pkgAcquire::ItemDesc &Itm) +{ + if (Quiet > 1) + return; + + // Ignore certain kinds of transient failures (bad code) + if (Itm.Owner->Status == pkgAcquire::Item::StatIdle) + return; + + if (Quiet <= 0) + cout << '\r' << BlankLine << '\r'; + + if (Itm.Owner->Status == pkgAcquire::Item::StatDone) + { + cout << _("Ign ") << Itm.Description << endl; + } + else + { + cout << _("Err ") << Itm.Description << endl; + cout << " " << Itm.Owner->ErrorText << endl; + } + + Update = true; +}; + /*}}}*/ +// AcqTextStatus::Stop - Finished downloading /*{{{*/ +// --------------------------------------------------------------------- +/* This prints out the bytes downloaded and the overall average line + speed */ +void AcqTextStatus::Stop() +{ + pkgAcquireStatus::Stop(); + if (Quiet > 1) + return; + + if (Quiet <= 0) + cout << '\r' << BlankLine << '\r' << flush; + + if (FetchedBytes != 0 && _error->PendingError() == false) + ioprintf(cout,_("Fetched %sB in %s (%sB/s)\n"), + SizeToStr(FetchedBytes).c_str(), + TimeToStr(ElapsedTime).c_str(), + SizeToStr(CurrentCPS).c_str()); +} + /*}}}*/ +// 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 + bandwidth and ETA indicator. */ +bool AcqTextStatus::Pulse(pkgAcquire *Owner) +{ + pkgAcquireStatus::Pulse(Owner); + + if (Quiet > 0) + return true; + + 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)) + { + S += strlen(S); + + // There is no item running + if (I->CurrentItem == 0) + { + if (I->Status.empty() == false) + { + snprintf(S,End-S," [%s]",I->Status.c_str()); + Shown = true; + } + + continue; + } + + Shown = true; + + // 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); + + // 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); + + // 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); + else + snprintf(S,End-S,"/%sB %.0f%%",SizeToStr(I->TotalSize).c_str(), + (I->CurrentSize*100.0)/I->TotalSize); + } + S += strlen(S); + snprintf(S,End-S,"]"); + } + + // Show something.. + if (Shown == false) + snprintf(S,End-S,_(" [Working]")); + + /* Put in the ETA and cps meter, block off signals to prevent strangeness + during resizing */ + sigset_t Sigs,OldSigs; + sigemptyset(&Sigs); + sigaddset(&Sigs,SIGWINCH); + sigprocmask(SIG_BLOCK,&Sigs,&OldSigs); + + 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) + { + memset(Buffer + Len,' ',ScreenWidth - Len); + strcpy(Buffer + ScreenWidth - LenT,Tmp); + } + } + Buffer[ScreenWidth] = 0; + BlankLine[ScreenWidth] = 0; + 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; + else + cout << '\r' << BlankLine << '\r' << Buffer << flush; + if (_config->FindB("Apt::Color", false) == true) + cout << _config->Find("APT::Color::Neutral"); + + memset(BlankLine,' ',strlen(Buffer)); + BlankLine[strlen(Buffer)] = 0; + + Update = false; + + return true; +} + /*}}}*/ +// AcqTextStatus::MediaChange - Media need to be swapped /*{{{*/ +// --------------------------------------------------------------------- +/* Prompt for a media swap */ +bool AcqTextStatus::MediaChange(string Media,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 + // on your media change request + if (isatty(STDOUT_FILENO) != 1 && Quiet >= 2 && + (_config->FindB("APT::Get::Assume-Yes",false) == true || + _config->FindB("APT::Get::Force-Yes",false) == true || + _config->FindB("APT::Get::Trivial-Only",false) == true)) + + return false; + + if (Quiet <= 0) + cout << '\r' << BlankLine << '\r'; + ioprintf(cout,_("Media change: please insert the disc labeled\n" + " '%s'\n" + "in the drive '%s' and press enter\n"), + Media.c_str(),Drive.c_str()); + + char C = 0; + bool bStatus = true; + while (C != '\n' && C != '\r') + { + int len = read(STDIN_FILENO,&C,1); + if(C == 'c' || len <= 0) + bStatus = false; + } + + if(bStatus) + Update = true; + return bStatus; +} + /*}}}*/ diff --git a/apt-private/acqprogress.h b/apt-private/acqprogress.h new file mode 100644 index 000000000..e47bfb72d --- /dev/null +++ b/apt-private/acqprogress.h @@ -0,0 +1,38 @@ +// -*- mode: cpp; mode: fold -*- +// Description /*{{{*/ +/* ###################################################################### + + Acquire Progress - Command line progress meter + + ##################################################################### */ + /*}}}*/ +#ifndef ACQPROGRESS_H +#define ACQPROGRESS_H + +#include <apt-pkg/acquire.h> + +#include <string> + +class AcqTextStatus : public pkgAcquireStatus +{ + unsigned int &ScreenWidth; + char BlankLine[1024]; + unsigned long ID; + unsigned long Quiet; + + public: + + virtual bool MediaChange(std::string Media,std::string Drive); + virtual void IMSHit(pkgAcquire::ItemDesc &Itm); + virtual void Fetch(pkgAcquire::ItemDesc &Itm); + virtual void Done(pkgAcquire::ItemDesc &Itm); + virtual void Fail(pkgAcquire::ItemDesc &Itm); + virtual void Start(); + virtual void Stop(); + + bool Pulse(pkgAcquire *Owner); + + AcqTextStatus(unsigned int &ScreenWidth,unsigned int Quiet); +}; + +#endif diff --git a/apt-private/makefile b/apt-private/makefile new file mode 100644 index 000000000..8feb1ce6c --- /dev/null +++ b/apt-private/makefile @@ -0,0 +1,28 @@ +# -*- make -*- +BASE=.. +SUBDIR=apt-private + +# Header location +HEADER_TARGETDIRS = apt-private + +# Bring in the default rules +include ../buildlib/defaults.mak + +# The library name and version (indirectly used from init.h) +include ../buildlib/libversion.mak + +# The library name +LIBRARY=apt-private +MAJOR=0.0 +MINOR=0 +SLIBS=$(PTHREADLIB) -lapt-pkg + +PRIVATES=list install output cachefile cacheset update upgrade cmndline moo search show main +SOURCE += $(foreach private, $(PRIVATES), private-$(private).cc) +HEADERS += $(foreach private, $(PRIVATES), private-$(private).h) + +SOURCE+= acqprogress.cc +HEADERS+= acqprogress.h private-cacheset.h + +HEADERS := $(addprefix apt-private/,$(HEADERS)) +include $(LIBRARY_H) diff --git a/apt-private/private-cachefile.cc b/apt-private/private-cachefile.cc new file mode 100644 index 000000000..25f65ef09 --- /dev/null +++ b/apt-private/private-cachefile.cc @@ -0,0 +1,109 @@ +// Include files /*{{{*/ +#include<config.h> + +#include <apt-pkg/algorithms.h> +#include <apt-pkg/error.h> + +#include <cstdlib> + +#include "private-output.h" +#include "private-cachefile.h" + +#include <apti18n.h> + /*}}}*/ + +using namespace std; + +// CacheFile::NameComp - QSort compare by name /*{{{*/ +// --------------------------------------------------------------------- +/* */ +pkgCache *CacheFile::SortCache = 0; +int CacheFile::NameComp(const void *a,const void *b) +{ + if (*(pkgCache::Package **)a == 0 || *(pkgCache::Package **)b == 0) + return *(pkgCache::Package **)a - *(pkgCache::Package **)b; + + const pkgCache::Package &A = **(pkgCache::Package **)a; + const pkgCache::Package &B = **(pkgCache::Package **)b; + + return strcmp(SortCache->StrP + A.Name,SortCache->StrP + B.Name); +} + /*}}}*/ +// CacheFile::Sort - Sort by name /*{{{*/ +// --------------------------------------------------------------------- +/* */ +void CacheFile::Sort() +{ + delete [] List; + List = new pkgCache::Package *[Cache->Head().PackageCount]; + memset(List,0,sizeof(*List)*Cache->Head().PackageCount); + pkgCache::PkgIterator I = Cache->PkgBegin(); + for (;I.end() != true; ++I) + List[I->ID] = I; + + SortCache = *this; + qsort(List,Cache->Head().PackageCount,sizeof(*List),NameComp); +} + /*}}}*/ +// CacheFile::CheckDeps - Open the cache file /*{{{*/ +// --------------------------------------------------------------------- +/* This routine generates the caches and then opens the dependency cache + and verifies that the system is OK. */ +bool CacheFile::CheckDeps(bool AllowBroken) +{ + bool FixBroken = _config->FindB("APT::Get::Fix-Broken",false); + + if (_error->PendingError() == true) + return false; + + // Check that the system is OK + if (DCache->DelCount() != 0 || DCache->InstCount() != 0) + return _error->Error("Internal error, non-zero counts"); + + // Apply corrections for half-installed packages + if (pkgApplyStatus(*DCache) == false) + return false; + + if (_config->FindB("APT::Get::Fix-Policy-Broken",false) == true) + { + FixBroken = true; + if ((DCache->PolicyBrokenCount() > 0)) + { + // upgrade all policy-broken packages with ForceImportantDeps=True + for (pkgCache::PkgIterator I = Cache->PkgBegin(); !I.end(); ++I) + if ((*DCache)[I].NowPolicyBroken() == true) + DCache->MarkInstall(I,true,0, false, true); + } + } + + // Nothing is broken + if (DCache->BrokenCount() == 0 || AllowBroken == true) + return true; + + // Attempt to fix broken things + if (FixBroken == true) + { + c1out << _("Correcting dependencies...") << flush; + if (pkgFixBroken(*DCache) == false || DCache->BrokenCount() != 0) + { + c1out << _(" failed.") << endl; + ShowBroken(c1out,*this,true); + + return _error->Error(_("Unable to correct dependencies")); + } + if (pkgMinimizeUpgrade(*DCache) == false) + return _error->Error(_("Unable to minimize the upgrade set")); + + c1out << _(" Done") << endl; + } + else + { + 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 true; +} + /*}}}*/ diff --git a/apt-private/private-cachefile.h b/apt-private/private-cachefile.h new file mode 100644 index 000000000..f24d93020 --- /dev/null +++ b/apt-private/private-cachefile.h @@ -0,0 +1,51 @@ +#ifndef APT_PRIVATE_CACHEFILE_H +#define APT_PRIVATE_CACHEFILE_H + +#include <apt-pkg/cachefile.h> +#include <apt-pkg/progress.h> + + +// class CacheFile - Cover class for some dependency cache functions /*{{{*/ +// --------------------------------------------------------------------- +/* */ +class CacheFile : public pkgCacheFile +{ + static pkgCache *SortCache; + static int NameComp(const void *a,const void *b); + + public: + pkgCache::Package **List; + + 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) {}; + ~CacheFile() { + delete[] List; + } +}; + /*}}}*/ + +#endif diff --git a/apt-private/private-cacheset.cc b/apt-private/private-cacheset.cc new file mode 100644 index 000000000..6fb224010 --- /dev/null +++ b/apt-private/private-cacheset.cc @@ -0,0 +1,63 @@ +#include <apt-pkg/cachefile.h> +#include <apt-pkg/pkgcache.h> +#include <apt-pkg/depcache.h> +#include <apt-pkg/strutl.h> + +#include "private-cacheset.h" + +bool GetLocalitySortedVersionSet(pkgCacheFile &CacheFile, + LocalitySortedVersionSet &output_set, + OpProgress &progress) +{ + Matcher null_matcher = Matcher(); + return GetLocalitySortedVersionSet(CacheFile, output_set, + null_matcher, progress); +} + +bool GetLocalitySortedVersionSet(pkgCacheFile &CacheFile, + LocalitySortedVersionSet &output_set, + Matcher &matcher, + OpProgress &progress) +{ + pkgCache *Cache = CacheFile.GetPkgCache(); + pkgDepCache *DepCache = CacheFile.GetDepCache(); + + int Done=0; + progress.SubProgress(Cache->Head().PackageCount, _("Sorting")); + for (pkgCache::PkgIterator P = Cache->PkgBegin(); P.end() == false; ++P) + { + if (Done%500 == 0) + progress.Progress(Done); + Done++; + + if ((matcher)(P) == false) + continue; + + // exclude virtual pkgs + if (P.VersionList() == 0) + continue; + pkgDepCache::StateCache &state = (*DepCache)[P]; + if (_config->FindB("APT::Cmd::Installed") == true) + { + if (P.CurrentVer() != NULL) + { + output_set.insert(P.CurrentVer()); + } + } + else if (_config->FindB("APT::Cmd::Upgradable") == true) + { + if(P.CurrentVer() && state.Upgradable()) + { + pkgPolicy *policy = CacheFile.GetPolicy(); + output_set.insert(policy->GetCandidateVer(P)); + } + } + else + { + pkgPolicy *policy = CacheFile.GetPolicy(); + output_set.insert(policy->GetCandidateVer(P)); + } + } + progress.Done(); + return true; +} diff --git a/apt-private/private-cacheset.h b/apt-private/private-cacheset.h new file mode 100644 index 000000000..15b531e9d --- /dev/null +++ b/apt-private/private-cacheset.h @@ -0,0 +1,265 @@ +#ifndef APT_PRIVATE_CACHESET_H +#define APT_PRIVATE_CACHESET_H + +#include <apt-pkg/cachefile.h> +#include <apt-pkg/cacheset.h> +#include <apt-pkg/sptr.h> + +#include <algorithm> +#include <vector> + +#include "private-output.h" + +#include <apti18n.h> + +struct VersionSortDescriptionLocality +{ + bool operator () (const pkgCache::VerIterator &v_lhs, + const pkgCache::VerIterator &v_rhs) + { + pkgCache::DescFile *A = v_lhs.TranslatedDescription().FileList(); + pkgCache::DescFile *B = v_rhs.TranslatedDescription().FileList(); + if (A == 0 && B == 0) + return false; + + if (A == 0) + return true; + + if (B == 0) + return false; + + if (A->File == B->File) + return A->Offset < B->Offset; + + return A->File < B->File; + } +}; + +// sorted by locality which makes iterating much faster +typedef APT::VersionContainer< + std::set<pkgCache::VerIterator, + VersionSortDescriptionLocality> > LocalitySortedVersionSet; + +class Matcher { +public: + virtual bool operator () (const pkgCache::PkgIterator &P) { + return true;}; +}; + +// FIXME: add default argument for OpProgress (or overloaded function) +bool GetLocalitySortedVersionSet(pkgCacheFile &CacheFile, + LocalitySortedVersionSet &output_set, + Matcher &matcher, + OpProgress &progress); +bool GetLocalitySortedVersionSet(pkgCacheFile &CacheFile, + LocalitySortedVersionSet &output_set, + OpProgress &progress); + + +// CacheSetHelper saving virtual packages /*{{{*/ +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 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); + } + + CacheSetHelperVirtuals(bool const ShowErrors = true, GlobalError::MsgType const &ErrorType = GlobalError::NOTICE) : CacheSetHelper(ShowErrors, ErrorType) {} +}; + /*}}}*/ + +// CacheSetHelperAPTGet - responsible for message telling from the CacheSets/*{{{*/ +class CacheSetHelperAPTGet : public APT::CacheSetHelper { + /** \brief stream message should be printed to */ + std::ostream &out; + /** \brief were things like Task or RegEx used to select packages? */ + bool explicitlyNamed; + + APT::PackageSet virtualPkgs; + +public: + std::list<std::pair<pkgCache::VerIterator, std::string> > selectedByRelease; + + CacheSetHelperAPTGet(std::ostream &out) : APT::CacheSetHelper(true), out(out) { + explicitlyNamed = true; + } + + virtual void showTaskSelection(pkgCache::PkgIterator const &Pkg, std::string const &pattern) { + ioprintf(out, _("Note, selecting '%s' for task '%s'\n"), + Pkg.FullName(true).c_str(), pattern.c_str()); + explicitlyNamed = false; + } + virtual void showRegExSelection(pkgCache::PkgIterator const &Pkg, std::string const &pattern) { + ioprintf(out, _("Note, selecting '%s' for regex '%s'\n"), + Pkg.FullName(true).c_str(), pattern.c_str()); + explicitlyNamed = false; + } + virtual void showSelectedVersion(pkgCache::PkgIterator const &Pkg, pkgCache::VerIterator const Ver, + std::string const &ver, bool const verIsRel) { + if (ver == Ver.VerStr()) + return; + selectedByRelease.push_back(make_pair(Ver, ver)); + } + + bool showVirtualPackageErrors(pkgCacheFile &Cache) { + if (virtualPkgs.empty() == true) + return true; + for (APT::PackageSet::const_iterator Pkg = virtualPkgs.begin(); + Pkg != virtualPkgs.end(); ++Pkg) { + if (Pkg->ProvidesList != 0) { + ioprintf(c1out,_("Package %s is a virtual package provided by:\n"), + Pkg.FullName(true).c_str()); + + pkgCache::PrvIterator I = Pkg.ProvidesList(); + unsigned short provider = 0; + for (; I.end() == false; ++I) { + pkgCache::PkgIterator Pkg = I.OwnerPkg(); + + if (Cache[Pkg].CandidateVerIter(Cache) == I.OwnerVer()) { + c1out << " " << Pkg.FullName(true) << " " << I.OwnerVer().VerStr(); + if (Cache[Pkg].Install() == true && Cache[Pkg].NewInstall() == false) + c1out << _(" [Installed]"); + c1out << std::endl; + ++provider; + } + } + // if we found no candidate which provide this package, show non-candidates + if (provider == 0) + for (I = Pkg.ProvidesList(); I.end() == false; ++I) + c1out << " " << I.OwnerPkg().FullName(true) << " " << I.OwnerVer().VerStr() + << _(" [Not candidate version]") << std::endl; + else + out << _("You should explicitly select one to install.") << std::endl; + } else { + ioprintf(c1out, + _("Package %s is not available, but is referred to by another package.\n" + "This may mean that the package is missing, has been obsoleted, or\n" + "is only available from another source\n"),Pkg.FullName(true).c_str()); + + std::string List; + std::string VersionsList; + SPtrArray<bool> Seen = new bool[Cache.GetPkgCache()->Head().PackageCount]; + memset(Seen,0,Cache.GetPkgCache()->Head().PackageCount*sizeof(*Seen)); + for (pkgCache::DepIterator Dep = Pkg.RevDependsList(); + Dep.end() == false; ++Dep) { + if (Dep->Type != pkgCache::Dep::Replaces) + continue; + if (Seen[Dep.ParentPkg()->ID] == true) + continue; + Seen[Dep.ParentPkg()->ID] = true; + List += Dep.ParentPkg().FullName(true) + " "; + //VersionsList += std::string(Dep.ParentPkg().CurVersion) + "\n"; ??? + } + ShowList(c1out,_("However the following packages replace it:"),List,VersionsList); + } + c1out << std::endl; + } + return false; + } + + virtual pkgCache::VerIterator canNotFindCandidateVer(pkgCacheFile &Cache, pkgCache::PkgIterator const &Pkg) { + APT::VersionSet const verset = tryVirtualPackage(Cache, Pkg, APT::VersionSet::CANDIDATE); + if (verset.empty() == false) + return *(verset.begin()); + else if (ShowError == true) { + _error->Error(_("Package '%s' has no installation candidate"),Pkg.FullName(true).c_str()); + virtualPkgs.insert(Pkg); + } + return pkgCache::VerIterator(Cache, 0); + } + + virtual pkgCache::VerIterator canNotFindNewestVer(pkgCacheFile &Cache, pkgCache::PkgIterator const &Pkg) { + if (Pkg->ProvidesList != 0) + { + APT::VersionSet const verset = tryVirtualPackage(Cache, Pkg, APT::VersionSet::NEWEST); + if (verset.empty() == false) + return *(verset.begin()); + if (ShowError == true) + ioprintf(out, _("Virtual packages like '%s' can't be removed\n"), Pkg.FullName(true).c_str()); + } + else + { + 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) { + // 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()); + } + return pkgCache::VerIterator(Cache, 0); + } + + APT::VersionSet tryVirtualPackage(pkgCacheFile &Cache, pkgCache::PkgIterator const &Pkg, + APT::VersionSet::Version 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) + return APT::VersionSet(); + + pkgCache::PkgIterator Prov; + bool found_one = false; + for (pkgCache::PrvIterator P = Pkg.ProvidesList(); P; ++P) { + pkgCache::VerIterator const PVer = P.OwnerVer(); + pkgCache::PkgIterator const PPkg = PVer.ParentPkg(); + + /* Ignore versions that are not a candidate. */ + if (Cache[PPkg].CandidateVer != PVer) + continue; + + if (found_one == false) { + Prov = PPkg; + found_one = true; + } else if (PPkg != Prov) { + // same group, so it's a foreign package + if (PPkg->Group == Prov->Group) { + // do we already have the requested arch? + if (strcmp(Pkg.Arch(), Prov.Arch()) == 0 || + strcmp(Prov.Arch(), "all") == 0 || + unlikely(strcmp(PPkg.Arch(), Prov.Arch()) == 0)) // packages have only on candidate, but just to be sure + continue; + // see which architecture we prefer more and switch to it + std::vector<std::string> archs = APT::Configuration::getArchitectures(); + if (std::find(archs.begin(), archs.end(), PPkg.Arch()) < std::find(archs.begin(), archs.end(), Prov.Arch())) + Prov = PPkg; + continue; + } + found_one = false; // we found at least two + break; + } + } + + if (found_one == true) { + ioprintf(out, _("Note, selecting '%s' instead of '%s'\n"), + Prov.FullName(true).c_str(), Pkg.FullName(true).c_str()); + return APT::VersionSet::FromPackage(Cache, Prov, select, *this); + } + return APT::VersionSet(); + } + + inline bool allPkgNamedExplicitly() const { return explicitlyNamed; } + +}; + /*}}}*/ + +#endif diff --git a/apt-private/private-cmndline.cc b/apt-private/private-cmndline.cc new file mode 100644 index 000000000..aceb865d5 --- /dev/null +++ b/apt-private/private-cmndline.cc @@ -0,0 +1,268 @@ +// Include Files /*{{{*/ +#include <config.h> + +#include <apt-pkg/cmndline.h> +#include <apt-pkg/configuration.h> + +#include <vector> + +#include <stdarg.h> +#include <string.h> + +#include "private-cmndline.h" + +#include <apti18n.h> + /*}}}*/ + +bool strcmp_match_in_list(char const * const Cmd, ...) /*{{{*/ +{ + va_list args; + bool found = false; + va_start(args, Cmd); + char const * Match = NULL; + while ((Match = va_arg(args, char const *)) != NULL) + { + if (strcmp(Cmd, Match) != 0) + continue; + found = true; + break; + } + va_end(args); + return found; +} + /*}}}*/ +#define addArg(w,x,y,z) Args.push_back(CommandLine::MakeArgs(w,x,y,z)) +#define CmdMatches(...) strcmp_match_in_list(Cmd, __VA_ARGS__, NULL) +bool addArgumentsAPTCache(std::vector<CommandLine::Args> &Args, char const * const Cmd)/*{{{*/ +{ + if (CmdMatches("depends", "rdepends", "xvcg", "dotty")) + { + addArg('i', "important", "APT::Cache::Important", 0); + addArg(0, "installed", "APT::Cache::Installed", 0); + addArg(0, "pre-depends", "APT::Cache::ShowPre-Depends", 0); + addArg(0, "depends", "APT::Cache::ShowDepends", 0); + addArg(0, "recommends", "APT::Cache::ShowRecommends", 0); + addArg(0, "suggests", "APT::Cache::ShowSuggests", 0); + addArg(0, "replaces", "APT::Cache::ShowReplaces", 0); + addArg(0, "breaks", "APT::Cache::ShowBreaks", 0); + addArg(0, "conflicts", "APT::Cache::ShowConflicts", 0); + addArg(0, "enhances", "APT::Cache::ShowEnhances", 0); + addArg(0, "recurse", "APT::Cache::RecurseDepends", 0); + } + else if (CmdMatches("search")) + { + addArg('n', "names-only", "APT::Cache::NamesOnly", 0); + addArg('f', "full", "APT::Cache::ShowFull", 0); + } + else if (CmdMatches("show")) + { + addArg('a', "all-versions", "APT::Cache::AllVersions", 0); + } + else if (CmdMatches("pkgnames")) + { + addArg(0, "all-names", "APT::Cache::AllNames", 0); + } + else if (CmdMatches("gencaches", "showsrc", "showpkg", "stats", "dump", + "dumpavail", "unmet", "showauto", "policy", "madison")) + ; + else + return false; + + // FIXME: move to the correct command(s) + addArg('g', "generate", "APT::Cache::Generate", 0); + addArg('t', "target-release", "APT::Default-Release", CommandLine::HasArg); + addArg('t', "default-release", "APT::Default-Release", CommandLine::HasArg); + + addArg('p', "pkg-cache", "Dir::Cache::pkgcache", CommandLine::HasArg); + addArg('s', "src-cache", "Dir::Cache::srcpkgcache", CommandLine::HasArg); + return true; +} + /*}}}*/ +bool addArgumentsAPTCDROM(std::vector<CommandLine::Args> &Args, char const * const Cmd)/*{{{*/ +{ + if (CmdMatches("add", "ident") == false) + return false; + + // FIXME: move to the correct command(s) + addArg(0, "auto-detect", "Acquire::cdrom::AutoDetect", CommandLine::Boolean); + addArg('d', "cdrom", "Acquire::cdrom::mount", CommandLine::HasArg); + addArg('r', "rename", "APT::CDROM::Rename", 0); + addArg('m', "no-mount", "APT::CDROM::NoMount", 0); + addArg('f', "fast", "APT::CDROM::Fast", 0); + addArg('n', "just-print", "APT::CDROM::NoAct", 0); + addArg('n', "recon", "APT::CDROM::NoAct", 0); + addArg('n', "no-act", "APT::CDROM::NoAct", 0); + addArg('a', "thorough", "APT::CDROM::Thorough", 0); + return true; +} + /*}}}*/ +bool addArgumentsAPTConfig(std::vector<CommandLine::Args> &Args, char const * const Cmd)/*{{{*/ +{ + if (CmdMatches("dump")) + { + addArg(0,"empty","APT::Config::Dump::EmptyValue",CommandLine::Boolean); + addArg(0,"format","APT::Config::Dump::Format",CommandLine::HasArg); + } + else if (CmdMatches("shell")) + ; + else + return false; + + return true; +} + /*}}}*/ +bool addArgumentsAPTGet(std::vector<CommandLine::Args> &Args, char const * const Cmd)/*{{{*/ +{ + if (CmdMatches("install", "remove", "purge", "upgrade", "dist-upgrade", + "deselect-upgrade", "autoremove")) + { + addArg(0, "dpkg-progress", "DpkgPM::Progress", 0); + addArg('f', "fix-broken", "APT::Get::Fix-Broken", 0); + addArg(0, "purge", "APT::Get::Purge", 0); + addArg('V',"verbose-versions","APT::Get::Show-Versions",0); + addArg(0, "auto-remove", "APT::Get::AutomaticRemove", 0); + addArg(0, "reinstall", "APT::Get::ReInstall", 0); + addArg(0, "solver", "APT::Solver", CommandLine::HasArg); + if (CmdMatches("upgrade")) + { + addArg(0, "allow-new", "APT::Get::UpgradeAllowNew", 0); + } + } + else if (CmdMatches("update")) + { + addArg(0, "list-cleanup", "APT::Get::List-Cleanup", 0); + } + else if (CmdMatches("source")) + { + addArg('b', "compile", "APT::Get::Compile", 0); + addArg('b', "build", "APT::Get::Compile", 0); + addArg(0, "diff-only", "APT::Get::Diff-Only", 0); + addArg(0, "debian-only", "APT::Get::Diff-Only", 0); + addArg(0, "tar-only", "APT::Get::Tar-Only", 0); + addArg(0, "dsc-only", "APT::Get::Dsc-Only", 0); + } + else if (CmdMatches("build-dep")) + { + addArg('a', "host-architecture", "APT::Get::Host-Architecture", CommandLine::HasArg); + addArg(0, "solver", "APT::Solver", CommandLine::HasArg); + } + else if (CmdMatches("clean", "autoclean", "check", "download", "changelog") || + CmdMatches("markauto", "unmarkauto")) // deprecated commands + ; + else if (CmdMatches("moo")) + addArg(0, "color", "APT::Moo::Color", 0); + + if (CmdMatches("install", "remove", "purge", "upgrade", "dist-upgrade", + "deselect-upgrade", "autoremove", "clean", "autoclean", "check", + "build-dep")) + { + addArg('s', "simulate", "APT::Get::Simulate", 0); + addArg('s', "just-print", "APT::Get::Simulate", 0); + addArg('s', "recon", "APT::Get::Simulate", 0); + addArg('s', "dry-run", "APT::Get::Simulate", 0); + addArg('s', "no-act", "APT::Get::Simulate", 0); + } + + // FIXME: move to the correct command(s) + addArg('d',"download-only","APT::Get::Download-Only",0); + addArg('y',"yes","APT::Get::Assume-Yes",0); + addArg('y',"assume-yes","APT::Get::Assume-Yes",0); + addArg(0,"assume-no","APT::Get::Assume-No",0); + addArg('u',"show-upgraded","APT::Get::Show-Upgraded",0); + addArg('m',"ignore-missing","APT::Get::Fix-Missing",0); + addArg('t',"target-release","APT::Default-Release",CommandLine::HasArg); + addArg('t',"default-release","APT::Default-Release",CommandLine::HasArg); + addArg(0,"download","APT::Get::Download",0); + addArg(0,"fix-missing","APT::Get::Fix-Missing",0); + addArg(0,"ignore-hold","APT::Ignore-Hold",0); + addArg(0,"upgrade","APT::Get::upgrade",0); + addArg(0,"only-upgrade","APT::Get::Only-Upgrade",0); + addArg(0,"force-yes","APT::Get::force-yes",0); + addArg(0,"print-uris","APT::Get::Print-URIs",0); + addArg(0,"trivial-only","APT::Get::Trivial-Only",0); + addArg(0,"remove","APT::Get::Remove",0); + 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,"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; +} + /*}}}*/ +bool addArgumentsAPTMark(std::vector<CommandLine::Args> &Args, char const * const Cmd)/*{{{*/ +{ + if (CmdMatches("auto", "manual", "hold", "unhold", "showauto", + "showmanual", "showhold", "showholds", "install", + "markauto", "unmarkauto")) + ; + else + return false; + + addArg('v',"verbose","APT::MarkAuto::Verbose",0); + addArg('s',"simulate","APT::Mark::Simulate",0); + addArg('s',"just-print","APT::Mark::Simulate",0); + addArg('s',"recon","APT::Mark::Simulate",0); + addArg('s',"dry-run","APT::Mark::Simulate",0); + addArg('s',"no-act","APT::Mark::Simulate",0); + addArg('f',"file","Dir::State::extended_states",CommandLine::HasArg); + + return true; +} + /*}}}*/ +bool addArgumentsAPT(std::vector<CommandLine::Args> &Args, char const * const Cmd)/*{{{*/ +{ + if (CmdMatches("list")) + { + addArg(0,"installed","APT::Cmd::Installed",0); + addArg(0,"upgradable","APT::Cmd::Upgradable",0); + addArg('a', "all-versions", "APT::Cmd::AllVersions", 0); + } + else if (addArgumentsAPTGet(Args, Cmd) || addArgumentsAPTCache(Args, Cmd)) + { + // we have no (supported) command-name overlaps so far, so we call + // specifics in order until we find one which adds arguments + } + else + return false; + + return true; +} + /*}}}*/ +std::vector<CommandLine::Args> getCommandArgs(char const * const Program, char const * const Cmd)/*{{{*/ +{ + std::vector<CommandLine::Args> Args; + Args.reserve(50); + if (Program == NULL || Cmd == NULL) + ; // FIXME: Invalid command supplied + else if (strcmp(Cmd, "help") == 0) + ; // no options for help so no need to implement it in each + else if (strcmp(Program, "apt-get") == 0) + addArgumentsAPTGet(Args, Cmd); + else if (strcmp(Program, "apt-cache") == 0) + addArgumentsAPTCache(Args, Cmd); + else if (strcmp(Program, "apt-cdrom") == 0) + addArgumentsAPTCDROM(Args, Cmd); + else if (strcmp(Program, "apt-config") == 0) + addArgumentsAPTConfig(Args, Cmd); + else if (strcmp(Program, "apt-mark") == 0) + addArgumentsAPTMark(Args, Cmd); + else if (strcmp(Program, "apt") == 0) + addArgumentsAPT(Args, Cmd); + + // options without a command + addArg('h', "help", "help", 0); + addArg('v', "version", "version", 0); + // general options + addArg('q', "quiet", "quiet", CommandLine::IntLevel); + addArg('q', "silent", "quiet", CommandLine::IntLevel); + addArg('c', "config-file", 0, CommandLine::ConfigFile); + addArg('o', "option", 0, CommandLine::ArbItem); + addArg(0, NULL, NULL, 0); + + return Args; +} + /*}}}*/ +#undef CmdMatches +#undef addArg diff --git a/apt-private/private-cmndline.h b/apt-private/private-cmndline.h new file mode 100644 index 000000000..76045ffe7 --- /dev/null +++ b/apt-private/private-cmndline.h @@ -0,0 +1,10 @@ +#ifndef APT_PRIVATE_CMNDLINE_H +#define APT_PRIVATE_CMNDLINE_H + +#include <apt-pkg/cmndline.h> + +#include <vector> + +std::vector<CommandLine::Args> getCommandArgs(char const * const Program, char const * const Cmd); + +#endif diff --git a/apt-private/private-install.cc b/apt-private/private-install.cc new file mode 100644 index 000000000..d5052fcc0 --- /dev/null +++ b/apt-private/private-install.cc @@ -0,0 +1,852 @@ +// Include Files /*{{{*/ +#include <config.h> + +#include <apt-pkg/aptconfiguration.h> +#include <apt-pkg/error.h> +#include <apt-pkg/cmndline.h> +#include <apt-pkg/init.h> +#include <apt-pkg/depcache.h> +#include <apt-pkg/sourcelist.h> +#include <apt-pkg/algorithms.h> +#include <apt-pkg/acquire-item.h> +#include <apt-pkg/strutl.h> +#include <apt-pkg/fileutl.h> +#include <apt-pkg/clean.h> +#include <apt-pkg/srcrecords.h> +#include <apt-pkg/version.h> +#include <apt-pkg/cachefile.h> +#include <apt-pkg/cacheset.h> +#include <apt-pkg/sptr.h> +#include <apt-pkg/md5.h> +#include <apt-pkg/versionmatch.h> +#include <apt-pkg/progress.h> +#include <apt-pkg/pkgsystem.h> +#include <apt-pkg/pkgrecords.h> +#include <apt-pkg/indexfile.h> + +#include <set> +#include <locale.h> +#include <langinfo.h> +#include <fstream> +#include <termios.h> +#include <sys/ioctl.h> +#include <sys/stat.h> +#include <sys/statfs.h> +#include <sys/statvfs.h> +#include <signal.h> +#include <unistd.h> +#include <stdio.h> +#include <errno.h> +#include <regex.h> +#include <sys/wait.h> +#include <sstream> + +#include "private-install.h" +#include "private-cachefile.h" +#include "private-output.h" +#include "private-cacheset.h" +#include "acqprogress.h" + +#include <apti18n.h> + /*}}}*/ + +// CheckAuth - check if each download comes form a trusted source /*{{{*/ +// --------------------------------------------------------------------- +/* */ +static bool CheckAuth(pkgAcquire& Fetcher) +{ + std::string UntrustedList; + for (pkgAcquire::ItemIterator I = Fetcher.ItemsBegin(); I < Fetcher.ItemsEnd(); ++I) + { + if (!(*I)->IsTrusted()) + { + UntrustedList += std::string((*I)->ShortDesc()) + " "; + } + } + + if (UntrustedList == "") + { + return true; + } + + ShowList(c2out,_("WARNING: The following packages cannot be authenticated!"),UntrustedList,""); + + if (_config->FindB("APT::Get::AllowUnauthenticated",false) == true) + { + c2out << _("Authentication warning overridden.\n"); + return true; + } + + if (_config->FindI("quiet",0) < 2 + && _config->FindB("APT::Get::Assume-Yes",false) == false) + { + c2out << _("Install these packages without verification?") << std::flush; + if (!YnPrompt(false)) + return _error->Error(_("Some packages could not be authenticated")); + + return true; + } + else if (_config->FindB("APT::Get::Force-Yes",false) == true) + { + return true; + } + + return _error->Error(_("There are problems and -y was used without --force-yes")); +} + /*}}}*/ + + +// InstallPackages - Actually download and install the packages /*{{{*/ +// --------------------------------------------------------------------- +/* This displays the informative messages describing what is going to + happen and then calls the download routines */ +bool InstallPackages(CacheFile &Cache,bool ShwKept,bool Ask, bool Safety) +{ + if (_config->FindB("APT::Get::Purge",false) == true) + { + pkgCache::PkgIterator I = Cache->PkgBegin(); + for (; I.end() == false; ++I) + { + if (I.Purge() == false && Cache[I].Mode == pkgDepCache::ModeDelete) + Cache->MarkDelete(I,true); + } + } + + bool Fail = false; + bool Essential = false; + + // Show all the various warning indicators + ShowDel(c1out,Cache); + ShowNew(c1out,Cache); + if (ShwKept == true) + ShowKept(c1out,Cache); + Fail |= !ShowHold(c1out,Cache); + if (_config->FindB("APT::Get::Show-Upgraded",true) == true) + ShowUpgraded(c1out,Cache); + Fail |= !ShowDowngraded(c1out,Cache); + if (_config->FindB("APT::Get::Download-Only",false) == false) + Essential = !ShowEssential(c1out,Cache); + Fail |= Essential; + Stats(c1out,Cache); + + // Sanity check + if (Cache->BrokenCount() != 0) + { + ShowBroken(c1out,Cache,false); + return _error->Error(_("Internal error, InstallPackages was called with broken packages!")); + } + + if (Cache->DelCount() == 0 && Cache->InstCount() == 0 && + 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) + { + pkgSimulate PM(Cache); + int status_fd = _config->FindI("APT::Status-Fd",-1); + pkgPackageManager::OrderResult Res = PM.DoInstall(status_fd); + if (Res == pkgPackageManager::Failed) + return false; + if (Res != pkgPackageManager::Completed) + return _error->Error(_("Internal error, Ordering didn't finish")); + return true; + } + + // Create the text record parser + pkgRecords Recs(Cache); + if (_error->PendingError() == true) + return false; + + // Create the download object + pkgAcquire Fetcher; + AcqTextStatus Stat(ScreenWidth,_config->FindI("quiet",0)); + 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) + return false; + + // Read the source list + if (Cache.BuildSourceList() == false) + return false; + pkgSourceList *List = Cache.GetSourceList(); + + // Create the package manager and prepare to download + SPtr<pkgPackageManager> PM= _system->CreatePM(Cache); + if (PM->GetArchives(&Fetcher,List,&Recs) == false || + _error->PendingError() == true) + return false; + + // Display statistics + unsigned long long FetchBytes = Fetcher.FetchNeeded(); + unsigned long long FetchPBytes = Fetcher.PartialPresent(); + unsigned long long DebBytes = Fetcher.TotalNeeded(); + if (DebBytes != Cache->DebSize()) + { + c0out << DebBytes << ',' << Cache->DebSize() << std::endl; + c0out << _("How odd.. The sizes didn't match, email apt@packages.debian.org") << std::endl; + } + + // Number of bytes + if (DebBytes != FetchBytes) + //TRANSLATOR: The required space between number and unit is already included + // in the replacement strings, so %sB will be correctly translate in e.g. 1,5 MB + ioprintf(c1out,_("Need to get %sB/%sB of archives.\n"), + SizeToStr(FetchBytes).c_str(),SizeToStr(DebBytes).c_str()); + else if (DebBytes != 0) + //TRANSLATOR: The required space between number and unit is already included + // in the replacement string, so %sB will be correctly translate in e.g. 1,5 MB + ioprintf(c1out,_("Need to get %sB of archives.\n"), + SizeToStr(DebBytes).c_str()); + + // Size delta + if (Cache->UsrSize() >= 0) + //TRANSLATOR: The required space between number and unit is already included + // in the replacement string, so %sB will be correctly translate in e.g. 1,5 MB + ioprintf(c1out,_("After this operation, %sB of additional disk space will be used.\n"), + SizeToStr(Cache->UsrSize()).c_str()); + else + //TRANSLATOR: The required space between number and unit is already included + // in the replacement string, so %sB will be correctly translate in e.g. 1,5 MB + ioprintf(c1out,_("After this operation, %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; + 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()); + } + } + + // 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")); + } + + if (Essential == true && Safety == true) + { + if (_config->FindB("APT::Get::Trivial-Only",false) == true) + return _error->Error(_("Trivial Only specified but this is not a trivial operation.")); + + // TRANSLATOR: This string needs to be typed by the user as a confirmation, so be + // careful with hard to type or special characters (like non-breaking spaces) + const char *Prompt = _("Yes, do as I say!"); + ioprintf(c2out, + _("You are about to do something potentially harmful.\n" + "To continue type in the phrase '%s'\n" + " ?] "),Prompt); + c2out << std::flush; + if (AnalPrompt(Prompt) == false) + { + c2out << _("Abort.") << std::endl; + exit(1); + } + } + else + { + // Prompt to continue + if (Ask == true || Fail == true) + { + if (_config->FindB("APT::Get::Trivial-Only",false) == true) + return _error->Error(_("Trivial Only specified but this is not a trivial operation.")); + + if (_config->FindI("quiet",0) < 2 && + _config->FindB("APT::Get::Assume-Yes",false) == false) + { + c2out << _("Do you want to continue?") << std::flush; + if (YnPrompt() == false) + { + c2out << _("Abort.") << std::endl; + exit(1); + } + } + } + } + + // Just print out the uris an exit if the --print-uris flag was used + if (_config->FindB("APT::Get::Print-URIs") == true) + { + pkgAcquire::UriIterator I = Fetcher.UriBegin(); + for (; I != Fetcher.UriEnd(); ++I) + c1out << '\'' << I->URI << "' " << flNotDir(I->Owner->DestFile) << ' ' << + I->Owner->FileSize << ' ' << I->Owner->HashSum() << std::endl; + return true; + } + + if (!CheckAuth(Fetcher)) + return false; + + /* 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) + { + 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; + for (pkgAcquire::ItemIterator I = Fetcher.ItemsBegin(); I != Fetcher.ItemsEnd(); ++I) + { + if ((*I)->Status == pkgAcquire::Item::StatDone && + (*I)->Complete == true) + continue; + + if ((*I)->Status == pkgAcquire::Item::StatIdle) + { + Transient = true; + // Failed = true; + continue; + } + + 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 and there were + 'failures' then the user must specify -m. Furthermore, there + is no such thing as a transient error in no-download mode! */ + if (Transient == true && + _config->FindB("APT::Get::Download",true) == false) + { + Transient = false; + Failed = true; + } + + if (_config->FindB("APT::Get::Download-Only",false) == true) + { + if (Failed == true && _config->FindB("APT::Get::Fix-Missing",false) == false) + return _error->Error(_("Some files failed to download")); + c1out << _("Download complete and in download only mode") << std::endl; + return true; + } + + if (Failed == true && _config->FindB("APT::Get::Fix-Missing",false) == false) + { + return _error->Error(_("Unable to fetch some archives, maybe run apt-get update or try with --fix-missing?")); + } + + if (Transient == true && Failed == true) + return _error->Error(_("--fix-missing and media swapping is not currently supported")); + + // Try to deal with missing package files + if (Failed == true && PM->FixMissing() == false) + { + c2out << _("Unable to correct missing packages.") << std::endl; + return _error->Error(_("Aborting install.")); + } + + _system->UnLock(); + int status_fd = _config->FindI("APT::Status-Fd",-1); + pkgPackageManager::OrderResult Res = PM->DoInstall(status_fd); + if (Res == pkgPackageManager::Failed || _error->PendingError() == true) + return false; + if (Res == pkgPackageManager::Completed) + break; + + // Reload the fetcher object and loop again for media swapping + Fetcher.Shutdown(); + if (PM->GetArchives(&Fetcher,List,&Recs) == false) + return false; + + _system->Lock(); + } + + std::set<std::string> const disappearedPkgs = PM->GetDisappearedPackages(); + if (disappearedPkgs.empty() == true) + return true; + + std::string disappear; + for (std::set<std::string>::const_iterator d = disappearedPkgs.begin(); + d != disappearedPkgs.end(); ++d) + disappear.append(*d).append(" "); + + ShowList(c1out, P_("The following package disappeared from your system as\n" + "all files have been overwritten by other packages:", + "The following packages disappeared from your system as\n" + "all files have been overwritten by other packages:", disappearedPkgs.size()), disappear, ""); + c0out << _("Note: This is done automatically and on purpose by dpkg.") << std::endl; + + return true; +} + /*}}}*/ + + +// DoAutomaticRemove - Remove all automatic unused packages /*{{{*/ +// --------------------------------------------------------------------- +/* Remove unused automatic packages */ +bool DoAutomaticRemove(CacheFile &Cache) +{ + bool Debug = _config->FindI("Debug::pkgAutoRemove",false); + bool doAutoRemove = _config->FindB("APT::Get::AutomaticRemove", false); + bool hideAutoRemove = _config->FindB("APT::Get::HideAutoRemove"); + + pkgDepCache::ActionGroup group(*Cache); + if(Debug) + std::cout << "DoAutomaticRemove()" << std::endl; + + if (doAutoRemove == true && + _config->FindB("APT::Get::Remove",true) == false) + { + c1out << _("We are not supposed to delete stuff, can't start " + "AutoRemover") << std::endl; + return false; + } + + bool purgePkgs = _config->FindB("APT::Get::Purge", false); + bool smallList = (hideAutoRemove == false && + strcasecmp(_config->Find("APT::Get::HideAutoRemove","").c_str(),"small") == 0); + + unsigned long autoRemoveCount = 0; + APT::PackageSet tooMuch; + APT::PackageList autoRemoveList; + // look over the cache to see what can be removed + for (unsigned J = 0; J < Cache->Head().PackageCount; ++J) + { + pkgCache::PkgIterator Pkg(Cache,Cache.List[J]); + if (Cache[Pkg].Garbage) + { + if(Pkg.CurrentVer() != 0 || Cache[Pkg].Install()) + if(Debug) + std::cout << "We could delete %s" << Pkg.FullName(true).c_str() << std::endl; + + if (doAutoRemove) + { + if(Pkg.CurrentVer() != 0 && + Pkg->CurrentState != pkgCache::State::ConfigFiles) + Cache->MarkDelete(Pkg, purgePkgs, 0, false); + else + Cache->MarkKeep(Pkg, false, false); + } + else + { + if (hideAutoRemove == false && Cache[Pkg].Delete() == false) + autoRemoveList.insert(Pkg); + // if the package is a new install and already garbage we don't need to + // install it in the first place, so nuke it instead of show it + if (Cache[Pkg].Install() == true && Pkg.CurrentVer() == 0) + { + if (Pkg.CandVersion() != 0) + tooMuch.insert(Pkg); + Cache->MarkDelete(Pkg, false, 0, false); + } + // only show stuff in the list that is not yet marked for removal + else if(hideAutoRemove == false && Cache[Pkg].Delete() == false) + ++autoRemoveCount; + } + } + } + + // we could have removed a new dependency of a garbage package, + // so check if a reverse depends is broken and if so install it again. + if (tooMuch.empty() == false && (Cache->BrokenCount() != 0 || Cache->PolicyBrokenCount() != 0)) + { + bool Changed; + do { + Changed = false; + for (APT::PackageSet::const_iterator Pkg = tooMuch.begin(); + Pkg != tooMuch.end() && Changed == false; ++Pkg) + { + APT::PackageSet too; + too.insert(*Pkg); + for (pkgCache::PrvIterator Prv = Cache[Pkg].CandidateVerIter(Cache).ProvidesList(); + Prv.end() == false; ++Prv) + too.insert(Prv.ParentPkg()); + for (APT::PackageSet::const_iterator P = too.begin(); + P != too.end() && Changed == false; ++P) { + for (pkgCache::DepIterator R = P.RevDependsList(); + R.end() == false; ++R) + { + if (R.IsNegative() == true || + Cache->IsImportantDep(R) == false) + continue; + pkgCache::PkgIterator N = R.ParentPkg(); + if (N.end() == true || (N->CurrentVer == 0 && (*Cache)[N].Install() == false)) + continue; + if (Debug == true) + std::clog << "Save " << Pkg << " as another installed garbage package depends on it" << std::endl; + Cache->MarkInstall(Pkg, false, 0, false); + if (hideAutoRemove == false) + ++autoRemoveCount; + tooMuch.erase(Pkg); + Changed = true; + break; + } + } + } + } while (Changed == true); + } + + std::string autoremovelist, autoremoveversions; + if (smallList == false && autoRemoveCount != 0) + { + for (APT::PackageList::const_iterator Pkg = autoRemoveList.begin(); Pkg != autoRemoveList.end(); ++Pkg) + { + if (Cache[Pkg].Garbage == false) + continue; + autoremovelist += Pkg.FullName(true) + " "; + autoremoveversions += std::string(Cache[Pkg].CandVersion) + "\n"; + } + } + + // Now see if we had destroyed anything (if we had done anything) + if (Cache->BrokenCount() != 0) + { + c1out << _("Hmm, seems like the AutoRemover destroyed something which really\n" + "shouldn't happen. Please file a bug report against apt.") << std::endl; + c1out << std::endl; + c1out << _("The following information may help to resolve the situation:") << std::endl; + c1out << std::endl; + ShowBroken(c1out,Cache,false); + + return _error->Error(_("Internal Error, AutoRemover broke stuff")); + } + + // if we don't remove them, we should show them! + if (doAutoRemove == false && (autoremovelist.empty() == false || autoRemoveCount != 0)) + { + if (smallList == false) + ShowList(c1out, P_("The following package was automatically installed and is no longer required:", + "The following packages were automatically installed and are no longer required:", + autoRemoveCount), autoremovelist, autoremoveversions); + else + ioprintf(c1out, P_("%lu package was automatically installed and is no longer required.\n", + "%lu packages were automatically installed and are no longer required.\n", autoRemoveCount), autoRemoveCount); + c1out << P_("Use 'apt-get autoremove' to remove it.", "Use 'apt-get autoremove' to remove them.", autoRemoveCount) << std::endl; + } + return true; +} + /*}}}*/ + + + + +// DoInstall - Install packages from the command line /*{{{*/ +// --------------------------------------------------------------------- +/* Install named packages */ +bool DoInstall(CommandLine &CmdL) +{ + CacheFile Cache; + if (Cache.OpenForInstall() == false || + Cache.CheckDeps(CmdL.FileSize() != 1) == false) + return false; + + // Enter the special broken fixing mode if the user specified arguments + bool BrokenFix = false; + if (Cache->BrokenCount() != 0) + BrokenFix = true; + + pkgProblemResolver* Fix = NULL; + if (_config->FindB("APT::Get::CallResolver", true) == true) + Fix = new pkgProblemResolver(Cache); + + static const unsigned short MOD_REMOVE = 1; + static const unsigned short MOD_INSTALL = 2; + + unsigned short fallback = MOD_INSTALL; + if (strcasecmp(CmdL.FileList[0],"remove") == 0) + fallback = MOD_REMOVE; + else if (strcasecmp(CmdL.FileList[0], "purge") == 0) + { + _config->Set("APT::Get::Purge", true); + fallback = MOD_REMOVE; + } + else if (strcasecmp(CmdL.FileList[0], "autoremove") == 0) + { + _config->Set("APT::Get::AutomaticRemove", "true"); + fallback = MOD_REMOVE; + } + + std::list<APT::VersionSet::Modifier> mods; + mods.push_back(APT::VersionSet::Modifier(MOD_INSTALL, "+", + APT::VersionSet::Modifier::POSTFIX, APT::VersionSet::CANDIDATE)); + mods.push_back(APT::VersionSet::Modifier(MOD_REMOVE, "-", + APT::VersionSet::Modifier::POSTFIX, APT::VersionSet::NEWEST)); + CacheSetHelperAPTGet helper(c0out); + std::map<unsigned short, APT::VersionSet> verset = APT::VersionSet::GroupedFromCommandLine(Cache, + CmdL.FileList + 1, mods, fallback, helper); + + if (_error->PendingError() == true) + { + helper.showVirtualPackageErrors(Cache); + if (Fix != NULL) + delete Fix; + return false; + } + + + TryToInstall InstallAction(Cache, Fix, BrokenFix); + TryToRemove RemoveAction(Cache, Fix); + + // new scope for the ActionGroup + { + pkgDepCache::ActionGroup group(Cache); + unsigned short const order[] = { MOD_REMOVE, MOD_INSTALL, 0 }; + + for (unsigned short i = 0; order[i] != 0; ++i) + { + if (order[i] == MOD_INSTALL) + InstallAction = std::for_each(verset[MOD_INSTALL].begin(), verset[MOD_INSTALL].end(), InstallAction); + else if (order[i] == MOD_REMOVE) + RemoveAction = std::for_each(verset[MOD_REMOVE].begin(), verset[MOD_REMOVE].end(), RemoveAction); + } + + if (Fix != NULL && _config->FindB("APT::Get::AutoSolving", true) == true) + { + for (unsigned short i = 0; order[i] != 0; ++i) + { + if (order[i] != MOD_INSTALL) + continue; + InstallAction.propergateReleaseCandiateSwitching(helper.selectedByRelease, c0out); + InstallAction.doAutoInstall(); + } + } + + if (_error->PendingError() == true) + { + if (Fix != NULL) + delete Fix; + return false; + } + + /* If we are in the Broken fixing mode we do not attempt to fix the + problems. This is if the user invoked install without -f and gave + packages */ + if (BrokenFix == true && Cache->BrokenCount() != 0) + { + c1out << _("You might want to run 'apt-get -f install' to correct these:") << std::endl; + ShowBroken(c1out,Cache,false); + if (Fix != NULL) + delete Fix; + return _error->Error(_("Unmet dependencies. Try 'apt-get -f install' with no packages (or specify a solution).")); + } + + if (Fix != NULL) + { + // Call the scored problem resolver + Fix->Resolve(true); + delete Fix; + } + + // Now we check the state of the packages, + if (Cache->BrokenCount() != 0) + { + c1out << + _("Some packages could not be installed. This may mean that you have\n" + "requested an impossible situation or if you are using the unstable\n" + "distribution that some required packages have not yet been created\n" + "or been moved out of Incoming.") << std::endl; + /* + if (Packages == 1) + { + c1out << std::endl; + c1out << + _("Since you only requested a single operation it is extremely likely that\n" + "the package is simply not installable and a bug report against\n" + "that package should be filed.") << std::endl; + } + */ + + c1out << _("The following information may help to resolve the situation:") << std::endl; + c1out << std::endl; + ShowBroken(c1out,Cache,false); + if (_error->PendingError() == true) + return false; + else + return _error->Error(_("Broken packages")); + } + } + if (!DoAutomaticRemove(Cache)) + return false; + + /* Print out a list of packages that are going to be installed extra + to what the user asked */ + if (Cache->InstCount() != verset[MOD_INSTALL].size()) + { + std::string List; + std::string VersionsList; + for (unsigned J = 0; J < Cache->Head().PackageCount; J++) + { + pkgCache::PkgIterator I(Cache,Cache.List[J]); + if ((*Cache)[I].Install() == false) + continue; + pkgCache::VerIterator Cand = Cache[I].CandidateVerIter(Cache); + + if (verset[MOD_INSTALL].find(Cand) != verset[MOD_INSTALL].end()) + continue; + + List += I.FullName(true) + " "; + VersionsList += std::string(Cache[I].CandVersion) + "\n"; + } + + ShowList(c1out,_("The following extra packages will be installed:"),List,VersionsList); + } + + /* Print out a list of suggested and recommended packages */ + { + std::string SuggestsList, RecommendsList; + std::string SuggestsVersions, RecommendsVersions; + for (unsigned J = 0; J < Cache->Head().PackageCount; J++) + { + pkgCache::PkgIterator Pkg(Cache,Cache.List[J]); + + /* Just look at the ones we want to install */ + if ((*Cache)[Pkg].Install() == false) + continue; + + // get the recommends/suggests for the candidate ver + pkgCache::VerIterator CV = (*Cache)[Pkg].CandidateVerIter(*Cache); + for (pkgCache::DepIterator D = CV.DependsList(); D.end() == false; ) + { + pkgCache::DepIterator Start; + pkgCache::DepIterator End; + D.GlobOr(Start,End); // advances D + + // FIXME: we really should display a or-group as a or-group to the user + // the problem is that ShowList is incapable of doing this + std::string RecommendsOrList,RecommendsOrVersions; + std::string SuggestsOrList,SuggestsOrVersions; + bool foundInstalledInOrGroup = false; + for(;;) + { + /* Skip if package is installed already, or is about to be */ + std::string target = Start.TargetPkg().FullName(true) + " "; + pkgCache::PkgIterator const TarPkg = Start.TargetPkg(); + if (TarPkg->SelectedState == pkgCache::State::Install || + TarPkg->SelectedState == pkgCache::State::Hold || + Cache[Start.TargetPkg()].Install()) + { + foundInstalledInOrGroup=true; + break; + } + + /* Skip if we already saw it */ + if (int(SuggestsList.find(target)) != -1 || int(RecommendsList.find(target)) != -1) + { + foundInstalledInOrGroup=true; + break; + } + + // this is a dep on a virtual pkg, check if any package that provides it + // should be installed + if(Start.TargetPkg().ProvidesList() != 0) + { + pkgCache::PrvIterator I = Start.TargetPkg().ProvidesList(); + for (; I.end() == false; ++I) + { + pkgCache::PkgIterator Pkg = I.OwnerPkg(); + if (Cache[Pkg].CandidateVerIter(Cache) == I.OwnerVer() && + Pkg.CurrentVer() != 0) + foundInstalledInOrGroup=true; + } + } + + if (Start->Type == pkgCache::Dep::Suggests) + { + SuggestsOrList += target; + SuggestsOrVersions += std::string(Cache[Start.TargetPkg()].CandVersion) + "\n"; + } + + if (Start->Type == pkgCache::Dep::Recommends) + { + RecommendsOrList += target; + RecommendsOrVersions += std::string(Cache[Start.TargetPkg()].CandVersion) + "\n"; + } + + if (Start >= End) + break; + ++Start; + } + + if(foundInstalledInOrGroup == false) + { + RecommendsList += RecommendsOrList; + RecommendsVersions += RecommendsOrVersions; + SuggestsList += SuggestsOrList; + SuggestsVersions += SuggestsOrVersions; + } + + } + } + + ShowList(c1out,_("Suggested packages:"),SuggestsList,SuggestsVersions); + ShowList(c1out,_("Recommended packages:"),RecommendsList,RecommendsVersions); + + } + + // if nothing changed in the cache, but only the automark information + // we write the StateFile here, otherwise it will be written in + // cache.commit() + if (InstallAction.AutoMarkChanged > 0 && + Cache->DelCount() == 0 && Cache->InstCount() == 0 && + Cache->BadCount() == 0 && + _config->FindB("APT::Get::Simulate",false) == false) + Cache->writeStateFile(NULL); + + // See if we need to prompt + // FIXME: check if really the packages in the set are going to be installed + if (Cache->InstCount() == verset[MOD_INSTALL].size() && Cache->DelCount() == 0) + return InstallPackages(Cache,false,false); + + return InstallPackages(Cache,false); +} + /*}}}*/ diff --git a/apt-private/private-install.h b/apt-private/private-install.h new file mode 100644 index 000000000..fcf4cbced --- /dev/null +++ b/apt-private/private-install.h @@ -0,0 +1,181 @@ +#ifndef APT_PRIVATE_INSTALL_H +#define APT_PRIVATE_INSTALL_H + +#include <apt-pkg/cacheset.h> +#include <apt-pkg/cmndline.h> +#include <apt-pkg/strutl.h> + +#include "private-cachefile.h" +#include "private-output.h" + +#include <apti18n.h> + +#define RAMFS_MAGIC 0x858458f6 + +bool DoInstall(CommandLine &Cmd); + + +bool InstallPackages(CacheFile &Cache,bool ShwKept,bool Ask = true, + bool Safety = true); + + +// TryToInstall - Mark a package for installation /*{{{*/ +struct TryToInstall { + pkgCacheFile* Cache; + pkgProblemResolver* Fix; + bool FixBroken; + unsigned long AutoMarkChanged; + APT::PackageSet doAutoInstallLater; + + 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; + 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(); + } +}; + /*}}}*/ +// TryToRemove - Mark a package for removal /*{{{*/ +struct TryToRemove { + pkgCacheFile* Cache; + pkgProblemResolver* Fix; + bool PurgePkgs; + + 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); + } +}; + /*}}}*/ + + +#endif diff --git a/apt-private/private-list.cc b/apt-private/private-list.cc new file mode 100644 index 000000000..ac72ce51a --- /dev/null +++ b/apt-private/private-list.cc @@ -0,0 +1,158 @@ +// Include Files /*{{{*/ +#include <config.h> + +#include <apt-pkg/error.h> +#include <apt-pkg/cachefile.h> +#include <apt-pkg/cachefilter.h> +#include <apt-pkg/cacheset.h> +#include <apt-pkg/init.h> +#include <apt-pkg/progress.h> +#include <apt-pkg/sourcelist.h> +#include <apt-pkg/cmndline.h> +#include <apt-pkg/strutl.h> +#include <apt-pkg/fileutl.h> +#include <apt-pkg/pkgrecords.h> +#include <apt-pkg/srcrecords.h> +#include <apt-pkg/version.h> +#include <apt-pkg/policy.h> +#include <apt-pkg/tagfile.h> +#include <apt-pkg/algorithms.h> +#include <apt-pkg/sptr.h> +#include <apt-pkg/pkgsystem.h> +#include <apt-pkg/indexfile.h> +#include <apt-pkg/metaindex.h> + +#include <sstream> +#include <vector> +#include <utility> +#include <cassert> +#include <locale.h> +#include <iostream> +#include <unistd.h> +#include <errno.h> +#include <regex.h> +#include <stdio.h> +#include <algorithm> + +#include "private-cmndline.h" +#include "private-list.h" +#include "private-output.h" +#include "private-cacheset.h" + +#include <apti18n.h> + /*}}}*/ + +struct PackageSortAlphabetic +{ + bool operator () (const pkgCache::PkgIterator &p_lhs, + const pkgCache::PkgIterator &p_rhs) + { + const std::string &l_name = p_lhs.FullName(true); + const std::string &r_name = p_rhs.FullName(true); + return (l_name < r_name); + } +}; + +class PackageNameMatcher : public Matcher +{ + public: + PackageNameMatcher(const char **patterns) + { + for(int i=0; patterns[i] != NULL; i++) + { + std::string pattern = patterns[i]; + APT::CacheFilter::PackageMatcher *cachefilter = NULL; + if(_config->FindB("APT::Cmd::UseRegexp", false) == true) + cachefilter = new APT::CacheFilter::PackageNameMatchesRegEx(pattern); + else + cachefilter = new APT::CacheFilter::PackageNameMatchesFnmatch(pattern); + filters.push_back(cachefilter); + } + } + virtual ~PackageNameMatcher() + { + for(J=filters.begin(); J != filters.end(); J++) + delete *J; + } + virtual bool operator () (const pkgCache::PkgIterator &P) + { + for(J=filters.begin(); J != filters.end(); J++) + { + APT::CacheFilter::PackageMatcher *cachefilter = *J; + if((*cachefilter)(P)) + return true; + } + return false; + } + +private: + std::vector<APT::CacheFilter::PackageMatcher*> filters; + std::vector<APT::CacheFilter::PackageMatcher*>::const_iterator J; +}; + + +void ListAllVersions(pkgCacheFile &CacheFile, pkgRecords &records, + pkgCache::PkgIterator P, + std::ostream &outs) +{ + for (pkgCache::VerIterator Ver = P.VersionList(); + Ver.end() == false; Ver++) + ListSingleVersion(CacheFile, records, Ver, outs); +} + +// list - list package based on criteria /*{{{*/ +// --------------------------------------------------------------------- +bool List(CommandLine &Cmd) +{ + pkgCacheFile CacheFile; + pkgCache *Cache = CacheFile.GetPkgCache(); + pkgRecords records(CacheFile); + + if (unlikely(Cache == NULL)) + return false; + + const char **patterns; + const char *all_pattern[] = { "*", NULL}; + + if (strv_length(Cmd.FileList + 1) == 0) + { + patterns = all_pattern; + } else { + patterns = Cmd.FileList + 1; + } + + std::map<std::string, std::string> output_map; + std::map<std::string, std::string>::const_iterator K; + + PackageNameMatcher matcher(patterns); + LocalitySortedVersionSet bag; + OpTextProgress progress; + progress.OverallProgress(0, + Cache->Head().PackageCount, + Cache->Head().PackageCount, + _("Listing")); + GetLocalitySortedVersionSet(CacheFile, bag, matcher, progress); + for (LocalitySortedVersionSet::iterator V = bag.begin(); V != bag.end(); V++) + { + std::stringstream outs; + if(_config->FindB("APT::Cmd::AllVersions", false) == true) + { + ListAllVersions(CacheFile, records, V.ParentPkg(), outs); + output_map.insert(std::make_pair<std::string, std::string>( + V.ParentPkg().Name(), outs.str())); + } else { + ListSingleVersion(CacheFile, records, V, outs); + 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 + for (K = output_map.begin(); K != output_map.end(); K++) + std::cout << (*K).second << std::endl; + + + return true; +} + diff --git a/apt-private/private-list.h b/apt-private/private-list.h new file mode 100644 index 000000000..6f5aad27a --- /dev/null +++ b/apt-private/private-list.h @@ -0,0 +1,9 @@ +#ifndef APT_PRIVATE_LIST_H +#define APT_PRIVATE_LIST_H + +#include <apt-pkg/cmndline.h> + +bool List(CommandLine &Cmd); + + +#endif diff --git a/apt-private/private-main.cc b/apt-private/private-main.cc new file mode 100644 index 000000000..1fdf3f0be --- /dev/null +++ b/apt-private/private-main.cc @@ -0,0 +1,26 @@ + +#include<unistd.h> +#include<cstring> + +#include <apt-pkg/configuration.h> +#include "private-main.h" + +#include <apti18n.h> + +void CheckSimulateMode(CommandLine &CmdL) +{ + // simulate user-friendly if apt-get has no root privileges + if (getuid() != 0 && _config->FindB("APT::Get::Simulate") == true && + (CmdL.FileSize() == 0 || + (strcmp(CmdL.FileList[0], "source") != 0 && strcmp(CmdL.FileList[0], "download") != 0 && + strcmp(CmdL.FileList[0], "changelog") != 0))) + { + if (_config->FindB("APT::Get::Show-User-Simulation-Note",true) == true) + std::cout << _("NOTE: This is only a simulation!\n" + " apt-get needs root privileges for real execution.\n" + " Keep also in mind that locking is deactivated,\n" + " so don't depend on the relevance to the real current situation!" + ) << std::endl; + _config->Set("Debug::NoLocking",true); + } +} diff --git a/apt-private/private-main.h b/apt-private/private-main.h new file mode 100644 index 000000000..f9a95c4ec --- /dev/null +++ b/apt-private/private-main.h @@ -0,0 +1,9 @@ +#ifndef APT_PRIVATE_MAIN_H +#define APT_PRIVATE_MAIN_H + +#include <apt-pkg/cmndline.h> + +void CheckSimulateMode(CommandLine &CmdL); + + +#endif diff --git a/apt-private/private-moo.cc b/apt-private/private-moo.cc new file mode 100644 index 000000000..9b5b94654 --- /dev/null +++ b/apt-private/private-moo.cc @@ -0,0 +1,193 @@ +// -*- mode: cpp; mode: fold -*- +// Description /*{{{*/ +/* ###################################################################### + + Here be cows – but: Never ask, never tell + + ##################################################################### */ + /*}}}*/ +// Include Files /*{{{*/ +#include<config.h> + +#include <apt-pkg/configuration.h> +#include <apt-pkg/cmndline.h> +#include <apt-pkg/strutl.h> + +#include <strings.h> +#include <sstream> + +#include "private-moo.h" +#include "private-output.h" + +#include <apti18n.h> + /*}}}*/ + +std::string getMooLine() { /*{{{*/ + time_t const timenow = time(NULL); + struct tm special; + localtime_r(&timenow, &special); + enum { NORMAL, PACKAGEMANAGER, APPRECIATION, AGITATION, AIRBORN } line; + if (special.tm_mon == 11 && special.tm_mday == 25) + line = PACKAGEMANAGER; + else if (special.tm_mon == 7 && special.tm_mday == 16) + line = APPRECIATION; + else if (special.tm_mon == 10 && special.tm_mday == 7) + line = AGITATION; + else if (special.tm_mon == 1 && special.tm_mday == 18) + line = AIRBORN; + else + line = NORMAL; + + bool const quiet = _config->FindI("quiet") >= 2; + std::ostringstream out; + if (quiet == false) + out << "...\""; + + switch(line) + { + case PACKAGEMANAGER: out << "Happy package management day!"; break; + case APPRECIATION: out << "Three moos for Debian!"; break; + case AGITATION: out << "Whoever needs milk, bows to the animal."; break; + case AIRBORN: out << "It's a Bird ... It's a Plane ... It's Super Cow!"; break; + default: out << "Have you mooed today?"; break; + } + + if (quiet == true) + out << std::endl; + else + out << "\"..." << std::endl; + + return out.str(); +} + /*}}}*/ +bool printMooLine() { /*{{{*/ + std::cerr << getMooLine() << std::endl; + return true; +} + /*}}}*/ +bool DoMoo1(CommandLine &CmdL) /*{{{*/ +{ + // our trustworthy super cow since 2001 + if (_config->FindI("quiet") >= 2) + return printMooLine(); + std::string const moo = getMooLine(); + size_t const depth = moo.length()/4; + c1out << + OutputInDepth(depth, " ") << " (__) \n" << + OutputInDepth(depth, " ") << " (oo) \n" << + OutputInDepth(depth, " ") << " /------\\/ \n" << + OutputInDepth(depth, " ") << " / | || \n" << + OutputInDepth(depth, " ") << " * /\\---/\\ \n" << + OutputInDepth(depth, " ") << " ~~ ~~ \n" << + moo; + return true; +} + /*}}}*/ +bool DoMoo2(CommandLine &CmdL) /*{{{*/ +{ + // by Fernando Ribeiro in lp:56125 + if (_config->FindI("quiet") >= 2) + return printMooLine(); + std::string const moo = getMooLine(); + size_t const depth = moo.length()/4; + if (_config->FindB("APT::Moo::Color", false) == false) + c1out << + OutputInDepth(depth, " ") << " (__) \n" << + OutputInDepth(depth, " ") << " _______~(..)~ \n" << + OutputInDepth(depth, " ") << " ,----\\(oo) \n" << + OutputInDepth(depth, " ") << " /|____|,' \n" << + OutputInDepth(depth, " ") << " * /\"\\ /\\ \n" << + OutputInDepth(depth, " ") << " ~ ~ ~ ~ \n" << + moo; + else + { + c1out << + OutputInDepth(depth, " ") << " \e[1;97m(\e[0;33m__\e[1;97m)\e[0m\n" << + OutputInDepth(depth, " ") << " \e[31m_______\e[33m~(\e[1;34m..\e[0;33m)~\e[0m\n" << + OutputInDepth(depth, " ") << " \e[33m,----\e[31m\\\e[33m(\e[1;4;35moo\e[0;33m)\e[0m\n" << + OutputInDepth(depth, " ") << " \e[33m/|____|,'\e[0m\n" << + OutputInDepth(depth, " ") << " \e[1;5;97m*\e[0;33m /\\ /\\\e[0m\n" << + "\e[32m"; + for (size_t i = moo.length()/2; i > 1; --i) + c1out << "wW"; + + c1out << "w\e[0m\n" << moo; + } + + return true; +} + /*}}}*/ +bool DoMoo3(CommandLine &CmdL) /*{{{*/ +{ + // by Robert Millan in deb:134156 + if (_config->FindI("quiet") >= 2) + return printMooLine(); + std::string const moo = getMooLine(); + size_t const depth = moo.length()/16; + c1out << + OutputInDepth(depth, " ") << " \\_/ \n" << + OutputInDepth(depth, " ") << " m00h (__) -(_)- \n" << + OutputInDepth(depth, " ") << " \\ ~Oo~___ / \\\n" << + OutputInDepth(depth, " ") << " (..) |\\ \n" << + OutputInDepth(depth, "_") << "_________|_|_|__________" << + OutputInDepth((moo.length() - (depth + 27)), "_") << "\n" << moo; + return true; +} + /*}}}*/ +bool DoMooApril(CommandLine &CmdL) /*{{{*/ +{ + // by Christopher Allan Webber and proposed by Paul Tagliamonte + // in a "Community outreach": https://lists.debian.org/debian-devel/2013/04/msg00045.html + if (_config->FindI("quiet") >= 2) + { + std::cerr << "Have you smashed some milk today?" << std::endl; + return true; + } + c1out << + " _ _\n" + " (_\\___( \\,\n" + " )___ _ Have you smashed some milk today?\n" + " /( (_)-(_) /\n" + " ,---------' \\_\n" + " //( ',__,' \\ (' ')\n" + " // ) '----'\n" + " '' ; \\ .--. ,/\n" + " | )',_,'----( ;\n" + " ||| ''' '||\n"; + return true; +} + /*}}}*/ +bool DoMoo(CommandLine &CmdL) /*{{{*/ +{ + time_t const timenow = time(NULL); + struct tm april; + localtime_r(&timenow, &april); + if (april.tm_mday == 1 && april.tm_mon == 3) + return DoMooApril(CmdL); + + signed short SuperCow = 1; + if (CmdL.FileSize() != 0) + for (const char **Moo = CmdL.FileList + 1; *Moo != 0; Moo++) + if (strcasecmp(*Moo, "moo") == 0) + SuperCow++; + + // time is random enough for our purpose + if (SuperCow > 3) + { + if (april.tm_sec == 1) + SuperCow = 1 + (timenow % 4); + else + SuperCow = 1 + (timenow % 3); + } + + switch(SuperCow) { + case 1: return DoMoo1(CmdL); + case 2: return DoMoo2(CmdL); + case 3: return DoMoo3(CmdL); + case 4: return DoMooApril(CmdL); + default: return DoMoo1(CmdL); + } + + return true; +} + /*}}}*/ diff --git a/apt-private/private-moo.h b/apt-private/private-moo.h new file mode 100644 index 000000000..7bfc5c1fc --- /dev/null +++ b/apt-private/private-moo.h @@ -0,0 +1,12 @@ +#ifndef APT_PRIVATE_MOO_H +#define APT_PRIVATE_MOO_H + +class CommandLine; + +bool DoMoo(CommandLine &CmdL); +bool DoMoo1(CommandLine &CmdL); +bool DoMoo2(CommandLine &CmdL); +bool DoMoo3(CommandLine &CmdL); +bool DoMooApril(CommandLine &CmdL); + +#endif diff --git a/apt-private/private-output.cc b/apt-private/private-output.cc new file mode 100644 index 000000000..659975476 --- /dev/null +++ b/apt-private/private-output.cc @@ -0,0 +1,753 @@ +// Include files /*{{{*/ +#include<config.h> + +#include <apt-pkg/configuration.h> +#include <apt-pkg/strutl.h> +#include <apt-pkg/error.h> +#include <apt-pkg/cachefile.h> +#include <apt-pkg/pkgrecords.h> +#include <apt-pkg/policy.h> + +#include <iomanip> +#include <iostream> +#include <locale.h> +#include <langinfo.h> +#include <unistd.h> + +#include "private-output.h" +#include "private-cachefile.h" + +#include <apti18n.h> + /*}}}*/ + +using namespace std; + +std::ostream c0out(0); +std::ostream c1out(0); +std::ostream c2out(0); +std::ofstream devnull("/dev/null"); +unsigned int ScreenWidth = 80 - 1; /* - 1 for the cursor */ + + +bool InitOutput() +{ + c0out.rdbuf(cout.rdbuf()); + c1out.rdbuf(cout.rdbuf()); + c2out.rdbuf(cout.rdbuf()); + if (_config->FindI("quiet",0) > 0) + c0out.rdbuf(devnull.rdbuf()); + if (_config->FindI("quiet",0) > 1) + c1out.rdbuf(devnull.rdbuf()); + + if(!isatty(1)) + { + _config->Set("APT::Color", "false"); + _config->Set("APT::Color::Highlight", ""); + _config->Set("APT::Color::Neutral", ""); + } else { + // Colors + _config->CndSet("APT::Color::Highlight", "\x1B[32m"); + _config->CndSet("APT::Color::Neutral", "\x1B[0m"); + + _config->CndSet("APT::Color::Red", "\x1B[31m"); + _config->CndSet("APT::Color::Green", "\x1B[32m"); + _config->CndSet("APT::Color::Yellow", "\x1B[33m"); + _config->CndSet("APT::Color::Blue", "\x1B[34m"); + _config->CndSet("APT::Color::Magenta", "\x1B[35m"); + _config->CndSet("APT::Color::Cyan", "\x1B[36m"); + _config->CndSet("APT::Color::White", "\x1B[37m"); + } + + return true; +} + +std::string GetArchiveSuite(pkgCacheFile &CacheFile, pkgCache::VerIterator ver) +{ + std::string suite = ""; + if (ver && ver.FileList() && ver.FileList()) + { + pkgCache::VerFileIterator VF = ver.FileList(); + for (; VF.end() == false ; ++VF) + { + // XXX: how to figure out the relevant suite? if its in multiple ones? + suite = suite + "," + VF.File().Archive(); + //suite = VF.File().Archive(); + } + suite = suite.erase(0, 1); + } + return suite; +} + +std::string GetFlagsStr(pkgCacheFile &CacheFile, pkgCache::PkgIterator P) +{ + pkgDepCache *DepCache = CacheFile.GetDepCache(); + pkgDepCache::StateCache &state = (*DepCache)[P]; + + std::string flags_str; + if (state.NowBroken()) + flags_str = "B"; + if (P.CurrentVer() && state.Upgradable()) + flags_str = "g"; + else if (P.CurrentVer() != NULL) + flags_str = "i"; + else + flags_str = "-"; + return flags_str; +} + +std::string GetCandidateVersion(pkgCacheFile &CacheFile, pkgCache::PkgIterator P) +{ + pkgPolicy *policy = CacheFile.GetPolicy(); + pkgCache::VerIterator cand = policy->GetCandidateVer(P); + + return cand ? cand.VerStr() : "(none)"; +} + +std::string GetInstalledVersion(pkgCacheFile &CacheFile, pkgCache::PkgIterator P) +{ + pkgCache::VerIterator inst = P.CurrentVer(); + + return inst ? inst.VerStr() : "(none)"; +} + +std::string GetVersion(pkgCacheFile &CacheFile, pkgCache::VerIterator V) +{ + pkgCache::PkgIterator P = V.ParentPkg(); + if (V == P.CurrentVer()) + { + pkgDepCache *DepCache = CacheFile.GetDepCache(); + pkgDepCache::StateCache &state = (*DepCache)[P]; + std::string inst_str = DeNull(V.VerStr()); + if (state.Upgradable()) + return "**"+inst_str; + return inst_str; + } + + if(V) + return DeNull(V.VerStr()); + return "(none)"; +} + +std::string GetArchitecture(pkgCacheFile &CacheFile, pkgCache::PkgIterator P) +{ + pkgPolicy *policy = CacheFile.GetPolicy(); + pkgCache::VerIterator inst = P.CurrentVer(); + pkgCache::VerIterator cand = policy->GetCandidateVer(P); + + return inst ? inst.Arch() : cand.Arch(); +} + +std::string GetShortDescription(pkgCacheFile &CacheFile, pkgRecords &records, pkgCache::PkgIterator P) +{ + pkgPolicy *policy = CacheFile.GetPolicy(); + + pkgCache::VerIterator ver; + if (P.CurrentVer()) + ver = P.CurrentVer(); + else + ver = policy->GetCandidateVer(P); + + std::string ShortDescription = "(none)"; + if(ver) + { + pkgCache::DescIterator Desc = ver.TranslatedDescription(); + pkgRecords::Parser & parser = records.Lookup(Desc.FileList()); + + ShortDescription = parser.ShortDesc(); + } + return ShortDescription; +} + +void ListSingleVersion(pkgCacheFile &CacheFile, pkgRecords &records, + pkgCache::VerIterator V, std::ostream &out) +{ + pkgCache::PkgIterator P = V.ParentPkg(); + + pkgDepCache *DepCache = CacheFile.GetDepCache(); + pkgDepCache::StateCache &state = (*DepCache)[P]; + + std::string suite = GetArchiveSuite(CacheFile, V); + std::string name_str = P.Name(); + + if (_config->FindB("APT::Cmd::use-format", false)) + { + 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(); + out << std::setiosflags(std::ios::left) + << _config->Find("APT::Color::Highlight", "") + << name_str + << _config->Find("APT::Color::Neutral", "") + << "/" << suite + << " "; + if(P.CurrentVer() == V && state.Upgradable()) { + out << GetVersion(CacheFile, V) + << " " + << "[" << _("installed,upgradable to: ") + << GetCandidateVersion(CacheFile, P) << "]"; + } else if (P.CurrentVer() == V) { + out << GetVersion(CacheFile, V) + << " "; + if(!V.Downloadable()) + out << _("[installed,local]"); + else + if(V.Automatic() && state.Garbage) + out << _("[installed,auto-removable]"); + else if (state.Flags & pkgCache::Flag::Auto) + out << _("[installed,automatic]"); + else + out << _("[installed]"); + } else if (P.CurrentVer() && + policy->GetCandidateVer(P) == V && + state.Upgradable()) { + out << GetVersion(CacheFile, V) + << " " + << _("[upgradable from: ") + << GetInstalledVersion(CacheFile, P) << "]"; + } else { + if (V.ParentPkg()->CurrentState == pkgCache::State::ConfigFiles) + out << GetVersion(CacheFile, V) + << " " + << _("[residual-config]"); + else + out << GetVersion(CacheFile, V); + } + out << " " << GetArchitecture(CacheFile, P) << " "; + out << std::endl + << " " << GetShortDescription(CacheFile, records, P) + << std::endl; + } +} + + +// ShowList - Show a list /*{{{*/ +// --------------------------------------------------------------------- +/* 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,string VersionsList) +{ + 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; + + out << Title << endl; + string::size_type Start = 0; + string::size_type VersionsStart = 0; + while (Start < List.size()) + { + if(_config->FindB("APT::Get::Show-Versions",false) == true && + VersionsList.size() > 0) { + string::size_type End; + string::size_type VersionsEnd; + + End = List.find(' ',Start); + VersionsEnd = VersionsList.find('\n', VersionsStart); + + out << " " << string(List,Start,End - Start) << " (" << + string(VersionsList,VersionsStart,VersionsEnd - VersionsStart) << + ")" << endl; + + if (End == string::npos || End < Start) + End = Start + ScreenWidth; + + Start = End + 1; + VersionsStart = VersionsEnd + 1; + } else { + string::size_type End; + + if (Start + ScreenWidth >= List.size()) + End = List.size(); + else + End = List.rfind(' ',Start+ScreenWidth); + + if (End == string::npos || End < Start) + End = Start + ScreenWidth; + out << " " << string(List,Start,End - Start) << endl; + Start = End + 1; + } + } + + return false; +} + /*}}}*/ +// ShowBroken - Debugging aide /*{{{*/ +// --------------------------------------------------------------------- +/* 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. + + 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) +{ + if (Cache->BrokenCount() == 0) + return; + + 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 (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.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;) + { + // 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[End] & pkgDepCache::DepGNow) == pkgDepCache::DepGNow) + continue; + } + else + { + 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; + + if (FirstOr == false) + { + 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) + { + out << ' '; + pkgCache::VerIterator Ver = Cache[Targ].InstVerIter(Cache); + if (Now == true) + Ver = Targ.CurrentVer(); + + if (Ver.end() == false) + { + 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 << _("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")); + } + } + + if (Start != End) + out << _(" or"); + out << endl; + + if (Start == End) + break; + ++Start; + } + } + } +} + /*}}}*/ +// ShowNew - Show packages to newly install /*{{{*/ +// --------------------------------------------------------------------- +/* */ +void ShowNew(ostream &out,CacheFile &Cache) +{ + /* Print out a list of packages that are going to be installed extra + to what the user asked */ + string List; + string VersionsList; + for (unsigned J = 0; J < Cache->Head().PackageCount; J++) + { + pkgCache::PkgIterator I(Cache,Cache.List[J]); + if (Cache[I].NewInstall() == true) { + List += I.FullName(true) + " "; + VersionsList += string(Cache[I].CandVersion) + "\n"; + } + } + + ShowList(out,_("The following NEW packages will be installed:"),List,VersionsList); +} + /*}}}*/ +// ShowDel - Show packages to delete /*{{{*/ +// --------------------------------------------------------------------- +/* */ +void ShowDel(ostream &out,CacheFile &Cache) +{ + /* Print out a list of packages that are going to be removed extra + to what the user asked */ + string List; + string VersionsList; + for (unsigned J = 0; J < Cache->Head().PackageCount; J++) + { + pkgCache::PkgIterator I(Cache,Cache.List[J]); + if (Cache[I].Delete() == true) + { + if ((Cache[I].iFlags & pkgDepCache::Purge) == pkgDepCache::Purge) + List += I.FullName(true) + "* "; + else + List += I.FullName(true) + " "; + + VersionsList += string(Cache[I].CandVersion)+ "\n"; + } + } + + ShowList(out,_("The following packages will be REMOVED:"),List,VersionsList); +} + /*}}}*/ +// ShowKept - Show kept packages /*{{{*/ +// --------------------------------------------------------------------- +/* */ +void ShowKept(ostream &out,CacheFile &Cache) +{ + string List; + string VersionsList; + for (unsigned J = 0; J < Cache->Head().PackageCount; J++) + { + pkgCache::PkgIterator I(Cache,Cache.List[J]); + + // Not interesting + if (Cache[I].Upgrade() == true || Cache[I].Upgradable() == false || + I->CurrentVer == 0 || Cache[I].Delete() == true) + continue; + + List += I.FullName(true) + " "; + VersionsList += string(Cache[I].CurVersion) + " => " + Cache[I].CandVersion + "\n"; + } + ShowList(out,_("The following packages have been kept back:"),List,VersionsList); +} + /*}}}*/ +// ShowUpgraded - Show upgraded packages /*{{{*/ +// --------------------------------------------------------------------- +/* */ +void ShowUpgraded(ostream &out,CacheFile &Cache) +{ + string List; + string VersionsList; + for (unsigned J = 0; J < Cache->Head().PackageCount; J++) + { + pkgCache::PkgIterator I(Cache,Cache.List[J]); + + // Not interesting + if (Cache[I].Upgrade() == false || Cache[I].NewInstall() == true) + continue; + + List += I.FullName(true) + " "; + VersionsList += string(Cache[I].CurVersion) + " => " + Cache[I].CandVersion + "\n"; + } + ShowList(out,_("The following packages will be upgraded:"),List,VersionsList); +} + /*}}}*/ +// ShowDowngraded - Show downgraded packages /*{{{*/ +// --------------------------------------------------------------------- +/* */ +bool ShowDowngraded(ostream &out,CacheFile &Cache) +{ + string List; + string VersionsList; + 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 += I.FullName(true) + " "; + VersionsList += string(Cache[I].CurVersion) + " => " + Cache[I].CandVersion + "\n"; + } + return ShowList(out,_("The following packages will be DOWNGRADED:"),List,VersionsList); +} + /*}}}*/ +// ShowHold - Show held but changed packages /*{{{*/ +// --------------------------------------------------------------------- +/* */ +bool ShowHold(ostream &out,CacheFile &Cache) +{ + string List; + string VersionsList; + for (unsigned J = 0; J < Cache->Head().PackageCount; J++) + { + pkgCache::PkgIterator I(Cache,Cache.List[J]); + if (Cache[I].InstallVer != (pkgCache::Version *)I.CurrentVer() && + I->SelectedState == pkgCache::State::Hold) { + List += I.FullName(true) + " "; + VersionsList += string(Cache[I].CurVersion) + " => " + Cache[I].CandVersion + "\n"; + } + } + + return ShowList(out,_("The following held packages will be changed:"),List,VersionsList); +} + /*}}}*/ +// ShowEssential - Show an essential package warning /*{{{*/ +// --------------------------------------------------------------------- +/* This prints out a warning message that is not to be ignored. It shows + all essential packages and their dependents that are to be removed. + It is insanely risky to remove the dependents of an essential package! */ +bool ShowEssential(ostream &out,CacheFile &Cache) +{ + string List; + string VersionsList; + 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 && + (I->Flags & pkgCache::Flag::Important) != pkgCache::Flag::Important) + continue; + + // The essential package is being removed + if (Cache[I].Delete() == true) + { + if (Added[I->ID] == false) + { + Added[I->ID] = true; + List += I.FullName(true) + " "; + //VersionsList += string(Cache[I].CurVersion) + "\n"; ??? + } + } + else + continue; + + if (I->CurrentVer == 0) + continue; + + // Print out any essential package depenendents that are to be removed + for (pkgCache::DepIterator D = I.CurrentVer().DependsList(); D.end() == false; ++D) + { + // Skip everything but depends + if (D->Type != pkgCache::Dep::PreDepends && + D->Type != pkgCache::Dep::Depends) + continue; + + pkgCache::PkgIterator P = D.SmartTargetPkg(); + if (Cache[P].Delete() == true) + { + if (Added[P->ID] == true) + continue; + Added[P->ID] = true; + + char S[300]; + snprintf(S,sizeof(S),_("%s (due to %s) "),P.FullName(true).c_str(),I.FullName(true).c_str()); + List += S; + //VersionsList += "\n"; ??? + } + } + } + + delete [] Added; + return ShowList(out,_("WARNING: The following essential packages will be removed.\n" + "This should NOT be done unless you know exactly what you are doing!"),List,VersionsList); +} + + /*}}}*/ +// Stats - Show some statistics /*{{{*/ +// --------------------------------------------------------------------- +/* */ +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) + { + 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++; + } + + ioprintf(out,_("%lu upgraded, %lu newly installed, "), + Upgrade,Install); + + if (ReInstall != 0) + 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) + ioprintf(out,_("%lu not fully installed or removed.\n"), + Dep.BadCount()); +} + /*}}}*/ +// YnPrompt - Yes No Prompt. /*{{{*/ +// --------------------------------------------------------------------- +/* Returns true on a Yes.*/ +bool YnPrompt(bool Default) +{ + /* nl_langinfo does not support LANGUAGE setting, so we unset it here + to have the help-message (hopefully) match the expected characters */ + char * language = getenv("LANGUAGE"); + if (language != NULL) + language = strdup(language); + if (language != NULL) + unsetenv("LANGUAGE"); + + if (Default == true) + // TRANSLATOR: Yes/No question help-text: defaulting to Y[es] + // e.g. "Do you want to continue? [Y/n] " + // The user has to answer with an input matching the + // YESEXPR/NOEXPR defined in your l10n. + c2out << " " << _("[Y/n]") << " " << std::flush; + else + // TRANSLATOR: Yes/No question help-text: defaulting to N[o] + // e.g. "Should this file be removed? [y/N] " + // The user has to answer with an input matching the + // YESEXPR/NOEXPR defined in your l10n. + c2out << " " << _("[y/N]") << " " << std::flush; + + if (language != NULL) + { + setenv("LANGUAGE", language, 0); + free(language); + } + + if (_config->FindB("APT::Get::Assume-Yes",false) == true) + { + // TRANSLATOR: "Yes" answer printed for a yes/no question if --assume-yes is set + c1out << _("Y") << std::endl; + return true; + } + else if (_config->FindB("APT::Get::Assume-No",false) == true) + { + // TRANSLATOR: "No" answer printed for a yes/no question if --assume-no is set + c1out << _("N") << std::endl; + return false; + } + + char response[1024] = ""; + std::cin.getline(response, sizeof(response)); + + if (!std::cin) + return false; + + if (strlen(response) == 0) + return Default; + + regex_t Pattern; + int Res; + + Res = regcomp(&Pattern, nl_langinfo(YESEXPR), + REG_EXTENDED|REG_ICASE|REG_NOSUB); + + if (Res != 0) { + char Error[300]; + regerror(Res,&Pattern,Error,sizeof(Error)); + return _error->Error(_("Regex compilation error - %s"),Error); + } + + Res = regexec(&Pattern, response, 0, NULL, 0); + if (Res == 0) + return true; + return false; +} + /*}}}*/ +// AnalPrompt - Annoying Yes No Prompt. /*{{{*/ +// --------------------------------------------------------------------- +/* Returns true on a Yes.*/ +bool AnalPrompt(const char *Text) +{ + char Buf[1024]; + std::cin.getline(Buf,sizeof(Buf)); + if (strcmp(Buf,Text) == 0) + return true; + return false; +} + /*}}}*/ diff --git a/apt-private/private-output.h b/apt-private/private-output.h new file mode 100644 index 000000000..9283e39ab --- /dev/null +++ b/apt-private/private-output.h @@ -0,0 +1,49 @@ +#ifndef APT_PRIVATE_OUTPUT_H +#define APT_PRIVATE_OUTPUT_H + + +#include <iostream> +#include <fstream> +#include <string> + +#include "private-cachefile.h" + +// forward declaration +class pkgCacheFile; +class CacheFile; +class pkgCache; +class pkgDepCache; +class pkgRecords; + + +extern std::ostream c0out; +extern std::ostream c1out; +extern std::ostream c2out; +extern std::ofstream devnull; +extern unsigned int ScreenWidth; + +bool InitOutput(); +void ListSingleVersion(pkgCacheFile &CacheFile, pkgRecords &records, + pkgCache::VerIterator V, std::ostream &out); + + + +bool ShowList(std::ostream &out, std::string Title, std::string List, + std::string VersionsList); +void ShowBroken(std::ostream &out,CacheFile &Cache,bool Now); +void ShowNew(std::ostream &out,CacheFile &Cache); +void ShowDel(std::ostream &out,CacheFile &Cache); +void ShowKept(std::ostream &out,CacheFile &Cache); +void ShowUpgraded(std::ostream &out,CacheFile &Cache); +bool ShowDowngraded(std::ostream &out,CacheFile &Cache); +bool ShowHold(std::ostream &out,CacheFile &Cache); + +bool ShowEssential(std::ostream &out,CacheFile &Cache); + +void Stats(std::ostream &out, pkgDepCache &Dep); + +// prompting +bool YnPrompt(bool Default=true); +bool AnalPrompt(const char *Text); + +#endif diff --git a/apt-private/private-search.cc b/apt-private/private-search.cc new file mode 100644 index 000000000..6881f482f --- /dev/null +++ b/apt-private/private-search.cc @@ -0,0 +1,99 @@ +#include <apt-pkg/error.h> +#include <apt-pkg/cachefile.h> +#include <apt-pkg/cachefilter.h> +#include <apt-pkg/cacheset.h> +#include <apt-pkg/init.h> +#include <apt-pkg/progress.h> +#include <apt-pkg/sourcelist.h> +#include <apt-pkg/cmndline.h> +#include <apt-pkg/strutl.h> +#include <apt-pkg/fileutl.h> +#include <apt-pkg/pkgrecords.h> +#include <apt-pkg/srcrecords.h> +#include <apt-pkg/version.h> +#include <apt-pkg/policy.h> +#include <apt-pkg/tagfile.h> +#include <apt-pkg/algorithms.h> +#include <apt-pkg/sptr.h> +#include <apt-pkg/pkgsystem.h> +#include <apt-pkg/indexfile.h> +#include <apt-pkg/metaindex.h> + +#include <sstream> +#include <utility> +#include <cassert> +#include <locale.h> +#include <iostream> +#include <unistd.h> +#include <errno.h> +#include <regex.h> +#include <stdio.h> +#include <iomanip> +#include <algorithm> +#include <map> + +#include "private-search.h" +#include "private-cacheset.h" + + +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; + + std::map<std::string, std::string> output_map; + std::map<std::string, std::string>::const_iterator K; + + LocalitySortedVersionSet bag; + OpTextProgress progress; + progress.OverallProgress(0, 100, 50, _("Sorting")); + GetLocalitySortedVersionSet(CacheFile, bag, progress); + LocalitySortedVersionSet::iterator V = bag.begin(); + + progress.OverallProgress(50, 100, 50, _("Full Text Search")); + progress.SubProgress(bag.size()); + int Done = 0; + for ( ;V != bag.end(); V++) + { + if (Done%500 == 0) + progress.Progress(Done); + Done++; + + int i; + pkgCache::DescIterator Desc = V.TranslatedDescription(); + pkgRecords::Parser &parser = records.Lookup(Desc.FileList()); + + bool all_found = true; + for(i=0; patterns[i] != NULL; i++) + { + // FIXME: use regexp instead of simple find() + const char *pattern = patterns[i]; + all_found &= ( + strstr(V.ParentPkg().Name(), pattern) != NULL || + parser.ShortDesc().find(pattern) != std::string::npos || + parser.LongDesc().find(pattern) != std::string::npos); + } + if (all_found) + { + std::stringstream outs; + ListSingleVersion(CacheFile, records, V, outs); + output_map.insert(std::make_pair<std::string, std::string>( + V.ParentPkg().Name(), outs.str())); + } + } + progress.Done(); + + // FIXME: SORT! and make sorting flexible (alphabetic, by pkg status) + // output the sorted map + for (K = output_map.begin(); K != output_map.end(); K++) + std::cout << (*K).second << std::endl; + + return true; +} diff --git a/apt-private/private-search.h b/apt-private/private-search.h new file mode 100644 index 000000000..17faffebc --- /dev/null +++ b/apt-private/private-search.h @@ -0,0 +1,9 @@ +#ifndef APT_PRIVATE_SEARCH_H +#define APT_PRIVATE_SEARCH_H + +#include <apt-pkg/cmndline.h> + +bool FullTextSearch(CommandLine &CmdL); + + +#endif diff --git a/apt-private/private-show.cc b/apt-private/private-show.cc new file mode 100644 index 000000000..e26a2b30a --- /dev/null +++ b/apt-private/private-show.cc @@ -0,0 +1,122 @@ +#include <apt-pkg/error.h> +#include <apt-pkg/cachefile.h> +#include <apt-pkg/cachefilter.h> +#include <apt-pkg/cacheset.h> +#include <apt-pkg/init.h> +#include <apt-pkg/progress.h> +#include <apt-pkg/sourcelist.h> +#include <apt-pkg/cmndline.h> +#include <apt-pkg/strutl.h> +#include <apt-pkg/fileutl.h> +#include <apt-pkg/pkgrecords.h> +#include <apt-pkg/srcrecords.h> +#include <apt-pkg/version.h> +#include <apt-pkg/policy.h> +#include <apt-pkg/tagfile.h> +#include <apt-pkg/algorithms.h> +#include <apt-pkg/sptr.h> +#include <apt-pkg/pkgsystem.h> +#include <apt-pkg/indexfile.h> +#include <apt-pkg/metaindex.h> + +#include <apti18n.h> + +#include "private-output.h" +#include "private-cacheset.h" + +namespace APT { + namespace Cmd { + +// DisplayRecord - Displays the complete record for the package /*{{{*/ +// --------------------------------------------------------------------- +bool DisplayRecord(pkgCacheFile &CacheFile, pkgCache::VerIterator V, + ostream &out) +{ + pkgCache *Cache = CacheFile.GetPkgCache(); + if (unlikely(Cache == NULL)) + return false; + + // Find an appropriate file + pkgCache::VerFileIterator Vf = V.FileList(); + for (; Vf.end() == false; ++Vf) + if ((Vf.File()->Flags & pkgCache::Flag::NotSource) == 0) + break; + if (Vf.end() == true) + Vf = V.FileList(); + + // Check and load the package list file + pkgCache::PkgFileIterator I = Vf.File(); + if (I.IsOk() == false) + return _error->Error(_("Package file %s is out of sync."),I.FileName()); + + // Read the record + FileFd PkgF; + if (PkgF.Open(I.FileName(), FileFd::ReadOnly, FileFd::Extension) == false) + return false; + pkgTagSection Tags; + pkgTagFile TagF(&PkgF); + + TFRewriteData RW[] = { + {"Conffiles",0}, + {"Description",0}, + {"Description-md5",0}, + {} + }; + const char *Zero = 0; + if (TagF.Jump(Tags, V.FileList()->Offset) == false || + TFRewrite(stdout,Tags,&Zero,RW) == false) + { + _error->Error("Internal Error, Unable to parse a package record"); + return false; + } + + // write the description + pkgRecords Recs(*Cache); + pkgCache::DescIterator Desc = V.TranslatedDescription(); + if (Desc.end() == false) + { + pkgRecords::Parser &P = Recs.Lookup(Desc.FileList()); + if (strcmp(Desc.LanguageCode(),"") != 0) + out << "Description-lang: " << Desc.LanguageCode() << std::endl; + out << "Description" << P.LongDesc(); + } + + // write a final newline (after the description) + out << std::endl << std::endl; + + return true; +} + /*}}}*/ + +bool ShowPackage(CommandLine &CmdL) +{ + pkgCacheFile CacheFile; + CacheSetHelperVirtuals helper(true, GlobalError::NOTICE); + APT::VersionList::Version const select = APT::VersionList::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; + + for (APT::PackageSet::const_iterator Pkg = helper.virtualPkgs.begin(); + Pkg != helper.virtualPkgs.end(); ++Pkg) + { + c1out << "Package: " << Pkg.FullName(true) << std::endl; + c1out << "State: " << _("not a real pacakge (virtual)") << std::endl; + // FIXME: show providers, see private-cacheset.h + // CacheSetHelperAPTGet::showVirtualPackageErrors() + } + + if (verset.empty() == true) + { + if (helper.virtualPkgs.empty() == true) + return _error->Error(_("No packages found")); + else + _error->Notice(_("No packages found")); + } + + return true; +} + /*}}}*/ +} // namespace Cmd +} // namespace APT diff --git a/apt-private/private-show.h b/apt-private/private-show.h new file mode 100644 index 000000000..b428c7af0 --- /dev/null +++ b/apt-private/private-show.h @@ -0,0 +1,12 @@ +#ifndef APT_PRIVATE_SHOW_H +#define APT_PRIVATE_SHOW_H + +#include <apt-pkg/cmndline.h> + +namespace APT { + namespace Cmd { + + bool ShowPackage(CommandLine &CmdL); + } +} +#endif diff --git a/apt-private/private-update.cc b/apt-private/private-update.cc new file mode 100644 index 000000000..61259748d --- /dev/null +++ b/apt-private/private-update.cc @@ -0,0 +1,93 @@ +// Include files /*{{{*/ +#include<config.h> + +#include <apt-pkg/aptconfiguration.h> +#include <apt-pkg/error.h> +#include <apt-pkg/cmndline.h> +#include <apt-pkg/init.h> +#include <apt-pkg/depcache.h> +#include <apt-pkg/sourcelist.h> +#include <apt-pkg/algorithms.h> +#include <apt-pkg/acquire-item.h> +#include <apt-pkg/strutl.h> +#include <apt-pkg/fileutl.h> +#include <apt-pkg/clean.h> +#include <apt-pkg/srcrecords.h> +#include <apt-pkg/version.h> +#include <apt-pkg/cachefile.h> +#include <apt-pkg/cacheset.h> +#include <apt-pkg/sptr.h> +#include <apt-pkg/md5.h> +#include <apt-pkg/versionmatch.h> +#include <apt-pkg/progress.h> +#include <apt-pkg/pkgsystem.h> +#include <apt-pkg/pkgrecords.h> +#include <apt-pkg/indexfile.h> + +#include <sys/types.h> +#include <sys/stat.h> +#include <unistd.h> + +#include "private-cachefile.h" +#include "private-output.h" +#include "acqprogress.h" + +#include <apti18n.h> + /*}}}*/ + +// DoUpdate - Update the package lists /*{{{*/ +// --------------------------------------------------------------------- +/* */ +bool DoUpdate(CommandLine &CmdL) +{ + if (CmdL.FileSize() != 1) + return _error->Error(_("The update command takes no arguments")); + + CacheFile Cache; + + // Get the source list + if (Cache.BuildSourceList() == false) + return false; + pkgSourceList *List = Cache.GetSourceList(); + + // Create the progress + AcqTextStatus Stat(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) + { + // force a hashsum for compatibility reasons + _config->CndSet("Acquire::ForceHash", "md5sum"); + + // get a fetcher + pkgAcquire Fetcher; + if (Fetcher.Setup(&Stat) == false) + return false; + + // Populate it with the source selection and get all Indexes + // (GetAll=true) + if (List->GetIndexes(&Fetcher,true) == false) + return false; + + pkgAcquire::UriIterator I = Fetcher.UriBegin(); + for (; I != Fetcher.UriEnd(); ++I) + c1out << '\'' << I->URI << "' " << flNotDir(I->Owner->DestFile) << ' ' << + I->Owner->FileSize << ' ' << I->Owner->HashSum() << std::endl; + return true; + } + + // do the work + if (_config->FindB("APT::Get::Download",true) == true) + ListUpdate(Stat, *List); + + // Rebuild the cache. + if (_config->FindB("pkgCacheFile::Generate", true) == true) + { + pkgCacheFile::RemoveCaches(); + if (Cache.BuildCaches() == false) + return false; + } + + return true; +} + /*}}}*/ diff --git a/apt-private/private-update.h b/apt-private/private-update.h new file mode 100644 index 000000000..d3d0b7af9 --- /dev/null +++ b/apt-private/private-update.h @@ -0,0 +1,8 @@ +#ifndef APT_PRIVATE_UPDATE_H +#define APT_PRIVATE_UPDATE_H + +class CommandLine; + +bool DoUpdate(CommandLine &CmdL); + +#endif diff --git a/apt-private/private-upgrade.cc b/apt-private/private-upgrade.cc new file mode 100644 index 000000000..85b5a492a --- /dev/null +++ b/apt-private/private-upgrade.cc @@ -0,0 +1,47 @@ + +#include <apt-pkg/algorithms.h> + +#include "private-install.h" +#include "private-cachefile.h" +#include "private-upgrade.h" +#include "private-output.h" + + +// DoUpgradeNoNewPackages - Upgrade all packages /*{{{*/ +// --------------------------------------------------------------------- +/* Upgrade all packages without installing new packages or erasing old + packages */ +bool DoUpgradeNoNewPackages(CommandLine &CmdL) +{ + CacheFile Cache; + 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 InstallPackages(Cache,true); +} + /*}}}*/ + +// DoSafeUpgrade - Upgrade all packages with install but not remove /*{{{*/ +bool DoUpgradeWithAllowNewPackages(CommandLine &CmdL) +{ + CacheFile Cache; + if (Cache.OpenForInstall() == false || Cache.CheckDeps() == false) + return false; + + // Do the upgrade + if (pkgAllUpgradeNoDelete(Cache) == false) + { + ShowBroken(c1out,Cache,false); + return _error->Error(_("Internal error, AllUpgrade broke stuff")); + } + + return InstallPackages(Cache,true); +} + /*}}}*/ diff --git a/apt-private/private-upgrade.h b/apt-private/private-upgrade.h new file mode 100644 index 000000000..6ede6f96c --- /dev/null +++ b/apt-private/private-upgrade.h @@ -0,0 +1,11 @@ +#ifndef APTPRIVATE_PRIVATE_UPGRADE_H +#define APTPRIVATE_PRIVATE_UPGRADE_H + +#include <apt-pkg/cmndline.h> + + +bool DoUpgradeNoNewPackages(CommandLine &CmdL); +bool DoUpgradeWithAllowNewPackages(CommandLine &CmdL); + + +#endif |