f518e03d8f56af784ec14536a7bdc0daed9a38fd chmalee Wed Sep 16 11:11:32 2026 -0700 Send each file's genome with a hubtools upload so hubSpace rows get a db, and stop the server rewriting a user-uploaded hub.txt, no redmine Co-Authored-By: Claude Opus 5 (1M context) diff --git src/hg/hgHubConnect/hooks/pre-finish.c src/hg/hgHubConnect/hooks/pre-finish.c index d41b1aebe6f..a79d7988cf7 100644 --- src/hg/hgHubConnect/hooks/pre-finish.c +++ src/hg/hgHubConnect/hooks/pre-finish.c @@ -56,31 +56,30 @@ else { char *tusFile = NULL, *tusInfo = NULL; struct errCatch *errCatch = errCatchNew(0); if (errCatchStart(errCatch)) { // the variables for the row entry for this file, some can be NULL char *userName = NULL; char *dataDir = NULL, *userDataDir = NULL; char *fileName = NULL; long long fileSize = 0; char *fileType = NULL; char *db = NULL; char *reqLm = NULL; time_t lastModified = 0; - boolean isHubToolsUpload = FALSE; char *parentDir = NULL, *encodedParentDir = NULL; struct lineFile *lf = lineFileStdin(FALSE); char *request = lineFileReadAll(lf); struct jsonElement *req = jsonParse(request); fprintf(stderr, "Hook request:\n"); jsonPrintToFile(req, NULL, stderr, 0); char *reqCookie= jsonQueryString(req, "", "Event.HTTPRequest.Header.Cookie[0]", NULL); if (reqCookie) { setenv("HTTP_COOKIE", reqCookie, 0); } fprintf(stderr, "reqCookie='%s'\n", reqCookie); userName = getUserName(); if (!userName) @@ -205,64 +204,66 @@ // Derive hubType server-side; never trust the client's hubType. // A 2bit always promotes its hub to assembly. Otherwise inherit // the existing hub's type, defaulting to trackHub. // both lookups below are about the hub as a whole, whose row and hub.txt // live at the top level, so use the hub component of parentDir char *parentDirForCheck = encodedParentDir ? hubRootFromParentDir(encodedParentDir) : ""; char *hubDir = encodedParentDir ? hubPathFromParentDir(encodedParentDir, userDataDir) : NULL; if (sameOk(fileType, "2bit")) row->hubType = "assemblyHub"; else { char *existingType = existingHubTypeForDir(userName, parentDirForCheck); row->hubType = existingType ? existingType : "trackHub"; } + // both the browser and hubtools set batchHasHubTxt when the upload brings + // its own hub.txt, which makes that hub.txt the user's to write, not ours char *batchHasHubTxtStr = jsonQueryString(req, "", "Event.Upload.MetaData.batchHasHubTxt", NULL); boolean batchHasHubTxt = sameOk(batchHasHubTxtStr, "true"); boolean userOwnNamedHubTxt = userHasOwnNamedHubTxtInDir(userName, parentDirForCheck, hubDir); boolean userAuth = batchHasHubTxt || userOwnNamedHubTxt; boolean isHubTxt = sameOk(fileType, "hub.txt"); boolean isTwoBit = sameOk(fileType, "2bit"); // Serialize hub.txt read-modify-write across parallel pre-finish // processes for the same hub. flock is held for the entire // decision + action so writeHubText's fileExists check and the // upgrade's read-rewrite are atomic with respect to siblings. // Lock the directory the hub.txt is in, so uploads into different // subdirectories of one hub still serialize against each other. int hubLockFd = -1; if (hubDir) hubLockFd = lockHubDir(hubDir); - if (!isHubToolsUpload && !isHubTxt) + if (!isHubTxt) { if (!userAuth) { if (isTwoBit) { // createNewTempHubForUpload is a no-op when the hub.txt and its // row are already there, and it backfills the row when they are not createNewTempHubForUpload(reqId, row, userDataDir); - upgradeExistingHubToAssembly(row, userDataDir); + upgradeExistingHubToAssembly(row, userDataDir, TRUE); } else createNewTempHubForUpload(reqId, row, userDataDir); } else if (isTwoBit) { // user's hub.txt is authoritative; just flip rows to assemblyHub. - upgradeExistingHubToAssembly(row, userDataDir); + upgradeExistingHubToAssembly(row, userDataDir, FALSE); } } // still under the hub lock: makeParentDirRows checks for a row and then // inserts it, so two uploads to one hub would otherwise both insert the // same directory row // first make the parentDir rows // the directory rows carry the upload's own timestamp. row->lastModified // holds it as a GMT clock string, which sqlDateToUnixTime would read as // local time, so pass the seconds directly makeParentDirRows(row->userName, lastModified, row->db, row->parentDir, userDataDir, row->hubType); row->parentDir = encodedParentDir ? hubLeafFromPath(encodedParentDir) : ""; addHubSpaceRowForFile(row); unlockHubDir(hubLockFd); fprintf(stderr, "added hubSpace row for file '%s'\n", fileName); fflush(stderr);