diff options
author | Michael Vogt <michael.vogt@ubuntu.com> | 2010-11-18 10:32:41 +0100 |
---|---|---|
committer | Michael Vogt <michael.vogt@ubuntu.com> | 2010-11-18 10:32:41 +0100 |
commit | 2d555a8205eccc4cb17b93f7c92b71a854e8f82e (patch) | |
tree | 560bb435bfb46f73abe61174edfffbfce1b2de85 | |
parent | 0e3e112e3d60647e335aee7e6ce308b29fd11988 (diff) | |
parent | d786352da27c6f05bc372a061f3a78237b69e6f4 (diff) |
merged lp:~mvo/apt/apt-get-changelog
-rw-r--r-- | apt-pkg/contrib/strutl.cc | 9 | ||||
-rw-r--r-- | apt-pkg/contrib/strutl.h | 1 | ||||
-rw-r--r-- | cmdline/apt-get.cc | 153 | ||||
-rw-r--r-- | doc/examples/configure-index | 97 | ||||
-rw-r--r-- | test/integration/framework | 1 | ||||
-rwxr-xr-x | test/integration/test-changelog | 34 |
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 + |