summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJulian Andres Klode <jak@debian.org>2023-03-03 18:06:47 +0000
committerJulian Andres Klode <jak@debian.org>2023-03-03 18:06:47 +0000
commit6ba6b29e37a7e7b867a88f1d74e7dcfd7f83c30e (patch)
tree508ceccdaff78234a7e8c3f5be93b0f6d0494a28
parentedcdc251c527141bddb502e799d9a3911a73841b (diff)
parentacbfdf0533602a05de066aa86d1f756b5fe0f4a3 (diff)
Merge branch 'bookworm/aptchangelog' into 'main'
Detect trimmed changelogs and pick online instead See merge request apt-team/apt!288
-rw-r--r--apt-pkg/acquire-item.cc67
-rwxr-xr-xtest/integration/test-apt-get-changelog7
2 files changed, 63 insertions, 11 deletions
diff --git a/apt-pkg/acquire-item.cc b/apt-pkg/acquire-item.cc
index 384101de3..2014a50d5 100644
--- a/apt-pkg/acquire-item.cc
+++ b/apt-pkg/acquire-item.cc
@@ -3710,17 +3710,62 @@ std::string pkgAcqChangelog::URI(pkgCache::VerIterator const &Ver) /*{{{*/
pkgCache::PkgIterator const Pkg = Ver.ParentPkg();
if (Pkg->CurrentVer != 0 && Pkg.CurrentVer() == Ver)
{
- std::string const root = _config->FindDir("Dir");
- std::string const basename = root + std::string("usr/share/doc/") + Pkg.Name() + "/changelog";
- std::string const debianname = basename + ".Debian";
- if (FileExists(debianname))
- return "copy://" + debianname;
- else if (FileExists(debianname + ".gz"))
- return "store://" + debianname + ".gz";
- else if (FileExists(basename))
- return "copy://" + basename;
- else if (FileExists(basename + ".gz"))
- return "store://" + basename + ".gz";
+ auto const LocalFile = [](pkgCache::PkgIterator const &Pkg) -> std::string {
+ std::string const root = _config->FindDir("Dir");
+ std::string const basename = root + std::string("usr/share/doc/") + Pkg.Name() + "/changelog";
+ std::string const debianname = basename + ".Debian";
+ auto const exts = APT::Configuration::getCompressorExtensions(); // likely we encounter only .gz
+ for (auto file : { debianname, basename })
+ {
+ if (FileExists(file))
+ return "copy://" + file;
+ for (auto const& ext : exts)
+ {
+ auto const compressedfile = file + ext;
+ if (FileExists(compressedfile))
+ return "store://" + compressedfile;
+ }
+ }
+ return "";
+ }(Pkg);
+ if (not LocalFile.empty())
+ {
+ _error->PushToStack();
+ FileFd trimmed;
+ if (APT::String::Startswith(LocalFile, "copy://"))
+ trimmed.Open(LocalFile.substr(7), FileFd::ReadOnly, FileFd::None);
+ else
+ trimmed.Open(LocalFile.substr(8), FileFd::ReadOnly, FileFd::Extension);
+
+ bool trimmedFile = false;
+ if (trimmed.IsOpen())
+ {
+ /* We want to look at the last lineā€¦ in a (likely) compressed file,
+ which means we more or less have to uncompress the entire file.
+ So we skip ahead the filesize minus our choosen line size in
+ the hope that changelogs don't grow by being compressed to
+ avoid doing this costly dance on at least a bit of the file. */
+ char buffer[150];
+ if (auto const filesize = trimmed.FileSize(); filesize > sizeof(buffer))
+ trimmed.Skip(filesize - sizeof(buffer));
+ std::string_view giveaways[] = {
+ "# To read the complete changelog use", // Debian
+ "# For older changelog entries, run", // Ubuntu
+ };
+ while (trimmed.ReadLine(buffer, sizeof(buffer)) != nullptr)
+ {
+ std::string_view const line{buffer};
+ if (std::any_of(std::begin(giveaways), std::end(giveaways), [=](auto const gw) { return line.compare(0, gw.size(), gw) == 0; }))
+ {
+ trimmedFile = true;
+ break;
+ }
+ }
+ }
+ _error->RevertToStack();
+ if (not trimmedFile)
+ return LocalFile;
+ }
}
}
diff --git a/test/integration/test-apt-get-changelog b/test/integration/test-apt-get-changelog
index b216f6f9a..c0eecba8b 100755
--- a/test/integration/test-apt-get-changelog
+++ b/test/integration/test-apt-get-changelog
@@ -127,6 +127,13 @@ testsuccessequal "'http://localhost:${APTHTTPPORT}/pool/main/a/awesome/awesome_4
testsuccessequal "'http://localhost:${APTHTTPPORT}/pool/main/a/awesome/awesome_42/changelog' awesome.changelog" apt changelog awesome --print-uris -o Acquire::Changelogs::AlwaysOnline=false -o Acquire::Changelogs::AlwaysOnline::Origin::Ubuntu=true
testsuccessequal "'copy://${TMPWORKINGDIRECTORY}/rootdir/usr/share/doc/awesome/changelog' awesome.changelog" apt changelog awesome --print-uris -o Acquire::Changelogs::AlwaysOnline=false -o Acquire::Changelogs::AlwaysOnline::Origin::Debian=true
+printf '\n# Older entries have been removed from this changelog.' >> rootdir/usr/share/doc/awesome/changelog
+testsuccessequal "'copy://${TMPWORKINGDIRECTORY}/rootdir/usr/share/doc/awesome/changelog' awesome.changelog" apt changelog awesome --print-uris -o Acquire::Changelogs::AlwaysOnline=false
+printf '\n# To read the complete changelog use `apt changelog awesome`.' >> rootdir/usr/share/doc/awesome/changelog
+testsuccessequal "'http://localhost:${APTHTTPPORT}/pool/main/a/awesome/awesome_42/changelog' awesome.changelog" apt changelog awesome --print-uris -o Acquire::Changelogs::AlwaysOnline=false
+printf '\n# No guarantees the trigger is the last line' >> rootdir/usr/share/doc/awesome/changelog
+testsuccessequal "'http://localhost:${APTHTTPPORT}/pool/main/a/awesome/awesome_42/changelog' awesome.changelog" apt changelog awesome --print-uris -o Acquire::Changelogs::AlwaysOnline=false
+
testsuccess apt changelog awesome -d
testfilestats 'awesome.changelog' '%U:%G:%a' '=' "${TEST_DEFAULT_USER}:${TEST_DEFAULT_GROUP}:644"
head -n 3 awesome.changelog > awesome.change