d9601b7485629b07bca40a2ce6205b53b162aad2
braney
  Tue Dec 14 14:55:50 2010 -0800
add the ability to add a release tag(s) to include statements #452
diff --git src/hg/lib/trackDbCustom.c src/hg/lib/trackDbCustom.c
index 69d6bb8..1fce4a2 100644
--- src/hg/lib/trackDbCustom.c
+++ src/hg/lib/trackDbCustom.c
@@ -83,30 +83,36 @@
 /* parse the track line */
 {
 char *val2 = cloneString(value);
 bt->track = nextWord(&val2);
 
 // check for override option
 if (val2 != NULL)
     {
     val2 = trimSpaces(val2);
     if (!sameString(val2, "override"))
         errAbort("invalid track line: %s:%d: track %s", lf->fileName, lf->lineIx, value);
     bt->overrides = hashNew(0);
     }
 }
 
+static void trackDbAddRelease(struct trackDb *bt, char *releaseTag)
+/* Add release tag */
+{
+hashAdd(bt->settingsHash, "release", cloneString(releaseTag));
+}
+
 static void trackDbAddInfo(struct trackDb *bt,
 	char *var, char *value, struct lineFile *lf)
 /* Add info from a variable/value pair to browser table. */
 {
 if (sameString(var, "track"))
     parseTrackLine(bt, value, lf);
 if (bt->settingsHash == NULL)
     bt->settingsHash = hashNew(7);
 hashAdd(bt->settingsHash, var, cloneString(value));
 
 if (bt->overrides != NULL)
     hashAdd(bt->overrides, var, NULL);
 }
 
 //not needed?
@@ -228,114 +234,145 @@
     bt->type = cloneString("");
 if (bt->priority == 0)
     bt->priority = 100.0;
 if (bt->url == NULL)
     bt->url = cloneString("");
 if (bt->html == NULL)
     bt->html = cloneString("");
 if (bt->grp == NULL)
     bt->grp = cloneString("x");
 if (bt->canPack == 2)
     bt->canPack = packableType(bt->type);
 if (bt->settings == NULL)
     bt->settings = cloneString("");
 }
 
-char *trackDbInclude(char *raFile, char *line)
+char *trackDbInclude(char *raFile, char *line, char **releaseTag)
 /* Get include filename from trackDb line.
    Return NULL if line doesn't contain include */
 {
 static char incFile[256];
 char *file;
 
 if (startsWith("include", line))
     {
     splitPath(raFile, incFile, NULL, NULL);
     nextWord(&line);
     file = nextQuotedWord(&line);
     strcat(incFile, file);
+    *releaseTag = nextWord(&line);
     return cloneString(incFile);
     }
 else
     return NULL;
 }
 
-struct trackDb *trackDbFromRa(char *raFile)
+struct trackDb *trackDbFromRa(char *raFile, char *releaseTag)
 /* Load track info from ra file into list. */
 {
 struct lineFile *lf = lineFileOpen(raFile, TRUE);
 char *line, *word;
 struct trackDb *btList = NULL, *bt;
 boolean done = FALSE;
 char *incFile;
 
 for (;;)
     {
     /* Seek to next line that starts with 'track' */
     for (;;)
 	{
+        char *subRelease;
+
 	if (!lineFileNext(lf, &line, NULL))
 	   {
 	   done = TRUE;
 	   break;
 	   }
 	line = skipLeadingSpaces(line);
         if (startsWithWord("track", line))
             {
             lineFileReuse(lf);
             break;
             }
-        else if ((incFile = trackDbInclude(raFile, line)) != NULL)
+        else if ((incFile = trackDbInclude(raFile, line, &subRelease)) != NULL)
             {
-            struct trackDb *incTdb = trackDbFromRa(incFile);
+            if (subRelease)
+                trackDbCheckValidRelease(subRelease);
+            if (releaseTag && subRelease && !sameString(subRelease, releaseTag))
+                errAbort("Include with release %s inside include with release %s line %d of %s", subRelease, releaseTag, lf->lineIx, lf->fileName);
+            struct trackDb *incTdb = trackDbFromRa(incFile, subRelease);
             btList = slCat(btList, incTdb);
             }
 	}
     if (done)
         break;
 
     /* Allocate track structure and fill it in until next blank line. */
     bt = trackDbNew();
     slAddHead(&btList, bt);
     for (;;)
         {
 	/* Break at blank line or EOF. */
 	if (!lineFileNext(lf, &line, NULL))
 	    break;
 	line = skipLeadingSpaces(line);
 	if (line == NULL || line[0] == 0)
 	    break;
 
 	/* Skip comments. */
 	if (line[0] == '#')
 	    continue;
 
 	/* Parse out first word and decide what to do. */
 	word = nextWord(&line);
 	if (line == NULL)
 	    errAbort("No value for %s line %d of %s", word, lf->lineIx, lf->fileName);
 	line = trimSpaces(line);
 	trackDbUpdateOldTag(&word, &line);
+        if (releaseTag && sameString(word, "release"))
+            errAbort("Release tag %s in stanza with include override %s, line %d of %s",
+                line, releaseTag, lf->lineIx, lf->fileName);
 	trackDbAddInfo(bt, word, line, lf);
 	}
+    if (releaseTag)
+        trackDbAddRelease(bt, releaseTag);
     }
 lineFileClose(&lf);
 
 slReverse(&btList);
 return btList;
 }
 
+boolean trackDbCheckValidRelease(char *tag)
+/* check to make sure release tag is valid */
+{
+char *words[5];
+
+int count = chopString(cloneString(tag), ",", words, ArraySize(words));
+if (count > 3)
+    return FALSE;
+
+int ii;
+for(ii=0; ii < count; ii++)
+    if (!sameString(words[ii], "alpha") && !sameString(words[ii], "beta") &&
+        !sameString(words[ii], "public"))
+            return FALSE;
+
+return TRUE;
+}
+
+
 struct hash *trackDbHashSettings(struct trackDb *tdb)
 /* Force trackDb to hash up it's settings.  Usually this is just
  * done on demand. Returns settings hash. */
 {
 if (tdb->settingsHash == NULL)
     tdb->settingsHash = trackDbSettingsFromString(tdb->settings);
 return tdb->settingsHash;
 }
 
 struct hash *trackDbSettingsFromString(char *string)
 /* Return hash of key/value pairs from string.  Differs
  * from raFromString in that it passes the key/val
  * pair through the backwards compatability routines. */
 {
 char *dupe = cloneString(string);