6425a939b8a452d5187fb3cc68c059373428face jcasper Wed Jul 24 16:03:50 2024 -0700 RNA structure picture generation should realize when the postscript file it wants to use doesn't exist, refs #34156 diff --git src/hg/hgGene/rnaStructure.c src/hg/hgGene/rnaStructure.c index 105cf61..69a6324 100644 --- src/hg/hgGene/rnaStructure.c +++ src/hg/hgGene/rnaStructure.c @@ -1,261 +1,289 @@ /* rnaStructure - do section on 3' and 5' UTR structure. */ /* Copyright (C) 2014 The Regents of the University of California * See kent/LICENSE or http://genome.ucsc.edu/license/ for licensing information. */ #include "common.h" #include <limits.h> #include "hash.h" #include "linefile.h" #include "jksql.h" #include "rnaFold.h" #include "hui.h" #include "web.h" #include "portable.h" #include "hgGene.h" #include "hgConfig.h" #include "pipeline.h" static void rnaTrashDirsInit(char **tables, int count) /* create trash directories if necessary */ { for ( count--; count > -1; count--) mkdirTrashDirectory(tables[count]); } static boolean rnaStructureExists(struct section *section, struct sqlConnection *conn, char *geneId) /* Return TRUE if tables exists and have our gene. */ { if (sqlTableExists(conn, "foldUtr3") && sqlRowExists(conn, "foldUtr3", "name", geneId)) return TRUE; if (sqlTableExists(conn, "foldUtr5") && sqlRowExists(conn, "foldUtr5", "name", geneId)) return TRUE; return FALSE; } static void rnaStructurePrint(struct section *section, struct sqlConnection *conn, char *geneId) /* Print out rnaStructure table. */ { static boolean firstTime = TRUE; static char *names[2] = {"5' UTR", "3' UTR"}; static char *tables[2] = {"foldUtr5", "foldUtr3"}; int side; if (firstTime) { rnaTrashDirsInit(tables, ArraySize(tables)); firstTime = FALSE; } webPrintLinkTableStart(); webPrintLabelCell("Region"); webPrintLabelCell("Fold Energy"); webPrintLabelCell("Bases"); webPrintLabelCell("Energy/Base"); webPrintWideCenteredLabelCell("Display As", 3); char *rnaPlotPath = cfgOptionDefault("rnaPlotPath", "../cgi-bin/RNAplot"); for (side = 0; side < ArraySize(names); ++side) { char *table = tables[side]; struct sqlResult *sr; char query[256], **row; sqlSafef(query, sizeof(query), "select * from %s where name = '%s'", table, geneId); sr = sqlGetResult(conn, query); if ((row = sqlNextRow(sr)) != NULL) { struct rnaFold fold; int bases; char psName[2048], altPsName[2048]; /* Load fold and save it as postScript. */ rnaFoldStaticLoad(row, &fold); safef(psName, sizeof(psName), "%s/%s/%s_%s.ps", trashDir(), table, table, geneId); // newer versions of RNAplot add _ss.ps to the file name safef(altPsName, sizeof(altPsName), "%s/%s/%s_%s.ps_ss.ps", trashDir(), table, table, geneId); bool plotDone = FALSE; if (fileExists(psName) || fileExists(altPsName)) plotDone = TRUE; else { FILE *f; if (!fileExists(rnaPlotPath)) { plotDone = FALSE; } else { char *absoluteRnaPlotPath = NULL; absoluteRnaPlotPath = realpath(rnaPlotPath, NULL); char *plotCmd[] = {absoluteRnaPlotPath, NULL}; char *curdir, outputDir[2048], psNameLocal[2048]; curdir = getCurrentDir(); safef(outputDir, sizeof(outputDir), "%s/%s/", trashDir(), table); setCurrentDir(outputDir); /* RNAplot only writes output to the current directory */ struct pipeline *plStruct = pipelineOpen1(plotCmd, pipelineWrite | pipelineNoAbort, "/dev/null", NULL, 0); safef(psNameLocal, sizeof(psNameLocal), "%s_%s.ps", table, geneId); f = pipelineFile(plStruct); if (f != NULL) { fprintf(f, ">%s\n", psNameLocal); /* This is used by RNAplot for the filename. */ fprintf(f, "%s\n%s\n", fold.seq, fold.fold); plotDone = TRUE; } pipelineClose(&plStruct); setCurrentDir(curdir); // return home free(absoluteRnaPlotPath); } } // newer versions of RNAplot add _ss.ps to the file name if (!fileExists(psName)) safecpy(psName, sizeof(psName), altPsName); /* Print row of table, starting with energy terms . */ hPrintf("</TR><TR>"); bases = strlen(fold.seq); webPrintLinkCell(names[side]); webPrintLinkCellStart(); hPrintf("%1.2f", fold.energy); webPrintLinkCellEnd(); webPrintLinkCellStart(); hPrintf("%d", bases); webPrintLinkCellEnd(); webPrintLinkCellStart(); hPrintf("%1.3f", fold.energy/bases); webPrintLinkCellEnd(); if (plotDone) { /* Print link to png image. */ webPrintLinkCellStart(); hPrintf("<A HREF=\"%s?%s&%s=%s&%s=%s&%s=%s\" class=\"toc\" TARGET=_blank>", geneCgi, cartSidUrlString(cart), hggMrnaFoldRegion, table, hggMrnaFoldPs, psName, hggDoRnaFoldDisplay, "picture"); hPrintf(" Picture "); hPrintf("</A>"); webPrintLinkCellEnd(); /* Print link to PostScript. */ webPrintLinkCellStart(); hPrintf("<A HREF=\"%s\" class=\"toc\">", psName); hPrintf(" PostScript "); hPrintf("</A>"); webPrintLinkCellEnd(); } /* Print link to text. */ webPrintLinkCellStart(); hPrintf("<A HREF=\"%s?%s&%s=%s&%s=%s\" class=\"toc\" TARGET=_blank>", geneCgi, cartSidUrlString(cart), hggMrnaFoldRegion, table, hggDoRnaFoldDisplay, "text"); hPrintf(" Text "); hPrintf("</A>"); webPrintLinkCellEnd(); } sqlFreeResult(&sr); } webPrintLinkTableEnd(); hPrintf("<BR>The RNAfold program from the "); hPrintf("<A HREF=\"http://www.tbi.univie.ac.at/~ivo/RNA/\" TARGET=_blank>"); hPrintf("Vienna RNA Package</A> is used to perform the "); hPrintf("secondary structure predictions and folding calculations. "); hPrintf("The estimated folding energy is in kcal/mol. The more "); hPrintf("negative the energy, the more secondary structure the RNA "); hPrintf("is likely to have."); } struct section *rnaStructureSection(struct sqlConnection *conn, struct hash *sectionRa) /* Create rnaStructure section. */ { struct section *section = sectionNew(sectionRa, "rnaStructure"); if (section != NULL) { section->exists = rnaStructureExists; section->print = rnaStructurePrint; } return section; } struct rnaFold *loadFold(struct sqlConnection *conn, char *table, char *name) /* Load named fold from table. */ { struct rnaFold *fold = NULL; struct sqlResult *sr; char query[256], **row; sqlSafef(query, sizeof(query), "select * from %s where name = '%s'", table, name); sr = sqlGetResult(conn, query); if ((row = sqlNextRow(sr)) != NULL) fold = rnaFoldLoad(row); sqlFreeResult(&sr); return fold; } void doRnaFoldDisplay(struct sqlConnection *conn, char *geneId, char *geneName) /* Show RNA folding somehow. */ { char *table = cartString(cart, hggMrnaFoldRegion); char *how = cartString(cart, hggDoRnaFoldDisplay); struct rnaFold *fold = loadFold(conn, table, geneId); if (fold == NULL) { warn("Couldn't load %s from %s", geneId, table); return; } if (sameString(how, "text")) { hPrintf("<TT><PRE>"); hPrintf("%s\n%s (%1.2f)\n", fold->seq, fold->fold, fold->energy); hPrintf("</PRE></TT>"); } else if (sameString(how, "picture")) { char *psFile = cartString(cart, hggMrnaFoldPs); + + // Sanity check the psFile variable + // It should point to a .ps file that exists in the trash/foldUtr5 or foldUtr3 directory. + // That means it should match trashDir()/foldUtr[35]/foldUtr[35]_.*\.ps as a regex, + // and that the file should exist. + + if (!endsWith(psFile, ".ps")) + { + warn("Invalid file provided for creating of RNA structure pdf/image"); + return; + } + char sanCheck[4096]; + safef(sanCheck, sizeof(sanCheck), "%s/foldUtr5/foldUtr5_", trashDir()); + if (!startsWith(sanCheck, psFile)) + { + safef(sanCheck, sizeof(sanCheck), "%s/foldUtr3/foldUtr3_", trashDir()); + if (!startsWith(sanCheck, psFile)) + { + warn("Invalid file provided for creating of RNA structure pdf/image"); + return; + } + } + if (!fileExists(psFile)) + { + warn("Indicated postscript file for RNA structure pdf/image generation does not exist."); + return; + } + char *rootName = cloneString(psFile); char pngName[256]; char pdfName[256]; chopSuffix(rootName); safef(pngName, sizeof(pngName), "%s.png", rootName); safef(pdfName, sizeof(pngName), "%s.pdf", rootName); hPrintf("<H2>%s (%s) %s energy %1.2f</H2>\n", geneName, geneId, table, fold->energy); if (!fileExists(pdfName)) { char *command[] = { "ps2pdf", psFile, pdfName, NULL}; struct pipeline *pl = pipelineOpen1(command, pipelineWrite | pipelineNoAbort, "/dev/null", NULL, 0); int sysRet = pipelineWait(pl); if (sysRet != 0) errAbort("System call returned %d for:\n %s", sysRet, pipelineDesc(pl)); } hPrintf("Click <A HREF=\"%s\">here for PDF version</A><BR>", pdfName); if (!fileExists(pngName)) { char outputBuf[1024]; safef(outputBuf, sizeof outputBuf, "-sOutputFile=%s", pngName); char *command[] = { "gs","-sDEVICE=png16m", outputBuf,"-dBATCH","-dNOPAUSE","-q", psFile, NULL}; struct pipeline *pl = pipelineOpen1(command, pipelineWrite | pipelineNoAbort, "/dev/null", NULL, 0); int sysRet = pipelineWait(pl); if (sysRet != 0) errAbort("System call returned %d for:\n %s", sysRet, pipelineDesc(pl)); } hPrintf("<IMG SRC=\"%s\">", pngName); } }