Repository 'jbrowse2'
hg clone https://toolshed.g2.bx.psu.edu/repos/fubar/jbrowse2

Changeset 57:94264fe60478 (2024-03-21)
Previous changeset 56:c0097a584a8a (2024-03-19) Next changeset 58:0e592dcaeb7f (2024-03-21)
Commit message:
planemo upload for repository https://github.com/usegalaxy-eu/temporary-tools/tree/master/jbrowse2 commit 4b5df41484f6bdf316edaf95b53c92d328ec1674-dirty
modified:
autogenJB2.py
convertMAF.sh
jb2_urlconf.py
jbrowse2.py
jbrowse2.xml
test-data/gff3/merlin.gff3
added:
jbrowse2broken.py
jbrowse2broken.xml
macrosbroken.xml
b
diff -r c0097a584a8a -r 94264fe60478 autogenJB2.py
--- a/autogenJB2.py Tue Mar 19 02:33:40 2024 +0000
+++ b/autogenJB2.py Thu Mar 21 08:01:42 2024 +0000
[
@@ -61,10 +61,10 @@
             genome_names = [x[2] for x in listgenomes]
             guseuri = []
             for x in genome_paths:
-                if x.startswith('http://') or x.startswith('https://'):
-                    guseuri.append('yes')
+                if x.startswith("http://") or x.startswith("https://"):
+                    guseuri.append("yes")
                 else:
-                    guseuri.append('no')
+                    guseuri.append("no")
             jc = jbC(
                 outdir=args.outdir,
                 jbrowse2path=args.jbrowse2path,
@@ -73,9 +73,10 @@
                         "path": x,
                         "label": genome_names[i],
                         "useuri": guseuri[i],
-                        "meta":  {"name": genome_names[i],
-                                            "dataset_dname": genome_names[i]
-                                        }
+                        "meta": {
+                            "name": genome_names[i],
+                            "dataset_dname": genome_names[i],
+                        },
                     }
                     for i, x in enumerate(genome_paths)
                 ],
@@ -99,7 +100,7 @@
                 tpath, trext, trackname = track[:3]
                 track_conf["dataset_id"] = trackname
                 useuri = "no"
-                if tpath.startswith('http://') or tpath.startswith('https://'):
+                if tpath.startswith("http://") or tpath.startswith("https://"):
                     useuri = "yes"
                 if trext == "paf":
                     refname = trackname + "_paf.fasta"
@@ -111,28 +112,55 @@
                         )
                         sys.exit(3)
                     else:
-                        track_conf.update({
-                            "conf": {
-                                "options": {
-                                    "paf": {"genome": refdat, "genome_label": trackname}
+                        track_conf.update(
+                            {
+                                "conf": {
+                                    "options": {
+                                        "paf": {
+                                            "genome": refdat,
+                                            "genome_label": trackname,
+                                        }
+                                    }
                                 }
                             }
-                        })
+                        )
                 elif trext == "bam":
-                    ipath  = track[3]
+                    ipath = track[3]
                     if not os.path.exists(ipath):
-                        ipath = os.path.realpath(os.path.join(jc.outdir, trackname + '.bai'))
-                        cmd = ["samtools", "index", "-b", "-o", ipath, os.path.realpath(track[0])]
-                        sys.stdout.write('#### calling %s' % ' '.join(cmd))
+                        ipath = os.path.realpath(
+                            os.path.join(jc.outdir, trackname + ".bai")
+                        )
+                        cmd = [
+                            "samtools",
+                            "index",
+                            "-b",
+                            "-o",
+                            ipath,
+                            os.path.realpath(track[0]),
+                        ]
+                        sys.stdout.write("#### calling %s" % " ".join(cmd))
                         jc.subprocess_check_call(cmd)
-                    track_conf.update({"conf": {"options": {"bam": {"bam_index": ipath}}}})
+                    track_conf.update(
+                        {"conf": {"options": {"bam": {"bam_index": ipath}}}}
+                    )
                 elif trext == "cram":
-                    ipath  = track[3]
+                    ipath = track[3]
                     if not os.path.exists(ipath):
-                        ipath = os.path.realpath(os.path.join('./', trackname + '.crai'))
-                        cmd = ["samtools", "index", "-c", "-o", ipath, os.path.realpath(track[0])]
+                        ipath = os.path.realpath(
+                            os.path.join("./", trackname + ".crai")
+                        )
+                        cmd = [
+                            "samtools",
+                            "index",
+                            "-c",
+                            "-o",
+                            ipath,
+                            os.path.realpath(track[0]),
+                        ]
                         jc.subprocess_check_call(cmd)
-                    track_conf.update({"conf": {"options": {"cram": {"cram_index": ipath}}}})
+                    track_conf.update(
+                        {"conf": {"options": {"cram": {"cram_index": ipath}}}}
+                    )
                 track_conf["path"] = tpath
                 track_conf["format"] = trext
                 track_conf["name"] = trackname
b
diff -r c0097a584a8a -r 94264fe60478 convertMAF.sh
--- a/convertMAF.sh Tue Mar 19 02:33:40 2024 +0000
+++ b/convertMAF.sh Thu Mar 21 08:01:42 2024 +0000
b
@@ -3,5 +3,5 @@
 #  MAF file must contain the species name and chromosome name
 #  e.g. hg38.chr1 in the sequence identifiers.
 perl $3/maf2bed.pl $2 < $1 | sort -k1,1 -k2,2n > $4.sorted.bed
-bgzip $4.sorted.bed
+bgzip -c $4.sorted.bed > $4.sorted.bed.gz
 tabix -p bed $4.sorted.bed.gz
b
diff -r c0097a584a8a -r 94264fe60478 jb2_urlconf.py
--- a/jb2_urlconf.py Tue Mar 19 02:33:40 2024 +0000
+++ b/jb2_urlconf.py Thu Mar 21 08:01:42 2024 +0000
[
@@ -1,18 +1,13 @@
-
-inconf = open('config.json', 'r').readlines()
-with open('config.json.local', 'w') as bak:
-    bak.write(''.join(inconf))
+inconf = open("config.json", "r").readlines()
+with open("config.json.local", "w") as bak:
+    bak.write("".join(inconf))
 urlbase = "https://galaxy.genomicsvl-students.cloud.edu.au/jbrowse/hum/"
 utag = '"uri":'
 for i, row in enumerate(inconf):
     ispath = False
     if row.strip().startswith(utag):
-            ispath = True
-            parth = row.split(utag)[1].strip().replace('"','').replace("'",'')
-            inconf[i] = '%s "%s%s"' % (utag, urlbase, parth)
-with open('config.json', 'w') as outconf:
-    outconf.write(''.join(inconf))
-
-
-
-
+        ispath = True
+        parth = row.split(utag)[1].strip().replace('"', "").replace("'", "")
+        inconf[i] = '%s "%s%s"' % (utag, urlbase, parth)
+with open("config.json", "w") as outconf:
+    outconf.write("".join(inconf))
b
diff -r c0097a584a8a -r 94264fe60478 jbrowse2.py
--- a/jbrowse2.py Tue Mar 19 02:33:40 2024 +0000
+++ b/jbrowse2.py Thu Mar 21 08:01:42 2024 +0000
[
b'@@ -1,4 +1,4 @@\n-#!/usr/bin/env python\n+ #!/usr/bin/env python\n # change to accumulating all configuration for config.json based on the default from the clone\n import argparse\n import binascii\n@@ -10,7 +10,6 @@\n import shutil\n import struct\n import subprocess\n-import sys\n import tempfile\n import urllib.request\n import xml.etree.ElementTree as ET\n@@ -480,9 +479,11 @@\n                             else:\n                                 self.genome_firstcontig = fl\n                     else:\n-                        fl = urllib.request.urlopen(fapath+".fai").readline()\n-                        if fl: # is first row of the text fai so the first contig name\n-                            self.genome_firstcontig = fl.decode(\'utf8\').strip().split()[0]\n+                        fl = urllib.request.urlopen(fapath + ".fai").readline()\n+                        if fl:  # is first row of the text fai so the first contig name\n+                            self.genome_firstcontig = (\n+                                fl.decode("utf8").strip().split()[0]\n+                            )\n         if self.config_json.get("assemblies", None):\n             self.config_json["assemblies"] += assemblies\n         else:\n@@ -538,6 +539,16 @@\n                 "adapter": adapter,\n             },\n             "rendering": {"type": "DivSequenceRenderer"},\n+            "displays": [\n+                {\n+                    "type": "LinearReferenceSequenceDisplay",\n+                    "displayId": "%s-LinearReferenceSequenceDisplay" % gname,\n+                },\n+                {\n+                    "type": "LinearGCContentDisplay",\n+                    "displayId": "%s-LinearGCContentDisplay" % gname,\n+                },\n+            ],\n         }\n         return trackDict\n \n@@ -604,13 +615,15 @@\n             uri = data\n         else:\n             uri = trackData["hic_url"]\n-        categ = trackData[\'category\']\n+        categ = trackData["category"]\n         trackDict = {\n             "type": "HicTrack",\n             "trackId": tId,\n             "name": uri,\n             "assemblyNames": [self.genome_name],\n-            "category": [categ,],\n+            "category": [\n+                categ,\n+            ],\n             "adapter": {\n                 "type": "HicAdapter",\n                 "hicLocation": uri,\n@@ -622,8 +635,6 @@\n                 },\n             ],\n         }\n-        style_json = self._prepare_track_style(trackDict)\n-        trackDict["style"] = style_json\n         self.tracksToAdd.append(trackDict)\n         self.trackIdlist.append(tId)\n \n@@ -643,7 +654,7 @@\n                 }\n             ]\n         }\n-        categ = trackData[\'category\']\n+        categ = trackData["category"]\n         fname = "%s.bed" % tId\n         dest = "%s/%s" % (self.outdir, fname)\n         gname = self.genome_name\n@@ -665,11 +676,14 @@\n         soutp = outp.split("\\n")\n         samp = [x.split("s ")[1] for x in soutp if x.startswith("s ")]\n         samples = [x.split(".")[0] for x in samp]\n+        logging.warn("### maf convert cmd = %s,\\nsamples=%s" % (\' \'.join(cmd), samples))\n         trackDict = {\n             "type": "MafTrack",\n             "trackId": tId,\n             "name": trackData["name"],\n-            "category": [categ,],\n+            "category": [\n+                categ,\n+            ],\n             "adapter": {\n                 "type": "MafTabixAdapter",\n                 "samples": samples,\n@@ -694,8 +708,6 @@\n                 },\n             ],\n         }\n-        style_json = self._prepare_track_style(trackDict)\n-        trackDict["style"] = style_json\n         self.tracksToAdd.append(trackDict)\n         self.trackIdlist.append(tId)\n         if self.config_json.get("plugins", None):\n@@ -717,11 +729,11 @@\n         ]\n         subprocess.check_call(cmd, cwd=self.outdir, stdout=gff3_unrebased)\n         gff3_unrebased.close()\n+        logging.warn("### blastxml to gff3 cmd = %s" % \' \'.join(cmd))\n         return gff3_unrebased.name\n \n     def add_blastxml(self,'..b'_name,\n-            "start": 2000,\n-            "end": 200000,\n+            "start": 1,\n+            "end": 100000,\n             "refName": "x",\n         }\n \n-        if data.get("defaultLocation", ""):\n-            ddl = data["defaultLocation"]\n+        if default_data.get("defaultLocation", ""):\n+            ddl = default_data["defaultLocation"]\n             loc_match = re.search(r"^([^:]+):([\\d,]*)\\.*([\\d,]*)$", ddl)\n             # allow commas like 100,000 but ignore as integer\n             if loc_match:\n@@ -1324,7 +1338,7 @@\n             logging.info(\n                 "@@@ no contig name found for default session - please add one!"\n             )\n-        session_name = data.get("session_name", "New session")\n+        session_name = default_data.get("session_name", "New session")\n         for key, value in mapped_chars.items():\n             session_name = session_name.replace(value, key)\n         # Merge with possibly existing defaultSession (if upgrading a jbrowse instance)\n@@ -1382,7 +1396,9 @@\n         """Clone a JBrowse directory into a destination directory. This also works in Biocontainer testing now"""\n         dest = self.outdir\n         if realclone:\n-            self.subprocess_check_call([\'jbrowse\', \'create\', dest,"-f", \'--tag\', f"{JB2VER}"])\n+            self.subprocess_check_call(\n+                ["jbrowse", "create", dest, "-f", "--tag", f"{JB2VER}"]\n+            )\n         else:\n             shutil.copytree(self.jbrowse2path, dest, dirs_exist_ok=True)\n         for fn in [\n@@ -1400,14 +1416,8 @@\n \n \n def parse_style_conf(item):\n-    if "type" in item.attrib and item.attrib["type"] in [\n-        "boolean",\n-        "integer",\n-    ]:\n-        if item.attrib["type"] == "boolean":\n-            return item.text in ("yes", "true", "True")\n-        elif item.attrib["type"] == "integer":\n-            return int(item.text)\n+    if item.text.lower() in [\'false\',\'true\',\'yes\',\'no\']:\n+            return item.text.lower in ("yes", "true")\n     else:\n         return item.text\n \n@@ -1473,6 +1483,7 @@\n         trackfiles = track.findall("files/trackFile")\n         if trackfiles:\n             for x in track.findall("files/trackFile"):\n+                track_conf["label"] = x.attrib["label"]\n                 track_conf["useuri"] = x.attrib["useuri"]\n                 if is_multi_bigwig:\n                     multi_bigwig_paths.append(\n@@ -1521,6 +1532,11 @@\n             track_conf["style"] = {\n                 item.tag: parse_style_conf(item) for item in track.find("options/style")\n             }\n+        else:\n+            track_conf["style"] = {}\n+        tst = track_conf["style"].get("type", None)\n+        if tst:\n+            track_conf["style"]["configuration"] = "%s-%s" % (track_conf["label"], tst)\n         if track.find("options/style_labels"):\n             track_conf["style_labels"] = {\n                 item.tag: parse_style_conf(item)\n@@ -1530,12 +1546,6 @@\n         track_conf["conf"] = etree_to_dict(track.find("options"))\n         track_conf["category"] = track.attrib["cat"]\n         track_conf["format"] = track.attrib["format"]\n-        try:\n-            # Only pertains to gff3 + blastxml. TODO?\n-            track_conf["style"] = {t.tag: t.text for t in track.find("options/style")}\n-        except TypeError:\n-            track_conf["style"] = {}\n-            pass\n         keys = jc.process_annotations(track_conf)\n \n         if keys:\n@@ -1544,9 +1554,7 @@\n                     track.attrib.get("visibility", "default_off")\n                 ].append(key)\n                 if track_conf.get("style", None):\n-                    default_session_data["style"][key] = track_conf[\n-                        "style"\n-                    ]  # TODO do we need this anymore?\n+                    default_session_data["style"][key] = track_conf["style"]\n                 if track_conf.get("style_lables", None):\n                     default_session_data["style_labels"][key] = track_conf.get(\n                         "style_labels", None\n'
b
diff -r c0097a584a8a -r 94264fe60478 jbrowse2.xml
--- a/jbrowse2.xml Tue Mar 19 02:33:40 2024 +0000
+++ b/jbrowse2.xml Thu Mar 21 08:01:42 2024 +0000
[
@@ -194,7 +194,18 @@
                     </files>
 
                     <options>
-
+                        <style>
+                        #if str($track.data_format.data_format_select) in ["gff", "bed", "vcf", "paf", "maf", "blastxml"]:
+                            <type>${track.data_format.jbstyle.track_style.display}</type>
+                            #if str($track.data_format.jbstyle.track_style.display) in ["LinearBasicDisplay", "LinearVariantDisplay"]:
+                                <trackShowLabels>${track.data_format.jbstyle.track_style.show_labels}</trackShowLabels>
+                                <trackShowDescriptions>${track.data_format.jbstyle.track_style.show_descriptions}</trackShowDescriptions>
+                            #end if
+                        #end if
+                        #if str($track.data_format.data_format_select) in ["bam", "cram"]:
+                            <type>"LinearAlignmentsDisplay"</type>
+                        #end if
+                        </style>
                     #if str($track.data_format.data_format_select) == "bam":
                         <bam>
                             #for $dataset in $track.data_format.useuri.annotation:
@@ -349,6 +360,7 @@
                             name="is_protein"
                             truevalue="true"
                             falsevalue="false" />
+                        <expand macro="track_styling_feature" />
                         <expand macro="track_visibility" />
                     </when>
                     <when value="vcf">
@@ -373,6 +385,7 @@
                             </when>
                             <when value="false" />
                         </conditional>
+                        <expand macro="track_styling_feature" />
                         <expand macro="track_visibility" />
                     </when>
                     <when value="bam">
@@ -381,6 +394,7 @@
                     </when>
                     <when value="bed">
                         <expand macro="input_conditional" label="BED Track Data" format="bed" />
+                        <expand macro="track_styling_feature" />
                         <expand macro="track_visibility" />
                     </when>
                     <when value="cram">
@@ -389,6 +403,7 @@
                     </when>
                     <when value="maf">
                         <expand macro="input_conditional" label="MAF Track Data" format="maf" />
+                        <expand macro="track_styling_feature" />
                         <expand macro="track_visibility" />
                     </when>
                     <when value="bigwig">
b
diff -r c0097a584a8a -r 94264fe60478 jbrowse2broken.py
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jbrowse2broken.py Thu Mar 21 08:01:42 2024 +0000
[
b'@@ -0,0 +1,1656 @@\n+#!/usr/bin/env python\n+# change to accumulating all configuration for config.json based on the default from the clone\n+import argparse\n+import binascii\n+import datetime\n+import json\n+import logging\n+import os\n+import re\n+import shutil\n+import struct\n+import subprocess\n+import tempfile\n+import urllib.request\n+import xml.etree.ElementTree as ET\n+from collections import defaultdict\n+\n+logging.basicConfig(level=logging.INFO)\n+log = logging.getLogger("jbrowse")\n+\n+JB2VER = "v2.10.3"\n+# version pinned for cloning\n+\n+TODAY = datetime.datetime.now().strftime("%Y-%m-%d")\n+GALAXY_INFRASTRUCTURE_URL = None\n+\n+# version pinned for cloning\n+\n+mapped_chars = {\n+    ">": "__gt__",\n+    "<": "__lt__",\n+    "\'": "__sq__",\n+    \'"\': "__dq__",\n+    "[": "__ob__",\n+    "]": "__cb__",\n+    "{": "__oc__",\n+    "}": "__cc__",\n+    "@": "__at__",\n+    "#": "__pd__",\n+    "": "__cn__",\n+}\n+\n+\n+class ColorScaling(object):\n+\n+    COLOR_FUNCTION_TEMPLATE = """\n+    function(feature, variableName, glyphObject, track) {{\n+        var score = {score};\n+        {opacity}\n+        return \'rgba({red}, {green}, {blue}, \' + opacity + \')\';\n+    }}\n+    """\n+\n+    COLOR_FUNCTION_TEMPLATE_QUAL = r"""\n+    function(feature, variableName, glyphObject, track) {{\n+        var search_up = function self(sf, attr){{\n+            if(sf.get(attr) !== undefined){{\n+                return sf.get(attr);\n+            }}\n+            if(sf.parent() === undefined) {{\n+                return;\n+            }}else{{\n+                return self(sf.parent(), attr);\n+            }}\n+        }};\n+\n+        var search_down = function self(sf, attr){{\n+            if(sf.get(attr) !== undefined){{\n+                return sf.get(attr);\n+            }}\n+            if(sf.children() === undefined) {{\n+                return;\n+            }}else{{\n+                var kids = sf.children();\n+                for(var child_idx in kids){{\n+                    var x = self(kids[child_idx], attr);\n+                    if(x !== undefined){{\n+                        return x;\n+                    }}\n+                }}\n+                return;\n+            }}\n+        }};\n+\n+        var color = ({user_spec_color} || search_up(feature, \'color\') || search_down(feature, \'color\') || {auto_gen_color});\n+        var score = (search_up(feature, \'score\') || search_down(feature, \'score\'));\n+        {opacity}\n+        if(score === undefined){{ opacity = 1; }}\n+        var result = /^#?([a-f\\d]{{2}})([a-f\\d]{{2}})([a-f\\d]{{2}})$/i.exec(color);\n+        var red = parseInt(result[1], 16);\n+        var green = parseInt(result[2], 16);\n+        var blue = parseInt(result[3], 16);\n+        if(isNaN(opacity) || opacity < 0){{ opacity = 0; }}\n+        return \'rgba(\' + red + \',\' + green + \',\' + blue + \',\' + opacity + \')\';\n+    }}\n+    """\n+\n+    OPACITY_MATH = {\n+        "linear": """\n+            var opacity = (score - ({min})) / (({max}) - ({min}));\n+        """,\n+        "logarithmic": """\n+            var opacity = Math.log10(score - ({min})) / Math.log10(({max}) - ({min}));\n+        """,\n+        "blast": """\n+            var opacity = 0;\n+            if(score == 0.0) {{\n+                opacity = 1;\n+            }} else {{\n+                opacity = (20 - Math.log10(score)) / 180;\n+            }}\n+        """,\n+    }\n+\n+    BREWER_COLOUR_IDX = 0\n+    BREWER_COLOUR_SCHEMES = [\n+        (166, 206, 227),\n+        (31, 120, 180),\n+        (178, 223, 138),\n+        (51, 160, 44),\n+        (251, 154, 153),\n+        (227, 26, 28),\n+        (253, 191, 111),\n+        (255, 127, 0),\n+        (202, 178, 214),\n+        (106, 61, 154),\n+        (255, 255, 153),\n+        (177, 89, 40),\n+        (228, 26, 28),\n+        (55, 126, 184),\n+        (77, 175, 74),\n+        (152, 78, 163),\n+        (255, 127, 0),\n+    ]\n+\n+    BREWER_DIVERGING_PALLETES = {\n+        "BrBg": ("#543005", "#003c30"),\n+        "PiYg": ("#8e0152", "#276419"),\n+        "PRGn": ("#40004b", "#00441b"),\n+        "PuOr": ("#7f3b08", "#2d004b'..b'"],\n+                                x.attrib["useuri"],\n+                                x.attrib["label"],\n+                                metadata,\n+                            )\n+                        else:\n+                            tfa = (\n+                                os.path.realpath(x.attrib["path"]),\n+                                x.attrib["ext"],\n+                                x.attrib["useuri"],\n+                                x.attrib["label"],\n+                                metadata,\n+                            )\n+                        track_conf["trackfiles"].append(tfa)\n+\n+        if is_multi_bigwig:\n+            metadata = metadata_from_node(x.find("metadata"))\n+\n+            track_conf["trackfiles"].append(\n+                (\n+                    multi_bigwig_paths,  # Passing an array of paths to represent as one track\n+                    "bigwig_multiple",\n+                    "MultiBigWig",  # Giving an hardcoded name for now\n+                    {},  # No metadata for multiple bigwig\n+                )\n+            )\n+        track_conf["category"] = track.attrib["cat"]\n+        track_conf["format"] = track.attrib["format"]\n+        if track.find("options/style"):\n+            track_conf["style"] = {\n+                item.tag: parse_style_conf(item) for item in track.find("options/style")\n+            }\n+        else:\n+            track_conf["style"] = {}\n+        tst = track_conf["style"].get("type", None)\n+        if tst:\n+            track_conf["style"]["configuration"] = "%s-%s" % (track_conf["label"], tst)\n+        logging.warn("### got %s for track style" % track_conf["style"])\n+        if track.find("options/style_labels"):\n+            track_conf["style_labels"] = {\n+                item.tag: parse_style_conf(item)\n+                for item in track.find("options/style_labels")\n+            }\n+        track_conf["conf"] = etree_to_dict(track.find("options"))\n+        track_conf["category"] = track.attrib["cat"]\n+        track_conf["format"] = track.attrib["format"]\n+        keys = jc.process_annotations(track_conf)\n+\n+        if keys:\n+            for key in keys:\n+                default_session_data["visibility"][\n+                    track.attrib.get("visibility", "default_off")\n+                ].append(key)\n+                if track_conf.get("style", None):\n+                    default_session_data["style"][key] = track_conf["style"]\n+                if track_conf.get("style_labels", None):\n+                    default_session_data["style_labels"][key] = track_conf.get(\n+                        "style_labels", None\n+                    )\n+        logging.warn(\n+            "# after process, key=%s def session style = %s"\n+            % (key, default_session_data["style"][key])\n+        )\n+    default_session_data["defaultLocation"] = root.find(\n+        "metadata/general/defaultLocation"\n+    ).text\n+    default_session_data["session_name"] = root.find(\n+        "metadata/general/session_name"\n+    ).text\n+    jc.zipOut = root.find("metadata/general/zipOut").text == "true"\n+    general_data = {\n+        "analytics": root.find("metadata/general/analytics").text,\n+        "primary_color": root.find("metadata/general/primary_color").text,\n+        "secondary_color": root.find("metadata/general/secondary_color").text,\n+        "tertiary_color": root.find("metadata/general/tertiary_color").text,\n+        "quaternary_color": root.find("metadata/general/quaternary_color").text,\n+        "font_size": root.find("metadata/general/font_size").text,\n+    }\n+    jc.add_general_configuration(general_data)\n+    trackconf = jc.config_json.get("tracks", None)\n+    if trackconf:\n+        jc.config_json["tracks"].update(jc.tracksToAdd)\n+    else:\n+        jc.config_json["tracks"] = jc.tracksToAdd\n+    jc.write_config()\n+    jc.add_default_session(default_session_data)\n+    logging.warn("### got default_session_data=%s" % default_session_data)\n+    # jc.text_index() not sure what broke here.\n'
b
diff -r c0097a584a8a -r 94264fe60478 jbrowse2broken.xml
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jbrowse2broken.xml Thu Mar 21 08:01:42 2024 +0000
[
b'@@ -0,0 +1,961 @@\n+ <tool id="jbrowse2" name="jbrowse2" version="@TOOL_VERSION@+@WRAPPER_VERSION@_7" profile="22.05">\n+    <description>genome browser</description>\n+    <macros>\n+        <import>macros.xml</import>\n+    </macros>\n+    <expand macro="edamInc"/>\n+    <xrefs>\n+        <xref type="bio.tools">jbrowse2</xref>\n+    </xrefs>\n+    <expand macro="requirements"/>\n+    <version_command>python \'${__tool_directory__}/jbrowse2.py\' --version</version_command>\n+    <command detect_errors="aggressive"><![CDATA[\n+mkdir -p \'$output.files_path\' &&\n+## Copy the XML file into the directory, mostly for debugging\n+## but nice if users want to reproduce locally\n+cp \'$trackxml\' \'$output.files_path/galaxy.xml\' &&\n+\n+export JBROWSE2_PATH=\\$(dirname \\$(which jbrowse))/../opt/jbrowse2  &&\n+\n+#if $jbgen.ucol.formcoll=="collect":\n+    python \'$__tool_directory__/autogenJB2.py\'\n+    #for $key in $autoCollection.keys():\n+        #if $autoCollection[$key].is_collection:\n+            #set subCol=$autoCollection[$key]\n+            #set pafs=[($subCol[x],$subcol[x].ext,x) for x in $subCol.keys() if $subCol[x].ext == \'paf\']\n+            #if len($pafs) > 0:\n+                 --pafmeta \'$pafs[0]\'\n+                #set refs = [($pafs[0][2],$subCol[x],x) for x in $subCol.keys() if $subCol[x].ext == \'fasta\']\n+                #for $ref in $refs:\n+                 --pafreferencemeta \'$ref\'\n+                #end for\n+            #end if\n+        #else if $autoCollection[$key].ext == \'fasta\':\n+          --referencemeta \'$autoCollection[$key],$autoCollection[$key].ext,$key\'\n+        #else if $autoCollection[$key].ext in [\'bed\', \'bigwig\', \'cool\', \'gff\', \'gff3\', \'hic\', \'maf\', \'mcool\', \'scool\', \'vcf\']\n+          --trackmeta \'$autoCollection[$key],$autoCollection[$key].ext,$key\'\n+        #else if $autoCollection[$key].ext in [\'bam\',]\n+          --trackmeta \'$autoCollection[$key],$autoCollection[$key].ext,$key,$autoCollection[$key].metadata.bam_index\'\n+         #else if $autoCollection[$key].ext in [\'cram\',]\n+          --trackmeta \'$autoCollection[$key],$autoCollection[$key].ext,$key,$autoCollection[$key].metadata.cram_index\'\n+        #end if\n+    #end for\n+    --outdir \'$output.files_path\'\n+    --jbrowse2path \\${JBROWSE2_PATH}\n+    --sessName "Autogen JBrowse" &&\n+    #if $jbgen.zipOut == "true":\n+        (cd \'$output.files_path\' && zip -r - . ) > \'$output\'\n+    #else\n+      cp \'$output.files_path/index.html\' \'$output\'\n+    #end if\n+#else:\n+    python \'$__tool_directory__/jbrowse2.py\'\n+    --jbrowse2path \\${JBROWSE2_PATH}\n+    --outdir \'$output.files_path\'\n+    --xml \'$trackxml\' &&\n+    #if $jbgen.zipOut == "true":\n+        (cd \'$output.files_path\' && zip -r - . ) > \'$output\'\n+    #else\n+      cp \'$output.files_path/index.html\' \'$output\'\n+    #end if\n+    ## Ugly testing hack since I cannot get <extra_files> to test the files I want to test. Hmph.\n+    #if str($uglyTestingHack) == "enabled":\n+       &&   cp \'$trackxml\' \'$output\'\n+    #end if\n+#end if\n+  ]]></command>\n+<configfiles>\n+        <configfile name="trackxml"><![CDATA[<?xml version="1.0"?>\n+#if $jbgen.ucol.formcoll=="form":\n+<root>\n+    <metadata>\n+        <genomes>\n+            #if str($reference_genome.genome_type_select) == "uri":\n+              <genome path="${reference_genome.uri}" label="${reference_genome.refname}" useuri="yes">\n+                  <metadata>\n+                     <dataset\n+                      dname = "${reference_genome.refname}" />\n+              </metadata>\n+              </genome>\n+            #else if str($reference_genome.genome_type_select) == "indexed":\n+              <genome path="${reference_genome.genome.fields.path}" label="${reference_genome.genome.fields.name}" useuri="no">\n+                  <metadata>\n+                     <dataset\n+                      dname = "${reference_genome.genome.fields.name}" />\n+                  </metadata>\n+              </genome>\n+            #else\n+              <genome path="$reference_genome.genome" label="${reference_genome.gen'..b'ternative codons for unusual genomes,\n+and detailed track styling is not yet implemented. Send code.\n+JBrowse1 development has now ceased in favour of JBrowse2.\n+\n+Use and local viewing\n+=====================\n+\n+\n+A JBrowse2 history item can be opened by viewing it (the "eye" icon).\n+\n+The same browser data and setup can also be downloaded as a compressed zip archive by clicking the download ("floppy disk") icon in the history.\n+This can be shared and viewed without Galaxy.\n+\n+A replacement application to serve the browser is required without Galaxy. A local python web server can be started using a script included in each archive,\n+assuming that Python3 is already working on your desktop - if not you will have to install it first. Unzip the archive (*unzip [filename].zip*) and change\n+directory to the first level in that zip archive. It contains a file named *jb2_webserver.py*\n+\n+With python3 installed,\n+\n+*python3 jb2_webserver.py*\n+\n+will serve the unarchived JBrowse2 configuration from the same directory as the python script automatically. If a new browser window does not open,\n+but the script appears to be running, try pointing your web browser to the default of *localhost:8080*\n+\n+Overview\n+--------\n+\n+JBrowse is a fast, embeddable genome browser built completely with\n+JavaScript and HTML5.\n+\n+The JBrowse-in-Galaxy (JiG) tool was written to help build complex\n+JBrowse installations straight from Galaxy. It allows you to build up a JBrowse instance without worrying\n+about how to run the command line tools to format your data, and which\n+options need to be supplied and where.\n+\n+Options\n+-------\n+\n+**Reference or Assembly**\n+\n+Choose either a built-in or select one from your history.\n+\n+Track coordinates and contig names *must* match this reference precisely\n+or they will not display.\n+\n+**Track Groups** represent a set of tracks in a single category.\n+\n+Annotation Tracks\n+-----------------\n+\n+GFF3/BED\n+~~~~~~~~\n+\n+Standard feature tracks. They usually highlight genes, mRNAs and other features of interest along a genomic region.\n+\n+When these contain tens of millions of features, such as repeat regions from a VGP assembly, displaying one at a time leads\n+to extremely slow loading times when a large region is in view, unless the "LinearPileupDisplay" display option is\n+selected for that track in the styling options section. The default is LinearBasicDisplay, which shows all details and works\n+well for relatively sparse bed files. A better option is to make a bigwig track using a set of windows based on the\n+lengths of each assembly or reference contig.\n+\n+BAM Pileups\n+~~~~~~~~~~~\n+\n+We support BAM files and can automatically generate SNP tracks based on\n+that bam data.\n+\n+\n+BlastXML\n+~~~~~~~~\n+\n+JiG now supports both blastn and blastp datasets. JiG internally uses a\n+blastXML to gapped GFF3 tool to convert your blastxml datasets into a\n+format amenable to visualization in JBrowse. This tool is also\n+available separately from the IUC on the toolshed.\n+\n+**Minimum Gap Size** reflects how long a gap must be before it becomes a\n+real gap in the processed gff3 file. In the picture above, various sizes\n+of gaps can be seen. If the minimum gap size was set much higher, say\n+100nt, many of the smaller gaps would disappear, and the features on\n+both sides would be merged into one, longer feature. This setting is\n+inversely proportional to runtime and output file size. *Do not set this\n+to a low value for large datasets*. By setting this number lower, you\n+will have extremely large outputs and extremely long runtimes. The\n+default was configured based off of the author\'s experience, but the\n+author only works on small viruses. It is *strongly* recommended that\n+you filter your blast results before display, e.g. picking out the top\n+10 hits or so.\n+\n+**Protein blast search** option merely informs underlying tools that\n+they should adjust feature locations by 3x.\n+\n+\n+@ATTRIBUTION@\n+]]></help>\n+    <expand macro="citations"/>\n+</tool>\n'
b
diff -r c0097a584a8a -r 94264fe60478 macrosbroken.xml
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/macrosbroken.xml Thu Mar 21 08:01:42 2024 +0000
[
b'@@ -0,0 +1,548 @@\n+<?xml version="1.0"?>\n+<macros>\n+    <token name="@TOOL_VERSION@">2.10.1</token>\n+    <xml name = "edamInc">\n+        <edam_topics>\n+            <edam_topic>topic_3307</edam_topic>\n+            <edam_topic>topic_0092</edam_topic>\n+        </edam_topics>\n+        <edam_operations>\n+            <edam_operation>operation_0573</edam_operation>\n+            <edam_operation>operation_0564</edam_operation>\n+        </edam_operations>\n+    </xml>\n+    <xml name="requirements">\n+        <requirements>\n+            <requirement type="package" version="@TOOL_VERSION@">jbrowse2</requirement>\n+            <requirement type="package" version="1.81">biopython</requirement>\n+            <requirement type="package" version="0.7.1">bcbio-gff</requirement>\n+            <requirement type="package" version="1.19">samtools</requirement>\n+            <requirement type="package" version="6.0.1">pyyaml</requirement>\n+            <requirement type="package" version="1.11">tabix</requirement>\n+            <requirement type="package" version="4.6.0">findutils</requirement>\n+            <requirement type="package" version="0.0.8">hictk</requirement>\n+            <yield/>\n+        </requirements>\n+    </xml>\n+    <token name="@DATA_DIR@">\\$GALAXY_JBROWSE_SHARED_DIR</token>\n+    <token name="@WRAPPER_VERSION@">galaxy2</token>\n+    <token name="@ATTRIBUTION@"><![CDATA[\n+**Attribution**\n+This Galaxy tool relies on the JBrowse2, maintained by the GMOD Community. The Galaxy wrapper is maintained by Ross Lazarus\n+until the IUC complete their own.\n+]]>\n+    </token>\n+    <xml name="genome_selector"\n+        token_help=""\n+        token_label="Fasta sequences"\n+        token_optional="False" >\n+        <conditional name="reference_genome">\n+            <param help="Built-in references" label="Reference genome to display" name="genome_type_select" type="select">\n+                <option selected="True" value="indexed">Use a built-in genome</option>\n+                <option value="history">Use a genome from history</option>\n+            </param>\n+            <when value="indexed">\n+                <param\n+                help="@HELP@"\n+                label="@LABEL@"\n+                name="genomes"\n+                type="select"\n+                optional="@OPTIONAL@"\n+                >\n+                    <options from_data_table="all_fasta">\n+                        <filter column="2" type="sort_by" />\n+                        <validator message="No genomes are available for the selected input dataset" type="no_options" />\n+                    </options>\n+                </param>\n+            </when>\n+            <when value="history">\n+                <param\n+                format="fasta"\n+                label="@LABEL@"\n+                help="@HELP@"\n+                name="genomes"\n+                type="data"\n+                optional="@OPTIONAL@"\n+                multiple="True" />\n+            </when>\n+        </conditional>\n+    </xml>\n+\n+    <xml name="auto_manual_tk"\n+        token_cond_label="Color"\n+        token_cond_name="color"\n+        token_select_label="Color Specification"\n+        token_select_name="color_select"\n+        token_automatic_label="Automatically selected"\n+        token_manual_label="Manual Color Selection">\n+        <conditional name="@COND_NAME@" label="@COND_LABEL@">\n+            <param type="select" label="@SELECT_LABEL@" name="@SELECT_NAME@">\n+                <option value="automatic" selected="true">@AUTOMATIC_LABEL@</option>\n+                <option value="manual">@MANUAL_LABEL@</option>\n+            </param>\n+            <when value="automatic">\n+            </when>\n+            <when value="manual">\n+                <yield />\n+            </when>\n+        </conditional>\n+    </xml>\n+\n+    <xml name="jb_color"\n+        token_label="JBrowse style.color"\n+        token_name="style_color"\n+        token_value="goldenrod"\n+        token_help="Basic color of features. Most glyphs interpret this as the fill col'..b'>\n+                    <option value="dijitIconUndo">Undo</option>\n+                    <option value="dijitIconEdit">Edit</option>\n+                    <option value="dijitIconNewTask">New Task</option>\n+                    <option value="dijitIconEditTask">Edit Task</option>\n+                    <option value="dijitIconEditProperty">Edit Property</option>\n+                    <option value="dijitIconTask">Task</option>\n+                    <option value="dijitIconFilter">Filter</option>\n+                    <option value="dijitIconConfigure">Configure</option>\n+                    <option value="dijitIconSearch">Search</option>\n+                    <option value="dijitIconApplication">Application</option>\n+                    <option value="dijitIconChart">Chart</option>\n+                    <option value="dijitIconConnector">Connector</option>\n+                    <option value="dijitIconDatabase">Database</option>\n+                    <option value="dijitIconDocuments">Documents</option>\n+                    <option value="dijitIconMail">Mail</option>\n+                    <option value="dijitLeaf">Leaf</option>\n+                    <option value="dijitIconFile">File</option>\n+                    <option value="dijitIconFunction">Function</option>\n+                    <option value="dijitIconKey">Key</option>\n+                    <option value="dijitIconPackage">Package</option>\n+                    <option value="dijitIconSample">Sample</option>\n+                    <option value="dijitIconTable">Table</option>\n+                    <option value="dijitIconUsers">Users</option>\n+                    <option value="dijitIconFolderClosed">Folder Closed</option>\n+                    <option value="dijitIconFolderOpen">Folder Open</option>\n+                    <option value="dijitIconError">Error</option>\n+                </param>\n+            </repeat>\n+        </section>\n+    </xml>\n+\n+    <xml name="menu_sanitize">\n+        <sanitizer>\n+            <valid>\n+                <add value="{"/>\n+                <add value="}"/>\n+                <add value="!"/>\n+                <add value="?"/>\n+                <add value="&amp;"/>\n+                <add value="+"/>\n+                <add value="="/>\n+                <add value="\'"/>\n+                <add value=\'"\'/>\n+            </valid>\n+        </sanitizer>\n+    </xml>\n+\n+    <xml name="input_conditional" token_label="Track Data" token_format="data">\n+        <conditional name="useuri">\n+                <param name="insource" type="select" label="Define track data as a history file or an internet URI"\n+                    help="A public URI implies that all the associated tabix files are also in place. They are created for history files">\n+                    <option value="history" selected="true">Track data from a history file</option>\n+                    <option value="uri" selected="true">Tabix data URI - index files must be available at corresponding URI</option>\n+                </param>\n+                <when value="history">\n+                       <param label="@LABEL@" format="@FORMAT@" name="annotation" multiple="True" optional="true" type="data" />\n+                </when>\n+                <when value="uri">\n+                       <param label="@LABEL@" name="annouri"  type="text" />\n+                       <param label="Short name for track display" name="annoname" type="text" >\n+                             <sanitizer invalid_char="_">\n+                                <valid initial="string.printable" >\n+                                    <remove value="\'" />\n+                                </valid>\n+                              </sanitizer>\n+                        </param>\n+                </when>\n+            </conditional>\n+     </xml>\n+    <xml name="citations">\n+        <citations>\n+        <citation type="doi">10.1186/s13059-016-0924-1</citation>\n+        <citation type="doi">10.1101/gr.094607.109</citation>\n+        </citations>\n+    </xml>\n+</macros>\n'
b
diff -r c0097a584a8a -r 94264fe60478 test-data/gff3/merlin.gff3
--- a/test-data/gff3/merlin.gff3 Tue Mar 19 02:33:40 2024 +0000
+++ b/test-data/gff3/merlin.gff3 Thu Mar 21 08:01:42 2024 +0000
b
@@ -1,38 +1,28 @@
-##gff-version 3
-##sequence-region Merlin 1 172788
-Merlin  GeneMark.hmm    gene    10  30  .   +   .   ID=Merlin_1;seqid=Merlin
-Merlin  GeneMark.hmm    mRNA    14  30  .   +   .   ID=Merlin_1_mRNA;Parent=Merlin_1
-Merlin  GeneMark.hmm    CDS 14  20  1000    +   0   ID=Merlin_1_CDS ;Parent=Merlin_1_mRNA
-Merlin  GeneMark.hmm    CDS 24  30  500 +   0   ID=Merlin_1_CDS ;Parent=Merlin_1_mRNA
-Merlin  GeneMark.hmm    gene    14  30  .   +   .   ID=Merlin_2;seqid=Merlin;color=#00ff00
-Merlin  GeneMark.hmm    mRNA    14  30  .   +   .   ID=Merlin_2_mRNA;seqid=Merlin;color=#00ff00;Parent=Merlin_2
-Merlin  GeneMark.hmm    CDS 14  20  500 +   0   ID=Merlin_2_CDS ;Parent=Merlin_2_mRNA;color=#0000ff
-Merlin  GeneMark.hmm    CDS 24  30  750 +   0   ID=Merlin_2_CDS ;Parent=Merlin_2_mRNA;color=#00ff00
-Merlin  GeneMark.hmm    gene    10  30  .   +   .   ID=Merlin_3;seqid=Merlin
-Merlin  GeneMark.hmm    mRNA    14  30  .   +   .   ID=Merlin_3A_mRNA;Parent=Merlin_3;color=#0000ff
-Merlin  GeneMark.hmm    CDS 14  18  1000    +   0   ID=Merlin_3A_CDS ;Parent=Merlin_3A_mRNA;color=#0000ff
-Merlin  GeneMark.hmm    CDS 20  30  800 +   0   ID=Merlin_3A_CDS ;Parent=Merlin_3A_mRNA;color=#0000ff
-Merlin  GeneMark.hmm    mRNA    14  30  .   +   .   ID=Merlin_3B_mRNA;Parent=Merlin_3;color=#0000ff
-Merlin  GeneMark.hmm    CDS 14  22  400 +   0   ID=Merlin_3B_CDS ;Parent=Merlin_3B_mRNA;color=#0000ff
-Merlin  GeneMark.hmm    CDS 24  30  1000    +   0   ID=Merlin_3B_CDS ;Parent=Merlin_3B_mRNA;color=#0000ff
-Merlin  exonerate   gene    1740    2300    .   +   .   Name=Apple3;Note=Gene with two splicing models;ID=1
-Merlin  exonerate   mRNA    1740    2300    .   +   .   Name=Apple3-a;Note=mRNA A with both CDSs and UTRs;ID=1A;Parent=1;
-Merlin  exonerate   UTR 1740    1799    .   +   .   Parent=1A
-Merlin  exonerate   CDS 1900    2080    .   +   0   Parent=1A
-Merlin  exonerate   CDS 2100    2120    .   +   2   Parent=1A
-Merlin  exonerate   UTR 2120    2300    .   +   .   Parent=1A
-Merlin  exonerate   mRNA    1740    2300    .   +   .   Name=Apple3-b;Note=mRNA B with both CDSs and UTRs;ID=1B;Parent=1;
-Merlin  exonerate   UTR 1740    1799    .   +   .   Parent=1B
-Merlin  exonerate   CDS 1800    1880    .   +   0   Parent=1B
-Merlin  exonerate   CDS 1900    1950    .   +   1   Parent=1B
-Merlin  exonerate   CDS 2100    2120    .   +   2   Parent=1B
-Merlin  exonerate   UTR 2120    2300    .   +   .   Parent=1B
-#    {
-#    "baseUrl": "http://localhost:8000/out/data/"
-#    "compress": 0,
-#    "label": "Transcript",
-#    "storeClass": "JBrowse/Store/SeqFeature/NCList",
-#    "trackType": "JBrowse/View/Track/CanvasFeatures",
-#    "type": "JBrowse/View/Track/CanvasFeatures",
-#    "urlTemplate": "tracks/42ff9cb16c0509f0abb4a76ce14077bc_0/{refseq}/trackData.json",
-#    }
+##gff-version3
+##sequence-region Merlin 1 172788
+Merlin GeneMark.hmm gene 10 30 . + . ID=Merlin_1;seqid=Merlin
+Merlin GeneMark.hmm mRNA 14 30 . + . ID=Merlin_1_mRNA;Parent=Merlin_1
+Merlin GeneMark.hmm CDS14 20 1000 + 0 ID=Merlin_1_CDS;Parent=Merlin_1_mRNA
+Merlin GeneMark.hmm CDS24 30 500+ 0 ID=Merlin_1_CDS;Parent=Merlin_1_mRNA
+Merlin GeneMark.hmm gene 14 30 . + . ID=Merlin_2;seqid=Merlin;color=#00ff00
+Merlin GeneMark.hmm mRNA 14 30 . + . ID=Merlin_2_mRNA;seqid=Merlin;color=#00ff00;Parent=Merlin_2
+Merlin GeneMark.hmm CDS14 20 500+ 0 ID=Merlin_2_CDS;Parent=Merlin_2_mRNA;color=#0000ff
+Merlin GeneMark.hmm CDS24 30 750+ 0 ID=Merlin_2_CDS;Parent=Merlin_2_mRNA;color=#00ff00
+Merlin GeneMark.hmm gene 10 30 . + . ID=Merlin_3;seqid=Merlin
+Merlin GeneMark.hmm mRNA 14 30 . + . ID=Merlin_3A_mRNA;Parent=Merlin_3;color=#0000ff
+Merlin GeneMark.hmm CDS14 18 1000 + 0 ID=Merlin_3A_CDS;Parent=Merlin_3A_mRNA;color=#0000ff
+Merlin GeneMark.hmm CDS20 30 800+ 0 ID=Merlin_3A_CDS;Parent=Merlin_3A_mRNA;color=#0000ff
+Merlin GeneMark.hmm mRNA 14 30 . + . ID=Merlin_3B_mRNA;Parent=Merlin_3;color=#0000ff
+Merlin GeneMark.hmm CDS14 22 400+ 0 ID=Merlin_3B_CDS;Parent=Merlin_3B_mRNA;color=#0000ff
+Merlin GeneMark.hmm CDS24 30 1000 + 0 ID=Merlin_3B_CDS;Parent=Merlin_3B_mRNA;color=#0000ff
+Merlin exonerate gene 1740 2300 . + . Name=Apple3;Note=Genewithtwosplicingmodels;ID=1
+Merlin exonerate mRNA 1740 2300 . + . Name=Apple3-a;Note=mRNAAwithbothCDSsandUTRs;ID=1A;Parent=1;
+# {
+# "baseUrl":"http://localhost:8000/out/data/"
+# "compress":0,
+# "label":"Transcript",
+# "storeClass":"JBrowse/Store/SeqFeature/NCList",
+# "trackType":"JBrowse/View/Track/CanvasFeatures",
+# "type":"JBrowse/View/Track/CanvasFeatures",
+# "urlTemplate":"tracks/42ff9cb16c0509f0abb4a76ce14077bc_0/{refseq}/trackData.json",
+# }