c1out << _("Y") << endl;
return true;
}
+ else if (_config->FindB("APT::Get::Assume-No",false) == true)
+ {
+ c1out << _("N") << endl;
+ return false;
+ }
char response[1024] = "";
cin.getline(response, sizeof(response));
{
pkgCache::PkgIterator I(Cache,Cache.List[J]);
if (Cache[I].NewInstall() == true) {
- if (Cache[I].CandidateVerIter(Cache).Pseudo() == true)
- continue;
List += I.FullName(true) + " ";
VersionsList += string(Cache[I].CandVersion) + "\n";
}
pkgCache::PkgIterator I(Cache,Cache.List[J]);
if (Cache[I].Delete() == true)
{
- if (Cache[I].CandidateVerIter(Cache).Pseudo() == true)
- continue;
if ((Cache[I].iFlags & pkgDepCache::Purge) == pkgDepCache::Purge)
List += I.FullName(true) + "* ";
else
// Not interesting
if (Cache[I].Upgrade() == false || Cache[I].NewInstall() == true)
continue;
- if (Cache[I].CandidateVerIter(Cache).Pseudo() == true)
- continue;
List += I.FullName(true) + " ";
VersionsList += string(Cache[I].CurVersion) + " => " + Cache[I].CandVersion + "\n";
// Not interesting
if (Cache[I].Downgrade() == false || Cache[I].NewInstall() == true)
continue;
- if (Cache[I].CandidateVerIter(Cache).Pseudo() == true)
- continue;
List += I.FullName(true) + " ";
VersionsList += string(Cache[I].CurVersion) + " => " + Cache[I].CandVersion + "\n";
unsigned long ReInstall = 0;
for (pkgCache::PkgIterator I = Dep.PkgBegin(); I.end() == false; I++)
{
- if (pkgCache::VerIterator(Dep, Dep[I].CandidateVer).Pseudo() == true)
- continue;
-
if (Dep[I].NewInstall() == true)
Install++;
else
unsigned long AutoMarkChanged;
APT::PackageSet doAutoInstallLater;
- TryToInstall(pkgCacheFile &Cache, pkgProblemResolver &PM, bool const &FixBroken) : Cache(&Cache), Fix(&PM),
+ TryToInstall(pkgCacheFile &Cache, pkgProblemResolver *PM, bool const &FixBroken) : Cache(&Cache), Fix(PM),
FixBroken(FixBroken), AutoMarkChanged(0) {};
void operator() (pkgCache::VerIterator const &Ver) {
ioprintf(c1out,_("Skipping %s, it is not installed and only upgrades are requested.\n"),
Pkg.FullName(true).c_str());
else {
- Fix->Clear(Pkg);
- Fix->Protect(Pkg);
+ if (Fix != NULL) {
+ Fix->Clear(Pkg);
+ Fix->Protect(Pkg);
+ }
Cache->GetDepCache()->MarkInstall(Pkg,false);
if (State.Install() == false) {
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();
bool PurgePkgs;
unsigned long AutoMarkChanged;
- TryToRemove(pkgCacheFile &Cache, pkgProblemResolver &PM) : Cache(&Cache), Fix(&PM),
+ 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();
- Fix->Clear(Pkg);
- Fix->Protect(Pkg);
- Fix->Remove(Pkg);
+ 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))
+ {
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);
}
return AllowFail;
}
+ if (_config->FindB("Debug::BuildDeps",false) == true)
+ {
+ if (Remove == true)
+ cout << " Trying to remove " << Pkg << endl;
+ else
+ cout << " Trying to install " << Pkg << endl;
+ }
+
if (Remove == true)
{
- TryToRemove RemoveAction(Cache, Fix);
+ TryToRemove RemoveAction(Cache, &Fix);
RemoveAction(Pkg.VersionList());
} else if (Cache[Pkg].CandidateVer != 0) {
- TryToInstall InstallAction(Cache, Fix, BrokenFix);
+ TryToInstall InstallAction(Cache, &Fix, BrokenFix);
InstallAction(Cache[Pkg].CandidateVerIter(Cache));
InstallAction.doAutoInstall();
} else
bool purgePkgs = _config->FindB("APT::Get::Purge", false);
bool smallList = (hideAutoRemove == false &&
- strcasecmp(_config->Find("APT::Get::HideAutoRemove","").c_str(),"small") == 0) ||
- // we don't want to autoremove and we don't want to see it, so don't generate lists
- (doAutoRemove == false && hideAutoRemove == true);
+ strcasecmp(_config->Find("APT::Get::HideAutoRemove","").c_str(),"small") == 0);
string autoremovelist, autoremoveversions;
unsigned long autoRemoveCount = 0;
+ APT::PackageSet tooMuch;
// look over the cache to see what can be removed
for (pkgCache::PkgIterator Pkg = Cache->PkgBegin(); ! Pkg.end(); ++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)
+ {
Cache->MarkDelete(Pkg, false);
+ tooMuch.insert(Pkg);
+ }
// only show stuff in the list that is not yet marked for removal
- else if(Cache[Pkg].Delete() == false)
+ else if(hideAutoRemove == false && Cache[Pkg].Delete() == false)
{
++autoRemoveCount;
// we don't need to fill the strings if we don't need them
}
}
+ // 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 P = tooMuch.begin();
+ P != tooMuch.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 " << P << " as another installed garbage package depends on it" << std::endl;
+ Cache->MarkInstall(P, false);
+ if(hideAutoRemove == false)
+ {
+ ++autoRemoveCount;
+ if (smallList == false)
+ {
+ autoremovelist += P.FullName(true) + " ";
+ autoremoveversions += string(Cache[P].CandVersion) + "\n";
+ }
+ }
+ tooMuch.erase(P);
+ Changed = true;
+ break;
+ }
+ }
+ } while (Changed == true);
+ }
+
// Now see if we had destroyed anything (if we had done anything)
if (Cache->BrokenCount() != 0)
{
bool BrokenFix = false;
if (Cache->BrokenCount() != 0)
BrokenFix = true;
-
- pkgProblemResolver Fix(Cache);
+
+ 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;
if (_error->PendingError() == true)
{
helper.showVirtualPackageErrors(Cache);
+ if (Fix != NULL)
+ delete Fix;
return false;
}
- unsigned short order[] = { 0, 0, 0 };
- if (fallback == MOD_INSTALL) {
- order[0] = MOD_INSTALL;
- order[1] = MOD_REMOVE;
- } else {
- order[0] = MOD_REMOVE;
- order[1] = MOD_INSTALL;
- }
+ unsigned short const order[] = { MOD_REMOVE, MOD_INSTALL, 0 };
TryToInstall InstallAction(Cache, Fix, BrokenFix);
TryToRemove RemoveAction(Cache, Fix);
for (unsigned short i = 0; order[i] != 0; ++i)
{
- if (order[i] == MOD_INSTALL) {
+ 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();
}
- else if (order[i] == MOD_REMOVE)
- RemoveAction = std::for_each(verset[MOD_REMOVE].begin(), verset[MOD_REMOVE].end(), RemoveAction);
}
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
{
c1out << _("You might want to run 'apt-get -f install' to correct these:") << 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)."));
}
-
- // Call the scored problem resolver
- Fix.InstallProtect();
- if (Fix.Resolve(true) == false)
- _error->Discard();
+
+ if (Fix != NULL)
+ {
+ // Call the scored problem resolver
+ Fix->InstallProtect();
+ Fix->Resolve(true);
+ delete Fix;
+ }
// Now we check the state of the packages,
if (Cache->BrokenCount() != 0)
c1out << _("The following information may help to resolve the situation:") << endl;
c1out << endl;
ShowBroken(c1out,Cache,false);
- return _error->Error(_("Broken packages"));
- }
+ if (_error->PendingError() == true)
+ return false;
+ else
+ return _error->Error(_("Broken packages"));
+ }
}
if (!DoAutomaticRemove(Cache))
return false;
pkgCache::PkgIterator I(Cache,Cache.List[J]);
if ((*Cache)[I].Install() == false)
continue;
+ pkgCache::VerIterator Cand = Cache[I].CandidateVerIter(Cache);
- const char **J;
- for (J = CmdL.FileList + 1; *J != 0; J++)
- if (strcmp(*J,I.Name()) == 0)
- break;
-
- if (*J == 0) {
- List += I.FullName(true) + " ";
- VersionsList += string(Cache[I].CandVersion) + "\n";
- }
+ if (verset[MOD_INSTALL].find(Cand) != verset[MOD_INSTALL].end())
+ continue;
+
+ List += I.FullName(true) + " ";
+ VersionsList += string(Cache[I].CandVersion) + "\n";
}
ShowList(c1out,_("The following extra packages will be installed:"),List,VersionsList);
return InstallPackages(Cache,false);
}
-
-/* mark packages as automatically/manually installed. */
+ /*}}}*/
+/* mark packages as automatically/manually installed. {{{*/
bool DoMarkAuto(CommandLine &CmdL)
{
bool Action = true;
AutoMarkChanged++;
}
}
+
+ _error->Notice(_("This command is deprecated. Please use 'apt-mark auto' and 'apt-mark manual' instead."));
+
if (AutoMarkChanged && ! _config->FindB("APT::Get::Simulate",false))
return Cache->writeStateFile(NULL);
return false;
Cleaner.Go(_config->FindDir("Dir::Cache::archives") + "partial/",*Cache);
}
/*}}}*/
+// DoDownload - download a binary /*{{{*/
+// ---------------------------------------------------------------------
+bool DoDownload(CommandLine &CmdL)
+{
+ CacheFile Cache;
+ if (Cache.ReadOnlyOpen() == false)
+ return false;
+
+ APT::CacheSetHelper helper(c0out);
+ APT::VersionSet verset = APT::VersionSet::FromCommandLine(Cache,
+ CmdL.FileList + 1, APT::VersionSet::CANDIDATE, helper);
+
+ if (verset.empty() == true)
+ return false;
+
+ pkgAcquire Fetcher;
+ AcqTextStatus Stat(ScreenWidth, _config->FindI("quiet",0));
+ if (_config->FindB("APT::Get::Print-URIs") == false)
+ Fetcher.Setup(&Stat);
+
+ pkgRecords Recs(Cache);
+ pkgSourceList *SrcList = Cache.GetSourceList();
+ for (APT::VersionSet::const_iterator Ver = verset.begin();
+ Ver != verset.end();
+ ++Ver)
+ {
+ string descr;
+ // get the right version
+ pkgCache::PkgIterator Pkg = Ver.ParentPkg();
+ pkgRecords::Parser &rec=Recs.Lookup(Ver.FileList());
+ pkgCache::VerFileIterator Vf = Ver.FileList();
+ if (Vf.end() == true)
+ return _error->Error("Can not find VerFile");
+ pkgCache::PkgFileIterator F = Vf.File();
+ pkgIndexFile *index;
+ if(SrcList->FindIndex(F, index) == false)
+ return _error->Error("FindIndex failed");
+ string uri = index->ArchiveURI(rec.FileName());
+ strprintf(descr, _("Downloading %s %s"), Pkg.Name(), Ver.VerStr());
+ // get the most appropriate hash
+ HashString hash;
+ if (rec.SHA512Hash() != "")
+ hash = HashString("sha512", rec.SHA512Hash());
+ if (rec.SHA256Hash() != "")
+ hash = HashString("sha256", rec.SHA256Hash());
+ else if (rec.SHA1Hash() != "")
+ hash = HashString("sha1", rec.SHA1Hash());
+ else if (rec.MD5Hash() != "")
+ hash = HashString("md5", rec.MD5Hash());
+ // get the file
+ new pkgAcqFile(&Fetcher, uri, hash.toStr(), (*Ver)->Size, descr, Pkg.Name(), ".");
+ }
+
+ // Just print out the uris and 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->HashSum() << endl;
+ return true;
+ }
+
+ return (Fetcher.Run() == pkgAcquire::Continue);
+}
+ /*}}}*/
// DoCheck - Perform the check operation /*{{{*/
// ---------------------------------------------------------------------
/* Opening automatically checks the system, this command is mostly used
// Create the download object
AcqTextStatus Stat(ScreenWidth,_config->FindI("quiet",0));
pkgAcquire Fetcher;
- if (Fetcher.Setup(&Stat) == false)
- return false;
+ Fetcher.SetLog(&Stat);
DscFile *Dsc = new DscFile[CmdL.FileSize()];
string Src;
pkgSrcRecords::Parser *Last = FindSrc(*I,Recs,SrcRecs,Src,*Cache);
- if (Last == 0)
+ if (Last == 0) {
+ delete[] Dsc;
return _error->Error(_("Unable to find a source package for %s"),Src.c_str());
+ }
string srec = Last->AsStr();
string::size_type pos = srec.find("\nVcs-");
// Back track
vector<pkgSrcRecords::File> Lst;
- if (Last->Files(Lst) == false)
+ if (Last->Files(Lst) == false) {
+ delete[] Dsc;
return false;
+ }
// Load them into the fetcher
for (vector<pkgSrcRecords::File>::const_iterator I = Lst.begin();
struct statvfs Buf;
string OutputDir = ".";
if (statvfs(OutputDir.c_str(),&Buf) != 0) {
+ delete[] Dsc;
if (errno == EOVERFLOW)
return _error->WarningE("statvfs",_("Couldn't determine free space in %s"),
OutputDir.c_str());
#if HAVE_STRUCT_STATFS_F_TYPE
|| unsigned(Stat.f_type) != RAMFS_MAGIC
#endif
- )
+ ) {
+ delete[] Dsc;
return _error->Error(_("You don't have enough free space in %s"),
OutputDir.c_str());
- }
+ }
+ }
// Number of bytes
if (DebBytes != FetchBytes)
// Run it
if (Fetcher.Run() == pkgAcquire::Failed)
+ {
+ delete[] Dsc;
return false;
+ }
// Print error messages
bool Failed = false;
Failed = true;
}
if (Failed == true)
+ {
+ delete[] Dsc;
return _error->Error(_("Failed to fetch some archives."));
-
+ }
+
if (_config->FindB("APT::Get::Download-only",false) == true)
{
c1out << _("Download complete and in download only mode") << endl;
// Try to compile it with dpkg-buildpackage
if (_config->FindB("APT::Get::Compile",false) == true)
{
+ string buildopts = _config->Find("APT::Get::Host-Architecture");
+ if (buildopts.empty() == false)
+ buildopts = "-a " + buildopts + " ";
+ buildopts.append(_config->Find("DPkg::Build-Options","-b -uc"));
+
// Call dpkg-buildpackage
char S[500];
snprintf(S,sizeof(S),"cd %s && %s %s",
Dir.c_str(),
_config->Find("Dir::Bin::dpkg-buildpackage","dpkg-buildpackage").c_str(),
- _config->Find("DPkg::Build-Options","-b -uc").c_str());
+ buildopts.c_str());
if (system(S) != 0)
{
bool DoBuildDep(CommandLine &CmdL)
{
CacheFile Cache;
+
+ _config->Set("APT::Install-Recommends", false);
+
if (Cache.Open(true) == false)
return false;
if (Fetcher.Setup(&Stat) == false)
return false;
+ bool StripMultiArch;
+ string hostArch = _config->Find("APT::Get::Host-Architecture");
+ if (hostArch.empty() == false)
+ {
+ std::vector<std::string> archs = APT::Configuration::getArchitectures();
+ if (std::find(archs.begin(), archs.end(), hostArch) == archs.end())
+ return _error->Error(_("No architecture information available for %s. See apt.conf(5) APT::Architectures for setup"), hostArch.c_str());
+ StripMultiArch = false;
+ }
+ else
+ StripMultiArch = true;
+
unsigned J = 0;
- bool const StripMultiArch = APT::Configuration::getArchitectures().size() <= 1;
for (const char **I = CmdL.FileList + 1; *I != 0; I++, J++)
{
string Src;
ioprintf(c1out,_("%s has no build depends.\n"),Src.c_str());
continue;
}
-
+
// Install the requested packages
vector <pkgSrcRecords::Parser::BuildDepRec>::iterator D;
pkgProblemResolver Fix(Cache);
if (skipAlternatives == true)
{
+ /*
+ * 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
+ */
if (!hasAlternatives)
skipAlternatives = false; // end of or group
continue;
if ((*D).Type == pkgSrcRecords::Parser::BuildConflict ||
(*D).Type == pkgSrcRecords::Parser::BuildConflictIndep)
{
- pkgCache::PkgIterator Pkg = Cache->FindPkg((*D).Package);
+ pkgCache::GrpIterator Grp = Cache->FindGrp((*D).Package);
// Build-conflicts on unknown packages are silently ignored
- if (Pkg.end() == true)
+ if (Grp.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)
- TryToInstallBuildDep(Pkg,Cache,Fix,true,false);
+ for (pkgCache::PkgIterator Pkg = Grp.PackageList(); Pkg.end() == false; Pkg = Grp.NextPkg(Pkg))
+ {
+ 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)
+ TryToInstallBuildDep(Pkg,Cache,Fix,true,false);
+ }
}
else // BuildDep || BuildDepIndep
{
- pkgCache::PkgIterator Pkg = Cache->FindPkg((*D).Package);
if (_config->FindB("Debug::BuildDeps",false) == true)
cout << "Looking for " << (*D).Package << "...\n";
+ pkgCache::PkgIterator Pkg;
+
+ // Cross-Building?
+ if (StripMultiArch == false)
+ {
+ size_t const colon = D->Package.find(":");
+ if (colon != string::npos &&
+ (strcmp(D->Package.c_str() + colon, ":any") == 0 || strcmp(D->Package.c_str() + colon, ":native") == 0))
+ Pkg = Cache->FindPkg(D->Package.substr(0,colon));
+ else
+ Pkg = Cache->FindPkg(D->Package);
+
+ // We need to decide if host or build arch, so find a version we can look at
+ pkgCache::VerIterator Ver;
+
+ // a bad version either is invalid or doesn't satify dependency
+ #define BADVER(Ver) Ver.end() == true || \
+ (Ver.end() == false && D->Version.empty() == false && \
+ Cache->VS().CheckDep(Ver.VerStr(),D->Op,D->Version.c_str()) == false)
+
+ if (Pkg.end() == false)
+ {
+ Ver = (*Cache)[Pkg].InstVerIter(*Cache);
+ if (BADVER(Ver))
+ Ver = (*Cache)[Pkg].CandidateVerIter(*Cache);
+ }
+ if (BADVER(Ver))
+ {
+ pkgCache::PkgIterator HostPkg = Cache->FindPkg(D->Package, hostArch);
+ if (HostPkg.end() == false)
+ {
+ Ver = (*Cache)[HostPkg].InstVerIter(*Cache);
+ if (BADVER(Ver))
+ Ver = (*Cache)[HostPkg].CandidateVerIter(*Cache);
+ }
+ }
+ if ((BADVER(Ver)) == false)
+ {
+ string forbidden;
+ if (Ver->MultiArch == pkgCache::Version::None || Ver->MultiArch == pkgCache::Version::All);
+ else if (Ver->MultiArch == pkgCache::Version::Same)
+ {
+ if (colon != string::npos)
+ Pkg = Ver.ParentPkg().Group().FindPkg(hostArch);
+ else if (strcmp(D->Package.c_str() + colon, ":any") == 0)
+ forbidden = "Multi-Arch: same";
+ // :native gets the buildArch
+ }
+ else if (Ver->MultiArch == pkgCache::Version::Foreign || Ver->MultiArch == pkgCache::Version::AllForeign)
+ {
+ if (colon != string::npos)
+ forbidden = "Multi-Arch: foreign";
+ }
+ else if (Ver->MultiArch == pkgCache::Version::Allowed || Ver->MultiArch == pkgCache::Version::AllAllowed)
+ {
+ if (colon == string::npos)
+ Pkg = Ver.ParentPkg().Group().FindPkg(hostArch);
+ else if (strcmp(D->Package.c_str() + colon, ":any") == 0)
+ {
+ // prefer any installed over preferred non-installed architectures
+ pkgCache::GrpIterator Grp = Ver.ParentPkg().Group();
+ // we don't check for version here as we are better of with upgrading than remove and install
+ for (Pkg = Grp.PackageList(); Pkg.end() == false; Pkg = Grp.NextPkg(Pkg))
+ if (Pkg.CurrentVer().end() == false)
+ break;
+ if (Pkg.end() == true)
+ Pkg = Grp.FindPreferredPkg(true);
+ }
+ // native gets buildArch
+ }
+ if (forbidden.empty() == false)
+ {
+ if (_config->FindB("Debug::BuildDeps",false) == true)
+ cout << " :any is not allowed from M-A: same package " << (*D).Package << endl;
+ if (hasAlternatives)
+ continue;
+ return _error->Error(_("%s dependency for %s can't be satisfied "
+ "because %s is not allowed on '%s' packages"),
+ Last->BuildDepType(D->Type), Src.c_str(),
+ D->Package.c_str(), "Multi-Arch: same");
+ }
+ }
+ else if (_config->FindB("Debug::BuildDeps",false) == true)
+ cout << " No multiarch info as we have no satisfying installed nor candidate for " << D->Package << " on build or host arch" << endl;
+ #undef BADVER
+ }
+ else
+ Pkg = Cache->FindPkg(D->Package);
+
if (Pkg.end() == true)
{
if (_config->FindB("Debug::BuildDeps",false) == true)
(*D).Package.c_str());
}
- /*
- * 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
- */
-
- /*
- * If this is a virtual package, we need to check the list of
- * packages that provide it and see if any of those are
- * installed
- */
- pkgCache::PrvIterator Prv = Pkg.ProvidesList();
- for (; Prv.end() != true; Prv++)
- {
- if (_config->FindB("Debug::BuildDeps",false) == true)
- cout << " Checking provider " << Prv.OwnerPkg().FullName() << endl;
-
- if ((*Cache)[Prv.OwnerPkg()].InstVerIter(*Cache).end() == false)
- break;
- }
-
- // Get installed version and version we are going to install
pkgCache::VerIterator IV = (*Cache)[Pkg].InstVerIter(*Cache);
+ if (IV.end() == false)
+ {
+ if (_config->FindB("Debug::BuildDeps",false) == true)
+ cout << " Is installed\n";
- if ((*D).Version[0] != '\0') {
- // Versioned dependency
-
- 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)
- {
- if (hasAlternatives)
- {
- continue;
- }
- else
- {
- 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());
- }
- }
- }
- else
- {
- // Only consider virtual packages if there is no versioned dependency
- if (Prv.end() == false)
- {
- if (_config->FindB("Debug::BuildDeps",false) == true)
- cout << " Is provided by installed package " << Prv.OwnerPkg().FullName() << endl;
- skipAlternatives = hasAlternatives;
- continue;
- }
- }
+ if (D->Version.empty() == true ||
+ Cache->VS().CheckDep(IV.VerStr(),(*D).Op,(*D).Version.c_str()) == true)
+ {
+ skipAlternatives = hasAlternatives;
+ continue;
+ }
- if (IV.end() == false)
- {
- if (_config->FindB("Debug::BuildDeps",false) == true)
- cout << " Is installed\n";
+ if (_config->FindB("Debug::BuildDeps",false) == true)
+ cout << " ...but the installed version doesn't meet the version requirement\n";
- if (Cache->VS().CheckDep(IV.VerStr(),(*D).Op,(*D).Version.c_str()) == true)
- {
- skipAlternatives = hasAlternatives;
- continue;
- }
+ if (((*D).Op & pkgCache::Dep::LessEq) == pkgCache::Dep::LessEq)
+ return _error->Error(_("Failed to satisfy %s dependency for %s: Installed package %s is too new"),
+ Last->BuildDepType((*D).Type), Src.c_str(), Pkg.FullName(true).c_str());
+ }
- if (_config->FindB("Debug::BuildDeps",false) == true)
- cout << " ...but the installed version doesn't meet the version requirement\n";
-
- if (((*D).Op & pkgCache::Dep::LessEq) == pkgCache::Dep::LessEq)
- {
- return _error->Error(_("Failed to satisfy %s dependency for %s: Installed package %s is too new"),
- Last->BuildDepType((*D).Type),
- Src.c_str(),
- Pkg.FullName(true).c_str());
- }
- }
+ // Only consider virtual packages if there is no versioned dependency
+ if ((*D).Version.empty() == true)
+ {
+ /*
+ * If this is a virtual package, we need to check the list of
+ * packages that provide it and see if any of those are
+ * installed
+ */
+ pkgCache::PrvIterator Prv = Pkg.ProvidesList();
+ for (; Prv.end() != true; Prv++)
+ {
+ if (_config->FindB("Debug::BuildDeps",false) == true)
+ cout << " Checking provider " << Prv.OwnerPkg().FullName() << endl;
+ if ((*Cache)[Prv.OwnerPkg()].InstVerIter(*Cache).end() == false)
+ break;
+ }
- if (_config->FindB("Debug::BuildDeps",false) == true)
- cout << " Trying to install " << (*D).Package << endl;
+ if (Prv.end() == false)
+ {
+ if (_config->FindB("Debug::BuildDeps",false) == true)
+ cout << " Is provided by installed package " << Prv.OwnerPkg().FullName() << endl;
+ skipAlternatives = hasAlternatives;
+ continue;
+ }
+ }
+ else // versioned dependency
+ {
+ pkgCache::VerIterator CV = (*Cache)[Pkg].CandidateVerIter(*Cache);
+ if (CV.end() == true ||
+ Cache->VS().CheckDep(CV.VerStr(),(*D).Op,(*D).Version.c_str()) == false)
+ {
+ if (hasAlternatives)
+ continue;
+ else if (CV.end() == false)
+ return _error->Error(_("%s dependency for %s cannot be satisfied "
+ "because candidate version of package %s "
+ "can't satisfy version requirements"),
+ Last->BuildDepType(D->Type), Src.c_str(),
+ D->Package.c_str());
+ else
+ return _error->Error(_("%s dependency for %s cannot be satisfied "
+ "because package %s has no candidate version"),
+ Last->BuildDepType(D->Type), Src.c_str(),
+ D->Package.c_str());
+ }
+ }
if (TryToInstallBuildDep(Pkg,Cache,Fix,false,false) == true)
{
return true;
}
/*}}}*/
+// GetChangelogPath - return a path pointing to a changelog file or dir /*{{{*/
+// ---------------------------------------------------------------------
+/* This returns a "path" string for the changelog url construction.
+ * Please note that its not complete, it either needs a "/changelog"
+ * appended (for the packages.debian.org/changelogs site) or a
+ * ".changelog" (for third party sites that store the changelog in the
+ * pool/ next to the deb itself)
+ * Example return: "pool/main/a/apt/apt_0.8.8ubuntu3"
+ */
+string GetChangelogPath(CacheFile &Cache,
+ pkgCache::PkgIterator Pkg,
+ pkgCache::VerIterator Ver)
+{
+ string path;
+
+ pkgRecords Recs(Cache);
+ pkgRecords::Parser &rec=Recs.Lookup(Ver.FileList());
+ string srcpkg = rec.SourcePkg().empty() ? Pkg.Name() : rec.SourcePkg();
+ string ver = Ver.VerStr();
+ // if there is a source version it always wins
+ if (rec.SourceVer() != "")
+ ver = rec.SourceVer();
+ path = flNotFile(rec.FileName());
+ path += srcpkg + "_" + StripEpoch(ver);
+ return path;
+}
+ /*}}}*/
+// GuessThirdPartyChangelogUri - return url /*{{{*/
+// ---------------------------------------------------------------------
+/* Contruct a changelog file path for third party sites that do not use
+ * packages.debian.org/changelogs
+ * This simply uses the ArchiveURI() of the source pkg and looks for
+ * a .changelog file there, Example for "mediabuntu":
+ * apt-get changelog mplayer-doc:
+ * http://packages.medibuntu.org/pool/non-free/m/mplayer/mplayer_1.0~rc4~try1.dsfg1-1ubuntu1+medibuntu1.changelog
+ */
+bool GuessThirdPartyChangelogUri(CacheFile &Cache,
+ pkgCache::PkgIterator Pkg,
+ pkgCache::VerIterator Ver,
+ string &out_uri)
+{
+ // get the binary deb server path
+ pkgCache::VerFileIterator Vf = Ver.FileList();
+ if (Vf.end() == true)
+ return false;
+ pkgCache::PkgFileIterator F = Vf.File();
+ pkgIndexFile *index;
+ pkgSourceList *SrcList = Cache.GetSourceList();
+ if(SrcList->FindIndex(F, index) == false)
+ return false;
+
+ // get archive uri for the binary deb
+ string path_without_dot_changelog = GetChangelogPath(Cache, Pkg, Ver);
+ out_uri = index->ArchiveURI(path_without_dot_changelog + ".changelog");
+
+ // now strip away the filename and add srcpkg_srcver.changelog
+ return true;
+}
+ /*}}}*/
+// DownloadChangelog - Download the changelog /*{{{*/
+// ---------------------------------------------------------------------
+bool DownloadChangelog(CacheFile &CacheFile, pkgAcquire &Fetcher,
+ pkgCache::VerIterator Ver, string targetfile)
+/* Download a changelog file for the given package version to
+ * targetfile. This will first try the server from Apt::Changelogs::Server
+ * (http://packages.debian.org/changelogs by default) and if that gives
+ * a 404 tries to get it from the archive directly (see
+ * GuessThirdPartyChangelogUri for details how)
+ */
+{
+ string path;
+ string descr;
+ string server;
+ string changelog_uri;
+
+ // data structures we need
+ pkgCache::PkgIterator Pkg = Ver.ParentPkg();
+
+ // make the server root configurable
+ server = _config->Find("Apt::Changelogs::Server",
+ "http://packages.debian.org/changelogs");
+ path = GetChangelogPath(CacheFile, Pkg, Ver);
+ strprintf(changelog_uri, "%s/%s/changelog", server.c_str(), path.c_str());
+ if (_config->FindB("APT::Get::Print-URIs", false) == true)
+ {
+ std::cout << '\'' << changelog_uri << '\'' << std::endl;
+ return true;
+ }
+
+ strprintf(descr, _("Changelog for %s (%s)"), Pkg.Name(), changelog_uri.c_str());
+ // queue it
+ new pkgAcqFile(&Fetcher, changelog_uri, "", 0, descr, Pkg.Name(), "ignored", targetfile);
+
+ // try downloading it, if that fails, try third-party-changelogs location
+ // FIXME: Fetcher.Run() is "Continue" even if I get a 404?!?
+ Fetcher.Run();
+ if (!FileExists(targetfile))
+ {
+ string third_party_uri;
+ if (GuessThirdPartyChangelogUri(CacheFile, Pkg, Ver, third_party_uri))
+ {
+ strprintf(descr, _("Changelog for %s (%s)"), Pkg.Name(), third_party_uri.c_str());
+ new pkgAcqFile(&Fetcher, third_party_uri, "", 0, descr, Pkg.Name(), "ignored", targetfile);
+ Fetcher.Run();
+ }
+ }
+
+ if (FileExists(targetfile))
+ return true;
+
+ // error
+ return _error->Error("changelog download failed");
+}
+ /*}}}*/
+// DisplayFileInPager - Display File with pager /*{{{*/
+void DisplayFileInPager(string filename)
+{
+ pid_t Process = ExecFork();
+ if (Process == 0)
+ {
+ const char *Args[3];
+ Args[0] = "/usr/bin/sensible-pager";
+ Args[1] = filename.c_str();
+ Args[2] = 0;
+ execvp(Args[0],(char **)Args);
+ exit(100);
+ }
+
+ // Wait for the subprocess
+ ExecWait(Process, "sensible-pager", false);
+}
+ /*}}}*/
+// DoChangelog - Get changelog from the command line /*{{{*/
+// ---------------------------------------------------------------------
+bool DoChangelog(CommandLine &CmdL)
+{
+ CacheFile Cache;
+ if (Cache.ReadOnlyOpen() == false)
+ return false;
+
+ APT::CacheSetHelper helper(c0out);
+ APT::VersionSet verset = APT::VersionSet::FromCommandLine(Cache,
+ CmdL.FileList + 1, APT::VersionSet::CANDIDATE, helper);
+ if (verset.empty() == true)
+ return false;
+ pkgAcquire Fetcher;
+
+ if (_config->FindB("APT::Get::Print-URIs", false) == true)
+ for (APT::VersionSet::const_iterator Ver = verset.begin();
+ Ver != verset.end(); ++Ver)
+ return DownloadChangelog(Cache, Fetcher, Ver, "");
+
+ AcqTextStatus Stat(ScreenWidth, _config->FindI("quiet",0));
+ Fetcher.Setup(&Stat);
+
+ bool const downOnly = _config->FindB("APT::Get::Download-Only", false);
+
+ char tmpname[100];
+ char* tmpdir = NULL;
+ if (downOnly == false)
+ {
+ const char* const tmpDir = getenv("TMPDIR");
+ if (tmpDir != NULL && *tmpDir != '\0')
+ snprintf(tmpname, sizeof(tmpname), "%s/apt-changelog-XXXXXX", tmpDir);
+ else
+ strncpy(tmpname, "/tmp/apt-changelog-XXXXXX", sizeof(tmpname));
+ tmpdir = mkdtemp(tmpname);
+ if (tmpdir == NULL)
+ return _error->Errno("mkdtemp", "mkdtemp failed");
+ }
+
+ for (APT::VersionSet::const_iterator Ver = verset.begin();
+ Ver != verset.end();
+ ++Ver)
+ {
+ string changelogfile;
+ if (downOnly == false)
+ changelogfile.append(tmpname).append("changelog");
+ else
+ changelogfile.append(Ver.ParentPkg().Name()).append(".changelog");
+ if (DownloadChangelog(Cache, Fetcher, Ver, changelogfile) && downOnly == false)
+ {
+ DisplayFileInPager(changelogfile);
+ // cleanup temp file
+ unlink(changelogfile.c_str());
+ }
+ }
+ // clenaup tmp dir
+ if (tmpdir != NULL)
+ rmdir(tmpdir);
+ return true;
+}
+ /*}}}*/
// DoMoo - Never Ask, Never Tell /*{{{*/
// ---------------------------------------------------------------------
/* */
" clean - Erase downloaded archive files\n"
" autoclean - Erase old downloaded archive files\n"
" check - Verify that there are no broken dependencies\n"
- " markauto - Mark the given packages as automatically installed\n"
- " unmarkauto - Mark the given packages as manually installed\n"
+ " changelog - Download and display the changelog for the given package\n"
+ " download - Download the binary package into the current directory\n"
"\n"
"Options:\n"
" -h This help text.\n"
{'s',"dry-run","APT::Get::Simulate",0},
{'s',"no-act","APT::Get::Simulate",0},
{'y',"yes","APT::Get::Assume-Yes",0},
- {'y',"assume-yes","APT::Get::Assume-Yes",0},
+ {'y',"assume-yes","APT::Get::Assume-Yes",0},
+ {0,"assume-no","APT::Get::Assume-No",0},
{'f',"fix-broken","APT::Get::Fix-Broken",0},
{'u',"show-upgraded","APT::Get::Show-Upgraded",0},
{'m',"ignore-missing","APT::Get::Fix-Missing",0},
{'t',"target-release","APT::Default-Release",CommandLine::HasArg},
{'t',"default-release","APT::Default-Release",CommandLine::HasArg},
+ {'a',"host-architecture","APT::Get::Host-Architecture",CommandLine::HasArg},
{0,"download","APT::Get::Download",0},
{0,"fix-missing","APT::Get::Fix-Missing",0},
{0,"ignore-hold","APT::Ignore-Hold",0},
{0,"auto-remove","APT::Get::AutomaticRemove",0},
{0,"allow-unauthenticated","APT::Get::AllowUnauthenticated",0},
{0,"install-recommends","APT::Install-Recommends",CommandLine::Boolean},
+ {0,"install-suggests","APT::Install-Suggests",CommandLine::Boolean},
{0,"fix-policy","APT::Get::Fix-Policy-Broken",0},
+ {0,"solver","APT::Solver",CommandLine::HasArg},
{'c',"config-file",0,CommandLine::ConfigFile},
{'o',"option",0,CommandLine::ArbItem},
{0,0,0,0}};
{"autoclean",&DoAutoClean},
{"check",&DoCheck},
{"source",&DoSource},
+ {"download",&DoDownload},
+ {"changelog",&DoChangelog},
{"moo",&DoMoo},
{"help",&ShowHelp},
{0,0}};
}
// simulate user-friendly if apt-get has no root privileges
- if (getuid() != 0 && _config->FindB("APT::Get::Simulate") == true)
+ 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)
cout << _("NOTE: This is only a simulation!\n"