ade26bcbd0927eaae0c456182a97877752c0eb4a
hiram
Wed Aug 12 16:23:05 2026 -0700
fixup the web page system to function properly with modern hub syntax and fixing bugs from code review refs #38005
diff --git src/hg/hubApi/hubApi.c src/hg/hubApi/hubApi.c
index 0c2b7a75203..979e8fa8725 100644
--- src/hg/hubApi/hubApi.c
+++ src/hg/hubApi/hubApi.c
@@ -254,76 +254,83 @@
/* print out a sample getData URL */
{
char errorPrint[2048];
errorPrint[0] = 0;
if (isNotEmpty(errorString))
{
safef(errorPrint, sizeof(errorPrint), " ERROR: %s", errorString);
}
boolean superChild = tdbIsSuperTrackChild(tdb);
char *genome = NULL;
if (hub)
genome = hub->genomeList->name;
+// tdb->track (and tdb->parent->track) carry the hub__ decoration;
+// display and outgoing URLs should show/use the name as it actually
+// appears in trackDb.txt. protectedTrack() below still needs the
+// decorated tdb->track, untouched, to recognize a hub track.
+char *trackName = trackHubSkipHubName(tdb->track);
+char *parentName = tdb->parent ? trackHubSkipHubName(tdb->parent->track) : NULL;
+
struct dyString *extraDyFlags = dyStringNew(128);
if (debug)
dyStringAppend(extraDyFlags, ";debug=1");
if (jsonOutputArrays)
dyStringAppend(extraDyFlags, ";jsonOutputArrays=1");
char *extraFlags = dyStringCannibalize(&extraDyFlags);
if (protectedTrack(db, tdb, tdb->track))
- hPrintf("%s : %s <protected data>\n", tdb->track, tdb->type);
+ hPrintf("%s : %s <protected data>\n", trackName, tdb->type);
else if (db)
{
if (hub)
{
char urlReference[2048];
- safef(urlReference, sizeof(urlReference), " (sample data)%s\n", urlPrefix, hub->url, genome, tdb->track, extraFlags, errorPrint);
+ safef(urlReference, sizeof(urlReference), " (sample data)%s\n", urlPrefix, hub->url, genome, trackName, extraFlags, errorPrint);
if (tdb->parent)
- hPrintf("%s: %s subtrack of parent: %s%s\n", tdb->track, tdb->type, tdb->parent->track, urlReference);
+ hPrintf("%s: %s subtrack of parent: %s%s\n", trackName, tdb->type, parentName, urlReference);
else
- hPrintf("%s: %s%s\n", tdb->track, tdb->type, urlReference);
+ hPrintf("%s: %s%s\n", trackName, tdb->type, urlReference);
}
else
{
char urlReference[2048];
- safef(urlReference, sizeof(urlReference), " (sample data)%s\n", urlPrefix, db, tdb->track, extraFlags, errorPrint);
+ safef(urlReference, sizeof(urlReference), " (sample data)%s\n", urlPrefix, db, trackName, extraFlags, errorPrint);
if (superChild)
- hPrintf("%s: %s superTrack child of parent: %s%s\n", tdb->track, tdb->type, tdb->parent->track, urlReference);
+ hPrintf("%s: %s superTrack child of parent: %s%s\n", trackName, tdb->type, parentName, urlReference);
else if (tdb->parent)
- hPrintf("%s: %s subtrack of parent: %s%s\n", tdb->track, tdb->type, tdb->parent->track, urlReference);
+ hPrintf("%s: %s subtrack of parent: %s%s\n", trackName, tdb->type, parentName, urlReference);
else
- hPrintf("%s: %s%s\n", tdb->track, tdb->type, urlReference );
+ hPrintf("%s: %s%s\n", trackName, tdb->type, urlReference );
}
}
else if (hub)
{
char urlReference[2048];
- safef(urlReference, sizeof(urlReference), " (sample data)%s\n", urlPrefix, hub->url, genome, tdb->track, extraFlags, errorPrint);
+ safef(urlReference, sizeof(urlReference), " (sample data)%s\n", urlPrefix, hub->url, genome, trackName, extraFlags, errorPrint);
if (tdb->parent)
- hPrintf("%s: %s subtrack of parent: %s%s\n", tdb->track, tdb->type, tdb->parent->track, urlReference);
+ hPrintf("%s: %s subtrack of parent: %s%s\n", trackName, tdb->type, parentName, urlReference);
else
- hPrintf("%s: %s%s\n", tdb->track, tdb->type, urlReference);
+ hPrintf("%s: %s%s\n", trackName, tdb->type, urlReference);
}
else
- hPrintf("%s : %s not db hub track ?\n", tdb->track, tdb->type);
+ hPrintf("%s : %s not db hub track ?\n", trackName, tdb->type);
}
static void hubSampleUrl(struct trackHub *hub, char *db, struct trackDb *tdb,
long chromCount, long itemCount, char *genome, char *errorString)
{
struct dyString *extraDyFlags = dyStringNew(128);
if (debug)
dyStringAppend(extraDyFlags, ";debug=1");
if (jsonOutputArrays)
dyStringAppend(extraDyFlags, ";jsonOutputArrays=1");
char *extraFlags = dyStringCannibalize(&extraDyFlags);
char errorPrint[2048];
errorPrint[0] = 0;
@@ -332,52 +339,56 @@
safef(errorPrint, sizeof(errorPrint), " : ERROR: %s", errorString);
}
char countsMessage[512];
countsMessage[0] = 0;
if (chromCount > 0 || itemCount > 0)
{
if (allowedBigBedType(tdb->type))
safef(countsMessage, sizeof(countsMessage), " : %ld chroms : %ld item count ", chromCount, itemCount);
else if (startsWithWord("bigWig", tdb->type))
safef(countsMessage, sizeof(countsMessage), " : %ld chroms : %ld bases covered ", chromCount, itemCount);
else
safef(countsMessage, sizeof(countsMessage), " : %ld chroms : %ld count ", chromCount, itemCount);
}
+// display and outgoing URLs get the name as it appears in trackDb.txt;
+// protectedTrack() below still needs the decorated tdb->track, untouched.
+char *trackName = trackHubSkipHubName(tdb->track);
+
if (protectedTrack(db, tdb, tdb->track))
- hPrintf(" %s: %s protected data\n", tdb->track, tdb->type);
+ hPrintf(" %s: %s protected data\n", trackName, tdb->type);
else if (isSupportedType(tdb->type))
{
char urlReference[2048];
- safef(urlReference, sizeof(urlReference), "(sample data)%s\n", urlPrefix, hub->url, genome, tdb->track, extraFlags, errorPrint);
+ safef(urlReference, sizeof(urlReference), "(sample data)%s\n", urlPrefix, hub->url, genome, trackName, extraFlags, errorPrint);
if (allowedBigBedType(tdb->type))
- hPrintf(" %s: %s%s%s\n", tdb->track, tdb->type, countsMessage, urlReference);
+ hPrintf(" %s: %s%s%s\n", trackName, tdb->type, countsMessage, urlReference);
else if (startsWithWord("bigWig", tdb->type))
- hPrintf(" %s: %s%s%s\n", tdb->track, tdb->type, countsMessage, urlReference);
+ hPrintf(" %s: %s%s%s\n", trackName, tdb->type, countsMessage, urlReference);
else
- hPrintf(" %s: %s%s%s\n", tdb->track, tdb->type, countsMessage, urlReference);
+ hPrintf(" %s: %s%s%s\n", trackName, tdb->type, countsMessage, urlReference);
}
else
{
if (allowedBigBedType(tdb->type))
- hPrintf(" %s: %s%s\n", tdb->track, tdb->type, countsMessage);
+ hPrintf(" %s: %s%s\n", trackName, tdb->type, countsMessage);
else if (startsWithWord("bigWig", tdb->type))
- hPrintf(" %s: %s%s\n", tdb->track, tdb->type, countsMessage);
+ hPrintf(" %s: %s%s\n", trackName, tdb->type, countsMessage);
else
- hPrintf(" %s: %s%s\n", tdb->track, tdb->type, countsMessage);
+ hPrintf(" %s: %s%s\n", trackName, tdb->type, countsMessage);
}
} /* static void hubSampleUrl(struct trackHub *hub, struct trackDb *tdb,
* long chromCount, long itemCount, char *genome)
*/
static void bbiLargestChrom(struct bbiChromInfo *chromList, char **chromName,
unsigned *chromSize)
/* find largest chromosome name and size in the chromList */
{
if (chromName && chromSize)
{
*chromSize = 0;
char *returnName = NULL;
struct bbiChromInfo *el;
for (el = chromList; el; el = el->next)
@@ -389,30 +400,40 @@
}
}
if (chromSize > 0)
*chromName = cloneString(returnName);
}
}
static int bbiBriefMeasure(char *type, char *bigDataUrl, char *bigDataIndex, long *chromCount, long *itemCount, struct dyString *errors, char **chromName, unsigned *chromSize)
/* check a bigDataUrl to find chrom count and item count, return
* name of largest chrom and its size
*/
{
int retVal = 0;
*chromCount = 0;
*itemCount = 0;
+if (isEmpty(bigDataUrl))
+ {
+ // a container/parent-level tdb (superTrack parent, view, etc. not
+ // already filtered out by the caller) has no bigDataUrl of its own --
+ // nothing to measure. Every bigFileOpen()/udcFileOpen() below assumes
+ // a non-NULL URL string and segfaults on NULL rather than erring out
+ // through the errCatch below, so this must be checked before any of it.
+ dyStringPrintf(errors, "no bigDataUrl to measure for type %s", type);
+ return 1;
+ }
struct errCatch *errCatch = errCatchNew();
if (errCatchStart(errCatch))
{
if (startsWithWord("bigNarrowPeak", type)
|| startsWithWord("bigBed", type)
|| startsWithWord("bigGenePred", type)
|| startsWithWord("bigPsl", type)
|| startsWithWord("bigDbSnp", type)
|| startsWithWord("bigMaf", type)
|| startsWithWord("bigChain", type)
|| startsWithWord("bigRmsk", type)
|| startsWithWord("bigBarChart", type)
|| startsWithWord("bigInteract", type))
{
struct bbiFile *bbi = NULL;
@@ -492,62 +513,67 @@
dyStringPrintf(errors, "%s", errCatch->message->string);
}
errCatchFree(&errCatch);
return retVal;
} /* static int bbiBriefMeasure() */
static void hubSubTracks(struct trackHub *hub, char *db, struct trackDb *tdb,
struct hash *countTracks, long chromCount, long itemCount,
char *chromName, unsigned chromSize, char *genome, char *errorString)
/* tdb has subtracks, show only subTracks, no details, this is RECURSIVE */
{
hPrintf(" \n");
if (debug)
{
- hPrintf(" - subtracks for '%s' db: '%s'
\n", tdb->track, db);
+ hPrintf(" - subtracks for '%s' db: '%s'
\n", trackHubSkipHubName(tdb->track), db);
hPrintf(" - chrom: '%s' size: %u
\n", chromName, chromSize);
}
if (tdb->subtracks)
{
struct trackDb *tdbEl = NULL;
for (tdbEl = tdb->subtracks; tdbEl; tdbEl = tdbEl->next)
{
- boolean compositeContainer = tdbIsComposite(tdbEl);
- boolean compositeView = tdbIsCompositeView(tdbEl);
- if (! (compositeContainer || compositeView) )
+ // display name as it appears in trackDb.txt; tdbEl->track itself
+ // stays decorated for hashCountTrack()/recursive calls below
+ char *tdbElName = trackHubSkipHubName(tdbEl->track);
+ char *tdbElParentName = tdbEl->parent ? trackHubSkipHubName(tdbEl->parent->track) : NULL;
+ // trackHasData() also excludes tdbIsContainer() (e.g. 'container
+ // multiWig'), which has no bigDataUrl of its own -- its data comes
+ // from its children.
+ if (trackHasData(tdbEl))
{
char *bigDataIndex = NULL;
char *relIdxUrl = trackDbSetting(tdbEl, "bigDataIndex");
if (relIdxUrl != NULL)
bigDataIndex = trackHubRelativeUrl(hub->genomeList->trackDbFile, relIdxUrl);
char *bigDataUrl = trackDbSetting(tdbEl, "bigDataUrl");
char *longName = NULL;
unsigned longSize = 0;
struct dyString *errors = dyStringNew(1024);
(void) bbiBriefMeasure(tdbEl->type, bigDataUrl, bigDataIndex, &chromCount, &itemCount, errors, &longName, &longSize);
chromSize = longSize;
chromName = longName;
}
if (tdbIsCompositeView(tdbEl))
- hPrintf("- %s: %s : composite view of parent: %s
\n", tdbEl->track, tdbEl->type, tdbEl->parent->track);
+ hPrintf("- %s: %s : composite view of parent: %s
\n", tdbElName, tdbEl->type, tdbElParentName);
else
{
if (isSupportedType(tdbEl->type))
hubSampleUrl(hub, db, tdbEl, chromCount, itemCount, genome, errorString);
else
- hPrintf("- %s: %s : subtrack of parent: %s
\n", tdbEl->track, tdbEl->type, tdbEl->parent->track);
+ hPrintf("- %s: %s : subtrack of parent: %s
\n", tdbElName, tdbEl->type, tdbElParentName);
}
hashCountTrack(tdbEl, countTracks);
if (tdbEl->subtracks)
hubSubTracks(hub, db, tdbEl, countTracks, chromCount, itemCount, chromName, chromSize, genome, errorString);
}
}
hPrintf("
\n");
} /* hubSubTracks() */
static void showSubTracks(struct trackHub *hub, char *db, struct trackDb *tdb, struct hash *countTracks,
char *chromName, unsigned chromSize, char *errorString)
/* tdb has subtracks, show only subTracks, no details */
{
hPrintf(" \n");
if (debug)
@@ -604,102 +630,109 @@
else if (protectedData && sameWord("bigDataUrl", hel->name))
hPrintf(" - bigDataUrl: <protected data>
\n");
else if (isEmpty((char *)hel->val))
hPrintf(" - %s: <empty>
\n", hel->name);
else
hPrintf(" - %s: '%s'
\n", hel->name, (char *)hel->val);
}
if (tdb->subtracks)
{
struct trackDb *tdbEl = NULL;
if (debug)
hPrintf(" - has %d subtrack(s)
\n", slCount(tdb->subtracks));
for (tdbEl = tdb->subtracks; tdbEl; tdbEl = tdbEl->next)
{
- hPrintf("- subtrack: %s of parent: %s : type: '%s' (TBD: sample data)
\n", tdbEl->track, tdbEl->parent->track, tdbEl->type);
+ hPrintf("- subtrack: %s of parent: %s : type: '%s' (TBD: sample data)
\n", trackHubSkipHubName(tdbEl->track), trackHubSkipHubName(tdbEl->parent->track), tdbEl->type);
hashCountTrack(tdbEl, countTracks);
trackSettings(db, tdbEl, countTracks);
}
}
hPrintf("
\n");
}
static void hubCountOneTdb(struct trackHub *hub, char *db, struct trackDb *tdb,
char *bigDataIndex, struct hash *countTracks, char *chromName,
unsigned chromSize, char *genome)
{
char *bigDataUrl = trackDbSetting(tdb, "bigDataUrl");
boolean compositeContainer = tdbIsComposite(tdb);
boolean compositeView = tdbIsCompositeView(tdb);
boolean superChild = tdbIsSuperTrackChild(tdb);
boolean depthSearch = cartUsualBoolean(cart, "depthSearch", FALSE);
hashCountTrack(tdb, countTracks);
long chromCount = 0;
long itemCount = 0;
struct dyString *errors = dyStringNew(1024);
/* if given a chromSize, it belongs to a UCSC db and this is *not* an
* assembly hub, otherwise, look up a chrom and size in the bbi file
+ * trackHasData() also excludes tdbIsContainer() (e.g. 'container multiWig'),
+ * which has no bigDataUrl of its own -- its data comes from its children.
*/
-if (! (compositeContainer || compositeView) )
+if (trackHasData(tdb))
{
if (chromSize < 1 || depthSearch)
{
char *longName = NULL;
unsigned longSize = 0;
(void) bbiBriefMeasure(tdb->type, bigDataUrl, bigDataIndex, &chromCount, &itemCount, errors, &longName, &longSize);
chromSize = longSize;
chromName = longName;
}
}
+// display name as it appears in trackDb.txt; tdb->track itself stays
+// decorated for hashCountTrack()/protectedTrack()/recursive calls
+char *trackName = trackHubSkipHubName(tdb->track);
+char *parentName = tdb->parent ? trackHubSkipHubName(tdb->parent->track) : NULL;
+
if (depthSearch && bigDataUrl)
{
if (isSupportedType(tdb->type))
hubSampleUrl(hub, db, tdb, chromCount, itemCount, genome, errors->string);
}
else
{
if (compositeContainer)
- hPrintf(" %s: %s : composite track container has %d subtracks\n", tdb->track, tdb->type, slCount(tdb->subtracks));
+ hPrintf(" %s: %s : composite track container has %d subtracks\n", trackName, tdb->type, slCount(tdb->subtracks));
else if (compositeView)
- hPrintf(" %s: %s : composite view of parent: %s\n", tdb->track, tdb->type, tdb->parent->track);
+ hPrintf(" %s: %s : composite view of parent: %s\n", trackName, tdb->type, parentName);
else if (superChild)
{
if (isSupportedType(tdb->type))
hubSampleUrl(hub, db, tdb, chromCount, itemCount, genome, errors->string);
else
- hPrintf(" %s: %s : superTrack child of parent: %s\n", tdb->track, tdb->type, tdb->parent->track);
+ hPrintf(" %s: %s : superTrack child of parent: %s\n", trackName, tdb->type, parentName);
}
else if (! depthSearch && bigDataUrl)
{
if (isSupportedType(tdb->type))
{
hubSampleUrl(hub, db, tdb, chromCount, itemCount, genome, errors->string);
}
}
else
{
if (isSupportedType(tdb->type))
{
hubSampleUrl(hub, db, tdb, chromCount, itemCount, genome, errors->string);
}
else
- hPrintf(" %s: %s (what is this)\n", tdb->track, tdb->type);
+ hPrintf(" %s: %s (what is this)\n", trackName, tdb->type);
}
}
if (allTrackSettings)
{
hPrintf(" \n");
trackSettings(db, tdb, countTracks); /* show all settings */
hPrintf("
\n");
}
else if (tdb->subtracks)
{
hubSubTracks(hub, db, tdb, countTracks, chromCount, itemCount, chromName, chromSize, genome, errors->string);
}
return;
} /* static void hubCountOneTdb(char *db, struct trackDb *tdb,
* char *bigDataIndex, struct hash *countTracks,
@@ -792,31 +825,37 @@
/* process the track list in a hub to show all tracks */
{
hPrintf(" \n");
if (topTrackDb)
{
struct hash *countTracks = hashNew(0);
struct trackDb *tdb = NULL;
for ( tdb = topTrackDb; tdb; tdb = tdb->next )
{
char *bigDataIndex = NULL;
char *relIdxUrl = trackDbSetting(topTrackDb, "bigDataIndex");
if (relIdxUrl != NULL)
bigDataIndex = trackHubRelativeUrl(genome->trackDbFile, relIdxUrl);
char *defaultGenome = NULL;
if (isNotEmpty(genome->name))
- defaultGenome = genome->name;
+ // genome->name is hub__ decorated for assembly hub genomes
+ // (anything with twoBitPath); strip it here so defaultGenome
+ // matches what every other consumer (list.c) passes around --
+ // otherwise protectedTrack() re-decorates an already-decorated
+ // name to hub__hub__ and hAllocConn() on that
+ // aborts with "Unknown database"
+ defaultGenome = trackHubSkipHubName(genome->name);
char *chromName = NULL;
unsigned chromSize = 0;
int chromCount = 0;
if (isEmpty(genome->twoBitPath))
chromSize = largestChrom(defaultGenome, &chromName, &chromCount);
hubCountOneTdb(hub, defaultGenome, tdb, bigDataIndex, countTracks, chromName, chromSize, defaultGenome);
if (timeOutReached())
break;
} /* for ( tdb = topTrackDb; tdb; tdb = tdb->next ) */
hPrintf(" - %d different track types
\n",countTracks->elCount - 1);
/* add this single genome count to the overall multi-genome counts */
if (countTracks->elCount)
{
hPrintf(" \n");
struct hashEl *hel, *helList = hashElListHash(countTracks);
@@ -911,46 +950,53 @@
hPrintf("\n", urlPrefix, hubTop->url);
if (NULL == genome)
{
hPrintf("odd error, can not find a genomeList ? at url: '%s'
\n", hubTop->url);
return;
}
hPrintf("\n");
long lastTime = clock1000();
for ( ; genome; genome = genome->next )
{
++totalAssemblyCount;
char urlReference[2048];
+ // genome->name and genome->organism carry the hub__ decoration for
+ // assembly hub genomes (trackHub.c addHubName()); display and outgoing
+ // links should show/use the name as it actually appears in genomes.txt.
+ // trackHubAllChromInfo()/trackHubGetGenome() lookups still need the
+ // decorated genome->name, untouched, to find the genome in hubAssemblyHash.
+ char *displayGenome = trackHubSkipHubName(genome->name);
+ char *displayOrganism = trackHubSkipHubName(genome->organism);
if (isNotEmpty(genome->twoBitPath))
{
- hPrintf("- Assembly genome '%s' twoBitPath: '%s'
\n", genome->name, genome->twoBitPath);
+ hPrintf("- Assembly genome '%s' twoBitPath: '%s'
\n", displayGenome, genome->twoBitPath);
char *chromName = NULL;
struct chromInfo *ci = trackHubAllChromInfo(genome->name);
unsigned chromSize = largestChromInfo(ci, &chromName);
char sizeString[64];
sprintLongWithCommas(sizeString, chromSize);
hPrintf("- Sequence count %d, largest: %s at %s bases
\n", slCount(ci), chromName, sizeString);
- safef(urlReference, sizeof(urlReference), " JSON example sequence output: %s:%u-%u", urlPrefix, hubTop->url, genome->name, chromName, chromSize/4, (chromSize/4)+128, chromName, chromSize/4, (chromSize/4)+128);
+ safef(urlReference, sizeof(urlReference), " JSON example sequence output: %s:%u-%u", urlPrefix, hubTop->url, displayGenome, chromName, chromSize/4, (chromSize/4)+128, chromName, chromSize/4, (chromSize/4)+128);
hPrintf("- %s
\n", urlReference);
}
- safef(urlReference, sizeof(urlReference), " JSON example list tracks output", urlPrefix, hubTop->url, genome->name, trackLeavesOnly ? ";trackLeavesOnly=1" : "");
+ safef(urlReference, sizeof(urlReference), " JSON example list tracks output", urlPrefix, hubTop->url, displayGenome, trackLeavesOnly ? ";trackLeavesOnly=1" : "");
hPrintf("- %s
\n", urlReference);
- hubInfo("organism", genome->organism);
- hubInfo("name", genome->name);
+ hubInfo("organism", displayOrganism);
+ hubInfo("name", displayGenome);
hubInfo("description", genome->description);
hubInfo("groups", genome->groups);
hubInfo("defaultPos", genome->defaultPos);
hubInfo("trackDbFile", genome->trackDbFile);
hubAssemblySettings(hubTop, genome);
struct trackDb *tdbList = obtainTdb(genome, NULL);
hubTrackList(hubTop, tdbList, genome);
if (measureTiming)
{
long thisTime = clock1000();
hPrintf("- processing time %s: %ld millis
\n", genome->name, thisTime - lastTime);
hPrintf("
\n");
}
if (timeOutReached())
break;