dcabcf3e37e0b1e3c71b6a98358c1fb844ca3b8a
braney
  Tue Apr 22 12:26:11 2025 -0700
sessions save a copy of the quickLift hub.

diff --git src/hg/lib/cart.c src/hg/lib/cart.c
index f139f6a88c8..3392bf80541 100644
--- src/hg/lib/cart.c
+++ src/hg/lib/cart.c
@@ -24,30 +24,31 @@
 #include "googleAnalytics.h"
 #include "wikiLink.h"
 #endif /* GBROWSE */
 #include "hgMaf.h"
 #include "hui.h"
 #include "geoMirror.h"
 #include "hubConnect.h"
 #include "trackHub.h"
 #include "cgiApoptosis.h"
 #include "customComposite.h"
 #include "regexHelper.h"
 #include "windowsToAscii.h"
 #include "jsonWrite.h"
 #include "verbose.h"
 #include "genark.h"
+#include "quickLift.h"
 
 static char *sessionVar = "hgsid";	/* Name of cgi variable session is stored in. */
 static char *positionCgiName = "position";
 
 DbConnector cartDefaultConnector = hConnectCart;
 DbDisconnect cartDefaultDisconnector = hDisconnectCart;
 static boolean cartDidContentType = FALSE;
 
 struct slPair *httpHeaders = NULL; // A list of headers to output before the content-type
 
 static void hashUpdateDynamicVal(struct hash *hash, char *name, void *val)
 /* Val is a dynamically allocated (freeMem-able) entity to put
  * in hash.  Override existing hash item with that name if any.
  * Otherwise make new hash item. */
 {
@@ -385,108 +386,130 @@
 {
 struct dyString *dy = dyStringNew(1024);
 int useCount;
 sqlDyStringPrintf(dy, "SELECT useCount FROM %s "
 	       "WHERE userName = '%s' AND sessionName = '%s';",
 	       namedSessionTable, encUserName, encSessionName);
 useCount = sqlQuickNum(conn, dy->string) + 1;
 dyStringClear(dy);
 sqlDyStringPrintf(dy, "UPDATE %s SET useCount = %d, lastUse=now() "
 	       "WHERE userName = '%s' AND sessionName = '%s';",
 	       namedSessionTable, useCount, encUserName, encSessionName);
 sqlUpdate(conn, dy->string);
 dyStringFree(&dy);
 }
 
-static void copyCustomComposites(struct cart *cart, struct hashEl *el)
+static void copyLocalHubs(struct cart *cart, struct hashEl *el)
 /* Copy a set of custom composites to a new hub file. Update the 
  * relevant cart variables. */
 {
 struct tempName hubTn;
 char *hubFileVar = el->name;
 char *oldHubFileName = el->val;
+if (startsWith(customCompositeCartName, el->name))
     trashDirDateFile(&hubTn, "hgComposite", "hub", ".txt");
+else if (startsWith(quickLiftCartName, el->name))
+    trashDirDateFile(&hubTn, "quickLift", "hub", ".txt");
 char *newHubFileName = cloneString(hubTn.forCgi);
 
 // let's make sure the hub hasn't been cleaned up
 int fd = open(oldHubFileName, O_RDONLY);
 if (fd < 0)
     {
     cartRemove(cart, hubFileVar);
     return;
     }
 
 close(fd);
 copyFile(oldHubFileName, newHubFileName);
 cartReplaceHubVars(cart, hubFileVar, oldHubFileName, newHubFileName);
 }
 
 void cartReplaceHubVars(struct cart *cart, char *hubFileVar, char *oldHubUrl, char *newHubUrl)
 /* Replace all cart variables corresponding to oldHubUrl (and/or its hub ID) with
  * equivalents for newHubUrl. */
 {
-if (! startsWith(customCompositeCartName, hubFileVar))
+if (! (startsWith(customCompositeCartName, hubFileVar) || startsWith(quickLiftCartName, hubFileVar) ))
     errAbort("cartReplaceHubVars: expected hubFileVar to begin with '"customCompositeCartName"' "
+             "or '"quickLiftCartName";"
              "but got '%s'", hubFileVar);
 char *errorMessage;
 unsigned oldHubId =  hubFindOrAddUrlInStatusTable(cart, oldHubUrl, &errorMessage);
 unsigned newHubId =  hubFindOrAddUrlInStatusTable(cart, newHubUrl, &errorMessage);
 
 // need to change hgHubConnect.hub.#hubNumber# (connected hubs)
 struct slPair *hv, *hubVarList = cartVarsWithPrefix(cart, hgHubConnectHubVarPrefix);
 char buffer[4096];
 for(hv = hubVarList; hv; hv = hv->next)
     {
     unsigned hubId = sqlUnsigned(hv->name + strlen(hgHubConnectHubVarPrefix));
     
     if (hubId == oldHubId)
         {
         cartRemove(cart, hv->name);
         safef(buffer, sizeof buffer, "%s%d", hgHubConnectHubVarPrefix, newHubId);
         cartSetString(cart, buffer, "1");
         }
     }
 
+// need to change "quickLift.#hubNumber#.#db# #quickLiftChainId#
+hubVarList = cartVarsWithPrefix(cart, "quickLift.");
+for(hv = hubVarList; hv; hv = hv->next)
+    {
+    char *hubPtr = cloneString(hv->name) + strlen("quickLift.");
+    char *db = strchr(hubPtr, '.'); 
+    *db++ = 0;
+    unsigned hubId = sqlUnsigned(hubPtr);
+    char *quickLiftChainId = cloneString(hv->val);
+    
+    if (hubId == oldHubId)
+        {
+        cartRemove(cart, hv->name);
+        safef(buffer, sizeof buffer, "%s%d.%s", "quickLift.", newHubId,db);
+        cartSetString(cart, buffer, quickLiftChainId);
+        }
+    }
+
 // need to change hub_#hubNumber#* (track visibilities)
 safef(buffer, sizeof buffer, "%s%d_", hubTrackPrefix, oldHubId);
 int oldNameLength = strlen(buffer);
 hubVarList = cartVarsWithPrefix(cart, buffer);
 for(hv = hubVarList; hv; hv = hv->next)
     {
     char *name = hv->name + oldNameLength;
     safef(buffer, sizeof buffer, "%s%d_%s", hubTrackPrefix, newHubId, name);
     cartSetString(cart, buffer, cloneString(hv->val));
     cartRemove(cart, hv->name);
     }
 
 // need to change hgtgroup_hub_#hubNumber# (blue bar open )
 // need to change expOrder_hub_#hubNumber#, simOrder_hub_#hubNumber# (sorting) -- values too
 
 // need to change trackHubs #hubNumber#   
 cartSetString(cart, hgHubConnectRemakeTrackHub, "on");
 cartSetString(cart, hubFileVar, newHubUrl);
 }
 
-void cartCopyCustomComposites(struct cart *cart)
+void cartCopyLocalHubs(struct cart *cart)
 /* Find any custom composite hubs and copy them so they can be modified. */
 {
 struct hashEl *el, *elList = hashElListHash(cart->hash);
 
 for (el = elList; el != NULL; el = el->next)
     {
-    if (startsWith(customCompositeCartName, el->name))
-        copyCustomComposites(cart, el);
+    if (startsWith(customCompositeCartName, el->name) || startsWith(quickLiftCartName, el->name))
+        copyLocalHubs(cart, el);
     }
 }
 
 static void storeInOldVars(struct cart *cart, struct hash *oldVars, char *var)
 /* Store all cart hash elements for var into oldVars (if it exists). */
 {
 if (oldVars == NULL)
     return;
 struct hashEl *hel = hashLookup(cart->hash, var);
 
 // NOTE: New cgi vars not in old cart cannot be distinguished from vars not newly set by cgi.
 //       Solution: Add 'empty' var to old vars for cgi vars not already in cart
 if (hel == NULL)
     hashAdd(oldVars, var, cloneString(CART_VAR_EMPTY));
 
@@ -1496,31 +1519,31 @@
             {
             warn("Unable to load session file: %s", dyMessage->string);
             }
 	didSessionLoad = ok;
         dyStringFree(&dyMessage);
 	}
     }
 #endif /* GBROWSE */
 
 /* wire up the assembly hubs so we can operate without sql */
 setUdcOptions(cart);
 if (cartVarExists(cart, hgHubDoDisconnect))
     doDisconnectHub(cart);
 
 if (didSessionLoad)
-    cartCopyCustomComposites(cart);
+    cartCopyLocalHubs(cart);
 
 char *newDatabase = hubConnectLoadHubs(cart);
 
 if (newDatabase != NULL)
     {
     char *cartDb = cartOptionalString(cart, "db");
 
     if ((cartDb == NULL) || differentString(cartDb, newDatabase))
         {
         // this is some magic to use the defaultPosition and reset cart variables
         if (oldVars)
             {
             struct hashEl *hel;
             if ((hel = hashLookup(oldVars,"db")) != NULL)
                 hel->val = "none";