X-Git-Url: https://git.saurik.com/apt.git/blobdiff_plain/21d4c9f192b5af9c8edb39356712aac853881348..f7cbd1fbc57bc13dfc2ebc246453ab0875d4151a:/cmdline/apt-get.cc diff --git a/cmdline/apt-get.cc b/cmdline/apt-get.cc index 38b93e7e5..e93d12c2b 100644 --- a/cmdline/apt-get.cc +++ b/cmdline/apt-get.cc @@ -25,6 +25,10 @@ ##################################################################### */ /*}}}*/ // Include Files /*{{{*/ +#define _LARGEFILE_SOURCE +#define _LARGEFILE64_SOURCE + +#include #include #include #include @@ -37,6 +41,7 @@ #include #include #include +#include #include #include #include @@ -45,7 +50,6 @@ #include #include "acqprogress.h" -#include "cacheset.h" #include #include @@ -63,6 +67,9 @@ #include #include #include + +#define statfs statfs64 +#define statvfs statvfs64 /*}}}*/ #define RAMFS_MAGIC 0x858458f6 @@ -531,7 +538,9 @@ bool ShowEssential(ostream &out,CacheFile &Cache) //VersionsList += string(Cache[I].CurVersion) + "\n"; ??? } } - + else + continue; + if (I->CurrentVer == 0) continue; @@ -619,6 +628,8 @@ class CacheSetHelperAPTGet : public APT::CacheSetHelper { APT::PackageSet virtualPkgs; public: + std::list > selectedByRelease; + CacheSetHelperAPTGet(std::ostream &out) : APT::CacheSetHelper(true), out(out) { explicitlyNamed = true; } @@ -637,9 +648,9 @@ public: } virtual void showSelectedVersion(pkgCache::PkgIterator const &Pkg, pkgCache::VerIterator const Ver, string const &ver, bool const &verIsRel) { - if (ver != Ver.VerStr()) - ioprintf(out, _("Selected version '%s' (%s) for '%s'\n"), - Ver.VerStr(), Ver.RelStr().c_str(), Pkg.FullName(true).c_str()); + if (ver == Ver.VerStr()) + return; + selectedByRelease.push_back(make_pair(Ver, ver)); } bool showVirtualPackageErrors(pkgCacheFile &Cache) { @@ -762,12 +773,14 @@ struct TryToInstall { 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]; @@ -798,8 +811,8 @@ struct TryToInstall { // Install it with autoinstalling enabled (if we not respect the minial // required deps or the policy) - if ((State.InstBroken() == true || State.InstPolicyBroken() == true) && FixBroken == false) - Cache->GetDepCache()->MarkInstall(Pkg,true); + if (FixBroken == false) + doAutoInstallLater.insert(Pkg); } // see if we need to fix the auto-mark flag @@ -817,6 +830,48 @@ struct TryToInstall { AutoMarkChanged++; } } + + bool propergateReleaseCandiateSwitching(std::list > start, std::ostream &out) + { + for (std::list >::const_iterator s = start.begin(); + s != start.end(); ++s) + Cache->GetDepCache()->SetCandidateVersion(s->first); + + bool Success = true; + std::list > Changed; + for (std::list >::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 >::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 /*{{{*/ @@ -824,9 +879,11 @@ struct TryToRemove { pkgCacheFile* Cache; pkgProblemResolver* Fix; bool FixBroken; + 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) { @@ -836,10 +893,11 @@ struct TryToRemove { Fix->Protect(Pkg); Fix->Remove(Pkg); - if (Pkg->CurrentVer == 0) + 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()); else - Cache->GetDepCache()->MarkDelete(Pkg,_config->FindB("APT::Get::Purge",false)); + Cache->GetDepCache()->MarkDelete(Pkg, PurgePkgs); } }; /*}}}*/ @@ -1054,20 +1112,18 @@ bool InstallPackages(CacheFile &Cache,bool ShwKept,bool Ask = true, { // force a hashsum for compatibility reasons _config->CndSet("Acquire::ForceHash", "md5sum"); - if (Fetcher.Setup(&Stat, "") == false) - return false; } else if (Fetcher.Setup(&Stat, _config->FindDir("Dir::Cache::Archives")) == false) return false; // Read the source list - pkgSourceList List; - if (List.ReadMainList() == false) - return _error->Error(_("The list of sources could not be read.")); + if (Cache.BuildSourceList() == false) + return false; + pkgSourceList *List = Cache.GetSourceList(); // Create the package manager and prepare to download SPtr PM= _system->CreatePM(Cache); - if (PM->GetArchives(&Fetcher,&List,&Recs) == false || + if (PM->GetArchives(&Fetcher,List,&Recs) == false || _error->PendingError() == true) return false; @@ -1083,17 +1139,25 @@ bool InstallPackages(CacheFile &Cache,bool ShwKept,bool Ask = true, // 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()); @@ -1283,7 +1347,7 @@ bool InstallPackages(CacheFile &Cache,bool ShwKept,bool Ask = true, // Reload the fetcher object and loop again for media swapping Fetcher.Shutdown(); - if (PM->GetArchives(&Fetcher,&List,&Recs) == false) + if (PM->GetArchives(&Fetcher,List,&Recs) == false) return false; _system->Lock(); @@ -1333,6 +1397,7 @@ bool TryToInstallBuildDep(pkgCache::PkgIterator Pkg,pkgCacheFile &Cache, } else if (Cache[Pkg].CandidateVer != 0) { TryToInstall InstallAction(Cache, Fix, BrokenFix); InstallAction(Cache[Pkg].CandidateVerIter(Cache)); + InstallAction.doAutoInstall(); } else return AllowFail; @@ -1518,11 +1583,13 @@ bool DoUpdate(CommandLine &CmdL) { if (CmdL.FileSize() != 1) return _error->Error(_("The update command takes no arguments")); - + + CacheFile Cache; + // Get the source list - pkgSourceList List; - if (List.ReadMainList() == false) + if (Cache.BuildSourceList() == false) return false; + pkgSourceList *List = Cache.GetSourceList(); // Create the progress AcqTextStatus Stat(ScreenWidth,_config->FindI("quiet",0)); @@ -1540,7 +1607,7 @@ bool DoUpdate(CommandLine &CmdL) // Populate it with the source selection and get all Indexes // (GetAll=true) - if (List.GetIndexes(&Fetcher,true) == false) + if (List->GetIndexes(&Fetcher,true) == false) return false; pkgAcquire::UriIterator I = Fetcher.UriBegin(); @@ -1551,9 +1618,8 @@ bool DoUpdate(CommandLine &CmdL) } // do the work - CacheFile Cache; if (_config->FindB("APT::Get::Download",true) == true) - ListUpdate(Stat, List); + ListUpdate(Stat, *List); // Rebuild the cache. if (Cache.BuildCaches() == false) @@ -1575,10 +1641,6 @@ bool DoAutomaticRemove(CacheFile &Cache) if(Debug) std::cout << "DoAutomaticRemove()" << std::endl; - // we don't want to autoremove and we don't want to see it, so why calculating? - if (doAutoRemove == false && hideAutoRemove == true) - return true; - if (doAutoRemove == true && _config->FindB("APT::Get::Remove",true) == false) { @@ -1589,7 +1651,7 @@ bool DoAutomaticRemove(CacheFile &Cache) bool purgePkgs = _config->FindB("APT::Get::Purge", false); bool smallList = (hideAutoRemove == false && - strcasecmp(_config->Find("APT::Get::HideAutoRemove","").c_str(),"small") == 0); + strcasecmp(_config->Find("APT::Get::HideAutoRemove","").c_str(),"small") == 0); string autoremovelist, autoremoveversions; unsigned long autoRemoveCount = 0; @@ -1612,8 +1674,12 @@ bool DoAutomaticRemove(CacheFile &Cache) } else { + // 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); // only show stuff in the list that is not yet marked for removal - 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 @@ -1626,20 +1692,9 @@ bool DoAutomaticRemove(CacheFile &Cache) } } } - // 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 is 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 << _("Use 'apt-get autoremove' to remove them.") << std::endl; - } + // Now see if we had destroyed anything (if we had done anything) - else if (Cache->BrokenCount() != 0) + 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.") << endl; @@ -1650,6 +1705,19 @@ bool DoAutomaticRemove(CacheFile &Cache) 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 << _("Use 'apt-get autoremove' to remove them.") << std::endl; + } return true; } /*}}}*/ @@ -1740,8 +1808,11 @@ bool DoInstall(CommandLine &CmdL) 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); + 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); } @@ -1804,16 +1875,15 @@ bool DoInstall(CommandLine &CmdL) pkgCache::PkgIterator I(Cache,Cache.List[J]); if ((*Cache)[I].Install() == false) continue; + pkgCache::VerIterator Cand = Cache[I].CandidateVerIter(Cache); + if (Cand.Pseudo() == true) + continue; - 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); @@ -2130,6 +2200,59 @@ bool DoAutoClean(CommandLine &CmdL) 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); + pkgAcquire Fetcher; + AcqTextStatus Stat(ScreenWidth, _config->FindI("quiet",0)); + Fetcher.Setup(&Stat); + + if (verset.empty() == true) + return false; + + 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.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(), "."); + } + bool result = (Fetcher.Run() == pkgAcquire::Continue); + + return result; +} + /*}}}*/ // DoCheck - Perform the check operation /*{{{*/ // --------------------------------------------------------------------- /* Opening automatically checks the system, this command is mostly used @@ -2163,13 +2286,13 @@ bool DoSource(CommandLine &CmdL) return _error->Error(_("Must specify at least one package to fetch source for")); // Read the source list - pkgSourceList List; - if (List.ReadMainList() == false) - return _error->Error(_("The list of sources could not be read.")); + if (Cache.BuildSourceList() == false) + return false; + pkgSourceList *List = Cache.GetSourceList(); // Create the text record parsers pkgRecords Recs(Cache); - pkgSrcRecords SrcRecs(List); + pkgSrcRecords SrcRecs(*List); if (_error->PendingError() == true) return false; @@ -2313,9 +2436,13 @@ bool DoSource(CommandLine &CmdL) // 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 source archives.\n"), SizeToStr(FetchBytes).c_str(),SizeToStr(DebBytes).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,_("Need to get %sB of source archives.\n"), SizeToStr(DebBytes).c_str()); @@ -2454,13 +2581,13 @@ bool DoBuildDep(CommandLine &CmdL) return _error->Error(_("Must specify at least one package to check builddeps for")); // Read the source list - pkgSourceList List; - if (List.ReadMainList() == false) - return _error->Error(_("The list of sources could not be read.")); + if (Cache.BuildSourceList() == false) + return false; + pkgSourceList *List = Cache.GetSourceList(); // Create the text record parsers pkgRecords Recs(Cache); - pkgSrcRecords SrcRecs(List); + pkgSrcRecords SrcRecs(*List); if (_error->PendingError() == true) return false; @@ -2471,6 +2598,7 @@ bool DoBuildDep(CommandLine &CmdL) return false; unsigned J = 0; + bool const StripMultiArch = APT::Configuration::getArchitectures().size() <= 1; for (const char **I = CmdL.FileList + 1; *I != 0; I++, J++) { string Src; @@ -2480,7 +2608,7 @@ bool DoBuildDep(CommandLine &CmdL) // Process the build-dependencies vector BuildDeps; - if (Last->BuildDepends(BuildDeps, _config->FindB("APT::Get::Arch-Only",true)) == false) + if (Last->BuildDepends(BuildDeps, _config->FindB("APT::Get::Arch-Only", false), StripMultiArch) == false) return _error->Error(_("Unable to get build-dependency information for %s"),Src.c_str()); // Also ensure that build-essential packages are present @@ -2693,6 +2821,169 @@ bool DoBuildDep(CommandLine &CmdL) 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()); + 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, they third-party-changelogs location + // FIXME: res is "Continue" even if I get a 404?!? + int res = 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); + res = 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); + pkgAcquire Fetcher; + AcqTextStatus Stat(ScreenWidth, _config->FindI("quiet",0)); + Fetcher.Setup(&Stat); + + if (verset.empty() == true) + return false; + char *tmpdir = mkdtemp(strdup("/tmp/apt-changelog-XXXXXX")); + if (tmpdir == NULL) { + return _error->Errno("mkdtemp", "mkdtemp failed"); + } + + for (APT::VersionSet::const_iterator Ver = verset.begin(); + Ver != verset.end(); + ++Ver) + { + string changelogfile = string(tmpdir) + "changelog"; + if (DownloadChangelog(Cache, Fetcher, Ver, changelogfile)) + DisplayFileInPager(changelogfile); + // cleanup temp file + unlink(changelogfile.c_str()); + } + // clenaup tmp dir + rmdir(tmpdir); + free(tmpdir); + return true; +} + /*}}}*/ // DoMoo - Never Ask, Never Tell /*{{{*/ // --------------------------------------------------------------------- /* */ @@ -2785,6 +3076,8 @@ bool ShowHelp(CommandLine &CmdL) " 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" @@ -2806,22 +3099,6 @@ bool ShowHelp(CommandLine &CmdL) return true; } /*}}}*/ -// GetInitialize - Initialize things for apt-get /*{{{*/ -// --------------------------------------------------------------------- -/* */ -void GetInitialize() -{ - _config->Set("quiet",0); - _config->Set("help",false); - _config->Set("APT::Get::Download-Only",false); - _config->Set("APT::Get::Simulate",false); - _config->Set("APT::Get::Assume-Yes",false); - _config->Set("APT::Get::Fix-Broken",false); - _config->Set("APT::Get::Force-Yes",false); - _config->Set("APT::Get::List-Cleanup",true); - _config->Set("APT::Get::AutomaticRemove",false); -} - /*}}}*/ // SigWinch - Window size change signal handler /*{{{*/ // --------------------------------------------------------------------- /* */ @@ -2899,6 +3176,8 @@ int main(int argc,const char *argv[]) /*{{{*/ {"autoclean",&DoAutoClean}, {"check",&DoCheck}, {"source",&DoSource}, + {"download",&DoDownload}, + {"changelog",&DoChangelog}, {"moo",&DoMoo}, {"help",&ShowHelp}, {0,0}};