547bbe0a4ad38df6b0b7a511d6a2ce24b3625fe7
max
Thu Sep 17 05:08:41 2026 -0700
hubtools import session: keep the track order of the session, refs #34405
#Preview2 week - bugs introduced now will need a build patch to fix
The custom track backup archive has one file per track and no ordering
information: hgSession wrote the files into a directory and tar walks it in
readdir order, which is not the order they were written. hubtools globbed
them, and a hub track without a priority is shown in alphabetical order of
its label, so an imported session came out sorted by label.
hgSession now writes the priority hgTracks orders the tracks by into each
track line of the archive, either the one the browser assigned when it
loaded the track or the cart variable that a drag-and-drop reorder left
behind. A track line that names its own priority is left alone. hubtools
sorts on that priority and numbers the hub stanzas, continuing the count
across assemblies so two genome stanzas cannot interleave. Archives made
before this have no priority and fall back to file name order.
diff --git src/hg/hgSession/backup.c src/hg/hgSession/backup.c
index aceba145466..b01efebecf3 100644
--- src/hg/hgSession/backup.c
+++ src/hg/hgSession/backup.c
@@ -921,30 +921,50 @@
struct wiggleDataStream *wds = NULL;
int operations = wigFetchAscii;
operations = wigFetchAscii;
wds = wiggleDataStreamNew();
wds->getData(wds, database, table, operations);
wds->asciiOut(wds, database, outFile, TRUE, FALSE);
wiggleDataStreamFree(&wds);
}
+static boolean trackLineHasSetting(char *trackLine, char *setting)
+/* Does the var=value list of a custom track line set this variable? Parses a copy,
+ * hashVarLine() chops up the line it is given. */
+{
+char *copy = cloneString(trackLine);
+char *pLine = copy;
+nextWord(&pLine);
+pLine = skipLeadingSpaces(pLine);
+if (isEmpty(pLine)) // a bare "track" line sets nothing
+ {
+ freeMem(copy);
+ return FALSE;
+ }
+struct hash *vars = hashVarLine(pLine, 1);
+boolean gotIt = (hashFindVal(vars, setting) != NULL);
+freeHashAndVals(&vars);
+freeMem(copy);
+return gotIt;
+}
+
void makeDownloadSessionCtData(char *param1, char *backgroundProgress)
/* Download tables and data to save save in compressed archive. */
{
char query[512];
char **row = NULL;
struct sqlResult *sr = NULL;
// Initialize .progress channel file
struct dyString *dyProg = dyStringNew(256);
dyStringPrintf(dyProg, "please wait, dumping data to archive ...
\n");
updateProgessFile(backgroundProgress, dyProg);
lazarusLives(20 * 60);
htmlOpen("Preparing Custom Tracks Backup Archive for Download");
@@ -1083,30 +1103,45 @@
dyStringPrintf(dyProg, "%s
\n", extra->name);
updateProgessFile(backgroundProgress, dyProg);
lazarusLives(20 * 60);
char outNameCt[2014];
safef(outNameCt, sizeof outNameCt, "%s/%s.ct", outDbDir, extra->name);
FILE *fct = mustOpen(outNameCt, "w");
// write the track header
if (extra->browserLines)
fprintf(fct, "%s", extra->browserLines); // should have ; converted \n already
if (!extra->trackLine)
errAbort("origTrackLine is NULL!");
+ // The archive holds one file per track and tar walks the directory in
+ // whatever order the file system hands out, so the order of the session
+ // is lost unless the track line itself carries it. The original track
+ // line rarely has a priority, the one hgTracks orders the tracks by
+ // does, so write that one out with it: the tdb priority the browser
+ // assigned when it loaded the track, or the cart variable that a
+ // drag-and-drop reorder left behind. A track line that names its own
+ // priority is left alone, the user asked for that one. A reader that
+ // does not care about the order is unaffected, priority is optional.
+ char prioVar[256];
+ safef(prioVar, sizeof prioVar, "%s.priority", track->tdb->track);
+ double priority = cartUsualDouble(cart, prioVar, track->tdb->priority);
+ if (priority != 0 && !trackLineHasSetting(extra->trackLine, "priority"))
+ fprintf(fct, "%s priority='%g'\n", extra->trackLine, priority);
+ else
fprintf(fct, "%s\n", extra->trackLine);
if (!extra->bigDataUrl)
{
// handle wiggle cts which have an additional wig binary
// wibFile='../trash/ct/hgtct_genome_542_dc1750.wib'
// wibFile='../trash/ct/ct_hgwdev_galt_e83f_3892d0.maf'
// wibFile='../trash/ct/ct_hgwdev_galt_4ba3_415cc0.vcf'
// symlink for speed, file should not change
if (track->wibFile)
{
if (endsWith(track->wibFile, ".wib"))
{