23b10b9fed9b850a60b7f601c6275811caa812e6
angie
  Mon Dec 3 11:43:50 2018 -0800
Don't reuse trash files where it can be avoided -- make new cart files when there are changes, so that we don't have to copy files every time we save or load a session.  refs #22440

diff --git src/hg/hgSession/hgSession.c src/hg/hgSession/hgSession.c
index cb33190..59f5ac6 100644
--- src/hg/hgSession/hgSession.c
+++ src/hg/hgSession/hgSession.c
@@ -809,33 +809,32 @@
     cleanHgSessionFromCart(cart);
     struct dyString *encoded = newDyString(4096);
     cartEncodeState(cart, encoded);
 
     // Now add all the default visibilities to output.
     outDefaultTracks(cart, encoded);
 
     sqlDyAppendEscaped(dy, encoded->string);
     dyStringFree(&encoded);
     dyStringAppend(dy, "', ");
     dyStringPrintf(dy, "%d, ", (shareSession ? 1 : 0));
     dyStringPrintf(dy, "%s, now(), %d, '');", firstUse, useCount);
     sqlUpdate(conn, dy->string);
     dyStringFree(&dy);
 
-    /* Prevent modification of custom tracks just saved to namedSessionDb: */
+    /* Prevent modification of custom track collections just saved to namedSessionDb: */
     cartCopyCustomComposites(cart);
-    cartCopyCustomTracks(cart);
 
     if (useCount > INITIAL_USE_COUNT)
 	dyStringPrintf(dyMessage,
 	  "Overwrote the contents of session <B>%s</B> "
 	  "(that %s be shared with other users).  "
 	  "%s %s",
 	  htmlEncode(sessionName), (shareSession ? "may" : "may not"),
 	  getSessionLink(encUserName, encSessionName),
 	  getSessionEmailLink(encUserName, encSessionName));
     else
 	dyStringPrintf(dyMessage,
 	  "Added a new session <B>%s</B> that %s be shared with other users.  "
 	  "%s %s",
 	  htmlEncode(sessionName), (shareSession ? "may" : "may not"),
 	  getSessionLink(encUserName, encSessionName),
@@ -1166,31 +1165,30 @@
 hel = cartFindPrefix(cart, hgsLoadPrefix);
 if (hel != NULL)
     {
     char *encSessionName = hel->name + strlen(hgsLoadPrefix);
     char *sessionName = cgiDecodeClone(encSessionName);
     char wildStr[256];
     safef(wildStr, sizeof(wildStr), "%s*", hgsLoadPrefix);
     dyStringPrintf(dyMessage,
 		   "Loaded settings from session <B>%s</B>. %s %s<BR>\n",
 		   htmlEncode(sessionName),
 		   getSessionLink(encUserName, encSessionName),
 		   getSessionEmailLink(encUserName, encSessionName));
     cartLoadUserSession(conn, userName, sessionName, cart, NULL, wildStr);
     cartCopyCustomComposites(cart);
     hubConnectLoadHubs(cart);
-    cartCopyCustomTracks(cart);
     cartHideDefaultTracks(cart);
     cartCheckForCustomTracks(cart, dyMessage);
     didSomething = TRUE;
     }
 
 cartHelList = cartFindPrefix(cart, hgsDeletePrefix);
 for (hel = cartHelList;  hel != NULL;  hel = hel->next)
     {
     char *encSessionName = hel->name + strlen(hgsDeletePrefix);
     char *sessionName = cgiDecodeClone(encSessionName);
     sqlSafef(query, sizeof(query), "select shared from %s "
       "where userName = '%s' and sessionName = '%s';",
       namedSessionTable, encUserName, encSessionName);
     int shared = sqlQuickNum(conn, query);
     if (shared >= 2)
@@ -1222,31 +1220,30 @@
 struct sqlConnection *conn = hConnectCentral();
 struct dyString *dyMessage = dyStringNew(1024);
 char *otherUser = trimSpaces(cartString(cart, hgsOtherUserName));
 char *sessionName = trimSpaces(cartString(cart, hgsOtherUserSessionName));
 char *encOtherUser = cgiEncodeFull(otherUser);
 char *encSessionName = cgiEncodeFull(sessionName);
 
 dyStringPrintf(dyMessage,
        "Loaded settings from user <B>%s</B>'s session <B>%s</B>. %s %s",
 	       otherUser, htmlEncode(sessionName),
 	       getSessionLink(otherUser, encSessionName),
 	       getSessionEmailLink(encOtherUser, encSessionName));
 cartLoadUserSession(conn, otherUser, sessionName, cart, NULL, actionVar);
 cartCopyCustomComposites(cart);
 hubConnectLoadHubs(cart);
-cartCopyCustomTracks(cart);
 cartHideDefaultTracks(cart);
 cartCheckForCustomTracks(cart, dyMessage);
 hDisconnectCentral(&conn);
 return dyStringCannibalize(&dyMessage);
 }
 
 void doSaveLocal()
 /* Output current settings to be saved as a file on the user's machine.
  * Return a message confirming what we did. */
 {
 char *fileName = textOutSanitizeHttpFileName(cartString(cart, hgsSaveLocalFileName));
 char *compressType = cartString(cart, hgsSaveLocalFileCompress);
 struct pipeline *compressPipe = textOutInit(fileName, compressType, NULL);
 
 cleanHgSessionFromCart(cart);
@@ -1333,31 +1330,30 @@
 	   "<A HREF=\"%shgTracks?%s=%s\">Browser</A>",
 	   hLocalHostCgiBinUrl(), 
 	   cartSessionVarName(), cartSessionId(cart));
     }
 if (lf != NULL)
     {
     lineFileCarefulNewlines(lf);
     struct dyString *dyLoadMessage = dyStringNew(0);
     boolean ok = cartLoadSettingsFromUserInput(lf, cart, NULL, actionVar, dyLoadMessage);
     lineFileClose(&lf);
     if (ok)
         {
         dyStringAppend(dyMessage, dyLoadMessage->string);
         cartCopyCustomComposites(cart);
         hubConnectLoadHubs(cart);
-        cartCopyCustomTracks(cart);
         cartHideDefaultTracks(cart);
         cartCheckForCustomTracks(cart, dyMessage);
         }
     else
         {
         dyStringClear(dyMessage);
         dyStringAppend(dyMessage, "<span style='color: red;'><b>"
                        "Unable to load session: </b></span>");
         dyStringAppend(dyMessage, dyLoadMessage->string);
         dyStringAppend(dyMessage, "The uploaded file needs to have been previously saved from the "
                        "<b>Save Settings</b> section.\n");
         // Looking for the words "custom track" in an error string is hokey, returning an enum
         // from cartLoadSettings would be better, but IMO that isn't worth a big refactoring.
         if (stringIn("custom track", dyLoadMessage->string))
             {