3d00d8348e1cb6eafec60cc3d7321f6de7e669be
braney
  Mon Dec 12 13:09:49 2022 -0800
be smarter about showing the user error messages

diff --git src/hg/lib/hubConnect.c src/hg/lib/hubConnect.c
index 05ff98f..503a1e7 100644
--- src/hg/lib/hubConnect.c
+++ src/hg/lib/hubConnect.c
@@ -134,30 +134,31 @@
     struct trackHubGenome *genomes = hub->genomeList;	/* List of associated genomes. */
 
     for(; genomes; genomes = genomes->next)
 	if (sameString(genomes->name, database))
 	    return TRUE;
     }
 return FALSE;
 }
 
 static struct trackHub *fetchHub(struct hubConnectStatus *hubStatus, char **errorMessage)
 {
 struct errCatch *errCatch = errCatchNew();
 struct trackHub *tHub = NULL;
 boolean gotWarning = FALSE;
 char *url = hubStatus->hubUrl;
+*errorMessage = NULL;
 
 char hubName[64];
 safef(hubName, sizeof(hubName), "hub_%d", hubStatus->id);
 
 if (errCatchStart(errCatch))
     tHub = trackHubOpen(url, cloneString(hubName)); // open hub
 errCatchEnd(errCatch);
 if (errCatch->gotError)
     {
     gotWarning = TRUE;
     *errorMessage = cloneString(errCatch->message->string);
     }
 errCatchFree(&errCatch);
 
 if (gotWarning)
@@ -182,49 +183,50 @@
 struct hubConnectStatus *hubConnectStatusForId(struct sqlConnection *conn, int id)
 {
 struct hubConnectStatus *hub = NULL;
 char query[1024];
 sqlSafef(query, sizeof(query), 
     "select hubUrl,status, errorMessage,lastNotOkTime, shortLabel from %s where id=%d", getHubStatusTableName(), id);
 struct sqlResult *sr = sqlGetResult(conn, query);
 char **row = sqlNextRow(sr);
 if (row != NULL)
     {
     AllocVar(hub);
     hub->id = id;
     hub->hubUrl = cloneString(row[0]);
     hub->status = sqlUnsigned(row[1]);
     hub->errorMessage = cloneString(row[2]);
-    char *shortLabel = row[4];
+    hub->shortLabel = cloneString(row[4]);
     if (isEmpty(row[2]) || hubTimeToCheck(hub, row[3]))
 	{
 	char *errorMessage = NULL;
 	hub->trackHub = fetchHub( hub, &errorMessage);
         if (hub->trackHub)
             hub->trackHub->hubStatus = hub;
 	hub->errorMessage = cloneString(errorMessage);
 	hubUpdateStatus( hub->errorMessage, hub);
 	if (!isEmpty(hub->errorMessage))
 	    {
             boolean isCollection = (strstr(hub->hubUrl, "hgComposite") != NULL);
             if (isCollection)
                 warn("You created a <a href=\"/cgi-bin/hgCollection\"><b>Track "
          "Collection</b></a> that has expired and been removed. Track Collections "
          "expire 48 hours after their last use. <a href=\"/cgi-bin/hgSession\"><b>"
          "Save your session</b></a> to preserve collections long-term and to allow sharing.");
-            else
-                warn("Could not connect to hub \"%s\": %s", shortLabel, hub->errorMessage);
+            // commenting this out, but leaving it in the source because we might use it later.
+            //else
+                //warn("Could not connect to hub \"%s\": %s", hub->shortLabel, hub->errorMessage);
 	    }
 	}
     }
 sqlFreeResult(&sr);
 return hub;
 }
 
 struct hubConnectStatus *hubConnectStatusListFromCartAll(struct cart *cart)
 /* Return list of all track hubs that are referenced by cart. */
 {
 struct hubConnectStatus *hubList = NULL, *hub;
 struct slPair *pair, *pairList = cartVarsWithPrefix(cart, hgHubConnectHubVarPrefix);
 struct sqlConnection *conn = hConnectCentral();
 for (pair = pairList; pair != NULL; pair = pair->next)
     {
@@ -505,30 +507,32 @@
 	errAbort("opened hub, but could not get it out of the hubStatus table");
 	}
     }
 
 /* allocate a hub */
 struct hubConnectStatus *hub = NULL;
 
 AllocVar(hub);
 hub->id = id;
 hub->hubUrl = cloneString(url);
 
 /* new fetch the contents of the hub to fill in the status table */
 struct trackHub *tHub = fetchHub( hub, &errorMessage);
 if (tHub != NULL)
     hub->trackHub = tHub;
+if (errorMessage != NULL)
+    hub->errorMessage = cloneString(errorMessage);
 
 /* update the status table with the lastest label and database information */
 hubUpdateStatus( errorMessage, hub);
 
 /* if we're turning on the hub, set the cart variable */
 if (set)
     {
     char hubName[32];
     safef(hubName, sizeof(hubName), "%s%u", hgHubConnectHubVarPrefix, id);
     cartSetString(cart, hubName, "1");
     }
 
 return hub;
 }
 
@@ -622,30 +626,32 @@
         if ((wantFirstDb != NULL) && (hub->trackHub != NULL)) // choose the first db
             newDatabase = hub->trackHub->defaultDb;
         else if (assemblyDb != NULL)
             {
             // Check to see if the user specified an assembly within
             // an assembly hub.
             struct trackHub *trackHub = hub->trackHub;
             if (trackHub != NULL)
                 {
                 struct trackHubGenome *genomeList = trackHub->genomeList;
 
                 for(; genomeList; genomeList = genomeList->next)
                     {
                     if (sameString(assemblyDb, hubConnectSkipHubPrefix(genomeList->name)))
                         {
+                        if (hub->errorMessage)
+                            errAbort("Hub error: %s", hub->errorMessage);
                         newDatabase = genomeList->name;
                         break;
                         }
                     }
                 }
             }
         }
     }
 
 cartRemove(cart, hgHubDataClearText);
 cartRemove(cart, hgHubDataText);
 cartRemove(cart, hgHubDoFirstDb);
 cartRemove(cart, hgHubGenome);
 return newDatabase;
 }
@@ -786,31 +792,31 @@
         if (doCache)
             trackDbHubCloneTdbListToSharedMem(hubGenome->trackDbFile, tdbList, memCheckPoint(), incFiles->string);
 	}
     }
 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->trackHub->shortLabel);
+grp->label = cloneString(hub->shortLabel);
 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;
@@ -833,30 +839,37 @@
         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);
 	    }
 
         errCatchFree(&errCatch);
 	}
+    else
+        {
+        /* create an empty group to hold the error message. */
+        struct grp *grp = grpFromHub(hub);
+        grp->errMessage = hub->errorMessage;
+        slAddHead(&hubGroups, grp);
+        }
     }
 
 hubTrackDbs = tdbList;
 if (pGroupList != NULL)
     *pGroupList = hubGroups;
 return tdbList;
 }
 
 static struct hubConnectStatus *globalHubList;
 
 struct hubConnectStatus *hubConnectGetHubs()
 /* return the static global to the track data hubs */
 {
 return globalHubList;
 }
@@ -1005,31 +1018,36 @@
     char *path = &dir[sizeof hubCuratedPrefix - 1];
     char url[4096];
     safef(url, sizeof url, "%s/%s/hub.txt", path, curatedHubPrefix);
 
     struct hubConnectStatus *status = getAndSetHubStatus( cart, url, TRUE);
 
     if (status && isEmpty(status->errorMessage))
         {
         char buffer[4096];
         safef(buffer, sizeof buffer, "hub_%d_%s", status->id, db);
         dbOveride = cloneString(buffer);
 
         return status->id;
         }
     else
+        {
+        if (!isEmpty(status->errorMessage))
+            errAbort("Hub error: url %s: error  %s.", url, status->errorMessage);
+        else
             errAbort("Cannot open hub %s.", url);
+        }
 
     }
 return 0;
 }
 
 
 char *hubConnectLoadHubs(struct cart *cart)
 /* load the track data hubs.  Set a static global to remember them */
 {
 int newCuratedHubId = 0;
 char *dbSpec = cartOptionalString(cart, "db");
 char *curatedHubPrefix = cfgOption("curatedHubPrefix");
 if (isEmpty(curatedHubPrefix))
     curatedHubPrefix = "public";
 if (dbSpec != NULL)