summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Vogt <michael.vogt@ubuntu.com>2010-11-18 10:32:41 +0100
committerMichael Vogt <michael.vogt@ubuntu.com>2010-11-18 10:32:41 +0100
commit2d555a8205eccc4cb17b93f7c92b71a854e8f82e (patch)
tree560bb435bfb46f73abe61174edfffbfce1b2de85
parent0e3e112e3d60647e335aee7e6ce308b29fd11988 (diff)
parentd786352da27c6f05bc372a061f3a78237b69e6f4 (diff)
merged lp:~mvo/apt/apt-get-changelog
-rw-r--r--apt-pkg/contrib/strutl.cc9
-rw-r--r--apt-pkg/contrib/strutl.h1
-rw-r--r--cmdline/apt-get.cc153
-rw-r--r--doc/examples/configure-index97
-rw-r--r--test/integration/framework1
-rwxr-xr-xtest/integration/test-changelog34
6 files changed, 250 insertions, 45 deletions
diff --git a/apt-pkg/contrib/strutl.cc b/apt-pkg/contrib/strutl.cc
index 987f4c3a4..c2b335ed7 100644
--- a/apt-pkg/contrib/strutl.cc
+++ b/apt-pkg/contrib/strutl.cc
@@ -1174,6 +1174,15 @@ char *safe_snprintf(char *Buffer,char *End,const char *Format,...)
return Buffer + Did;
}
/*}}}*/
+// StripEpoch - Remove the version "epoch" from a version string /*{{{*/
+// ---------------------------------------------------------------------
+string StripEpoch(const string &VerStr)
+{
+ size_t i = VerStr.find(":");
+ if (i == string::npos)
+ return VerStr;
+ return VerStr.substr(i+1);
+}
// tolower_ascii - tolower() function that ignores the locale /*{{{*/
// ---------------------------------------------------------------------
diff --git a/apt-pkg/contrib/strutl.h b/apt-pkg/contrib/strutl.h
index a457ff047..14cf5c943 100644
--- a/apt-pkg/contrib/strutl.h
+++ b/apt-pkg/contrib/strutl.h
@@ -61,6 +61,7 @@ void strprintf(string &out,const char *format,...) __like_printf(2);
char *safe_snprintf(char *Buffer,char *End,const char *Format,...) __like_printf(3);
bool CheckDomainList(const string &Host, const string &List);
int tolower_ascii(int const c) __attrib_const __hot;
+string StripEpoch(const string &VerStr);
#define APT_MKSTRCMP(name,func) \
inline int name(const char *A,const char *B) {return func(A,A+strlen(A),B,B+strlen(B));}; \
diff --git a/cmdline/apt-get.cc b/cmdline/apt-get.cc
index 116f4a07e..b645da878 100644
--- a/cmdline/apt-get.cc
+++ b/cmdline/apt-get.cc
@@ -2787,6 +2787,158 @@ bool DoBuildDep(CommandLine &CmdL)
return true;
}
/*}}}*/
+// GuessThirdPartyChangelogUri - return url /*{{{*/
+// ---------------------------------------------------------------------
+bool GuessThirdPartyChangelogUri(CacheFile &Cache,
+ pkgCache::PkgIterator Pkg,
+ pkgCache::VerIterator Ver,
+ string &out_uri)
+{
+ pkgRecords Recs(Cache);
+ pkgSourceList *SrcList = Cache.GetSourceList();
+
+ // get the binary deb server path
+ 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());
+
+ pkgCache::VerFileIterator Vf = Ver.FileList();
+ if (Vf.end() == true)
+ return false;
+ pkgCache::PkgFileIterator F = Vf.File();
+ pkgIndexFile *index;
+ if(SrcList->FindIndex(F, index) == false)
+ return false;
+ // get archive uri for the binary deb
+ string deb_uri = index->ArchiveURI(rec.FileName());
+
+ // now strip away the filename and add srcpkg_srcver.changelog
+ out_uri = flNotFile(deb_uri);
+ out_uri += srcpkg + "_" + srcver + ".changelog";
+ return true;
+}
+// DownloadChangelog - Download the changelog /*{{{*/
+// ---------------------------------------------------------------------
+bool DownloadChangelog(CacheFile &CacheFile, pkgAcquire &Fetcher, pkgCache::VerIterator V, string targetfile)
+{
+ string srcpkg;
+ string prefix;
+ string descr;
+ string src_section;
+ string verstr;
+ string server;
+ string path;
+
+ // 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();
+ // 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";
+
+ 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
+ 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());
+ // queue it
+ string changelog_uri = server+path;
+ strprintf(descr, _("Changelog for %s (%s)"), srcpkg.c_str(), changelog_uri.c_str());
+ new pkgAcqFile(&Fetcher, 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, V, 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 /*{{{*/
// ---------------------------------------------------------------------
/* */
@@ -2978,6 +3130,7 @@ int main(int argc,const char *argv[]) /*{{{*/
{"check",&DoCheck},
{"source",&DoSource},
{"download",&DoDownload},
+ {"changelog",&DoChangelog},
{"moo",&DoMoo},
{"help",&ShowHelp},
{0,0}};
diff --git a/doc/examples/configure-index b/doc/examples/configure-index
index c4c2acb64..ef4cff8a1 100644
--- a/doc/examples/configure-index
+++ b/doc/examples/configure-index
@@ -114,54 +114,61 @@ APT
// does a ExecFork)
Keep-Fds {};
+ Changelogs
+ {
+ // server the provides the changelogs, the code will automatically
+ // append "/changelogs/pool/%s/%s/%s/%s_%s/changelog" to the uri
+ Server "http://packages.debian.org/";
+ }:
+
// control parameters for cron jobs by /etc/cron.daily/apt
Periodic
{
- BackupArchiveInterval "0";
- // - Backup after n-days if archive contents changed.(0=disable)
-
- BackupLevel "3";
- // - Backup level.(0=disable), 1 is invalid.
-
- // APT::Archives::MaxAge "0"; (old, deprecated)
- MaxAge "0"; // (new)
- // - Set maximum allowed age of a cache package file. If a cache
- // package file is older it is deleted (0=disable)
-
- // APT::Archives::MinAge "2"; (old, deprecated)
- MinAge "2"; // (new)
- // - Set minimum age of a package file. If a file is younger it
- // will not be deleted (0=disable). Usefull to prevent races
- // and to keep backups of the packages for emergency.
-
- // APT::Archives::MaxSize "0"; (old, deprecated)
- MaxSize "0"; // (new)
- // - Set maximum size of the cache in MB (0=disable). If the cache
- // is bigger, cached package files are deleted until the size
- // requirement is met (the biggest packages will be deleted
- // first).
-
- Update-Package-Lists "0";
- // - Do "apt-get update" automatically every n-days (0=disable)
- //
- Download-Upgradeable-Packages "0";
- // - Do "apt-get upgrade --download-only" every n-days (0=disable)
- //
- Unattended-Upgrade "0";
- // - Run the "unattended-upgrade" security upgrade script
- // every n-days (0=disabled)
- // Requires the package "unattended-upgrades" and will write
- // a log in /var/log/unattended-upgrades
- //
- AutocleanInterval "0";
- // - Do "apt-get autoclean" every n-days (0=disable)
-
- Verbose "0";
- // - Send report mail to root
- // 0: no report (or null string)
- // 1: progress report (actually any string)
- // 2: + command outputs (remove -qq, remove 2>/dev/null, add -d)
- // 3: + trace on
+ BackupArchiveInterval "0";
+ // - Backup after n-days if archive contents changed.(0=disable)
+
+ BackupLevel "3";
+ // - Backup level.(0=disable), 1 is invalid.
+
+ // APT::Archives::MaxAge "0"; (old, deprecated)
+ MaxAge "0"; // (new)
+ // - Set maximum allowed age of a cache package file. If a cache
+ // package file is older it is deleted (0=disable)
+
+ // APT::Archives::MinAge "2"; (old, deprecated)
+ MinAge "2"; // (new)
+ // - Set minimum age of a package file. If a file is younger it
+ // will not be deleted (0=disable). Usefull to prevent races
+ // and to keep backups of the packages for emergency.
+
+ // APT::Archives::MaxSize "0"; (old, deprecated)
+ MaxSize "0"; // (new)
+ // - Set maximum size of the cache in MB (0=disable). If the cache
+ // is bigger, cached package files are deleted until the size
+ // requirement is met (the biggest packages will be deleted
+ // first).
+
+ Update-Package-Lists "0";
+ // - Do "apt-get update" automatically every n-days (0=disable)
+ //
+ Download-Upgradeable-Packages "0";
+ // - Do "apt-get upgrade --download-only" every n-days (0=disable)
+ //
+ Unattended-Upgrade "0";
+ // - Run the "unattended-upgrade" security upgrade script
+ // every n-days (0=disabled)
+ // Requires the package "unattended-upgrades" and will write
+ // a log in /var/log/unattended-upgrades
+ //
+ AutocleanInterval "0";
+ // - Do "apt-get autoclean" every n-days (0=disable)
+
+ Verbose "0";
+ // - Send report mail to root
+ // 0: no report (or null string)
+ // 1: progress report (actually any string)
+ // 2: + command outputs (remove -qq, remove 2>/dev/null, add -d)
+ // 3: + trace on
};
};
diff --git a/test/integration/framework b/test/integration/framework
index 2422f0886..f78ae2ee1 100644
--- a/test/integration/framework
+++ b/test/integration/framework
@@ -117,6 +117,7 @@ setupenvironment() {
echo "Debug::NoLocking \"true\";" >> aptconfig.conf
echo "APT::Get::Show-User-Simulation-Note \"false\";" >> aptconfig.conf
echo "Dir::Bin::dpkg \"fakeroot\";" >> aptconfig.conf
+ echo "Dir::Bin::methods \"${BUILDDIRECTORY}/methods\";" >> aptconfig.conf
echo "DPKG::options:: \"dpkg\";" >> aptconfig.conf
echo "DPKG::options:: \"--root=${TMPWORKINGDIRECTORY}/rootdir\";" >> aptconfig.conf
echo "DPKG::options:: \"--force-not-root\";" >> aptconfig.conf
diff --git a/test/integration/test-changelog b/test/integration/test-changelog
new file mode 100755
index 000000000..292df6e32
--- /dev/null
+++ b/test/integration/test-changelog
@@ -0,0 +1,34 @@
+#!/bin/sh
+set -e
+
+TESTDIR=$(readlink -f $(dirname $0))
+. $TESTDIR/framework
+
+setupenvironment
+configarchitecture "i386"
+
+# this will be valid until ubuntu lucid is EOL (04/2015)
+pkgchangelogtest="Package: apt
+Architecture: i386
+Version: 0.7.25.3ubuntu7
+Filename: pool/main/a/apt/apt_0.7.25.3ubuntu7_i386.deb
+Section: admin
+"
+cat <<-EOF >aptarchive/Packages
+$pkgchangelogtest
+EOF
+
+setupaptarchive
+
+echo "Apt::Changelogs::Server \"http://changelogs.ubuntu.com/\";" >> ./aptconfig.conf
+msgnmsg "apt-get changelog: "
+aptget changelog apt -qq > downloaded-changelog
+expected="apt (0.7.25.3ubuntu7) lucid; urgency=low"
+got="$(head -n1 downloaded-changelog)"
+if [ -s downloaded-changelog ] && [ "$got" = "$expected" ]; then
+ msgpass
+else
+ msgfail
+ msgwarn "$got != $expected"
+fi
+