6b77d537ee23bc5d43543fe6cdc11764b776cab5
larrym
  Wed Mar 16 13:43:25 2011 -0700
changed webTimeStampedLinkToResource as follows: (a) stop trying to create softlink as this usually didn't work and violates the fact that we are now imposing version checking in production sites (see redmine 3170); (b) improve/update code comments; (c) improve error message shown to user when appropriate version isn't found
diff --git src/hg/lib/web.c src/hg/lib/web.c
index 08ed3b7..d250d00 100644
--- src/hg/lib/web.c
+++ src/hg/lib/web.c
@@ -1281,103 +1281,91 @@
 }
 
 void webFinishPartialLinkOutTable(int rowIx, int itemPos, int maxPerRow)
 /* Fill out partially empty last row. */
 {
 finishPartialTable(rowIx, itemPos, maxPerRow, webPrintLinkOutCellStart);
 }
 
 void webFinishPartialLinkTable(int rowIx, int itemPos, int maxPerRow)
 /* Fill out partially empty last row. */
 {
 finishPartialTable(rowIx, itemPos, maxPerRow, webPrintLinkCellStart);
 }
 
 char *webTimeStampedLinkToResource(char *fileName, boolean wrapInHtml)
-// Returns full path of timestamped link to the requested resource file (js, or css).
-// If wrapInHtml, then returns link embedded in style or script html. Free after use.
+// If wrapInHtml
+//   returns versioned link embedded in style or script html (free after use).
+// else
+//   returns full path of a versioned path to the requested resource file (js, or css).
 // NOTE: png, jpg and gif should also be supported but are untested.
+//
+// In production sites we use a versioned softlink that includes the CGI version. This has the following benefits:
+// a) flushes user's web browser cache when the user visits a GB site whose version has changed since their last visit;
+// b) enforces the requirement that static files are the same version as the CGIs (something that often fails to happen in mirrors).
+// (see notes in redmine #3170).
+//
+// In dev trees we use mtime to create a pseudo-version; this forces web browsers to reload css/js file when it changes,
+// so we don't get odd behavior that can be caused by caching of mis-matched javascript and style files in dev trees.
+//
+// In either case, the actual file has to have been previously created by running make in the appropriate directory (kent/src/hg/js
+// or kent/src/hg/htdocs/style).
 {
 char baseName[PATH_LEN];
 char extension[FILEEXT_LEN];
 splitPath(fileName, NULL, baseName, extension);
 boolean js = sameString(".js",extension);
 boolean style = !js && sameString(".css",extension);
 boolean image = !js && !style && (sameString(".png",extension) || sameString(".jpg",extension) || sameString(".gif",extension));
 if(!js && !style) // && !image) NOTE: This code has not been tested on images but should work.
     errAbort("webTimeStampedLinkToResource: unknown resource type for %s.\n", fileName);
 
 // Build and verify directory
 char *dirName = "";
 if (js)
     dirName = cfgOptionDefault("browser.javaScriptDir", "js");
 else if (style)
     dirName = cfgOptionDefault("browser.styleDir","style");
 else if (image)
     dirName = cfgOptionDefault("browser.styleImagesDir","style/images");
 struct dyString *fullDirName = NULL;
 char *docRoot = hDocumentRoot();
-if(docRoot != NULL) // tolerate missing docRoot (i.e. when running from command line)
+if(docRoot != NULL)
     fullDirName = dyStringCreate("%s/%s", docRoot, dirName);
 else
+    // tolerate missing docRoot (i.e. when running from command line)
     fullDirName = dyStringCreate("%s", dirName);
 if(!fileExists(dyStringContents(fullDirName)))
     errAbort("webTimeStampedLinkToResource: dir: %s doesn't exist.\n", dyStringContents(fullDirName));
 
 // build and verify real path to file
 struct dyString *realFileName = dyStringCreate("%s/%s", dyStringContents(fullDirName), fileName);
 if(!fileExists(dyStringContents(realFileName)))
     errAbort("webTimeStampedLinkToResource: file: %s doesn't exist.\n", dyStringContents(realFileName));
 
-// build and verify link path including timestamp in the form of dir/baseName-timeStamp.ext
-long mtime = fileModTime(dyStringContents(realFileName));   // We add mtime to create a pseudo-version; this forces browsers to reload css/js file when it changes
+// build and verify link path including timestamp in the form of dir/baseName + timeStamp or CGI Version + ext
+long mtime = fileModTime(dyStringContents(realFileName));
 struct dyString *linkWithTimestamp;
 if(hIsPreviewHost() || hIsPrivateHost())
     linkWithTimestamp = dyStringCreate("%s/%s-%ld%s", dyStringContents(fullDirName), baseName, mtime, extension);
 else
     linkWithTimestamp = dyStringCreate("%s/%s-v%s%s", dyStringContents(fullDirName), baseName, CGI_VERSION, extension);
 
-// If link does not exist, then create it !!
 if(!fileExists(dyStringContents(linkWithTimestamp)))
-    {
-    // The versioned copy should be created by the install process; however, mirrors may fail
-    // to preserve mtime's when copying over the javascript/css files, in which case the
-    // versioned softlinks won't match the real file; in that case, we try to create
-    // the versioned links on the fly (which requires write access to the javascript or style directory!).
-
-    // Remove older links
-    struct dyString *pattern = dyStringCreate("%s-[0-9]+\\%s", baseName, extension);
-    struct slName *file, *files = listDirRegEx(dyStringContents(fullDirName), dyStringContents(pattern), REG_EXTENDED);
-    struct dyString *oldLink = dyStringNew(256);
-    for (file = files; file != NULL; file = file->next)
-        {
-        dyStringClear(oldLink);
-        dyStringPrintf(oldLink, "%s/%s", dyStringContents(fullDirName), file->name);
-        unlink(dyStringContents(oldLink));
-        }
-    dyStringFree(&oldLink);
-    slFreeList(&files);
-    dyStringFree(&pattern);
+    errAbort("Cannot find correct version of file '%s'; this is due to an installation error\n\nError details: %s does not exist",
+             fileName, dyStringContents(linkWithTimestamp));
 
-    // Create new link
-    if(symlink(dyStringContents(realFileName), dyStringContents(linkWithTimestamp)))
-        {
-        int err = errno;
-        errAbort("webTimeStampedLinkToResource: symlink of %s failed: errno: %d (%s); the directory '%s' must be writeable by user '%s'; alternatively, the installation process must create the versioned files\n",
-                 dyStringContents(linkWithTimestamp), err, strerror(err), dyStringContents(fullDirName), getUser());
-        }
-    }
 // Free up all that extra memory
 dyStringFree(&realFileName);
 dyStringFree(&fullDirName);
 char *linkFull = dyStringCannibalize(&linkWithTimestamp);
 char *link = linkFull;
 if (docRoot != NULL)
     link = cloneString(linkFull + strlen(docRoot) + 1);
 freeMem(linkFull);
 
 if (wrapInHtml) // wrapped for christmas
     {
     struct dyString *wrapped = dyStringNew(0);
     if (js)
         dyStringPrintf(wrapped,"<script type='text/javascript' SRC='../%s'></script>\n", link);
     else if (style)