9a4d8c8cdd36457a18219cfb445abf9ce4e3f843 braney Fri Sep 4 17:28:09 2026 -0700 hgc: make the RNA fold diagram actually appear. RNAplot takes the name of its output file from the sequence id on the fasta header it is given: it keeps the first 42 characters of that id and appends "_ss.ps". We were handing it "../trash//
_.ps" and then asking ghostscript to read back exactly that path, which is wrong twice over. The "_ss.ps" means the name never matched even for a short item, and the path prefix alone is 41 characters, so RNAplot kept a single letter of the item name and every item in a track landed on the same file. Ghostscript was then pointed at something that had never been written, returned 1, and until the previous commit that killed the whole details page. There is no output-file option in RNAplot, and no way to hand our pipeline a working directory, so the id has to carry the path and still fit. The item name cannot be part of it: names in wuhCor1.rnaStructRangan are themselves 42 characters. So the id is now a short trash directory plus a 20 character hash of the track and item name, which is always 37 characters, and ghostscript reads the "_ss.ps" file RNAplot really wrote. All 112 items of wuhCor1.rnaStructRangan, the only rnaStruct track we have, now draw their own diagram: 112 distinct images where before there were none. Note for whoever looks at this next: RNAplot is not part of this tree and is not installed by it. It sits in the shared cgi-bin and in cgi-bin-beta, and it is absent from cgi-bin-$USER, so this feature cannot be exercised from a developer sandbox without setting rnaPlotPath in hg.conf. Worth confirming the binary is present in the RR's cgi-bin. Where it is missing the page now says the diagram could not be made rather than failing outright. refs #37424 diff --git src/hg/hgc/rnaFoldClick.c src/hg/hgc/rnaFoldClick.c index bcf9afa10a1..f8f9ed2dc52 100644 --- src/hg/hgc/rnaFoldClick.c +++ src/hg/hgc/rnaFoldClick.c @@ -7,30 +7,31 @@ #include "jksql.h" #include "hgMaf.h" #include "maf.h" #include "cart.h" #include "hgc.h" #include "hCommon.h" #include "hgColors.h" #include "obscure.h" #include "customTrack.h" #include "htmshell.h" #include "rnautil.h" #include "rnaSecStr.h" #include "memalloc.h" #include "hgConfig.h" #include "pipeline.h" +#include "md5.h" /* Taken from hgc.c (should probably be in hgc.h)*/ #define RED 0xFF0000 #define GREEN 0x00FF00 #define BLUE 0x0000FF #define BLACK 0x000000 #define CYAN 0x00FFFF #define GRAY 0xcccccc #define LTGRAY 0x999999 #define ORANGE 0xDD6600 #define MAGENTA 0xFF00FF #define LTPURPLE 0x9966CC #define SCORE_SHADES_COUNT 10 @@ -360,79 +361,96 @@ if ((mcThis = mafMayFindCompSpecies(maf, species[i], '.')) == NULL) continue; newOrder[mcCount++] = mcThis; } maf->components = NULL; for (i = 0; i < mcCount; i++) { newOrder[i]->next = 0; slAddHead(&maf->components, newOrder[i]); } slReverse(&maf->components); } +/* RNAplot truncates the sequence id it is given to 42 characters, and the id has to + * carry the output path, so both of these are kept deliberately short: 9 for + * "../trash/", 8 for the directory and its slash, and 20 for the hash is 37. */ +#define RNA_FOLD_TRASH_DIR "rnaFold" +#define RNA_FOLD_HASH_LEN 20 + void htmlPrintSecStr(FILE *f, char *table, struct rnaSecStr *item, int start) /* Print out the details for an rnaStruct* table. */ { // grab the sequence struct dnaSeq *seq = hChromSeq(database, item->chrom, item->chromStart, item->chromEnd); touppers(seq->dna); if (item->strand[0] == '-') reverseComplement(seq->dna, seq->size); toRna(seq->dna); // make sure the dna is not longer than the paren string seq->dna[strlen(item->secStr)] = 0; char *rnaPlotPath = cfgOptionDefault("rnaPlotPath", "../cgi-bin/RNAplot"); -mkdirTrashDirectory(table); +mkdirTrashDirectory(RNA_FOLD_TRASH_DIR); + +/* RNAplot takes the name of its output file from the sequence id on the fasta header + * written below: it keeps the first 42 characters of that id and appends "_ss.ps". + * So the id has to be a relative path that survives the truncation intact and is + * still unique per item. There is no room to spell the item out - names in + * wuhCor1.rnaStructRangan reach 42 characters on their own - so hash the table and + * item name into a fixed-width base. The id below is always 37 characters. + * refs #37424 */ +char idText[PATH_LEN]; +safef(idText, sizeof idText, "%s/%s", table, item->name); +char *idHash = md5HexForString(idText); +idHash[RNA_FOLD_HASH_LEN] = '\0'; + +char psRoot[PATH_LEN]; +safef(psRoot, sizeof psRoot, "../trash/%s/%s", RNA_FOLD_TRASH_DIR, idHash); +freeMem(idHash); -char psName[512]; -safef(psName, sizeof(psName), "../trash/%s/%s_%s.ps", table, table, item->name); char *plotCmd[] = {rnaPlotPath, NULL}; struct pipeline *plStruct = pipelineOpen1(plotCmd, pipelineWrite | pipelineNoAbort, "/dev/null", NULL, 0); FILE *of = pipelineFile(plStruct); if (of != NULL) { - fprintf(of, ">%s\n", psName); /* This tells where to put file. */ + fprintf(of, ">%s\n", psRoot); /* This tells where to put file. */ fprintf(of, "%s\n%s\n", seq->dna, item->secStr); } pipelineClose(&plStruct); -char pngName[256]; -char *rootName = cloneString(psName); - -chopSuffix(rootName); -safef(pngName, sizeof(pngName), "%s.png", rootName); +/* RNAplot appended "_ss.ps" to the id, so that, not psRoot, is the file gs reads. */ +char psName[PATH_LEN]; +safef(psName, sizeof psName, "%s_ss.ps", psRoot); +char pngName[PATH_LEN]; +safef(pngName, sizeof pngName, "%s.png", psRoot); char outputBuf[1024]; safef(outputBuf, sizeof outputBuf, "-sOutputFile=%s", pngName); char *pipeCmd[] = {"gs", "-sDEVICE=png16m", outputBuf, "-dBATCH","-dNOPAUSE","-q", psName, NULL}; struct pipeline *pl = pipelineOpen1(pipeCmd, pipelineWrite | pipelineNoAbort, "/dev/null", NULL, 0); int sysRet = pipelineWait(pl); printf("Display on PseudoViewer
", seq->dna, item->secStr, start); htmlHorizontalLine(); if (sysRet != 0) { - /* Always fires today: RNAplot truncates the sequence id we hand it to 42 - * characters and appends "_ss.ps", and psName's directory prefix is already 41 - * characters, so RNAplot writes rnaStructRangan__ss.ps and gs is - * pointed at a file that was never created. Drop just the diagram; the rest of - * the page is still worth showing. refs #37424 */ + /* RNAplot wrote no PostScript file, or gs could not read it. Drop just the + * diagram; the rest of the page is still worth showing. refs #37424 */ printf("RNAFold diagram could not be made.
"); warn("Could not make the RNA fold diagram: system call returned %d for:\n %s", sysRet, pipelineDesc(pl)); } else { printf("RNAFold diagram:
"); printf("", pngName); } } void htmlPrintSecStrEvofoldDrawing(FILE *f, struct rnaSecStr *item) { char fileName[512]; struct dnaSeq *seq;