// -*- mode: cpp; mode: fold -*-
// Description /*{{{*/
-// $Id: apt-get.cc,v 1.104 2001/03/13 05:23:42 jgg Exp $
+// $Id: apt-get.cc,v 1.126 2003/02/12 16:14:08 doogie Exp $
/* ######################################################################
apt-get - Cover for dpkg
#include "acqprogress.h"
-#include <fstream.h>
+#include <locale.h>
+#include <fstream>
#include <termios.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <sys/wait.h>
/*}}}*/
-ostream c0out;
-ostream c1out;
-ostream c2out;
+using namespace std;
+
+ostream c0out(0);
+ostream c1out(0);
+ostream c2out(0);
ofstream devnull("/dev/null");
unsigned int ScreenWidth = 80;
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);
return true;
};
+ bool OpenForInstall()
+ {
+ if (_config->FindB("APT::Get::Print-URIs") == true)
+ return Open(false);
+ else
+ return Open(true);
+ }
CacheFile() : List(0) {};
};
/*}}}*/
{
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;
description.
The output looks like:
- Sorry, but the following packages have unmet dependencies:
+ The following packages have unmet dependencies:
exim: Depends: libc6 (>= 2.1.94) but 2.1.3-10 is to be installed
Depends: libldap2 (>= 2.0.2-2) but it is not going to be installed
Depends: libsasl7 but it is not going to be installed
*/
void ShowBroken(ostream &out,CacheFile &Cache,bool Now)
{
- out << _("Sorry, but the following packages have unmet dependencies:") << endl;
+ out << _("The following packages have unmet dependencies:") << endl;
for (unsigned J = 0; J < Cache->Head().PackageCount; J++)
{
pkgCache::PkgIterator I(Cache,Cache.List[J]);
- if (Cache[I].InstBroken() == false)
- continue;
-
+ if (Now == true)
+ {
+ if (Cache[I].NowBroken() == false)
+ continue;
+ }
+ else
+ {
+ if (Cache[I].InstBroken() == false)
+ continue;
+ }
+
// Print out each package and the failed dependencies
out <<" " << I.Name() << ":";
unsigned Indent = strlen(I.Name()) + 3;
bool First = true;
- if (Cache[I].InstVerIter(Cache).end() == true)
+ pkgCache::VerIterator Ver;
+
+ if (Now == true)
+ Ver = I.CurrentVer();
+ else
+ Ver = Cache[I].InstVerIter(Cache);
+
+ if (Ver.end() == true)
{
- cout << endl;
+ out << endl;
continue;
}
- for (pkgCache::DepIterator D = Cache[I].InstVerIter(Cache).DependsList(); D.end() == false;)
+ for (pkgCache::DepIterator D = Ver.DependsList(); D.end() == false;)
{
// Compute a single dependency element (glob or)
pkgCache::DepIterator Start;
pkgCache::DepIterator End;
D.GlobOr(Start,End);
- if (Cache->IsImportantDep(End) == false ||
- (Cache[End] & pkgDepCache::DepGInstall) == pkgDepCache::DepGInstall)
+ if (Cache->IsImportantDep(End) == false)
continue;
-
+
+ if (Now == true)
+ {
+ if ((Cache[End] & pkgDepCache::DepGNow) == pkgDepCache::DepGNow)
+ continue;
+ }
+ else
+ {
+ if ((Cache[End] & pkgDepCache::DepGInstall) == pkgDepCache::DepGInstall)
+ continue;
+ }
+
bool FirstOr = true;
while (1)
{
{
out << ' ';
pkgCache::VerIterator Ver = Cache[Targ].InstVerIter(Cache);
+ if (Now == true)
+ Ver = Targ.CurrentVer();
+
if (Ver.end() == false)
{
if (Now == true)
if (Downgrade != 0)
ioprintf(out,_("%lu downgraded, "),Downgrade);
- ioprintf(out,_("%lu to remove and %lu not upgraded.\n"),
+ ioprintf(out,_("%lu to remove and %lu not upgraded.\n"),
Dep.DelCount(),Dep.KeepCount());
if (Dep.BadCount() != 0)
// Lock the archive directory
FileFd Lock;
- if (_config->FindB("Debug::NoLocking",false) == false)
+ if (_config->FindB("Debug::NoLocking",false) == false &&
+ _config->FindB("APT::Get::Print-URIs") == false)
{
Lock.Fd(GetLock(_config->FindDir("Dir::Cache::Archives") + "lock"));
if (_error->PendingError() == true)
// Number of bytes
if (DebBytes != FetchBytes)
- ioprintf(c1out,_("Need to get %sB/%sB of archives. "),
+ ioprintf(c1out,_("Need to get %sB/%sB of archives.\n"),
SizeToStr(FetchBytes).c_str(),SizeToStr(DebBytes).c_str());
else
- ioprintf(c1out,_("Need to get %sB of archives. "),
+ ioprintf(c1out,_("Need to get %sB of archives.\n"),
SizeToStr(DebBytes).c_str());
// Size delta
if (Cache->UsrSize() >= 0)
- ioprintf(c1out,_("After unpacking %sB will be used.\n"),
+ ioprintf(c1out,_("After unpacking %sB of additional disk space will be used.\n"),
SizeToStr(Cache->UsrSize()).c_str());
else
- ioprintf(c1out,_("After unpacking %sB will be freed.\n"),
+ ioprintf(c1out,_("After unpacking %sB disk space will be freed.\n"),
SizeToStr(-1*Cache->UsrSize()).c_str());
if (_error->PendingError() == true)
/* Check for enough free space, but only if we are actually going to
download */
- if (_config->FindB("APT::Get::Print-URIs") == false)
+ if (_config->FindB("APT::Get::Print-URIs") == false &&
+ _config->FindB("APT::Get::Download",true) == true)
{
struct statvfs Buf;
string OutputDir = _config->FindDir("Dir::Cache::Archives");
return _error->Errno("statvfs","Couldn't determine free space in %s",
OutputDir.c_str());
if (unsigned(Buf.f_bfree) < (FetchBytes - FetchPBytes)/Buf.f_bsize)
- return _error->Error(_("Sorry, you don't have enough free space in %s to hold all the .debs."),
+ return _error->Error(_("You don't have enough free space in %s."),
OutputDir.c_str());
}
bool Transient = false;
if (_config->FindB("APT::Get::Download",true) == false)
{
- for (pkgAcquire::Item **I = Fetcher.ItemsBegin(); I < Fetcher.ItemsEnd();)
+ for (pkgAcquire::ItemIterator I = Fetcher.ItemsBegin(); I < Fetcher.ItemsEnd();)
{
if ((*I)->Local == true)
{
// Print out errors
bool Failed = false;
- for (pkgAcquire::Item **I = Fetcher.ItemsBegin(); I != Fetcher.ItemsEnd(); I++)
+ for (pkgAcquire::ItemIterator I = Fetcher.ItemsBegin(); I != Fetcher.ItemsEnd(); I++)
{
if ((*I)->Status == pkgAcquire::Item::StatDone &&
(*I)->Complete == true)
pkgDepCache::StateCache &State = Cache[Pkg];
if (Remove == true && Pkg->CurrentVer == 0)
{
+ Fix.Clear(Pkg);
+ Fix.Protect(Pkg);
+ Fix.Remove(Pkg);
+
/* We want to continue searching for regex hits, so we return false here
otherwise this is not really an error. */
if (AllowFail == false)
- return false;
+ return false;
+
ioprintf(c1out,_("Package %s is not installed, so not removed\n"),Pkg.Name());
return true;
}
if (_config->FindB("APT::Get::ReInstall",false) == true)
{
if (Pkg->CurrentVer == 0 || Pkg.CurrentVer().Downloadable() == false)
- ioprintf(c1out,_("Sorry, re-installation of %s is not possible, it cannot be downloaded."),
+ ioprintf(c1out,_("Reinstallation of %s is not possible, it cannot be downloaded.\n"),
Pkg.Name());
else
Cache.SetReInstall(Pkg,true);
else
{
if (AllowFail == true)
- ioprintf(c1out,_("Sorry, %s is already the newest version.\n"),
+ ioprintf(c1out,_("%s is already the newest version.\n"),
Pkg.Name());
}
}
bool TryToChangeVer(pkgCache::PkgIterator Pkg,pkgDepCache &Cache,
const char *VerTag,bool IsRel)
{
- pkgVersionMatch Match(VerTag,(IsRel == true?pkgVersionMatch::Release:pkgVersionMatch::Version));
+ pkgVersionMatch Match(VerTag,(IsRel == true?pkgVersionMatch::Release :
+ pkgVersionMatch::Version));
pkgCache::VerIterator Ver = Match.Find(Pkg);
// Create the download object
AcqTextStatus Stat(ScreenWidth,_config->FindI("quiet",0));
pkgAcquire Fetcher(&Stat);
-
+
// Populate it with the source selection
if (List.GetIndexes(&Fetcher) == false)
return false;
+ // Just print out the uris an exit if the --print-uris flag was used
+ if (_config->FindB("APT::Get::Print-URIs") == true)
+ {
+ pkgAcquire::UriIterator I = Fetcher.UriBegin();
+ for (; I != Fetcher.UriEnd(); I++)
+ cout << '\'' << I->URI << "' " << flNotDir(I->Owner->DestFile) << ' ' <<
+ I->Owner->FileSize << ' ' << I->Owner->MD5Sum() << endl;
+ return true;
+ }
+
// Run it
if (Fetcher.Run() == pkgAcquire::Failed)
return false;
bool Failed = false;
- for (pkgAcquire::Item **I = Fetcher.ItemsBegin(); I != Fetcher.ItemsEnd(); I++)
+ for (pkgAcquire::ItemIterator I = Fetcher.ItemsBegin(); I != Fetcher.ItemsEnd(); I++)
{
if ((*I)->Status == pkgAcquire::Item::StatDone)
continue;
// Prepare the cache.
CacheFile Cache;
- if (Cache.Open() == false)
+ if (Cache.BuildCaches() == false)
return false;
if (Failed == true)
bool DoUpgrade(CommandLine &CmdL)
{
CacheFile Cache;
- if (Cache.Open() == false || Cache.CheckDeps() == false)
+ if (Cache.OpenForInstall() == false || Cache.CheckDeps() == false)
return false;
// Do the upgrade
bool DoInstall(CommandLine &CmdL)
{
CacheFile Cache;
- if (Cache.Open() == false || Cache.CheckDeps(CmdL.FileSize() != 1) == false)
+ if (Cache.OpenForInstall() == false ||
+ Cache.CheckDeps(CmdL.FileSize() != 1) == false)
return false;
// Enter the special broken fixing mode if the user specified arguments
// Check if the name is a regex
const char *I;
for (I = S; *I != 0; I++)
- if (*I == '.' || *I == '?' || *I == '*' || *I == '|')
+ if (*I == '?' || *I == '*' || *I == '|' ||
+ *I == '[' || *I == '^' || *I == '$')
break;
if (*I == 0)
return _error->Error(_("Couldn't find package %s"),S);
if ((Res = regcomp(&Pattern,S,REG_EXTENDED | REG_ICASE |
REG_NOSUB)) != 0)
{
- char Error[300];
+ char Error[300];
regerror(Res,&Pattern,Error,sizeof(Error));
return _error->Error(_("Regex compilation error - %s"),Error);
}
if (regexec(&Pattern,Pkg.Name(),0,0,0) != 0)
continue;
+ ioprintf(c1out,_("Note, selecting %s for regex '%s'\n"),
+ Pkg.Name(),S);
+
if (VerTag != 0)
if (TryToChangeVer(Pkg,Cache,VerTag,VerIsRel) == false)
return false;
c1out << _("The following information may help to resolve the situation:") << endl;
c1out << endl;
ShowBroken(c1out,Cache,false);
- return _error->Error(_("Sorry, broken packages"));
+ return _error->Error(_("Broken packages"));
}
/* Print out a list of packages that are going to be installed extra
bool DoDistUpgrade(CommandLine &CmdL)
{
CacheFile Cache;
- if (Cache.Open() == false || Cache.CheckDeps() == false)
+ if (Cache.OpenForInstall() == false || Cache.CheckDeps() == false)
return false;
c0out << _("Calculating Upgrade... ") << flush;
bool DoDSelectUpgrade(CommandLine &CmdL)
{
CacheFile Cache;
- if (Cache.Open() == false || Cache.CheckDeps() == false)
+ if (Cache.OpenForInstall() == false || Cache.CheckDeps() == false)
return false;
// Install everything with the install flag set
return _error->Errno("statvfs","Couldn't determine free space in %s",
OutputDir.c_str());
if (unsigned(Buf.f_bfree) < (FetchBytes - FetchPBytes)/Buf.f_bsize)
- return _error->Error(_("Sorry, you don't have enough free space in %s"),
+ return _error->Error(_("You don't have enough free space in %s"),
OutputDir.c_str());
// Number of bytes
// Print error messages
bool Failed = false;
- for (pkgAcquire::Item **I = Fetcher.ItemsBegin(); I != Fetcher.ItemsEnd(); I++)
+ for (pkgAcquire::ItemIterator I = Fetcher.ItemsBegin(); I != Fetcher.ItemsEnd(); I++)
{
if ((*I)->Status == pkgAcquire::Item::StatDone &&
(*I)->Complete == true)
// Process the build-dependencies
vector<pkgSrcRecords::Parser::BuildDepRec> BuildDeps;
- if (Last->BuildDepends(BuildDeps) == false)
+ if (Last->BuildDepends(BuildDeps, _config->FindB("APT::Get::Arch-Only",false)) == false)
return _error->Error(_("Unable to get build-dependency information for %s"),Src.c_str());
+ // Also ensure that build-essential packages are present
+ Configuration::Item const *Opts = _config->Tree("APT::Build-Essential");
+ if (Opts)
+ Opts = Opts->Child;
+ for (; Opts; Opts = Opts->Next)
+ {
+ if (Opts->Value.empty() == true)
+ continue;
+
+ pkgSrcRecords::Parser::BuildDepRec rec;
+ rec.Package = Opts->Value;
+ rec.Type = pkgSrcRecords::Parser::BuildDependIndep;
+ rec.Op = 0;
+ BuildDeps.insert(BuildDeps.begin(), rec);
+ }
+
if (BuildDeps.size() == 0)
{
ioprintf(c1out,_("%s has no build depends.\n"),Src.c_str());
pkgProblemResolver Fix(Cache);
for (D = BuildDeps.begin(); D != BuildDeps.end(); D++)
{
- pkgCache::PkgIterator Pkg = Cache->FindPkg((*D).Package);
- if (Pkg.end() == true)
- return _error->Error(_("%s dependency on %s cannot be satisfied because the package %s cannot be found"),
- Last->BuildDepType((*D).Type),Src.c_str(),(*D).Package.c_str());
- pkgCache::VerIterator IV = (*Cache)[Pkg].InstVerIter(*Cache);
-
- if ((*D).Type == pkgSrcRecords::Parser::BuildConflict ||
+ if ((*D).Type == pkgSrcRecords::Parser::BuildConflict ||
(*D).Type == pkgSrcRecords::Parser::BuildConflictIndep)
- {
- /*
- * conflict; need to remove if we have an installed version
- * that satisfies the version criterial
- */
- if (IV.end() == false &&
- Cache->VS().CheckDep(IV.VerStr(),(*D).Op,(*D).Version.c_str()) == true)
- TryToInstall(Pkg,Cache,Fix,true,false,ExpectedInst);
- }
- else
- {
+ {
+ pkgCache::PkgIterator Pkg = Cache->FindPkg((*D).Package);
+ // Build-conflicts on unknown packages are silently ignored
+ if (Pkg.end() == true)
+ continue;
+
+ pkgCache::VerIterator IV = (*Cache)[Pkg].InstVerIter(*Cache);
+
+ /*
+ * Remove if we have an installed version that satisfies the
+ * version criteria
+ */
+ if (IV.end() == false &&
+ Cache->VS().CheckDep(IV.VerStr(),(*D).Op,(*D).Version.c_str()) == true)
+ TryToInstall(Pkg,Cache,Fix,true,false,ExpectedInst);
+ }
+ else // BuildDep || BuildDepIndep
+ {
+ pkgCache::PkgIterator Pkg = Cache->FindPkg((*D).Package);
+ if (Pkg.end() == true)
+ {
+ // Check if there are any alternatives
+ if (((*D).Op & pkgCache::Dep::Or) != pkgCache::Dep::Or)
+ return _error->Error(_("%s dependency for %s cannot be satisfied "
+ "because the package %s cannot be found"),
+ Last->BuildDepType((*D).Type),Src.c_str(),
+ (*D).Package.c_str());
+ // Try the next alternative
+ continue;
+ }
+
+ /*
+ * if there are alternatives, we've already picked one, so skip
+ * the rest
+ *
+ * TODO: this means that if there's a build-dep on A|B and B is
+ * installed, we'll still try to install A; more importantly,
+ * if A is currently broken, we cannot go back and try B. To fix
+ * this would require we do a Resolve cycle for each package we
+ * add to the install list. Ugh
+ */
+ while (D != BuildDeps.end() &&
+ (((*D).Op & pkgCache::Dep::Or) == pkgCache::Dep::Or))
+ D++;
+
/*
* If this is a virtual package, we need to check the list of
* packages that provide it and see if any of those are
for (; Prv.end() != true; Prv++)
if ((*Cache)[Prv.OwnerPkg()].InstVerIter(*Cache).end() == false)
break;
-
- if (Prv.end() == true)
- {
- /*
- * depends; need to install or upgrade if we don't have the
- * package installed or if the version does not satisfy the
- * build dep. This is complicated by the fact that if we
- * depend on a version lower than what we already have
- * installed it is not clear what should be done; in practice
- * this case should be rare though and right now nothing
- * is done about it :-(
- */
- if (IV.end() == true ||
- Cache->VS().CheckDep(IV.VerStr(),(*D).Op,(*D).Version.c_str()) == false)
- TryToInstall(Pkg,Cache,Fix,false,false,ExpectedInst);
- }
+
+ // Get installed version and version we are going to install
+ pkgCache::VerIterator IV = (*Cache)[Pkg].InstVerIter(*Cache);
+ pkgCache::VerIterator CV = (*Cache)[Pkg].CandidateVerIter(*Cache);
+
+ for (; CV.end() != true; CV++)
+ {
+ if (Cache->VS().CheckDep(CV.VerStr(),(*D).Op,(*D).Version.c_str()) == true)
+ break;
+ }
+ if (CV.end() == true)
+ return _error->Error(_("%s dependency for %s cannot be satisfied "
+ "because no available versions of package %s "
+ "can satisfy version requirements"),
+ Last->BuildDepType((*D).Type),Src.c_str(),
+ (*D).Package.c_str());
+
+ /*
+ * TODO: if we depend on a version lower than what we already have
+ * installed it is not clear what should be done; in practice
+ * this case should be rare, and right now nothing is
+ * done about it :-(
+ */
+ if (Prv.end() == true && // Nothing provides it; and
+ (IV.end() == true || // It is not installed, or
+ Cache->VS().CheckDep(IV.VerStr(),(*D).Op,(*D).Version.c_str()) == false))
+ // the version installed doesn't
+ // satisfy constraints
+ TryToInstall(Pkg,Cache,Fix,false,false,ExpectedInst);
}
}
{0,"trivial-only","APT::Get::Trivial-Only",0},
{0,"remove","APT::Get::Remove",0},
{0,"only-source","APT::Get::Only-Source",0},
+ {0,"arch-only","APT::Get::Arch-Only",0},
{'c',"config-file",0,CommandLine::ConfigFile},
{'o',"option",0,CommandLine::ArbItem},
{0,0,0,0}};
{"clean",&DoClean},
{"autoclean",&DoAutoClean},
{"check",&DoCheck},
- {"source",&DoSource},
+ {"source",&DoSource},
{"moo",&DoMoo},
- {"help",&ShowHelp},
+ {"help",&ShowHelp},
{0,0}};
-
+
+ // Set up gettext support
+ setlocale(LC_ALL,"");
+ textdomain(PACKAGE);
+
// Parse the command line and initialize the package library
CommandLine CmdL(Args,_config);
if (pkgInitConfig(*_config) == false ||