diff options
author | Michael Vogt <michael.vogt@ubuntu.com> | 2010-11-18 12:02:56 +0100 |
---|---|---|
committer | Michael Vogt <michael.vogt@ubuntu.com> | 2010-11-18 12:02:56 +0100 |
commit | 62e9c098df91e031913049f2011ce9bc71961a83 (patch) | |
tree | fc09ca10765f577debc428b03f0db1789c8bae58 /cmdline | |
parent | 7919ca7bb009b81976aad47d775d7afef67c23f3 (diff) | |
parent | 6f4574e8dbbabc6b9bb67b31edc765602b63a088 (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.cc | 218 |
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}}; |