3024edbfb4af164c8ef34eded35ec41015437c5c hiram Wed Mar 11 14:56:35 2026 -0700 allow GenArk hubs to exist as "curated" hubs with a dbDb entry such as rn8 and a nibPath to the GenArk /gbdb/ directory refs #32985 diff --git src/hg/lib/hubConnect.c src/hg/lib/hubConnect.c index 1ad63ece3b3..42f8259c3e1 100644 --- src/hg/lib/hubConnect.c +++ src/hg/lib/hubConnect.c @@ -1202,102 +1202,173 @@ hDisconnectCentral(&conn); return added; } static char *getCuratedHubPrefix() /* figure out what sandbox we're in. */ { char *curatedHubPrefix = cfgOption("curatedHubPrefix"); if (isEmpty(curatedHubPrefix)) curatedHubPrefix = "public"; return curatedHubPrefix; } +static boolean genarkCurated(char *dirPath, char **hubUrl) +/* Given a dirPath to a GenArk hub, find the appropriate hub.txt */ +{ +boolean ret = FALSE; +if (dirPath != NULL && isDirectory(dirPath)) + { + *hubUrl = NULL; + char *prefix = getCuratedHubPrefix(); + + /* Try .hub.txt first */ + char candidate[4096]; + safef(candidate, sizeof candidate, "%s/%s.hub.txt", dirPath, prefix); + if (fileExists(candidate)) + { + *hubUrl = cloneString(candidate); + ret = TRUE; + } + else /* no specific 'prefix.hub.txt' than simply use the 'hub.txt' */ + { + safef(candidate, sizeof candidate, "%s/hub.txt", dirPath); + if (fileExists(candidate)) + { + *hubUrl = cloneString(candidate); + ret = TRUE; + } + } + } + +return ret; +} + + +// nibPath: hub:/gbdb/hs1/hubs - 'hs1' style +// nibPath: hub:/gbdb/genark/GCF/036/323/735/GCF_036323735.1 - GenArk style boolean hubConnectGetCuratedUrl(char *db, char **hubUrl) /* Check to see if this db is a curated hub and if so return its hubUrl */ { struct sqlConnection *conn = hConnectCentral(); char query[4096]; sqlSafef(query, sizeof query, "SELECT nibPath from %s where name = '%s' AND nibPath like '%s%%'", dbDbTable(), db, hubCuratedPrefix); char *dir = sqlQuickString(conn, query); boolean ret = !isEmpty(dir); hDisconnectCentral(&conn); if (hubUrl != NULL) // if user passed in hubUrl, calculate what it should be { *hubUrl = NULL; if (!isEmpty(dir)) // this is a curated hub { char *path = dir + sizeof(hubCuratedPrefix) - 1; char url[4096]; + safef(url, sizeof url, "%s/%s", path, getCuratedHubPrefix()); + if (isDirectory(url)) // 'hs1' style curated hub + { safef(url, sizeof url, "%s/%s/hub.txt", path,getCuratedHubPrefix()); *hubUrl = cloneString(url); } + else + { + if (genarkCurated(path, hubUrl)) + { + ret = TRUE; + } + } + } } return ret; } boolean hubConnectIsCurated(char *db) /* Look in the dbDb table to see if this hub is curated. */ { return hubConnectGetCuratedUrl(db, NULL); } static int lookForCuratedHubs(struct cart *cart, char *db, char *curatedHubPrefix) /* Check to see if db is a curated hub which will require the hub to be attached. * The variable curatedHubPrefix has the release to use (alpha, beta, public, or a user name ) */ { struct sqlConnection *conn = hConnectCentral(); char query[4096]; sqlSafef(query, sizeof query, "SELECT nibPath from %s where name = '%s' AND nibPath like '%s%%'", dbDbTable(), db, hubCuratedPrefix); char *dir = cloneString(sqlQuickString(conn, query)); hDisconnectCentral(&conn); if (!isEmpty(dir)) { char *path = &dir[sizeof hubCuratedPrefix - 1]; char urlBuf[4096]; + safef(urlBuf, sizeof urlBuf, "%s/%s", path, curatedHubPrefix); + char *url = NULL; + if (isDirectory(urlBuf)) // 'hs1' style curated hub + { safef(urlBuf, sizeof urlBuf, "%s/%s/hub.txt", path, curatedHubPrefix); - char *url = hReplaceGbdb(urlBuf); + url = hReplaceGbdb(urlBuf); + } + else // GenArk style curated hub + { + safef(urlBuf, sizeof urlBuf, "%s/%s.hub.txt", path, curatedHubPrefix); + if (fileExists(urlBuf)) + url = hReplaceGbdb(urlBuf); + else + { + safef(urlBuf, sizeof urlBuf, "%s/hub.txt", path); + url = hReplaceGbdb(urlBuf); + } + } 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); + /* For GenArk-style hubs the hub.txt names the genome by accession + * (e.g. GCF_036323735.1), not by the dbDb browser name (e.g. rn8). + * Use the actual genome name from the fetched hub so that the cart + * db matches what is registered in hubAssemblyHash. The genome + * name is already hub-decorated (hub__) at this + * point, so use it directly. + */ + char *genomeName = db; + if (status->trackHub && status->trackHub->genomeList) + genomeName = trackHubSkipHubName(status->trackHub->genomeList->name); + safef(buffer, sizeof buffer, "hub_%d_%s", status->id, genomeName); cartSetString(cart, "db", buffer); if (cgiOptionalString("db")) { /* user specified db on URL, we need to decorate and put it back. */ cgiVarSet("db", cloneString(buffer)); } return status->id; } else { - if (!isEmpty(status->errorMessage)) + if (status && isNotEmpty(status->errorMessage)) errAbort("Hub error: url %s: error %s.", url, status->errorMessage); else errAbort("Cannot open hub %s.", url); } } return 0; } static void portHubStatus(struct cart *cart) /* When a session has been saved on a different host it may have cart variables that reference hubStatus id's * that are different than what the local machine has. Look for these cases using the "assumesHub" cart variable * that maps id numbers to URL's. */ { char *assumesHubStr = cartOptionalString(cart, "assumesHub");