summaryrefslogtreecommitdiff
path: root/cmdline
diff options
context:
space:
mode:
authorMichael Vogt <michael.vogt@ubuntu.com>2010-11-18 12:02:56 +0100
committerMichael Vogt <michael.vogt@ubuntu.com>2010-11-18 12:02:56 +0100
commit62e9c098df91e031913049f2011ce9bc71961a83 (patch)
treefc09ca10765f577debc428b03f0db1789c8bae58 /cmdline
parent7919ca7bb009b81976aad47d775d7afef67c23f3 (diff)
parent6f4574e8dbbabc6b9bb67b31edc765602b63a088 (diff)
* merged lp:~mvo/apt/mvo, this brings two new commands:
- apt-get download binary-pkgname to download a deb - apt-get changelog binary-pkgname to display the changelog
Diffstat (limited to 'cmdline')
-rw-r--r--cmdline/apt-get.cc218
1 files changed, 218 insertions, 0 deletions
diff --git a/cmdline/apt-get.cc b/cmdline/apt-get.cc
index 8efcd0e2e..0c7100283 100644
--- a/cmdline/apt-get.cc
+++ b/cmdline/apt-get.cc
@@ -2165,6 +2165,60 @@ 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;
+
+ 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
@@ -2733,6 +2787,168 @@ 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();
+ // FIXME: deal with cases like gcc-defaults (srcver != binver)
+ string srcver = StripEpoch(Ver.VerStr());
+ path = flNotFile(rec.FileName());
+ path += srcpkg + "_" + srcver;
+ 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 srcpkg;
+ 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)"), srcpkg.c_str(), changelog_uri.c_str());
+ // queue it
+ new pkgAcqFile(&Fetcher, changelog_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, Ver, 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 /*{{{*/
// ---------------------------------------------------------------------
/* */
@@ -2923,6 +3139,8 @@ int main(int argc,const char *argv[]) /*{{{*/
{"autoclean",&DoAutoClean},
{"check",&DoCheck},
{"source",&DoSource},
+ {"download",&DoDownload},
+ {"changelog",&DoChangelog},
{"moo",&DoMoo},
{"help",&ShowHelp},
{0,0}};