summaryrefslogtreecommitdiff
path: root/cmdline
diff options
context:
space:
mode:
authorDavid Kalnischkies <david@kalnischkies.de>2015-06-13 11:13:45 +0200
committerDavid Kalnischkies <david@kalnischkies.de>2015-06-15 14:39:37 +0200
commitd56e2917f27a722b54685de13aeb1bb7592fc61b (patch)
tree2ab5e8f7704050189851e0ba6b9cce97a129b7ce /cmdline
parentd2cb5b153fb13d587b1ff632cab34ce0c403326e (diff)
provide a public interface for acquiring changelogs
Provided is a specialized acquire item which given a version can figure out the correct URI to try by itself and if not provides an error message alongside with static methods to get just the URI it would try to download if it should just be displayed or similar such. The URI is constructed as follows: Release files can provide an URI template in the "Changelogs" field, otherwise we lookup a configuration item based on the "Label" or "Origin" of the Release file to get a (hopefully known) default value for now. This template should contain the string CHANGEPATH which is replaced with the information about the version we want the changelog for (e.g. main/a/apt/apt_1.1). This middleway was choosen as this path part was consistent over the three known implementations (+1 defunct), while the rest of the URI varies widely between them. The benefit of this construct is that it is now easy to get changelogs for Debian packages on Ubuntu and vice versa – even at the moment where the Changelogs field is present nowhere. Strictly better than what apt-get had before as it would even fail to get changelogs from security… Now it will notice that security identifies as Origin: Debian and pick this setting (assuming again that no Changelogs field exists). If on the other hand security would ship its changelogs in a different location we could set it via the Label option overruling Origin. Closes: 687147, 739854, 784027, 787190
Diffstat (limited to 'cmdline')
-rw-r--r--cmdline/apt-get.cc204
1 files changed, 39 insertions, 165 deletions
diff --git a/cmdline/apt-get.cc b/cmdline/apt-get.cc
index a4cd3c377..184b51d23 100644
--- a/cmdline/apt-get.cc
+++ b/cmdline/apt-get.cc
@@ -1410,196 +1410,70 @@ static 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"
- */
-static string GetChangelogPath(CacheFile &Cache,
- pkgCache::VerIterator Ver)
-{
- pkgRecords Recs(Cache);
- pkgRecords::Parser &rec=Recs.Lookup(Ver.FileList());
- string path = flNotFile(rec.FileName());
-#if APT_PKG_ABI >= 413
- path.append(Ver.SourcePkgName());
- path.append("_");
- path.append(StripEpoch(Ver.SourceVerStr()));
-#else
- string srcpkg = rec.SourcePkg().empty() ? Ver.ParentPkg().Name() : rec.SourcePkg();
- string ver = Ver.VerStr();
- // if there is a source version it always wins
- if (rec.SourceVer() != "")
- ver = rec.SourceVer();
- path += srcpkg + "_" + StripEpoch(ver);
-#endif
- 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
- */
-static bool GuessThirdPartyChangelogUri(CacheFile &Cache,
- 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, 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 /*{{{*/
-// ---------------------------------------------------------------------
-static 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)
- */
-{
- // make the server root configurable
- string const server = _config->Find("Apt::Changelogs::Server",
- "http://packages.debian.org/changelogs");
- string const path = GetChangelogPath(CacheFile, Ver);
- string changelog_uri;
- if (APT::String::Endswith(server, "/") == true)
- strprintf(changelog_uri, "%s%s/changelog", server.c_str(), path.c_str());
- else
- strprintf(changelog_uri, "%s/%s/changelog", server.c_str(), path.c_str());
- if (_config->FindB("APT::Get::Print-URIs", false) == true)
- {
- std::cout << '\'' << changelog_uri << '\'' << std::endl;
- return true;
- }
- pkgCache::PkgIterator const Pkg = Ver.ParentPkg();
-
- string descr;
- strprintf(descr, _("Changelog for %s (%s)"), Pkg.Name(), changelog_uri.c_str());
- // queue it
- pkgAcquire::Item const * itm = new pkgAcqFile(&Fetcher, changelog_uri, "", 0, descr, Pkg.Name(), "ignored", targetfile);
-
- // Disable drop-privs if "_apt" can not write to the target dir
- CheckDropPrivsMustBeDisabled(Fetcher);
-
- // try downloading it, if that fails, try third-party-changelogs location
- // FIXME: Fetcher.Run() is "Continue" even if I get a 404?!?
- Fetcher.Run();
- if (itm->Status != pkgAcquire::Item::StatDone)
- {
- string third_party_uri;
- if (GuessThirdPartyChangelogUri(CacheFile, Ver, third_party_uri))
- {
- strprintf(descr, _("Changelog for %s (%s)"), Pkg.Name(), third_party_uri.c_str());
- itm = new pkgAcqFile(&Fetcher, third_party_uri, "", 0, descr, Pkg.Name(), "ignored", targetfile);
- Fetcher.Run();
- }
- }
-
- if (itm->Status == pkgAcquire::Item::StatDone)
- return true;
-
- // error
- return _error->Error("changelog download failed");
-}
- /*}}}*/
// DoChangelog - Get changelog from the command line /*{{{*/
-// ---------------------------------------------------------------------
static bool DoChangelog(CommandLine &CmdL)
{
CacheFile Cache;
if (Cache.ReadOnlyOpen() == false)
return false;
-
+
APT::CacheSetHelper helper;
APT::VersionList verset = APT::VersionList::FromCommandLine(Cache,
CmdL.FileList + 1, APT::CacheSetHelper::CANDIDATE, helper);
if (verset.empty() == true)
return false;
pkgAcquire Fetcher;
+ AcqTextStatus Stat(std::cout, ScreenWidth,_config->FindI("quiet",0));
+ Fetcher.SetLog(&Stat);
- if (_config->FindB("APT::Get::Print-URIs", false) == true)
+ bool const downOnly = _config->FindB("APT::Get::Download-Only", false);
+ bool const printOnly = _config->FindB("APT::Get::Print-URIs", false);
+
+ for (APT::VersionList::const_iterator Ver = verset.begin();
+ Ver != verset.end();
+ ++Ver)
{
- bool Success = true;
- for (APT::VersionList::const_iterator Ver = verset.begin();
- Ver != verset.end(); ++Ver)
- Success &= DownloadChangelog(Cache, Fetcher, Ver, "");
- return Success;
+ if (printOnly)
+ new pkgAcqChangelog(&Fetcher, Ver, "/dev/null");
+ else if (downOnly)
+ new pkgAcqChangelog(&Fetcher, Ver, ".");
+ else
+ new pkgAcqChangelog(&Fetcher, Ver);
}
- AcqTextStatus Stat(std::cout, ScreenWidth,_config->FindI("quiet",0));
- Fetcher.SetLog(&Stat);
+ if (printOnly == false)
+ {
+ // Disable drop-privs if "_apt" can not write to the target dir
+ CheckDropPrivsMustBeDisabled(Fetcher);
+ if (_error->PendingError() == true)
+ return false;
- bool const downOnly = _config->FindB("APT::Get::Download-Only", false);
+ bool Failed = false;
+ if (AcquireRun(Fetcher, 0, &Failed, NULL) == false || Failed == true)
+ return false;
+ }
- char tmpname[100];
- const char* tmpdir = NULL;
- if (downOnly == false)
+ if (downOnly == false || printOnly == true)
{
- std::string systemTemp = GetTempDir();
- snprintf(tmpname, sizeof(tmpname), "%s/apt-changelog-XXXXXX",
- systemTemp.c_str());
- tmpdir = mkdtemp(tmpname);
- if (tmpdir == NULL)
- return _error->Errno("mkdtemp", "mkdtemp failed");
-
- std::string const SandboxUser = _config->Find("APT::Sandbox::User");
- if (getuid() == 0 && SandboxUser.empty() == false) // if we aren't root, we can't chown, so don't try it
+ bool Failed = false;
+ for (pkgAcquire::ItemIterator I = Fetcher.ItemsBegin(); I != Fetcher.ItemsEnd(); ++I)
{
- struct passwd const * const pw = getpwnam(SandboxUser.c_str());
- struct group const * const gr = getgrnam("root");
- if (pw != NULL && gr != NULL)
+ if (printOnly)
{
- // chown the tmp dir directory we use to the sandbox user
- if(chown(tmpdir, pw->pw_uid, gr->gr_gid) != 0)
- _error->WarningE("DoChangelog", "chown to %s:%s of directory %s failed", SandboxUser.c_str(), "root", tmpdir);
+ if ((*I)->ErrorText.empty() == false)
+ {
+ Failed = true;
+ _error->Error("%s", (*I)->ErrorText.c_str());
+ }
+ else
+ cout << '\'' << (*I)->DescURI() << "' " << flNotDir((*I)->DestFile) << std::endl;
}
+ else
+ DisplayFileInPager((*I)->DestFile);
}
+ return Failed == false;
}
- for (APT::VersionList::const_iterator Ver = verset.begin();
- Ver != verset.end();
- ++Ver)
- {
- string changelogfile;
- if (downOnly == false)
- changelogfile.append(tmpname).append("/changelog");
- else
- changelogfile.append(Ver.ParentPkg().Name()).append(".changelog");
- if (DownloadChangelog(Cache, Fetcher, Ver, changelogfile) && downOnly == false)
- {
- DisplayFileInPager(changelogfile);
- // cleanup temp file
- unlink(changelogfile.c_str());
- }
- }
- // clenaup tmp dir
- if (tmpdir != NULL)
- rmdir(tmpdir);
return true;
}
/*}}}*/