c6d419ecfb6f122d7a0cb99c37f56c32c089bea3
chmalee
  Thu Jan 22 10:41:38 2026 -0800
HubSpace changes: Allow users to overwrite already uploaded files, but warn them first. When a hub.txt file is being uploaded, don't auto-generate one. Check if the tracks being uploaded already exist in the hub.txt before adding a default stanza for it. Add some more checks in the hook files to prevent faulty uploads. Have the tus client clear localStorage on successful uploads so re-uploads of the same file don't cause confusing errors

diff --git src/hg/lib/userdata.c src/hg/lib/userdata.c
index 6df0e5f1902..b00694a5e52 100644
--- src/hg/lib/userdata.c
+++ src/hg/lib/userdata.c
@@ -361,37 +361,80 @@
 
 static char *hubPathFromParentDir(char *parentDir, char *userDataDir)
 /* Assume parentDir does not have leading '/' or '.', parse out the first dir component
  * and add it to the users directory*/
 {
 char *copy = cloneString(parentDir);
 char *firstSlash = strchr(copy, '/');
 if (!firstSlash)
     {
     return copy;
     }
 firstSlash = 0;
 return catTwoStrings(userDataDir, copy);
 }
 
+static boolean bigDataUrlExistsInHub(char *hubFileName, char *fileName)
+/* Check if a bigDataUrl line already references this file in the hub.txt.
+ * Simple line-by-line check - not a full trackDb parser. */
+{
+if (!hubFileName || !fileName)
+    return FALSE;
+
+struct lineFile *lf = lineFileMayOpen(hubFileName, TRUE);
+if (!lf)
+    return FALSE;
+
+char *line;
+while (lineFileNext(lf, &line, NULL))
+    {
+    char *trimmedLine = skipLeadingSpaces(line);
+    if (startsWith("bigDataUrl ", trimmedLine))
+        {
+        char *url = trimmedLine + 11; // skip "bigDataUrl "
+        url = skipLeadingSpaces(url);
+        if (isEmpty(url))
+            continue;
+        // Check if the URL ends with this filename (handles relative paths)
+        if (endsWith(url, fileName) || sameString(url, fileName))
+            {
+            lineFileClose(&lf);
+            return TRUE;
+            }
+        }
+    }
+lineFileClose(&lf);
+return FALSE;
+}
+
 static void writeTrackStanza(char *hubFileName, char *track, char *bigDataUrl, char *type, char *label, char *bigFileLocation)
 {
 if ( (sameString(type, "bamIndex") || sameString(type, "tabixIndex") || sameString(type, "text")) )
     // don't need to make track stanzas for these supporting files
     return;
 
+// Skip if this file is already referenced in hub.txt (e.g., user uploaded their own hub.txt)
+if (bigDataUrlExistsInHub(hubFileName, bigDataUrl))
+    {
+    fprintf(stderr, "DEBUG: bigDataUrl '%s' already exists in '%s', skipping stanza\n",
+            bigDataUrl, hubFileName);
+    return;
+    }
+
 FILE *f = mustOpen(hubFileName, "a");
+// Always add a leading newline to ensure separation from previous content
+fprintf(f, "\n");
 char *trackDbType = type;
 if (sameString(type, "bigBed"))
     {
     // don't errAbort if the file is actually not a bigBed
     struct errCatch *errCatch = errCatchNew();
     if (errCatchStart(errCatch))
         {
         // figure out the type based on the bbiFile header
         struct bbiFile *bbi = bigBedFileOpen(bigFileLocation);
         char tdbType[32];
         safef(tdbType, sizeof(tdbType), "bigBed %d%s", bbi->definedFieldCount, bbi->fieldCount > bbi->definedFieldCount ? " +" : "");
         trackDbType = tdbType;
         bigBedFileClose(&bbi);
         }
     errCatchEnd(errCatch);