build/checkBeat12XML.c

John J. McDonough jjmcd at fedoraproject.org
Tue Sep 22 12:56:52 UTC 2009


 build/checkBeat12XML.c |  422 +++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 422 insertions(+)

New commits:
commit 9e04e373d34a37ec18e649a50abd94e469494e6d
Author: John J. McDonough <jjmcd at fedoraproject.org>
Date:   Tue Sep 22 08:53:03 2009 -0400

    Add program used to generate change tables
    
    Added build/checkBeat12XML.c which reads a list of packages
    and checks two repo databases for differences in those packages.
    The result is output as an XML table.  This is the program that
    generates the "All Changes" tables for the release notes.  Requires
    -lsqlite3 to link.  Requires that two primary.sqlite files be
    downloaded from the two repos of interest.

diff --git a/build/checkBeat12XML.c b/build/checkBeat12XML.c
new file mode 100644
index 0000000..d83b11b
--- /dev/null
+++ b/build/checkBeat12XML.c
@@ -0,0 +1,422 @@
+/*! \file checkBeat12XML.c
+
+ \brief Make an XML table of changes to a beat
+
+checkBeat reads a "beat" file listing packages in a beat.  It then
+reads the yum databases for the current Fedora release and the
+development repository.  checkBeat compares versions and creates
+an XML table of the differences on stdout.
+
+NOTE that the primary.sqlite for the old and new repos must be
+./old and ./new and must have been renamed to primary.sqlite.
+
+In practice, it is probably easier to cover all the changes
+by grouping by rpm_group rather than beat.  In this way the
+.beat files can be generated programatically.
+
+*/
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <sqlite3.h>
+
+//! Name of the yum database file for the current release
+#define DBFILE1 "old/primary.sqlite"
+//! Name of the yum database file for the development repo
+#define DBFILE2 "new/primary.sqlite"
+
+//! Entry to hold packages, their versions and project URL
+struct stEntry
+{
+  //! Package name
+  char szName[128];
+  //! Version number of package at initial release
+  char szOldVer[64];
+  //! Version number of package in development repo
+  char szNewVer[64];
+  //! URL of the package's project website
+  char szURL[2048];
+  //! Package short description
+  char szDesc[2048];
+} rcEntry[8192];
+
+//! File pointer to beat file
+FILE *f;
+//! Number of entries found in the beat file
+int nNumEntries;
+//! Buffer for reading the beat file
+char szBuffer[1024];
+//! Current entry being processed
+/*! nCurEntry contains the current entry in rcEntry being
+    processsed.  This is a global variable sine the query cannot
+    directly pass variables to the callback routines.
+*/
+int nCurEntry;
+//! String used to hold the SQL query
+char szQuery[256];
+//! Number of entries tested for different versions
+int nNumChecked;
+//! Number of entries found to have changed
+int nNumDiffs;
+
+//! Trim trailing newlines from string
+/*! trim() checks for control characters at the end
+    of a string and replaces them with null characters.
+*/
+void trim( char *s )
+{
+  while ( s[strlen(szBuffer)-1] < ' ' )
+    s[strlen(szBuffer)-1] = '\0';
+}
+
+//! Callback for getNewVersions
+/*! gnvCallback() is called by sqlite in response to a query for
+    the version in the development database.  The function simply
+    inserts the version into the rcEntry structure.
+*/
+static int gnvCallback(void *NotUsed, int argc, char **argv, char **azColName)
+{
+#ifdef DEBUG
+  printf("%3d: %s %s\n",nCurEntry,rcEntry[nCurEntry].szName,argv[0]);
+#endif
+  strcpy(rcEntry[nCurEntry].szNewVer,argv[0]);
+}
+
+//! Get newest versions
+/*! getNewVersion() opens the development database, then for
+    each entry in the rcEntry struct issues a query for the
+    package's version.  sqlite returns the result to gnvCallback().
+*/
+void getNewVersions( void )
+{
+  sqlite3 *db;
+  char *szErrMsg = 0;
+  int rc;
+
+  rc = sqlite3_open(DBFILE2,&db);
+  if ( rc )
+    {         
+      fprintf(stderr, "%s: %s\n", DBFILE2, sqlite3_errmsg(db));
+      sqlite3_close(db);
+      exit(1);
+    }
+
+  for ( nCurEntry=0; nCurEntry < nNumEntries; nCurEntry++ )
+    {
+      sprintf(szQuery,"SELECT version FROM packages WHERE name='%s';",
+	      rcEntry[nCurEntry].szName);
+#ifdef DEBUG
+      printf("%3d \"%s\"\n",nCurEntry,szQuery);
+#endif
+      rc = sqlite3_exec(db, szQuery, gnvCallback, 0, &szErrMsg );
+      if ( (rc != SQLITE_OK) && (rc != 4) )
+	{
+	  fprintf(stderr,"Return from %s is %d.\n",szQuery,rc);
+	  fprintf(stderr, "SQL error: %s\n", szErrMsg );
+	  sqlite3_free(szErrMsg);
+	  exit(1);
+	}
+      sqlite3_free(szErrMsg);
+    }
+  sqlite3_close(db);
+
+#ifdef DEBUG
+  for ( nCurEntry=0; nCurEntry < nNumEntries; nCurEntry++ )
+    {
+      printf("%-20s %-20s %-20s\n",rcEntry[nCurEntry].szName,
+	     rcEntry[nCurEntry].szOldVer,rcEntry[nCurEntry].szNewVer);
+    }
+#endif
+}
+
+//! Callback for get original versions
+/*! govCallback() is called by sqlite in response to a query for
+    the version in the original database.  The function simply
+    inserts the version and URL into the rcEntry structure.
+*/
+static int govCallback(void *NotUsed, int argc, char **argv, char **azColName)
+{
+#ifdef DEBUG
+  printf("%3d: %s %s %s\n",nCurEntry,rcEntry[nCurEntry].szName,argv[0],argv[1]);
+#endif
+  strcpy(rcEntry[nCurEntry].szOldVer,argv[0]);
+  if ( argv[1] )
+    strcpy(rcEntry[nCurEntry].szURL,argv[1]);
+  if ( argv[2] )
+    strcpy(rcEntry[nCurEntry].szDesc,argv[2]);
+}
+
+//! Get original versions and project's URL
+/*! getOriginalVersion() opens the original database, then for
+    each entry in the rcEntry struct issues a query for the
+    package's version and project URL.  sqlite returns the
+    result to govCallback().
+*/
+void getOriginalVersions( void )
+{
+  sqlite3 *db;
+  char *szErrMsg = 0;
+  int rc;
+
+  rc = sqlite3_open(DBFILE1,&db);
+  if ( rc )
+    {         
+      fprintf(stderr, "%s: %s\n", DBFILE1, sqlite3_errmsg(db));
+      sqlite3_close(db);
+      exit(1);
+    }
+
+  for ( nCurEntry=0; nCurEntry < nNumEntries; nCurEntry++ )
+    {
+      sprintf(szQuery,"SELECT version,url,summary FROM packages WHERE name='%s';",
+	      rcEntry[nCurEntry].szName);
+#ifdef DEBUG
+      printf("%3d \"%s\"\n",nCurEntry,szQuery);
+#endif
+      rc = sqlite3_exec(db, szQuery, govCallback, 0, &szErrMsg );
+      if ( (rc != SQLITE_OK) && (rc != 4) )
+	{
+	  fprintf(stderr,"Return from %s is %d.\n",szQuery,rc);
+	  fprintf(stderr, "SQL error: %s\n", szErrMsg );
+	  sqlite3_free(szErrMsg);
+	  exit(1);
+	}
+      sqlite3_free(szErrMsg);
+    }
+  sqlite3_close(db);
+
+#ifdef DEBUG
+  for ( nCurEntry=0; nCurEntry < nNumEntries; nCurEntry++ )
+    {
+      printf("%-20s %-20s\n",rcEntry[nCurEntry].szName,
+	     rcEntry[nCurEntry].szOldVer);
+    }
+#endif
+}
+
+//! Build a list of packages to check
+/*! buildList() reads the beat file and creates an entry
+    in rcEntries for each package.
+*/
+void buildList( char *szFilename )
+{
+  int i;
+
+  f = fopen(szFilename,"r");
+  if ( f==NULL )
+    {
+      perror("Beat file");
+      exit(1);
+    }
+  nNumEntries = 0;
+  while ( !feof(f) )
+    {
+      fgets(szBuffer,sizeof(szBuffer),f);
+      if ( !feof(f) )
+	{
+	  trim( szBuffer );
+#ifdef DEBUG
+	  printf("[%s]\n",szBuffer);
+#endif
+	  strcpy(rcEntry[nNumEntries].szName,szBuffer);
+	  nNumEntries++;
+	}
+    }
+#ifdef DEBUG
+  printf("%d entries.\n",nNumEntries);
+  for ( i=0; i<nNumEntries; i++ )
+    printf("(%s) ",rcEntry[i].szName);
+#endif
+  printf("\n");
+  fclose(f);
+}
+
+//! Compare versions of packages in beat and display
+/* compareVersions() goes through the rcEntry structure
+   and compares the new and original versions.  If they are
+   different it displays the package name, old and new
+   versions, and the project's URL.
+*/
+void compareVersions( char *name )
+{
+  char szBeatName[64];
+  char szBeatWork[64];
+  char szURLwork[2048];
+  char *p,*q;
+  int nNumLines, nNumTables,nNumIE;
+  int i;
+
+  i = 0;
+  for ( nCurEntry=0; nCurEntry < nNumEntries; nCurEntry++ )
+    if ( strcmp(rcEntry[nCurEntry].szOldVer,rcEntry[nCurEntry].szNewVer) )
+      i++;
+  if ( i )
+    {
+      //  printf("Package,Cat1,Cat2,Cat3,Summary,\"Old Ver\",\"New Ver\"\r\n");
+      strcpy(szBeatName,name);
+      p = strchr(szBeatName,'.');
+      if ( p )
+	*p = '\0';
+      strcpy(szBeatWork,szBeatName);
+      p = szBeatWork;
+      while ( *p )
+	{
+	  if ( *p == '/' ) *p='-';
+	  if ( *p == ' ' ) *p='-';
+	  p++;
+	}
+      printf("    <section id=\"sect-Release_Notes-Changes-%s\">\n",szBeatWork);
+      //printf("    <section>\n");
+      strcpy(szBeatWork,szBeatName);
+      p = szBeatWork;
+      while ( *p )
+	{
+	  if ( *p == '_' ) *p=' ';
+	  p++;
+	}
+      printf("      <title>%s</title>\n      <para>\n",szBeatWork);
+
+      nNumIE=0;
+      for ( nCurEntry=0; nCurEntry < nNumEntries; nCurEntry++ )
+	{
+	  //if ( strlen(rcEntry[nCurEntry].szNewVer)>0 )
+	  if ( strcmp(rcEntry[nCurEntry].szOldVer,rcEntry[nCurEntry].szNewVer) )
+	    {
+	      // Stupid poxml limitation
+	      nNumIE++;
+	      if ( nNumIE<1000 )
+		{
+		  printf("\t<indexterm>\n");
+		  printf("\t  <primary>%s</primary>\n",rcEntry[nCurEntry].szName);
+		  printf("\t</indexterm>\n");
+		}
+	    }
+	}
+      printf("\t<table frame=\"all\" id=\"tbl-%s-changes\">\n",szBeatName);
+      printf("\t  <title>All %s changes</title>\n\t  <tgroup cols=\"4\">\n",szBeatName);
+      printf("\t    <thead>\n\t      <row>\n");
+      printf("\t\t<entry>\n\t\t  Package\n\t\t</entry>\n");
+      printf("\t\t<entry>\n\t\t  Old Version\n\t\t</entry>\n");
+      printf("\t\t<entry>\n\t\t  New Version\n\t\t</entry>\n");
+      printf("\t\t<entry>\n\t\t  Upstream URL\n\t\t</entry>\n");
+      printf("\t      </row>\n\t    </thead>\n\t    <tbody>\n");
+
+      nNumLines = 0;
+      nNumTables = 1;
+      nNumChecked = nNumDiffs = 0;
+      for ( nCurEntry=0; nCurEntry < nNumEntries; nCurEntry++ )
+	{
+	  nNumChecked++;
+	  if ( strcmp(rcEntry[nCurEntry].szOldVer,rcEntry[nCurEntry].szNewVer) )
+	    //if ( strlen(rcEntry[nCurEntry].szNewVer)>0 )
+	    {
+	      printf("\t      <row>\n\t\t<entry>\n\t\t  <package>%s</package>\n\t\t</entry>\n",
+		     rcEntry[nCurEntry].szName);
+	      if ( strlen(rcEntry[nCurEntry].szOldVer)>0 )
+		printf("\t\t<entry>\n\t\t  %s\n\t\t</entry>\n",
+		       rcEntry[nCurEntry].szOldVer);
+	      else
+		printf("\t\t<entry>\n\t\t  new\n\t\t</entry>\n");
+	      if ( strlen(rcEntry[nCurEntry].szNewVer)>0 )
+		printf("\t\t<entry>\n\t\t  %s\n\t\t</entry>\n",
+		       rcEntry[nCurEntry].szNewVer);
+	      else
+		printf("\t\t<entry>\n\t\t  dropped\n\t\t</entry>\n");
+	      if ( strlen(rcEntry[nCurEntry].szURL)>0 )
+		{
+		  p = rcEntry[nCurEntry].szURL;
+		  q = szURLwork;
+		  while( *p )
+		    {
+		      if ( *p == '&' )
+			{
+			  strcat(szURLwork,"&");
+			  q+=5;
+			}
+		      else
+			{
+			  *q = *p;
+			  q++;
+			}
+		      p++;
+		    }
+		  *q = 0;
+
+		  printf("\t \t<entry>\n");
+		  printf("\t\t  <ulink type=\"http\" url=\"%s\"></ulink>\n",
+			 szURLwork);
+		  printf("\t\t</entry>\n");
+		}
+	      else
+		printf("\t\t<entry>\n\t\t  n/a\n\t\t</entry>\n");
+	      printf("\t      </row>\n");
+	      nNumDiffs++;
+#ifdef DEBUG
+	      printf("\t");
+	      for (i=0; i<strlen(rcEntry[nCurEntry].szOldVer); i++)
+		printf("%3d ",rcEntry[nCurEntry].szOldVer[i]);
+	      printf("\n");
+	      printf("\t");
+	      for (i=0; i<strlen(rcEntry[nCurEntry].szNewVer); i++)
+		printf("%3d ",rcEntry[nCurEntry].szNewVer[i]);
+	      printf("\n");
+#endif
+	    }
+	  // Limit table size to avoid Publican limitations
+	  nNumLines++;
+	  if ( nNumLines >= 400 )
+	    {
+	      printf("\t    </tbody>\n\t  </tgroup>\n\t</table>\n");
+	      printf("\t<table frame=\"all\" id=\"tbl-%s-changes-%d\">\n",szBeatName,nNumTables);
+	      printf("\t  <title>All %s changes (cont'd)</title>\n\t  <tgroup cols=\"4\">\n",szBeatName);
+	      printf("\t    <thead>\n\t      <row>\n");
+	      printf("\t\t<entry>\n\t\t  Package\n\t\t</entry>\n");
+	      printf("\t\t<entry>\n\t\t  Old Version\n\t\t</entry>\n");
+	      printf("\t\t<entry>\n\t\t  New Version\n\t\t</entry>\n");
+	      printf("\t\t<entry>\n\t\t  Upstream URL\n\t\t</entry>\n");
+	      printf("\t      </row>\n\t    </thead>\n\t    <tbody>\n");
+	      nNumTables++;
+	      nNumLines=0;
+	    }
+	}
+      //      if ( nNumDiffs == 0 )
+      //	{
+      //	  printf("\t      <row><entry>No Changes</entry></row>\n");
+      //	}
+      printf("\t    </tbody>\n\t  </tgroup>\n\t</table>\n");
+      printf("      </para>\n      <para>\n");
+      printf("        <informaltable frame='none'>\n");
+      printf("          <tgroup cols='2'>\n");
+      printf("            <tbody>\n");
+      printf("              <row><entry>Packages changed</entry><entry>%d</entry></row>\n",nNumDiffs);
+      printf("              <row><entry>Packages unchanged</entry><entry>%d</entry></row>\n",nNumChecked-nNumDiffs);
+      printf("              <row><entry>Total packages</entry><entry>%d</entry></row>\n",nNumChecked);
+      printf("            </tbody>\n");
+      printf("          </tgroup>\n");
+      printf("        </informaltable>\n");
+      printf("      </para>\n    </section>\n");
+    }
+}
+
+//! Compare versions in two primary.sqlite files for a beat
+/* checkBeat main() tests the number of arguments to ensure the
+   user has provided a beat file, then calls buildList(),
+   getOriginalVersions(), getNewVersions() and compareVersions().
+*/
+int main( int argc, char *argv[] )
+{
+
+  if ( argc != 2 )
+    {
+      fprintf(stderr,"Usage: %s <packagelist>\n",argv[0]);
+      exit(1);
+    }
+
+  buildList(argv[1]);
+  getOriginalVersions();
+  getNewVersions();
+  compareVersions(argv[1]);
+
+  return 0;
+}





More information about the Fedora-docs-commits mailing list