Просмотр исходного кода

merged lp:~mvo/apt/apt-get-changelog

Michael Vogt лет назад: 15
Родитель
Сommit
2d555a8205

+ 9 - 0
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		/*{{{*/
 // ---------------------------------------------------------------------

+ 1 - 0
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));}; \

+ 153 - 0
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}};

+ 52 - 45
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            
   };
 };
 

+ 1 - 0
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

+ 34 - 0
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
+