9f5d584ee7e9b2f7d9cda1196e7933384501441d angie Wed Apr 8 16:03:10 2015 -0700 Matt found that an assembly hub with no track groups (e.g. ThorntonHub) caused errors in hgIntegrator. Detect that case and make an "All Tracks" group if there are no other groups. refs #14579 note 32 diff --git src/hg/lib/cartJson.c src/hg/lib/cartJson.c index 0264433..ba3ca2e 100644 --- src/hg/lib/cartJson.c +++ src/hg/lib/cartJson.c @@ -1,30 +1,31 @@ /* cartJson - parse and execute JSON commands to update cart and/or return cart data as JSON. */ #include "common.h" #include "cartJson.h" #include "cartTrackDb.h" #include "cheapcgi.h" #include "grp.h" #include "hdb.h" #include "hgFind.h" #include "htmshell.h" #include "hubConnect.h" #include "hui.h" #include "jsonParse.h" #include "obscure.h" #include "regexHelper.h" #include "suggest.h" +#include "trackDb.h" #include "trackHub.h" #include "web.h" char *cartJsonOptionalParam(struct hash *paramHash, char *name) /* Convenience function for a CartJsonHandler function: Look up name in paramHash. * Return the string contained in its jsonElement value, or NULL if not found. */ { struct jsonElement *jel = hashFindVal(paramHash, name); if (jel) return jsonStringVal(jel, name); return NULL; } char *cartJsonRequiredParam(struct hash *paramHash, char *name, struct jsonWrite *jw, char *context) /* Convenience function for a CartJsonHandler function: Look up name in paramHash. @@ -387,68 +388,105 @@ { struct hashEl *hel = hashLookup(hash, tdb->grp); struct slRef *slr = slRefNew(tdb); if (hel) slAddHead(&(hel->val), slr); else hashAdd(hash, tdb->grp, slr); } struct hashCookie cookie = hashFirst(hash); struct hashEl *hel; while ((hel = hashNext(&cookie)) != NULL) slSort(&hel->val, trackDbRefCmp); return hash; } +int trackDbRefCmpShortLabel(const void *va, const void *vb) +/* Do trackDbCmpShortLabel on list of references as opposed to actual trackDbs. */ +{ +const struct slRef *aRef = *((struct slRef **)va); +const struct slRef *bRef = *((struct slRef **)vb); +struct trackDb *a = aRef->val, *b = bRef->val; +return trackDbCmpShortLabel(&a, &b); +} + +static struct slRef *sortedAllTracks(struct trackDb *trackList) +/* Return an slRef list containing all tdbs in track list, sorted by shortLabel. */ +{ +struct slRef *trackRefList = NULL; +struct trackDb *tdb; +for (tdb = trackList; tdb != NULL; tdb = tdb->next) + slAddHead(&trackRefList, slRefNew(tdb)); +slSort(&trackRefList, trackDbRefCmpShortLabel); +return trackRefList; +} + +static void writeGroupedTrack(struct jsonWrite *jw, char *name, char *label, struct hash *fieldHash, + int maxDepth, struct slRef *tdbRefList) +{ +jsonWriteObjectStart(jw, NULL); +jsonWriteString(jw, "name", name); +jsonWriteString(jw, "label", label); +jsonWriteListStart(jw, "tracks"); +struct slRef *tdbRef; +for (tdbRef = tdbRefList; tdbRef != NULL; tdbRef = tdbRef->next) + { + struct trackDb *tdb = tdbRef->val; + rWriteTdb(jw, tdb, fieldHash, 1, maxDepth); + } +jsonWriteListEnd(jw); +jsonWriteObjectEnd(jw); +} + void cartJsonGetGroupedTrackDb(struct cartJson *cj, struct hash *paramHash) /* Translate trackDb list (only a subset of the fields) into JSON array of track group objects; * each group contains an array of track objects that may have subtracks. Send it in a wrapper * object that includes the database from which it was taken; it's possible that by the time * this reaches the client, the user might have switched to a new db. */ { struct trackDb *fullTrackList = NULL; struct grp *fullGroupList = NULL; cartTrackDbInit(cj->cart, &fullTrackList, &fullGroupList, /* useAccessControl=*/TRUE); struct hash *groupedTrackRefList = hashTracksByGroup(fullTrackList); // If the optional param 'fields' is given, hash the field names that should be returned. char *fields = cartJsonOptionalParam(paramHash, "fields"); struct hash *fieldHash = hashFromCommaString(fields); // Also check for optional parameter 'maxDepth': int maxDepth = -1; char *maxDepthStr = cartJsonOptionalParam(paramHash, "maxDepth"); if (isNotEmpty(maxDepthStr)) maxDepth = atoi(maxDepthStr); struct jsonWrite *jw = cj->jw; jsonWriteObjectStart(jw, "groupedTrackDb"); jsonWriteString(jw, "db", cartString(cj->cart, "db")); jsonWriteListStart(jw, "groupedTrackDb"); +int nonEmptyGroupCount = 0; struct grp *grp; for (grp = fullGroupList; grp != NULL; grp = grp->next) { - jsonWriteObjectStart(jw, NULL); - jsonWriteString(jw, "name", grp->name); - jsonWriteString(jw, "label", grp->label); - jsonWriteListStart(jw, "tracks"); struct slRef *tdbRefList = hashFindVal(groupedTrackRefList, grp->name); - struct slRef *tdbRef; - for (tdbRef = tdbRefList; tdbRef != NULL; tdbRef = tdbRef->next) + if (tdbRefList) { - struct trackDb *tdb = tdbRef->val; - rWriteTdb(jw, tdb, fieldHash, 1, maxDepth); + nonEmptyGroupCount++; + writeGroupedTrack(jw, grp->name, grp->label, fieldHash, maxDepth, tdbRefList); } - jsonWriteListEnd(jw); - jsonWriteObjectEnd(jw); + } +if (nonEmptyGroupCount == 0) + { + // Catch-all for assembly hubs that don't declare groups for their tracks: add All Tracks + struct slRef *allTracks = sortedAllTracks(fullTrackList); + writeGroupedTrack(jw, "allTracks", "All Tracks", fieldHash, maxDepth, allTracks); } jsonWriteListEnd(jw); jsonWriteObjectEnd(jw); } static char *hAssemblyDescription(char *db) /* Return a string containing db's description.html, or NULL if not found. */ //#*** LIBIFY: Code lifted from hgFind.c's hgPositionsHelpHtml. { char *htmlPath = hHtmlPath(db); char *htmlString = NULL; if (htmlPath != NULL) { if (fileExists(htmlPath)) readInGulp(htmlPath, &htmlString, NULL);