src/hg/makeDb/trackDbPatch/trackDbPatch.c 1.3

1.3 2009/12/04 00:41:00 kent
Did some testing, took out debugging statements, and polished interface a little.
Index: src/hg/makeDb/trackDbPatch/trackDbPatch.c
===================================================================
RCS file: /projects/compbio/cvsroot/kent/src/hg/makeDb/trackDbPatch/trackDbPatch.c,v
retrieving revision 1.2
retrieving revision 1.3
diff -b -B -U 4 -r1.2 -r1.3
--- src/hg/makeDb/trackDbPatch/trackDbPatch.c	23 Nov 2009 07:39:46 -0000	1.2
+++ src/hg/makeDb/trackDbPatch/trackDbPatch.c	4 Dec 2009 00:41:00 -0000	1.3
@@ -2,42 +2,48 @@
 #include "common.h"
 #include "linefile.h"
 #include "hash.h"
 #include "options.h"
+#include "obscure.h"
 #include "ra.h"
 #include "portable.h"
 
 static char const rcsid[] = "$Id$";
 
 char *clPatchDir = NULL;
 char *clKey = "track";
 boolean clFirstFile = FALSE;
+boolean clMultiFile = FALSE;
 
 void usage()
 /* Explain usage and exit. */
 {
 errAbort(
-  "trackDbPatch - Patch files in trackDb with a specification .ra file that has db, track, and file fields that say where to apply the patch, and other fields that are patched in.\n"
+  "trackDbPatch - Patch files in trackDb with a specification .ra file that has db, track, \n"
+  "and filePos fields that say where to apply the patch, and other fields that are patched in.\n"
+  "The filePos field contains a file name and a line number. Currently the line number is ignored\n"
   "usage:\n"
   "   trackDbPatch patches.ra backupDir\n"
   "options:\n"
   "   -test=patchDir - rather than doing patches in place, write patched output to this dir\n"
   "   -key=tagName - use tagName as key.  Default '%s'\n"
+  "   -multiFile - allow multiple files in filePos tag\n"
   "   -firstFile - when a patch can go to multiple files apply it to first rather than last file\n"
   , clKey
   );
 }
 
 static struct optionSpec options[] = {
    {"test", OPTION_STRING},
    {"key", OPTION_STRING},
+   {"multiFile", OPTION_BOOLEAN},
    {"firstFile", OPTION_BOOLEAN},
    {NULL, 0},
 };
 
 
-/* Program first reads in patchs to list of raPatches.  Then it creates a list of filePatches so that it can do all patches
- * in one pile at once. */
+/* Program first reads in patchs to list of raPatches.  Then it creates a list of filePatches 
+ * so that it can do all patches in one pile at once. */
 
 struct raPatch
 /* A patch record. */
     {
@@ -55,8 +61,12 @@
     char *fileName;		/* Name of file. */
     struct slRef *patchList;	/* References to raPatches associated with file.  */
     };
 
+int glPatchFieldModifyCount = 0;
+int glPatchFieldAddCount = 0;
+int glPatchRecordCount = 0;
+
 struct fileToPatch *groupPatchesByFiles(struct raPatch *patchList, boolean firstFile)
 /* Make fileToPatch list that covers all files in patchList. If lastFile is set will apply patch to first (as 
  * opposed to the usual last) file in list of files  associated with a patch. */
 {
@@ -129,11 +139,21 @@
         {
 	patch->track = tag->val;
 	freez(&tag);
 	}
-    else if (sameString(tag->name, "file"))
+    else if (sameString(tag->name, "filePos"))
         {
 	patch->fileList = makeFileList(tag->val);
+	int fileCount = slCount(patch->fileList);
+	if (fileCount != 1)
+	    {
+	    if (fileCount == 0)
+	        errAbort("Empty filePos tag near line %d of %s", lf->lineIx, lf->fileName);
+	    else if (!clMultiFile)
+	        errAbort("Multiple files in filePos near line %d of %s. "
+			"Use -multiFile option if this is not a mistake.", 
+			lf->lineIx, lf->fileName);
+	    }
 	freeMem(tag->val);
 	freez(&tag);
 	}
     else
@@ -199,9 +219,8 @@
     {
     char *simplePath = simplifyPathToDir(dir);
     if (simplePath[0] != 0)
 	{
-	uglyf("makeDirsOnPath(%s)\n", simplePath);
 	makeDirsOnPath(simplePath);
 	}
     freeMem(simplePath);
     }
@@ -256,9 +275,9 @@
     char *key = cloneFirstWord(patch->track);
     hashAdd(patchHash, key, patch);
     freeMem(key);
     }
-uglyf("%d patches in hash, %d in list\n", patchHash->elCount, slCount(patchRefList));
+verbose(2, "%d patches in hash, %d in list\n", patchHash->elCount, slCount(patchRefList));
 
 /* Open input and output files. */
 struct lineFile *lf = lineFileOpen(inName, TRUE);
 FILE *f = mustOpen(outName, "w");
@@ -289,9 +308,10 @@
 
     /* If have patch apply it, otherwise just copy. */
     if (patch)
         {
-	uglyf("Got patch %s with %d tags starting %s %s\n", patch->track, slCount(patch->tagList), patch->tagList->name, (char *)patch->tagList->val);
+	++glPatchRecordCount;
+	verbose(3, "Got patch %s with %d tags starting %s %s\n", patch->track, slCount(patch->tagList), patch->tagList->name, (char *)patch->tagList->val);
 	int indent = 0;
 	struct hash *appliedHash = hashNew(0);
 	for (line = stanza; line != NULL; line = line->next)
 	    {
@@ -308,9 +328,10 @@
 		        {
 			copyLine = FALSE;
 			spaceOut(f, indent);
 			fprintf(f, "%s %s\n", tagPatch->name, (char*)tagPatch->val);
-			uglyf("Applying patch '%s' to modify %s'\n", (char*)tagPatch->val, tagStart);
+			verbose(2, "Applying patch '%s' to modify %s'\n", (char*)tagPatch->val, tagStart);
+			++glPatchFieldModifyCount;
 			hashAdd(appliedHash, tagPatch->name, NULL);
 			break;
 			}
 		    }
@@ -325,9 +346,10 @@
 	    {
 	    if (!hashLookup(appliedHash, tagPatch->name))
 	        {
 		spaceOut(f, indent);
-		uglyf("Applying patch to %s adding %s %s\n", patch->track, tagPatch->name, (char*)tagPatch->val);
+		++glPatchFieldAddCount;
+		verbose(2, "Applying patch to %s adding %s %s\n", patch->track, tagPatch->name, (char*)tagPatch->val);
 		fprintf(f, "%s %s\n", tagPatch->name, (char*)tagPatch->val);
 		hashAdd(appliedHash, tagPatch->name, NULL);
 		}
 	    }
@@ -372,9 +394,8 @@
     /* Figure out name that skips most of the long path to the trackDb files */
     char *relName = skipTrackDbPathPrefix(file->fileName);
     if (relName == NULL)
          relName = file->fileName;
-    uglyf("full rel %s %s\n", file->fileName, relName);
 
     /* Create file names for backup file and temp file. */
     char backupPath[PATH_LEN], patchPath[PATH_LEN];
     char tempPath[PATH_LEN];
@@ -394,16 +415,19 @@
     if (clPatchDir)
 	{
         makeDirForFile(patchPath);
 	mustRename(tempPath, patchPath);
+	copyFile(file->fileName, backupPath);
 	}
     else
     /* If not testing then move original to backup and temp to original location. */
         {
 	mustRename(file->fileName, backupPath);
 	mustRename(tempPath, file->fileName);
 	}
     }
+verbose(1, "Modified %d records.  Modified %d fields, added %d fields\n",
+	glPatchRecordCount, glPatchFieldModifyCount, glPatchFieldAddCount);
 
 lineFileClose(&lf);
 }
 
@@ -415,9 +439,8 @@
     usage();
 clKey = optionVal("key", clKey);
 clPatchDir = optionVal("test", clPatchDir);
 clFirstFile = optionExists("firstFile");
-if (!clPatchDir)
-    errAbort("Must specify test option currently");
+clMultiFile = optionExists("multiFile");
 trackDbPatch(argv[1], argv[2]);
 return 0;
 }