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
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 V, string targetfile)
+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 prefix;
+ string path;
string descr;
- string src_section;
- string verstr;
string server;
- string path;
+ string changelog_uri;
// 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();
- strprintf(descr, _("Changelog for %s"), srcpkg.c_str());
- // 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";
+ pkgCache::PkgIterator Pkg = Ver.ParentPkg();
- 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
+ // make the server root 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());
- // get it
- new pkgAcqFile(&Fetcher, server+path, "", 0, descr, srcpkg, "ignored", targetfile);
+ "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;
" 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"
{"autoclean",&DoAutoClean},
{"check",&DoCheck},
{"source",&DoSource},
+ {"download",&DoDownload},
{"changelog",&DoChangelog},
{"moo",&DoMoo},
{"help",&ShowHelp},