992aeef92fea7be25a2acd916578898649212a32 braney Mon Sep 7 11:31:07 2026 -0700 quickLift: gate the alignment lift behind an hg.conf flag, refs #38249 Add browser.quickLiftAlignments, default FALSE, so the alignment lift ships dark and a machine turns it on with browser.quickLiftAlignments=on. It sits beside browser.quickLift, the gate on the rest of the feature. quickLiftAlignmentsEnabled() in hg/lib/quickLift.c is the one read, and validateOneTdb in hg/lib/trackHub.c is the one place that asks it, before an alignment track may enter a quickLift hub. That is the only door: quickLiftUrl and quickLiftDb, the pair every lift path keys off, are written by the quickLift hub writer and by nothing else, so with the flag off an alignment track never gets them and the lifting, drawing and details code behind them cannot be reached. pslTrack.c, chainTrack.c, wigMafTrack.c, bigBedTrack.c and hgc.c are unchanged. With the flag off hgConvert lists psl, bigPsl, chain, bigChain, maf, bigMaf and wigMaf tracks in its "type is not supported by QuickLift" table, which is what it did before this work. A hub built while the flag was on keeps working after it is turned off, since its stanzas are already in the hub file in trash, so this holds the feature back from people who have not used it rather than switching off a session that has. Read the hg.conf half with a literal cfgOptionBooleanDefault rather than cartOrCfgOption so harvestHgConf.py can see it; a cart variable of the same name still overrides it. Register the flag in hgConfCatalog.py with role="gate" so the sunset report tracks it, and turn it on in confs/hgwdev.hg.conf. diff --git src/hg/lib/trackHub.c src/hg/lib/trackHub.c index c5138f21acc..7daa2c8f8a9 100644 --- src/hg/lib/trackHub.c +++ src/hg/lib/trackHub.c @@ -1923,54 +1923,65 @@ dyStringPrintf(dy, "track %s\nquickLifted on\n", track); if (tdbIsSuperTrack(tdb)) { dyStringPrintf(dy, "superTrack on show\n"); } if (!isVetted(track)) dyStringPrintf(dy, "avoidHandler on\n"); dumpTdbAndChildren(cart, dy, tdb); return dy; } -static boolean validateOneTdb(char *db, struct trackDb *tdb, struct trackDb **badList) +static boolean isAlignmentType(char *type) +/* The alignment types quickLift can lift. These are newer than the rest of quickLift and + * are gated in hg.conf, so quickLiftAlignmentsEnabled decides whether one may enter the + * hub. This is the only door: quickLiftUrl and quickLiftDb, the pair every lift path + * keys off, are written by the quickLift hub writer and by nothing else. */ +{ +// trackDb types are matched without regard to case since that's how the rest of the +// browser reads them (some trackDb stanzas say "bigbed" rather than "bigBed"). +return startsWithNoCase("bigPsl", type) || + startsWithNoCase("bigChain", type) || + startsWithNoCase("bigMaf", type) || + startsWithNoCase("wigMaf", type) || + sameWord("chain", type) || + startsWithNoCase("chain ", type) || + sameWord("psl", type) || + startsWithNoCase("psl ", type); +} + +static boolean validateOneTdb(struct cart *cart, char *db, struct trackDb *tdb, struct trackDb **badList) /* Make sure the tdb is a track type we grok. badList may be NULL to validate * silently (no user-facing complaint about non-liftable types). */ { // trackDb types are matched without regard to case since that's how the rest of the // browser reads them (some trackDb stanzas say "bigbed" rather than "bigBed"). if (sameString("cytoBandIdeo", trackHubSkipHubName(tdb->track)) || !( startsWithNoCase("bigBed", tdb->type) || \ startsWithNoCase("bigWig", tdb->type) || \ startsWithNoCase("bigDbSnp", tdb->type) || \ startsWithNoCase("bigGenePred", tdb->type) || \ startsWithNoCase("gvf", tdb->type) || \ startsWithNoCase("genePred", tdb->type) || \ startsWithNoCase("narrowPeak", tdb->type) || \ startsWithNoCase("broadPeak", tdb->type) || \ startsWithNoCase("bigLolly", tdb->type) || \ - startsWithNoCase("bigPsl", tdb->type) || \ - startsWithNoCase("bigChain", tdb->type) || \ - startsWithNoCase("bigMaf", tdb->type) || \ - startsWithNoCase("wigMaf", tdb->type) || \ - sameWord("chain", tdb->type) || - startsWithNoCase("chain ", tdb->type) || - sameWord("psl", tdb->type) || - startsWithNoCase("psl ", tdb->type) || + (isAlignmentType(tdb->type) && quickLiftAlignmentsEnabled(cart)) || \ sameWord("bed", tdb->type) || startsWithNoCase("bed ", tdb->type))) { if (badList != NULL) slAddHead(badList, tdb); return FALSE; } // make sure we have a bigDataUrl if (startsWithNoCase("bigBed", tdb->type) || \ startsWithNoCase("bigPsl", tdb->type) || \ startsWithNoCase("bigChain", tdb->type) || \ startsWithNoCase("bigMaf", tdb->type) || \ startsWithNoCase("bigWig", tdb->type)) { @@ -2007,58 +2018,58 @@ { slAddHead(&validTdbs, view); if (view->visibility) count++; } } } else { for(; tdb; tdb = nextTdb) { nextTdb = tdb->next; boolean visible = isParentVisible(cart, tdb) && isSubtrackVisible(cart, tdb); // Lift all siblings of a visible subtrack, but only complain about // non-liftable ones the user actually asked for (visible ones). - if (validateOneTdb(db, tdb, visible ? badList : NULL)) + if (validateOneTdb(cart, db, tdb, visible ? badList : NULL)) { slAddHead(&validTdbs, tdb); if (visible) count++; } } } if (count) return validTdbs; return NULL; } static boolean validateTdb(struct cart *cart, char *db, struct trackDb *tdb, struct trackDb **badList) // make sure we only output track types that can // be quickLifted. Return true if we any tracks survive { if (tdb->subtracks) { tdb->subtracks = validateTdbChildren(cart, db, tdb->subtracks, badList); if (tdb->subtracks == NULL) return FALSE; return TRUE; } -return validateOneTdb(db, tdb, badList); +return validateOneTdb(cart, db, tdb, badList); } static void outTrack(struct dyString *out, struct cart *cart, struct trackDb *tdb, double priority) /* Set priority and output track to hub. */ { char buffer[1024]; safef(buffer, sizeof buffer, "%g", priority); hashReplace(tdb->settingsHash, "priority", cloneString(buffer)); struct dyString *dy = trackDbString(cart, tdb); dyStringPrintf(out, "%s\n", dy->string); dyStringFree(&dy); }