src/hg/lib/jsHelper.c 1.27
1.27 2009/07/08 17:09:51 larrym
implement javascript versioning with symlinks
Index: src/hg/lib/jsHelper.c
===================================================================
RCS file: /projects/compbio/cvsroot/kent/src/hg/lib/jsHelper.c,v
retrieving revision 1.26
retrieving revision 1.27
diff -b -B -U 4 -r1.26 -r1.27
--- src/hg/lib/jsHelper.c 15 Jun 2009 20:47:06 -0000 1.26
+++ src/hg/lib/jsHelper.c 8 Jul 2009 17:09:51 -0000 1.27
@@ -27,8 +27,9 @@
static boolean jsInited = FALSE;
static boolean defaultWarningShown = FALSE;
struct hash *includedFiles = NULL;
+boolean symlinkFailed = FALSE; // true when we can't create symlinks in js directory
void jsInit()
/* If this is the first call, set window.onload to the operations
* performed upon loading a page and print supporting javascript.
@@ -343,48 +344,87 @@
includedFiles = newHash(0);
if(hashLookup(includedFiles, fileName) == NULL)
{
char *docRoot = hDocumentRoot();
- char noScriptBuf[2048];
- long mtime = 0;
+ struct dyString *noScriptBuf = dyStringNew(0);
+ char baseName[PATH_LEN];
+ struct dyString *fileNameWithVersion = dyStringNew(0);
// dirName is configurable to allow developer specific javascript for developers on hgwdev;
// e.g. "javaScriptDir js/larrym"
char *dirName = cfgOptionDefault("browser.javaScriptDir", "js");
+ splitPath(fileName, NULL, baseName, NULL);
/* tolerate missing docRoot (i.e. when running from command line) */
if(docRoot != NULL)
{
- char fullDirName[2048];
- safef(fullDirName, sizeof(fullDirName), "%s/%s", docRoot, dirName);
- if(fileExists(fullDirName))
+ struct dyString *fullDirName = dyStringNew(0);
+ dyStringPrintf(fullDirName, "%s/%s", docRoot, dirName);
+ if(fileExists(dyStringContents(fullDirName)))
{
- char realFileName[2048];
- safef(realFileName, sizeof(realFileName), "%s/%s", fullDirName, fileName);
- if(!fileExists(realFileName))
+ struct dyString *realFileName = dyStringNew(0);
+ dyStringPrintf(realFileName, "%s/%s", dyStringContents(fullDirName), fileName);
+ if(!fileExists(dyStringContents(realFileName)))
{
- errAbort("jsIncludeFile: javascript file: %s doesn't exist.\n", realFileName);
+ errAbort("jsIncludeFile: javascript file: %s doesn't exist.\n", dyStringContents(realFileName));
+ }
+ if(!symlinkFailed)
+ {
+ // we add mtime to create a pseudo-version; this forces browsers to reload js file when it changes,
+ // which fixes bugs and odd behavior that occurs when the browser caches modified js files
+
+ long mtime = fileModTime(dyStringContents(realFileName));
+ struct dyString *fullNameWithVersion = dyStringNew(0);
+ dyStringPrintf(fileNameWithVersion, "%s-%ld.js", baseName, mtime);
+ dyStringPrintf(fullNameWithVersion, "%s/%s", dyStringContents(fullDirName), dyStringContents(fileNameWithVersion));
+ if(!fileExists(dyStringContents(fullNameWithVersion)))
+ {
+ // Make a new, versioned symlinks and delete any older versioned symlinks.
+ struct dyString *pattern = dyStringNew(0);
+ struct slName *files, *file;
+ dyStringPrintf(pattern, "%s-[0-9]+\\.js", baseName);
+ files = listDirRegEx(dyStringContents(fullDirName), dyStringContents(pattern), REG_EXTENDED);
+ for (file = files; file != NULL; file = file->next)
+ {
+ struct dyString *tmp = dyStringNew(0);
+ dyStringPrintf(tmp, "%s/%s", dyStringContents(fullDirName), file->name);
+ unlink(dyStringContents(tmp));
+ dyStringFree(&tmp);
+ }
+ slFreeList(&files);
+ dyStringFree(&pattern);
+ if(symlink(dyStringContents(realFileName), dyStringContents(fullNameWithVersion)))
+ {
+ // We do not report failed creation of symlinks b/c I think it will be common in mirrors for the
+ // www user to not have write permission to the js directory. When this happens,
+ // we fall back to using non-versioned javascript references
+
+ // fprintf(stderr, "jsIncludeFile: symlink failed: errno: %d (%s)\n", errno, strerror(errno));
+ symlinkFailed = TRUE;
+ dyStringClear(fileNameWithVersion);
}
- mtime = fileModTime(realFileName);
+ }
+ dyStringFree(&fullNameWithVersion);
+ }
+ dyStringFree(&fullDirName);
}
else
{
- errAbort("jsIncludeFile: javascript dir: %s doesn't exist.\n", fullDirName);
+ errAbort("jsIncludeFile: javascript dir: %s doesn't exist.\n", dyStringContents(fullDirName));
}
+ dyStringFree(&fullDirName);
}
hashAdd(includedFiles, fileName, NULL);
if(noScriptMsg == NULL && !defaultWarningShown)
{
noScriptMsg = "<b>Your browser does not support JavaScript so some functionality may be missing!</b>";
defaultWarningShown = 1;
}
if(noScriptMsg && strlen(noScriptMsg))
- safef(noScriptBuf, sizeof(noScriptBuf), "<noscript>%s</noscript>\n", noScriptMsg);
- else
- noScriptBuf[0] = 0;
- // we add mtime to create a pseudo-version; this forces browsers to reload js file when it changes,
- // which fixes bugs, odd behavior that occurs when the browser caches modified js files
- //hPrintf("<script type='text/javascript' src='../%s/%s?v=%ld'></script>\n%s", dirName, fileName, mtime, noScriptBuf);
- hPrintf("<script type='text/javascript' src='../%s/%s'></script>\n%s", dirName, fileName, noScriptBuf);
+ dyStringPrintf(noScriptBuf, "<noscript>%s</noscript>\n", noScriptMsg);
+ hPrintf("<script type='text/javascript' src='../%s/%s'></script>\n%s", dirName,
+ dyStringLen(fileNameWithVersion) ? dyStringContents(fileNameWithVersion) : fileName, dyStringContents(noScriptBuf));
+ dyStringFree(&fileNameWithVersion);
+ dyStringFree(&noScriptBuf);
}
}
char *jsCheckAllOnClickHandler(char *idPrefix, boolean state)