946812f7ebe9bd45e3e3fbaaa3db102e9696a973 braney Thu Mar 24 14:21:20 2011 -0700 add support for supertracks in hubs #3381 diff --git src/hg/lib/trackHub.c src/hg/lib/trackHub.c index 09a845b..e65aaec 100644 --- src/hg/lib/trackHub.c +++ src/hg/lib/trackHub.c @@ -96,31 +96,31 @@ /* Return setting if it exists, otherwise NULL. */ { return hashFindVal(hub->settings, name); } char *trackHubRequiredSetting(struct trackHub *hub, char *name) /* Return named setting. Abort with error message if not found. */ { char *val = trackHubSetting(hub, name); if (val == NULL) errAbort("Missing required setting %s from %s", name, hub->url); return val; } struct trackHub *trackHubOpen(char *url, char *hubName) -/* Open up a track hub from url. Reads and parses hub.ra and the genomesFile. +/* Open up a track hub from url. Reads and parses hub.txt and the genomesFile. * The hubName is generally just the asciified ID number. */ { struct lineFile *lf = udcWrapShortLineFile(url, NULL, 256*1024); struct hash *hubRa = raNextRecord(lf); if (hubRa == NULL) errAbort("empty %s in trackHubOpen", url); if (raNextRecord(lf) != NULL) errAbort("multiple records in %s", url); /* Allocate hub and fill in settings field and url. */ struct trackHub *hub; AllocVar(hub); hub->url = cloneString(url); hub->name = cloneString(hubName); hub->settings = hubRa; @@ -192,124 +192,155 @@ } static void expandBigDataUrl(struct trackHub *hub, struct trackHubGenome *genome, struct trackDb *tdb) /* Expand bigDataUrls so that no longer relative to genome->trackDbFile */ { struct hashEl *hel = hashLookup(tdb->settingsHash, "bigDataUrl"); if (hel != NULL) { char *oldVal = hel->val; hel->val = trackHubRelativeUrl(genome->trackDbFile, oldVal); freeMem(oldVal); } } -static void checkTagsLegal(struct trackHub *hub, struct trackHubGenome *genome, - struct trackDb *tdb) -/* Make sure that tdb has all the required tags and is of a supported type. */ +struct trackHubGenome *trackHubFindGenome(struct trackHub *hub, char *genomeName) +/* Return trackHubGenome of given name associated with hub. Return NULL if no + * such genome. */ +{ +return hashFindVal(hub->genomeHash, genomeName); +} + +static void validateOneTrack( struct trackHub *hub, + struct trackHubGenome *genome, struct trackDb *tdb) { /* Check for existence of fields required in all tracks */ requiredSetting(hub, genome, tdb, "shortLabel"); requiredSetting(hub, genome, tdb, "longLabel"); -/* Further checks depend whether it is a container. */ +// subtracks is not NULL if a track said we were its parent if (tdb->subtracks != NULL) { - if (trackDbSetting(tdb, "compositeTrack")) - { - } - else if (trackDbSetting(tdb, "container")) - { - } - else + boolean isSuper = FALSE; + char *superTrack = trackDbSetting(tdb, "superTrack"); + if ((superTrack != NULL) && sameString(superTrack, "on")) + isSuper = TRUE; + + if (!(trackDbSetting(tdb, "compositeTrack") || + trackDbSetting(tdb, "container") || + isSuper)) { - errAbort("Parent track %s is not compositeTrack or container in hub %s genome %s", + errAbort("Parent track %s is not compositeTrack, container, or superTrack in hub %s genome %s", tdb->track, hub->url, genome->name); } } else { /* Check type field. */ char *type = requiredSetting(hub, genome, tdb, "type"); - if (startsWithWord("bigWig", type)) - ; - else if (startsWithWord("bigBed", type)) - ; - else if (startsWithWord("bam", type)) - ; - else + if (!(startsWithWord("bigWig", type) || + startsWithWord("bigBed", type) || + startsWithWord("bam", type))) + { errAbort("Unsupported type %s in hub %s genome %s track %s", type, hub->url, genome->name, tdb->track); - - requiredSetting(hub, genome, tdb, "bigDataUrl"); } + requiredSetting(hub, genome, tdb, "bigDataUrl"); } - -struct trackHubGenome *trackHubFindGenome(struct trackHub *hub, char *genomeName) -/* Return trackHubGenome of given name associated with hub. Return NULL if no - * such genome. */ -{ -return hashFindVal(hub->genomeHash, genomeName); } -struct trackDb *trackHubTracksForGenome(struct trackHub *hub, struct trackHubGenome *genome) -/* Get list of tracks associated with genome. Check that it only is composed of legal - * types. Do a few other quick checks to catch errors early. */ +static void markContainers( struct trackHub *hub, + struct trackHubGenome *genome, struct trackDb *tdbList) +/* mark containers that are parents, or have them */ { -struct lineFile *lf = udcWrapShortLineFile(genome->trackDbFile, NULL, 16*1024*1024); -struct trackDb *tdbList = trackDbFromOpenRa(lf, NULL); -lineFileClose(&lf); - -/* Make bigDataUrls more absolute rather than relative to genome.ra dir */ +struct hash *hash = hashNew(0); struct trackDb *tdb; -for (tdb = tdbList; tdb != NULL; tdb = tdb->next) - expandBigDataUrl(hub, genome, tdb); -/* Connect up subtracks and parents. Note this loop does not actually move tracks - * from list to parent subtracks, it just uses the field as a marker. Just do this - * so when doing error checking can distinguish between container tracks and others. - * This does have the pleasant side effect of making good error messages for - * non-existant parents. */ -struct hash *hash = hashNew(0); +// add all the track names to a hash for (tdb = tdbList; tdb != NULL; tdb = tdb->next) hashAdd(hash, tdb->track, tdb); + +// go through and find the container tracks for (tdb = tdbList; tdb != NULL; tdb = tdb->next) { char *parentLine = trackDbLocalSetting(tdb, "parent"); + + // maybe it's a child of a supertrack? + if (parentLine == NULL) + { + parentLine = trackDbLocalSetting(tdb, "superTrack"); + if ((parentLine != NULL) && sameString(parentLine, "on")) + parentLine = NULL; + } + if (parentLine != NULL) { char *parentName = cloneFirstWord(parentLine); struct trackDb *parent = hashFindVal(hash, parentName); if (parent == NULL) errAbort("Parent %s of track %s doesn't exist in hub %s genome %s", parentName, tdb->track, hub->url, genome->name); - tdb->parent = parent; + // mark the parent as a container parent->subtracks = tdb; + + // ugh...do this so requiredSetting looks at parent + // in the case of views. We clear this after + // validating anyway + tdb->parent = parent; + freeMem(parentName); } } hashFree(&hash); +} + +static void validateTracks( struct trackHub *hub, struct trackHubGenome *genome, + struct trackDb *tdbList) +/* make sure a hub track list has the right settings and its parents exist */ +{ +// mark the containers by setting their subtracks pointer +markContainers(hub, genome, tdbList); -/* Loop through list checking tags and removing ad-hoc use of parent and subtracks tags. */ +/* Loop through list checking tags */ +struct trackDb *tdb; for (tdb = tdbList; tdb != NULL; tdb = tdb->next) { - checkTagsLegal(hub, genome, tdb); - tdb->parent = tdb->subtracks = NULL; + validateOneTrack(hub, genome, tdb); + + // clear these two pointers which we set in markContainers + tdb->subtracks = NULL; + tdb->parent = NULL; + } } +struct trackDb *trackHubTracksForGenome(struct trackHub *hub, struct trackHubGenome *genome) +/* Get list of tracks associated with genome. Check that it only is composed of legal + * types. Do a few other quick checks to catch errors early. */ +{ +struct lineFile *lf = udcWrapShortLineFile(genome->trackDbFile, NULL, 16*1024*1024); +struct trackDb *tdbList = trackDbFromOpenRa(lf, NULL); +lineFileClose(&lf); + +/* Make bigDataUrls more absolute rather than relative to genome.ra dir */ +struct trackDb *tdb; +for (tdb = tdbList; tdb != NULL; tdb = tdb->next) + expandBigDataUrl(hub, genome, tdb); + +validateTracks(hub, genome, tdbList); + trackDbAddTableField(tdbList); trackHubAddNamePrefix(hub->name, tdbList); trackHubAddGroupName(hub->name, tdbList); for (tdb = tdbList; tdb != NULL; tdb = tdb->next) { trackDbFieldsFromSettings(tdb); trackDbPolish(tdb); } return tdbList; } static void reprefixString(char **pString, char *prefix) /* Replace *pString with prefix + *pString, freeing * whatever was in *pString before. */ {