d1bc57639309864bb2665bd46eddfe75863f76e4
braney
  Tue Apr 23 16:42:54 2024 -0700
rearrange how we're doing hub groups.

diff --git src/hg/lib/hubConnect.c src/hg/lib/hubConnect.c
index 4fee1b1..2be2a6a 100644
--- src/hg/lib/hubConnect.c
+++ src/hg/lib/hubConnect.c
@@ -16,30 +16,45 @@
 #include "hdb.h"
 #include "net.h"
 #include "trackHub.h"
 #include "hubConnect.h"
 #include "hui.h"
 #include "errCatch.h"
 #include "obscure.h"
 #include "hgConfig.h"
 #include "grp.h"
 #include "udc.h"
 #include "hubPublic.h"
 #include "genark.h"
 #include "asmAlias.h"
 #include "cheapcgi.h"
 
+boolean hubsCanAddGroups()
+/* can track hubs have their own groups? */
+{
+static boolean canHubs = FALSE;
+static boolean canHubsSet = FALSE;
+
+if (!canHubsSet)
+    {
+    canHubs = cfgOptionBooleanDefault("trackHubsCanAddGroups", FALSE);
+    canHubsSet = TRUE;
+    }
+
+return canHubs;
+}
+
 boolean isHubTrack(char *trackName)
 /* Return TRUE if it's a hub track. */
 {
 return startsWith(hubTrackPrefix, trackName);
 }
 
 static char *hubStatusTableName = NULL;
 static char *_hubPublicTableName = NULL;
 
 static char *getHubStatusTableName()
 /* return the hubStatus table name from the environment, 
  * or hg.conf, or use the default.  Cache the result */
 {
 if (hubStatusTableName == NULL)
     hubStatusTableName = cfgOptionEnvDefault("HGDB_HUB_STATUS_TABLE",
@@ -347,30 +362,45 @@
 slReverse(&hubList);
 return hubList;
 }
 
 int hubIdFromCartName(char *cartName)
 /* Given something like "hgHubConnect.hub.123" return 123 */
 {
 assert(startsWith("hgHubConnect.hub.", cartName));
 
 char *ptr1 = strchr(cartName, '.');
 char *ptr2 = strchr(ptr1 + 1, '.');
 
 return sqlUnsigned(ptr2+1);
 }
 
+char *hubNameFromGroupName(char *groupName)
+/* Given something like "hub_123_myWig" return hub_123 */
+{
+char *hubName = cloneString(groupName);
+
+char *ptr1 = hubName;
+ptr1 += 4;
+char *ptr2 = strchr(ptr1, '_');
+
+if (ptr2 != NULL)
+    *ptr2 = 0;
+
+return hubName;
+}
+
 unsigned hubIdFromTrackName(char *trackName)
 /* Given something like "hub_123_myWig" return 123 */
 {
 assert(startsWith("hub_", trackName));
 char *ptr1 = trackName;
 ptr1 += 4;
 char *ptr2 = strchr(ptr1, '_');
 
 if (ptr2 == NULL)
     errAbort("hub track %s not in correct format\n", trackName);
 char save = *ptr2;
 *ptr2 = 0;
 unsigned val = sqlUnsigned(ptr1);
 *ptr2 = save;
 return  val;
@@ -866,49 +896,74 @@
 else if (tHub != NULL)
     {
     int dbCount = 0;
     char *dbList = getDbList(tHub, &dbCount);
     // users may include quotes in their hub names requiring escaping
     sqlSafef(query, sizeof(query),
 	"update %s set shortLabel=\"%s\",longLabel=\"%s\",dbCount=\"%d\",dbList=\"%s\",errorMessage=\"\",lastOkTime=now() where id=%d",
 	getHubStatusTableName(), tHub->shortLabel, tHub->longLabel, 
 	dbCount, dbList,
 	hub->id);
     sqlUpdate(conn, query);
     }
 hDisconnectCentral(&conn);
 }
 
-struct trackDb *hubAddTracks(struct hubConnectStatus *hub, char *database, boolean *foundFirstGenome, struct hash *trackDbNameHash)
+static void grpListAddHubName(struct grp *grpList, struct trackHub *hub)
+/* Add the hub name to the groups defined by a hub. */
+{
+char buffer[4096];
+
+for (; grpList; grpList = grpList->next)
+    {
+    safef(buffer, sizeof buffer, "%s_%s", hub->name, grpList->name);
+    grpList->name = cloneString(buffer);
+    safef(buffer, sizeof buffer, "Hub: %s : %s", hub->shortLabel, grpList->label);
+    grpList->label = cloneString(buffer);
+    }
+}
+
+struct trackDb *hubAddTracks(struct hubConnectStatus *hub, char *database, boolean *foundFirstGenome, struct hash *trackDbNameHash, struct grp **hubGroups)
 /* Load up stuff from data hub and append to list. The hubUrl points to
  * a trackDb.ra format file. Only the first example of a genome gets to 
  * populate groups, the others get a group for the trackHub.  A particular 
  * trackDb is only read once even if referenced from more than one hub.  */
 {
 struct trackDb *tdbList = NULL;
 struct trackHub *trackHub = hub->trackHub;
 
 if (trackHub != NULL)
     {
     struct trackHubGenome *hubGenome = trackHubFindGenome(trackHub, database);
     if ((hubGenome == NULL) || hashLookup(trackDbNameHash,  hubGenome->trackDbFile))
         hubGenome = NULL; // we already saw this trackDb, so ignore this stanza
     else
         hashStore(trackDbNameHash,  hubGenome->trackDbFile);
 
     if (hubGenome != NULL)
 	{
+        // add groups
+	if ((hubGenome->groups != NULL) && hubsCanAddGroups())
+            {
+            struct grp *list = readGroupRa(hubGenome->groups);
+            grpListAddHubName(list, hub->trackHub);
+
+            if (hubGroups)
+                *hubGroups = slCat(*hubGroups, list);
+            }
+
+        // now grab tracks
         boolean doCache = trackDbCacheOn();
 
         if (doCache)
             {
             // we have to open the trackDb file to get the udc cache to check for an update
             struct udcFile *checkCache = udcFileMayOpen(hubGenome->trackDbFile, NULL);
             if (checkCache != NULL)
                 {
                 time_t time = udcUpdateTime(checkCache);
                 udcFileClose(&checkCache);
 
                 struct trackDb *cacheTdb = trackDbHubCache(hubGenome->trackDbFile, time);
 
                 if (cacheTdb && hubGenome->quickLiftChain)
                     cacheTdb = fixForQuickLift(cacheTdb, hubGenome, hub);
@@ -933,62 +988,64 @@
         if (tdbList && hubGenome->quickLiftChain)
             tdbList = fixForQuickLift(tdbList, hubGenome, hub);
 	}
     }
 return tdbList;
 }
 
 static struct grp *grpFromHub(struct hubConnectStatus *hub)
 /* Make up a grp structur from hub */
 {
 struct grp *grp;
 AllocVar(grp);
 char name[16];
 safef(name, sizeof(name), "hub_%d", hub->id);
 grp->name = cloneString(name);
-grp->label = cloneString(hub->shortLabel);
+char buffer[4096];
+safef(buffer, sizeof buffer, "Hub: %s", hub->shortLabel);
+grp->label = cloneString(buffer);
 return grp;
 }
 
 struct trackDb *hubCollectTracks( char *database,  struct grp **pGroupList)
 /* Generate trackDb structures for all the tracks in attached hubs.  
  * Make grp structures for each hub. Returned group list is reversed. */
 {
 // return the cached copy if it exists
 static struct trackDb *hubTrackDbs;
 static struct grp *hubGroups;
 
 if (hubTrackDbs != NULL)
     {
     if (pGroupList != NULL)
 	*pGroupList = hubGroups;
     return hubTrackDbs;
     }
 
 struct hubConnectStatus *hub, *hubList =  hubConnectGetHubs();
 struct trackDb *tdbList = NULL;
 boolean foundFirstGenome = FALSE;
 struct hash *trackDbNameHash = newHash(5);
 for (hub = hubList; hub != NULL; hub = hub->next)
     {
     if (isEmpty(hub->errorMessage))
 	{
         /* error catching in so it won't just abort  */
         struct errCatch *errCatch = errCatchNew();
         if (errCatchStart(errCatch))
 	    {
-	    struct trackDb *thisList = hubAddTracks(hub, database, &foundFirstGenome, trackDbNameHash);
+	    struct trackDb *thisList = hubAddTracks(hub, database, &foundFirstGenome, trackDbNameHash, &hubGroups);
 	    tdbList = slCat(tdbList, thisList);
 	    }
         errCatchEnd(errCatch);
         if (errCatch->gotError)
 	    {
 	    warn("%s", errCatch->message->string);
 	    hubUpdateStatus( errCatch->message->string, hub);
 	    }
 	else
 	    {
             struct grp *grp = grpFromHub(hub);
             slAddHead(&hubGroups, grp);
 	    hubUpdateStatus(NULL, hub);
 	    }