|
|
@@ -2165,6 +2165,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
|
|
|
@@ -2733,6 +2786,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 /*{{{*/
|
|
|
// ---------------------------------------------------------------------
|
|
|
/* */
|
|
|
@@ -2825,6 +3041,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"
|
|
|
@@ -2923,6 +3141,8 @@ int main(int argc,const char *argv[]) /*{{{*/
|
|
|
{"autoclean",&DoAutoClean},
|
|
|
{"check",&DoCheck},
|
|
|
{"source",&DoSource},
|
|
|
+ {"download",&DoDownload},
|
|
|
+ {"changelog",&DoChangelog},
|
|
|
{"moo",&DoMoo},
|
|
|
{"help",&ShowHelp},
|
|
|
{0,0}};
|