8bf67a4375f3d5f15a109bea5a33a782c602fe67 braney Tue Mar 10 13:07:00 2026 -0700 hubCheck: warn about periods in track names refs #37223 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> diff --git src/hg/utils/hubCheck/hubCheck.c src/hg/utils/hubCheck/hubCheck.c index 65a6ef37a56..318507c9d9d 100644 --- src/hg/utils/hubCheck/hubCheck.c +++ src/hg/utils/hubCheck/hubCheck.c @@ -1094,30 +1094,43 @@ char *p; for (p = name; *p != '\0'; p++) { if (!isValidSeqNameChar(*p)) { warn("warning: sequence name '%s' in genome '%s' contains invalid character '%c' -" "only [A-Za-z0-9._-] are allowed. Consider using chromAlias for alternative names.", name, genomeName, *p); break; } } } slFreeList(&seqList); } +static void checkTrackNamesForDots(struct trackDb *tdbList) +/* Warn about track names containing periods before they get polished away. */ +{ +struct trackDb *tdb; +for (tdb = tdbList; tdb != NULL; tdb = tdb->next) + { + if (strchr(tdb->track, '.')) + warn("warning: track name \"%s\" contains a period which will be changed to an underscore. Periods in track names can cause problems with table browser filters. Consider using underscores instead.", tdb->track); + if (tdb->subtracks != NULL) + checkTrackNamesForDots(tdb->subtracks); + } +} + int hubCheckGenome(struct trackHub *hub, struct trackHubGenome *genome, struct trackHubCheckOptions *options, struct dyString *errors) /* Check out genome within hub. */ { struct errCatch *errCatch = errCatchNew(); struct trackDb *tdbList = NULL; int genomeErrorCount = 0; boolean openedGenome = FALSE; verbose(3, "checking genome %s\n", trackHubSkipHubName(genome->name)); if (errCatchStart(errCatch)) { if (genome->twoBitPath != NULL) { // check that twoBitPath is a valid file, warn instead of errAbort so we can continue checking @@ -1145,30 +1158,31 @@ char *groupsFile = genome->groups; if (groupsFile != NULL && !extFileExists(groupsFile)) warn("warning: '%s' groups file does not exist or is not accessible: '%s'", genome->name, groupsFile); char *htmlPath = hashFindVal(genome->settingsHash, "htmlPath"); if (htmlPath == NULL) warn("warning: missing htmlPath setting for assembly hub '%s'", genome->name); else if (!extFileExists(htmlPath)) warn("warning: '%s' htmlPath file does not exist or is not accessible: '%s'", genome->name, htmlPath); } boolean foundFirstGenome = FALSE; tdbList = trackHubTracksForGenome(hub, genome, NULL, &foundFirstGenome); tdbList = trackDbLinkUpGenerations(tdbList); tdbList = trackDbPolishAfterLinkup(tdbList, genome->name); + checkTrackNamesForDots(tdbList); trackHubPolishTrackNames(hub, tdbList); } errCatchEnd(errCatch); if (errCatch->gotError || errCatch->gotWarning) { openedGenome = TRUE; genomeErr(errors, errCatch->message->string, hub, genome, options->htmlOut); if (errCatch->gotError || !options->allowWarnings) genomeErrorCount += 1; } errCatchFree(&errCatch); verbose(2, "%d tracks in %s\n", slCount(tdbList), genome->name); struct trackDb *tdb; int tdbCheckVal;