#define _LARGEFILE_SOURCE
#define _LARGEFILE64_SOURCE
+#include <apt-pkg/aptconfiguration.h>
#include <apt-pkg/error.h>
#include <apt-pkg/cmndline.h>
#include <apt-pkg/init.h>
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)
{
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);
}
};
/*}}}*/
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<pkgPackageManager> PM= _system->CreatePM(Cache);
- if (PM->GetArchives(&Fetcher,&List,&Recs) == false ||
+ if (PM->GetArchives(&Fetcher,List,&Recs) == false ||
_error->PendingError() == true)
return false;
// 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());
// 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();
{
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));
// 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();
}
// 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)
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:",
+ 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
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;
+
+ bool result = true;
+ 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(), ".");
+ result &= (Fetcher.Run() == pkgAcquire::Continue);
+ }
+
+ return result;
+}
+ /*}}}*/
// DoCheck - Perform the check operation /*{{{*/
// ---------------------------------------------------------------------
/* Opening automatically checks the system, this command is mostly used
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;
// 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());
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;
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;
// Process the build-dependencies
vector<pkgSrcRecords::Parser::BuildDepRec> 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
return true;
}
/*}}}*/
+// GuessThirdPartyChangelogUri - return url /*{{{*/
+// ---------------------------------------------------------------------
+bool GuessThirdPartyChangelogUri(CacheFile &Cache,
+ pkgCache::PkgIterator Pkg,
+ pkgCache::VerIterator Ver,
+ string &out_uri)
+{
+ pkgRecords Recs(Cache);
+ pkgSourceList *SrcList = Cache.GetSourceList();
+
+ // get the binary deb server path
+ pkgRecords::Parser &rec=Recs.Lookup(Ver.FileList());
+ string srcpkg = rec.SourcePkg().empty() ? Pkg.Name() : rec.SourcePkg();
+ // FIXME: deal with cases like gcc-defaults (srcver != binver)
+ string srcver = StripEpoch(Ver.VerStr());
+
+ pkgCache::VerFileIterator Vf = Ver.FileList();
+ if (Vf.end() == true)
+ return false;
+ pkgCache::PkgFileIterator F = Vf.File();
+ pkgIndexFile *index;
+ if(SrcList->FindIndex(F, index) == false)
+ return false;
+ // get archive uri for the binary deb
+ string deb_uri = index->ArchiveURI(rec.FileName());
+
+ // now strip away the filename and add srcpkg_srcver.changelog
+ out_uri = flNotFile(deb_uri);
+ out_uri += srcpkg + "_" + srcver + ".changelog";
+ return true;
+}
+// DownloadChangelog - Download the changelog /*{{{*/
+// ---------------------------------------------------------------------
+bool DownloadChangelog(CacheFile &CacheFile, pkgAcquire &Fetcher, pkgCache::VerIterator V, string targetfile)
+{
+ string srcpkg;
+ string prefix;
+ string descr;
+ string src_section;
+ string verstr;
+ string server;
+ string path;
+
+ // data structures we need
+ pkgRecords Recs(CacheFile);
+ pkgCache::PkgIterator Pkg = V.ParentPkg();
+ pkgRecords::Parser &rec=Recs.Lookup(V.FileList());
+
+ // build uri
+ srcpkg = rec.SourcePkg().empty() ? Pkg.Name() : rec.SourcePkg();
+ // FIXME: we actually need the source section here
+ src_section= Pkg.Section();
+ if(src_section.find('/')!=src_section.npos)
+ src_section=string(src_section, 0, src_section.find('/'));
+ else
+ src_section="main";
+
+ prefix+=srcpkg[0];
+ if(srcpkg.size()>3 && srcpkg[0]=='l' && srcpkg[1]=='i' && srcpkg[2]=='b')
+ prefix=std::string("lib")+srcpkg[3];
+
+ verstr = V.VerStr();
+ if(verstr.find(':')!=verstr.npos)
+ verstr=string(verstr, verstr.find(':')+1);
+
+ // make the server configurable
+ server = _config->Find("Apt::Changelogs::Server",
+ "http://packages.debian.org/");
+ // ... but not the format string to avoid all possible attacks
+ strprintf(path, "/changelogs/pool/%s/%s/%s/%s_%s/changelog", src_section.c_str(), prefix.c_str(), srcpkg.c_str(), srcpkg.c_str(), verstr.c_str());
+ // queue it
+ string changelog_uri = server+path;
+ strprintf(descr, _("Changelog for %s (%s)"), srcpkg.c_str(), changelog_uri.c_str());
+ new pkgAcqFile(&Fetcher, uri, "", 0, descr, srcpkg, "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, V, third_party_uri))
+ {
+ strprintf(descr, _("Changelog for %s (%s)"), srcpkg.c_str(), third_party_uri.c_str());
+ new pkgAcqFile(&Fetcher, third_party_uri, "", 0, descr, srcpkg, "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 /*{{{*/
// ---------------------------------------------------------------------
/* */
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 /*{{{*/
// ---------------------------------------------------------------------
/* */
{"autoclean",&DoAutoClean},
{"check",&DoCheck},
{"source",&DoSource},
+ {"download",&DoDownload},
+ {"changelog",&DoChangelog},
{"moo",&DoMoo},
{"help",&ShowHelp},
{0,0}};