cdb3401bc60e54dae514885304914b5cd70c45ae braney Fri Aug 7 12:07:40 2026 -0700 quickLift: keep the source track order on the target, refs #38032 The hub writer replaced each track's priority with a counter handed out in walk order. The hub file is appended to across requests, and new tracks started after the highest priority already in the file, so a track added in a later request always sorted below one added earlier no matter where it sat on the source. Carry the source priority across instead. The group setting already survives into the hub, so the target orders within a group on the same key the source does. The append-after-existing bookkeeping is no longer needed. diff --git src/hg/lib/trackHub.c src/hg/lib/trackHub.c index 16b1bc56204..7f058529ffa 100644 --- src/hg/lib/trackHub.c +++ src/hg/lib/trackHub.c @@ -1970,153 +1970,140 @@ // 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); } -static void outTrack(FILE *f, struct cart *cart, struct trackDb *tdb, unsigned priority) +static void outTrack(FILE *f, struct cart *cart, struct trackDb *tdb) /* Set priority and output track to hub. */ { char buffer[1024]; -safef(buffer, sizeof buffer, "%d", priority); +// Carry the source priority across rather than handing out a counter in walk order. +// The hub file is appended to across requests, so a counter ordered the target by the +// request a track happened to be added in instead of by how the source was laid out. +safef(buffer, sizeof buffer, "%g", tdb->priority); hashReplace(tdb->settingsHash, "priority", cloneString(buffer)); struct dyString *dy = trackDbString(cart, tdb); fprintf(f, "%s\n", dy->string); } static boolean checkCartVisibility(struct cart *cart, struct trackDb *tdb) { char *cartVis = cartOptionalString(cart, tdb->track); if (cartVis != NULL) tdb->visibility = hTvFromString(cartVis); return (tdb->visibility != tvHide); } static boolean isFromQuickLiftHub(struct trackDb *tdb) /* True if this tdb came from a quickLift hub (already a lifted shadow track). * Such tracks must not be lifted again. */ { return trackDbSetting(tdb, "quickLiftUrl") != NULL || trackDbSetting(tdb, "quickLifted") != NULL; } -static void walkTree(FILE *f, char *db, struct cart *cart, struct trackDb *tdb, struct dyString *visDy, struct trackDb **badList, struct hash *existingTracks, unsigned startPriority) +static void walkTree(FILE *f, char *db, struct cart *cart, struct trackDb *tdb, struct dyString *visDy, struct trackDb **badList, struct hash *existingTracks) /* walk tree looking for visible tracks to output to hub. Skip tracks that already * came from a quickLift hub, and skip tracks whose name is already present in * the existing hub file. */ { -unsigned priority = startPriority; struct hash *haveSuper = newHash(0); struct trackDb *tdbNext = NULL; for(; tdb; tdb = tdbNext) { tdbNext = tdb->next; if (isFromQuickLiftHub(tdb)) continue; if (existingTracks != NULL && hashLookup(existingTracks, trackHubSkipHubName(tdb->track)) != NULL) continue; boolean isVisible = FALSE; if (tdb->parent == NULL) isVisible = checkCartVisibility(cart, tdb); else if (isParentVisible(cart, tdb) && isSubtrackVisible(cart, tdb)) // child of supertrack { if (hashLookup(haveSuper, tdb->parent->track) == NULL) // output yet? { //if (checkCartVisibility(cart, tdb->parent)) { char *bareParent = trackHubSkipHubName(tdb->parent->track); if (existingTracks == NULL || hashLookup(existingTracks, bareParent) == NULL) { tdb->parent->visibility = hTvFromString("tvShow"); - outTrack(f, cart, tdb->parent, priority++); + outTrack(f, cart, tdb->parent); } hashStore(haveSuper, tdb->parent->track); } } isVisible = checkCartVisibility(cart, tdb); } if (isVisible && validateTdb(cart, db, tdb, badList)) { hashRemove(tdb->settingsHash, "superTrack"); // this gets inherited by subTracks(?) // is this a custom track? char *tdbType = trackDbSetting(tdb, "tdbType"); if (tdbType != NULL) { hashReplace(tdb->settingsHash, "type", tdbType); hashReplace(tdb->settingsHash, "shortLabel", trackDbSetting(tdb, "name")); hashReplace(tdb->settingsHash, "longLabel", trackDbSetting(tdb, "description")); } - outTrack(f, cart, tdb, priority++); + outTrack(f, cart, tdb); } } } -static void readExistingHubTracks(char *filename, struct hash *trackNames, unsigned *retMaxPriority) +static void readExistingHubTracks(char *filename, struct hash *trackNames) /* Scan an existing quickLift hub file and populate trackNames with the set of - * track names already present. Also returns the highest priority value seen - * (0 if the file has no track stanzas yet) so new tracks can be appended after - * existing ones. */ + * track names already present. */ { -unsigned maxPriority = 0; struct lineFile *lf = lineFileMayOpen(filename, TRUE); if (lf != NULL) { char *line; while (lineFileNextReal(lf, &line)) { if (startsWithWord("track", line)) { char *name = skipLeadingSpaces(line + 5); if (isNotEmpty(name)) hashStoreName(trackNames, cloneString(firstWordInLine(name))); } - else if (startsWithWord("priority", line)) - { - char *val = skipLeadingSpaces(line + 8); - if (isNotEmpty(val)) - { - unsigned p = sqlUnsigned(firstWordInLine(val)); - if (p > maxPriority) - maxPriority = p; - } - } } lineFileClose(&lf); } -if (retMaxPriority != NULL) - *retMaxPriority = maxPriority; } static int cmpPriority(const void *va, const void *vb) /* Compare to sort based on priority; use shortLabel as secondary sort key. */ { const struct trackDb *a = *((struct trackDb **)va); const struct trackDb *b = *((struct trackDb **)vb); float dif = 0; dif = a->groupPriority - b->groupPriority; if (dif == 0) dif = a->priority - b->priority; if (dif < 0) return -1; else if (dif == 0.0) @@ -2139,40 +2126,39 @@ struct hash *groupHash = newHash(0); struct grp *grp; for(grp = grpList; grp; grp = grp->next) hashAdd(groupHash, grp->name, grp); for(tdb = tdbList; tdb; tdb = tdb->next) { grp = hashFindVal(groupHash, tdb->grp); tdb->groupPriority = grp->priority; } slSort(&tdbList, cmpPriority); char *filename = getHubName(cart, db); struct hash *existingTracks = newHash(8); -unsigned maxPriority = 0; -readExistingHubTracks(filename, existingTracks, &maxPriority); +readExistingHubTracks(filename, existingTracks); boolean hubExists = (hashNumEntries(existingTracks) > 0); FILE *f = mustOpen(filename, hubExists ? "a" : "w"); chmod(filename, 0666); if (!hubExists) outHubHeader(f, trackHubSkipHubName(db)); -walkTree(f, db, cart, tdbList, visDy, badList, existingTracks, maxPriority + 1); +walkTree(f, db, cart, tdbList, visDy, badList, existingTracks); fclose(f); return cloneString(filename); } struct grp *trackHubGetGrps() /* Get the groups defined by attached track hubs. */ { return trackHubGrps; } struct trackDb *trackHubAddTracksGenome(struct trackHubGenome *hubGenome) /* Load up stuff from data hub and return list. */ { /* Load trackDb.ra file and make it into proper trackDb tree */