fa326179d9bd70fb1fb1d2fe4996c3a5545257aa
hiram
Tue Feb 12 14:57:50 2019 -0800
now traversing trackDb recursively to show all composite tracks refs #18869
diff --git src/hg/hubApi/hubApi.c src/hg/hubApi/hubApi.c
index a554615..ba07c64 100644
--- src/hg/hubApi/hubApi.c
+++ src/hg/hubApi/hubApi.c
@@ -54,87 +54,102 @@
char *longLabel; /* Hub long label. */
char *registrationTime; /* Time first registered */
unsigned dbCount; /* Number of databases hub has data for. */
char *dbList; /* Comma separated list of databases. */
char *descriptionUrl; /* URL to description HTML */
};
/* Global Variables */
static struct cart *cart; /* CGI and other variables */
static struct hash *oldVars = NULL;
static struct hash *trackCounter = NULL;
static long totalTracks = 0;
static boolean measureTiming = FALSE; /* set by CGI parameters */
static boolean allTrackSettings = FALSE; /* checkbox setting */
static char **shortLabels = NULL; /* public hub short labels in array */
-struct hubPublic *publicHubList = NULL;
+// struct hubPublic *publicHubList = NULL;
static int publicHubCount = 0;
static char *defaultHub = "Plants";
static char *defaultDb = "ce11";
static long enteredMainTime = 0; /* will become = clock1000() on entry */
/* to allow calculation of when to bail out, taking too long */
static long timeOutSeconds = 100;
static boolean timedOut = FALSE;
/* ######################################################################### */
static struct jsonWrite *jsonStartOutput()
-/* begin json output */
+/* begin json output with standard header information for all requests */
{
time_t timeNow = time(NULL);
// struct tm tm;
// gmtime_r(&timeNow, &tm);
struct jsonWrite *jw = jsonWriteNew();
jsonWriteObjectStart(jw, NULL);
jsonWriteString(jw, "apiVersion", "0.1");
jsonWriteString(jw, "source", "UCSantaCruz");
jsonWriteDateFromUnix(jw, "downloadTime", (long long) timeNow);
jsonWriteNumber(jw, "downloadTimeStamp", (long long) timeNow);
return jw;
}
static void jsonErrAbort(char *format, ...)
-/* Issue an error message in json format. */
+/* Issue an error message in json format, and exit(0) */
{
char errMsg[2048];
va_list args;
va_start(args, format);
vsnprintf(errMsg, sizeof(errMsg), format, args);
struct jsonWrite *jw = jsonStartOutput();
jsonWriteString(jw, "error", errMsg);
jsonWriteObjectEnd(jw);
fputs(jw->dy->string,stdout);
exit(0);
}
static void hubPublicJsonData(struct jsonWrite *jw, struct hubPublic *el)
/* Print array data for one row from hubPublic table, order here
* must be same as was stated in the columnName header element
* TODO: need to figure out how to use the order of the columns as
* they are in the 'desc' request
*/
{
jsonWriteListStart(jw, NULL);
jsonWriteString(jw, NULL, el->hubUrl);
jsonWriteString(jw, NULL, el->shortLabel);
jsonWriteString(jw, NULL, el->longLabel);
jsonWriteString(jw, NULL, el->registrationTime);
jsonWriteNumber(jw, NULL, (long long)el->dbCount);
jsonWriteString(jw, NULL, el->dbList);
jsonWriteString(jw, NULL, el->descriptionUrl);
jsonWriteListEnd(jw);
}
+int trackDbTrackCmp(const void *va, const void *vb)
+/* Compare to sort based on 'track' name; use shortLabel as secondary sort key.
+ * Note: parallel code to hgTracks.c:tgCmpPriority */
+{
+const struct trackDb *a = *((struct trackDb **)va);
+const struct trackDb *b = *((struct trackDb **)vb);
+int dif = strcmp(a->track, b->track);
+if (dif < 0)
+ return -1;
+else if (dif == 0.0)
+ return strcasecmp(a->shortLabel, b->shortLabel);
+else
+ return 1;
+}
+
static int publicHubCmpCase(const void *va, const void *vb)
/* Compare two slNames, ignore case. */
{
const struct hubPublic *a = *((struct hubPublic **)va);
const struct hubPublic *b = *((struct hubPublic **)vb);
return strcasecmp(a->shortLabel, b->shortLabel);
}
static void publicHubSortCase(struct hubPublic **pList)
/* Sort slName list, ignore case. */
{
slSort(pList, publicHubCmpCase);
}
static struct hubPublic *hubPublicLoad(char **row)
@@ -293,46 +308,73 @@
retVal = 1;
}
}
errCatchEnd(errCatch);
if (errCatch->gotError)
{
retVal = 1;
dyStringPrintf(errors, "%s", errCatch->message->string);
}
errCatchFree(&errCatch);
return retVal;
} /* static int bbiBriefMeasure() */
-static struct slName *trackList(struct trackDb *tdb, struct trackHubGenome *genome)
-/* process the track list to show all tracks */
+#ifdef NOT
+static void cloneTdb(struct trackDb *source, struct trackDb *destination)
+/* TBD: is there a cloneTdb() function somewhere else ? */
+{
+destination->track = cloneString(source->track);
+destination->shortLabel = cloneString(source->shortLabel);
+destination->type = cloneString(source->type);
+destination->longLabel = cloneString(source->longLabel);
+destination->visibility = source->visibility;
+destination->priority = source->priority;
+destination->colorR = source->colorR;
+destination->colorG = source->colorG;
+destination->colorB = source->colorB;
+destination->altColorR = source->altColorR;
+destination->altColorG = source->altColorG;
+destination->altColorB = source->altColorB;
+destination->useScore = source->useScore;
+destination->private = source->private;
+destination->url = cloneString(source->url);
+destination->html = cloneString(source->html);
+destination->grp = cloneString(source->grp);
+destination->canPack = source->canPack;
+destination->settings = cloneString(source->settings);
+destination->settingsHash = source->settingsHash;
+}
+#endif
+
+static void hubTrackList(struct trackDb *tdb, struct trackHubGenome *genome)
+/* process the track list to show all tracks, return trackDb list */
{
-struct slName *retList = NULL; /* for return of track list for 'genome' */
if (tdb)
{
struct hash *countTracks = hashNew(0);
hPrintf("
\n");
struct trackDb *track = tdb;
for ( ; track; track = track->next )
{
- struct slName *el = slNameNew(track->track);
- slAddHead(&retList, el);
- char *bigDataUrl = hashFindVal(track->settingsHash, "bigDataUrl");
- char *compositeTrack = hashFindVal(track->settingsHash, "compositeTrack");
- char *superTrack = hashFindVal(track->settingsHash, "superTrack");
+// char *bigDataUrl = hashFindVal(track->settingsHash, "bigDataUrl");
+ char *bigDataUrl = trackDbSetting(track, "bigDataUrl");
+// char *compositeTrack = hashFindVal(track->settingsHash, "compositeTrack");
+ char *compositeTrack = trackDbSetting(track, "compositeTrack");
+// char *superTrack = hashFindVal(track->settingsHash, "superTrack");
+ char *superTrack = trackDbSetting(track, "superTrack");
boolean depthSearch = cartUsualBoolean(cart, "depthSearch", FALSE);
if (compositeTrack)
hashIncInt(countTracks, "composite container");
else if (superTrack)
hashIncInt(countTracks, "superTrack container");
else if (isEmpty(track->type))
hashIncInt(countTracks, "no type specified");
else
hashIncInt(countTracks, track->type);
if (depthSearch && bigDataUrl)
{
char *bigDataIndex = NULL;
char *relIdxUrl = trackDbSetting(tdb, "bigDataIndex");
if (relIdxUrl != NULL)
bigDataIndex = trackHubRelativeUrl(genome->trackDbFile, relIdxUrl);
@@ -376,56 +418,56 @@
{
hPrintf(" \n");
struct hashEl *hel;
struct hashCookie hc = hashFirst(countTracks);
while ((hel = hashNext(&hc)) != NULL)
{
int prevCount = ptToInt(hashFindVal(trackCounter, hel->name));
totalTracks += ptToInt(hel->val);
hashReplace(trackCounter, hel->name, intToPt(prevCount + ptToInt(hel->val)));
hPrintf(" - %d - %s
\n", ptToInt(hel->val), hel->name);
}
hPrintf("
\n");
}
hPrintf("
\n");
}
-return retList;
-} /* static struct slName *trackList() */
+} /* static struct trackDb *hubTrackList() */
-static struct slName *assemblySettings(struct trackHubGenome *genome)
+static struct trackDb * assemblySettings(struct trackHubGenome *genome)
/* display all the assembly 'settingsHash' */
{
-struct slName *retList = NULL;
+struct trackDb *retTbd = NULL;
hPrintf(" \n");
struct hashEl *hel;
struct hashCookie hc = hashFirst(genome->settingsHash);
while ((hel = hashNext(&hc)) != NULL)
{
hPrintf(" - %s : %s
\n", hel->name, (char *)hel->val);
if (sameWord("trackDb", hel->name)) /* examine the trackDb structure */
{
struct trackDb *tdb = trackHubTracksForGenome(genome->trackHub, genome);
- retList = trackList(tdb, genome);
+ retTbd = tdb;
+ hubTrackList(tdb, genome);
}
if (timeOutReached())
break;
}
hPrintf("
\n");
-return retList;
+return retTbd;
}
-static struct slName *genomeList(struct trackHub *hubTop, struct slName **dbTrackList, char *selectGenome)
+static struct slName *genomeList(struct trackHub *hubTop, struct trackDb **dbTrackList, char *selectGenome)
/* follow the pointers from the trackHub to trackHubGenome and around
* in a circle from one to the other to find all hub resources
* return slName list of the genomes in this track hub
* optionally, return the trackList from this hub for the specified genome
*/
{
struct slName *retList = NULL;
long totalAssemblyCount = 0;
struct trackHubGenome *genome = hubTop->genomeList;
hPrintf("genome sequences (and tracks) present in this track hub
\n");
hPrintf("\n");
long lastTime = clock1000();
for ( ; genome; genome = genome->next )
@@ -435,35 +477,31 @@
if ( differentStringNullOk(selectGenome, genome->name) )
continue;
}
++totalAssemblyCount;
struct slName *el = slNameNew(genome->name);
slAddHead(&retList, el);
if (genome->organism)
{
hPrintf("- %s - %s - %s
\n", genome->organism, genome->name, genome->description);
}
else
{ /* can there be a description when organism is empty ? */
hPrintf("- %s
\n", genome->name);
}
if (genome->settingsHash)
- {
- struct slName *trackList = assemblySettings(genome);
- if (dbTrackList)
- *dbTrackList = trackList;
- }
+ *dbTrackList = assemblySettings(genome);
if (measureTiming)
{
long thisTime = clock1000();
hPrintf("processing time %s: %ld millis
\n", genome->name, thisTime - lastTime);
}
if (timeOutReached())
break;
}
if (trackCounter->elCount)
{
hPrintf(" - total genome assembly count: %ld
\n", totalAssemblyCount);
hPrintf(" - %ld total tracks counted, %d different track types:
\n", totalTracks, trackCounter->elCount);
hPrintf(" \n");
struct hashEl *hel;
struct hashCookie hc = hashFirst(trackCounter);
@@ -541,31 +579,31 @@
jsonWriteString(jw, NULL, row[0]);
sqlFreeResult(&sr);
hDisconnectCentral(&conn);
jsonWriteListEnd(jw);
return FALSE;
}
static void jsonPublicHubs()
/* output the hubPublic SQL table */
{
struct sqlConnection *conn = hConnectCentral();
char *dataTime = sqlTableUpdate(conn, hubPublicTableName());
hDisconnectCentral(&conn);
time_t dataTimeStamp = sqlDateToUnixTime(dataTime);
replaceChar(dataTime, ' ', 'T');
-struct hubPublic *el = publicHubList;
+struct hubPublic *el = hubPublicLoadAll();
struct jsonWrite *jw = jsonStartOutput();
jsonWriteString(jw, "dataTime", dataTime);
jsonWriteNumber(jw, "dataTimeStamp", (long long)dataTimeStamp);
freeMem(dataTime);
jsonWriteString(jw, "tableName", hubPublicTableName());
tableColumns(jw, hubPublicTableName());
jsonWriteListStart(jw, "publicHubData");
for ( ; el != NULL; el = el->next )
{
hubPublicJsonData(jw, el);
}
jsonWriteListEnd(jw);
jsonWriteObjectEnd(jw);
fputs(jw->dy->string,stdout);
}
@@ -687,54 +725,90 @@
jsonWriteNumber(jw, "dataTimeStamp", (long long)dataTimeStamp);
freeMem(dataTime);
jsonWriteNumber(jw, "chromCount", (long long)slCount(ciList));
jsonWriteObjectStart(jw, "chromosomes");
for ( ; el != NULL; el = el->next )
{
jsonWriteNumber(jw, el->chrom, (long long)el->size);
}
jsonWriteObjectEnd(jw); /* chromosomes */
jsonWriteObjectEnd(jw); /* top level */
fputs(jw->dy->string,stdout);
}
hFreeConn(&conn);
}
+static void recursiveTrackList(struct jsonWrite *jw, struct trackDb *tdb, char *type)
+{
+jsonWriteListStart(jw, type);
+struct trackDb *el;
+for (el = tdb; el != NULL; el = el->next )
+ {
+ jsonWriteObjectStart(jw, NULL);
+ jsonWriteString(jw, "track", el->track);
+ jsonWriteString(jw, "shortLabel", el->shortLabel);
+ jsonWriteString(jw, "type", el->type);
+ jsonWriteString(jw, "longLabel", el->longLabel);
+ if (tdbIsComposite(el))
+ {
+ recursiveTrackList(jw, el->subtracks, "subtracks");
+ }
+ if (tdb->parent && tdbIsSuperTrackChild(el))
+ jsonWriteString(jw, "superTrack", "TRUE");
+ jsonWriteObjectEnd(jw);
+ }
+jsonWriteListEnd(jw);
+}
+
static void trackDbJsonOutput(char *db, FILE *f)
/* return track list from specified UCSC database name */
{
struct sqlConnection *conn = hAllocConn(db);
char *dataTime = sqlTableUpdate(conn, "trackDb");
time_t dataTimeStamp = sqlDateToUnixTime(dataTime);
replaceChar(dataTime, ' ', 'T');
hFreeConn(&conn);
struct trackDb *tdbList = hTrackDb(db);
-struct trackDb *el;
struct jsonWrite *jw = jsonStartOutput();
jsonWriteString(jw, "db", db);
jsonWriteString(jw, "dataTime", dataTime);
jsonWriteNumber(jw, "dataTimeStamp", (long long)dataTimeStamp);
freeMem(dataTime);
-jsonWriteListStart(jw, "tracks");
-for (el = tdbList; el != NULL; el = el->next )
- jsonWriteString(jw, NULL, el->track);
-jsonWriteListEnd(jw);
+recursiveTrackList(jw, tdbList, "tracks");
jsonWriteObjectEnd(jw);
fputs(jw->dy->string,stdout);
} /* static void trackDbJsonOutput(char *db, FILE *f) */
+static void getTrackData()
+{
+}
+
+static void getSequenceData()
+{
+}
+
#define MAX_PATH_INFO 32
+static void apiGetData(char *words[MAX_PATH_INFO])
+/* 'getData' function, words[1] is the subCommand */
+{
+if (sameWord("track", words[1]))
+ getTrackData();
+if (sameWord("sequence", words[1]))
+ getSequenceData();
+jsonErrAbort("do not recognize endpoint function: '/%s/%s'", words[0], words[1]);
+}
+
static void apiList(char *words[MAX_PATH_INFO])
/* 'list' function words[1] is the subCommand */
{
if (sameWord("publicHubs", words[1]))
jsonPublicHubs();
else if (sameWord("ucscGenomes", words[1]))
jsonDbDb();
else if (sameWord("hubGenomes", words[1]))
{
char *hubUrl = cgiOptionalString("hubUrl");
if (isEmpty(hubUrl))
jsonErrAbort("ERROR: must supply hubUrl='http:...' some URL to a hub for /list/genomes");
struct trackHub *hub = trackHubOpen(hubUrl, "");
if (hub->genomeList)
@@ -764,74 +838,70 @@
if (isEmpty(hubUrl)) // missing hubUrl implies UCSC database
{
trackDbJsonOutput(db, stdout); // only need db for this function
return;
}
if (isEmpty(genome) || isEmpty(hubUrl))
{
if (isEmpty(genome))
warn("# must supply genome='someName' the name of a genome in a hub for /list/tracks\n");
if (isEmpty(hubUrl))
jsonErrAbort("ERROR: must supply hubUrl='http:...' some URL to a hub for /list/genomes");
}
struct trackHub *hub = trackHubOpen(hubUrl, "");
if (hub->genomeList)
{
- struct slName *dbTrackList = NULL;
+ struct trackDb *dbTrackList = NULL;
(void) genomeList(hub, &dbTrackList, genome);
+ slSort(dbTrackList, trackDbTrackCmp);
struct jsonWrite *jw = jsonStartOutput();
jsonWriteString(jw, "hubUrl", hubUrl);
- jsonWriteListStart(jw, "genome");
- slNameSort(&dbTrackList);
- struct slName *el = dbTrackList;
- for ( ; el != NULL; el = el->next )
- {
- jsonWriteString(jw, NULL, el->name);
- }
- jsonWriteListEnd(jw);
+ jsonWriteString(jw, "genome", genome);
+ recursiveTrackList(jw, dbTrackList, "tracks");
jsonWriteObjectEnd(jw);
fputs(jw->dy->string,stdout);
}
}
else if (sameWord("chromosomes", words[1]))
{
char *hubUrl = cgiOptionalString("hubUrl");
// char *genome = cgiOptionalString("genome");
char *db = cgiOptionalString("db");
if (isEmpty(hubUrl) && isEmpty(db))
jsonErrAbort("ERROR: must supply hubUrl or db name to return chromosome list");
if (isEmpty(hubUrl)) // missing hubUrl implies UCSC database
{
chromInfoJsonOutput(stdout, db);
return;
}
}
else
- jsonErrAbort("do not recognize endpoint: '/list/%s' request", words[1]);
+ jsonErrAbort("do not recognize endpoint function: '/%s/%s'", words[0], words[1]);
}
static struct hash *apiFunctionHash = NULL;
static void setupFunctionHash()
/* initialize the apiFunctionHash */
{
if (apiFunctionHash)
- return;
+ return; /* already done */
apiFunctionHash = hashNew(0);
hashAdd(apiFunctionHash, "list", &apiList);
+hashAdd(apiFunctionHash, "getData", &apiGetData);
}
static void apiFunctionSwitch(char *pathInfo)
/* given a pathInfo string: /command/subCommand/etc...
* parse that and decide on which function to acll
*/
{
hPrintDisable(); /* turn off all normal HTML output, doing JSON output */
/* the leading slash has been removed from the pathInfo, therefore, the
* chop will have the first word in words[0]
*/
char *words[MAX_PATH_INFO];/*expect no more than MAX_PATH_INFO number of words*/
int wordCount = chopByChar(pathInfo, '/', words, ArraySize(words));
if (wordCount < 2)
@@ -854,32 +924,30 @@
struct trackDb *track;
hPrintf("\n");
for (track = tdbList; track != NULL; track = track->next )
{
hPrintf("- %s
\n", track->track);
if (allTrackSettings)
trackSettings(track); /* show all settings */
}
hPrintf("
\n");
hPrintf("\n");
}
static void doMiddle(struct cart *theCart)
/* Set up globals and make web page */
{
-// struct hubPublic *hubList = hubPublicLoadAll();
-publicHubList = hubPublicLoadAll();
cart = theCart;
measureTiming = hPrintStatus() && isNotEmpty(cartOptionalString(cart, "measureTiming"));
measureTiming = TRUE;
char *database = NULL;
char *genome = NULL;
getDbAndGenome(cart, &database, &genome, oldVars);
initGenbankTableNames(database);
char *docRoot = cfgOptionDefault("browser.documentRoot", DOCUMENT_ROOT);
int timeout = cartUsualInt(cart, "udcTimeout", 300);
if (udcCacheTimeout() < timeout)
udcSetCacheTimeout(timeout);
knetUdcInstall();
@@ -887,30 +955,32 @@
char *pathInfo = getenv("PATH_INFO");
if (isNotEmpty(pathInfo))
{
puts("Content-Type:application/json");
puts("\n");
/* skip the first leading slash to simplify chopByChar parsing */
pathInfo += 1;
setupFunctionHash();
apiFunctionSwitch(pathInfo);
return;
}
puts("Content-Type:text/html");
puts("\n");
+(void) hubPublicLoadAll();
+
struct dbDb *dbList = ucscDbDb();
char **ucscDbList = NULL;
int listSize = slCount(dbList);
AllocArray(ucscDbList, listSize);
struct dbDb *el = dbList;
int ucscDataBaseCount = 0;
int maxDbNameWidth = 0;
for ( ; el != NULL; el = el->next )
{
ucscDbList[ucscDataBaseCount++] = el->name;
if (strlen(el->name) > maxDbNameWidth)
maxDbNameWidth = strlen(el->name);
}
maxDbNameWidth += 1;