Mercurial > repos > fubar2 > toolfactory_gtn
diff toolfactory/ToolFactory_tester.xml @ 0:f288fab71d8b draft default tip
Uploaded
author | fubar2 |
---|---|
date | Mon, 26 Apr 2021 04:18:54 +0000 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/toolfactory/ToolFactory_tester.xml Mon Apr 26 04:18:54 2021 +0000 @@ -0,0 +1,455 @@ +<tool name="toolfactory_tester" id="toolfactory_tester" version="1"> + <!--Source in git at: https://github.com/fubar2/toolfactory--> + <!--Created by admin@galaxy.org at 23/04/2021 10:25:58 using the Galaxy Tool Factory.--> + <description>Test an untested tool and update it</description> + <requirements> + <requirement type="package" version="2.30.2">git</requirement> + <requirement type="package" version="0.74.3">planemo</requirement> </requirements> + <stdio> + <exit_code range="1:" level="fatal"/> + </stdio> + <version_command><![CDATA[echo "1"]]></version_command> + <command><![CDATA[ +python +$runme +--in_tool_archive +$in_tool_archive +--new_tested_tool_archive +$new_tested_tool_archive +--galaxy_root +"$galaxyroot" +> +$tf_archive_tester_log; +]]></command> + <configfiles> + <configfile name="runme"><![CDATA[#raw + +# see https://github.com/fubar2/toolfactory +# +# copyright ross lazarus (ross stop lazarus at gmail stop com) May 2012 +# +# all rights reserved +# Licensed under the LGPL +# suggestions for improvement and bug fixes welcome at +# https://github.com/fubar2/toolfactory +# +# July 2020: BCC was fun and I feel like rip van winkle after 5 years. +# Decided to +# 1. Fix the toolfactory so it works - done for simplest case +# 2. Fix planemo so the toolfactory function works +# 3. Rewrite bits using galaxyxml functions where that makes sense - done + +import argparse +import copy +import os +import subprocess +import shutil +import sys +import tarfile +import tempfile +import time +import xml.etree.ElementTree as ET + + +myversion = "V2.2 April 2021" +verbose = True +debug = True +toolFactoryURL = "https://github.com/fubar2/toolfactory" + +def timenow(): + """return current time as a string""" + return time.strftime("%d/%m/%Y %H:%M:%S", time.localtime(time.time())) + +class ToolTester(): + # requires highly insecure docker settings - like write to tool_conf.xml and to tools ! + # if in a container possibly not so courageous. + # Fine on your own laptop but security red flag for most production instances + # uncompress passed tar, run planemo and rebuild a new tarball with tests + + def __init__(self, args=None, in_tool_archive='/galaxy-central/tools/newtool/newtool_toolshed.gz', new_tool_archive=None): + self.args = args + self.new_tool_archive = new_tool_archive + assert tarfile.is_tarfile(in_tool_archive) + # this is not going to go well with arbitrary names. + tff = tarfile.open(in_tool_archive, "r:*") + flist = tff.getnames() + ourdir = os.path.commonpath(flist) # eg pyrevpos + self.tool_name = ourdir + ourxmls = [x for x in flist if x.lower().endswith('.xml') and os.path.split(x)[0] == ourdir] + # planemo_test/planemo_test.xml + assert len(ourxmls) > 0 + self.ourxmls = ourxmls # [os.path.join(tool_path,x) for x in ourxmls] + res = tff.extractall() + self.update_tests(ourdir) + tff.close() + self.tooloutdir = "./tfout" + self.repdir = "./TF_run_report" + self.testdir = os.path.join(self.tooloutdir, "test-data") + if not os.path.exists(self.tooloutdir): + os.mkdir(self.tooloutdir) + if not os.path.exists(self.testdir): + os.mkdir(self.testdir) + if not os.path.exists(self.repdir): + os.mkdir(self.repdir) + self.makeTool() + self.moveRunOutputs() + self.makeToolTar() + + def call_planemo(self,xmlpath,ourdir): + penv = os.environ + #penv['HOME'] = os.path.join(self.args.galaxy_root,'planemo') + #penv["GALAXY_VIRTUAL_ENV"] = os.path.join(penv['HOME'],'.planemo','gx_venv_3.9') + penv["PIP_CACHE_DIR"] = os.path.join(self.args.galaxy_root,'pipcache') + toolfile = os.path.split(xmlpath)[1] + tool_name = self.tool_name + tool_test_output = f"{tool_name}_planemo_test_report.html" + cll = [ + "planemo", + "test", + "--biocontainers", + "--test_output", + os.path.abspath(tool_test_output), + "--galaxy_root", + self.args.galaxy_root, + "--update_test_data", + os.path.abspath(xmlpath), + ] + print(cll) + p = subprocess.run( + cll, + #capture_output=True, + encoding='utf8', + env = penv, + shell=False, + ) + return p + + def makeTool(self): + """write xmls and input samples into place""" + for xreal in self.ourxmls: + x = os.path.split(xreal)[1] + xout = os.path.join(self.tooloutdir,x) + shutil.copyfile(xreal, xout) + # for p in self.infiles: + # pth = p["name"] + # dest = os.path.join(self.testdir, "%s_sample" % p["infilename"]) + # shutil.copyfile(pth, dest) + # dest = os.path.join(self.repdir, "%s_sample" % p["infilename"]) + # shutil.copyfile(pth, dest) + + def makeToolTar(self): + """move outputs into test-data and prepare the tarball""" + excludeme = "_planemo_test_report.html" + + def exclude_function(tarinfo): + filename = tarinfo.name + return None if filename.endswith(excludeme) else tarinfo + + newtar = 'new_%s_toolshed.gz' % self.tool_name + ttf = tarfile.open(newtar, "w:gz") + ttf.add(name=self.tool_name, + arcname=self.tool_name, + filter=exclude_function) + ttf.close() + shutil.copyfile(newtar, self.new_tool_archive) + + def moveRunOutputs(self): + """need to move planemo or run outputs into toolfactory collection""" + with os.scandir(self.tooloutdir) as outs: + for entry in outs: + if not entry.is_file(): + continue + if "." in entry.name: + _, ext = os.path.splitext(entry.name) + if ext in [".tgz", ".json"]: + continue + if ext in [".yml", ".xml", ".yaml"]: + newname = f"{entry.name.replace('.','_')}.txt" + else: + newname = entry.name + else: + newname = f"{entry.name}.txt" + dest = os.path.join(self.repdir, newname) + src = os.path.join(self.tooloutdir, entry.name) + shutil.copyfile(src, dest) + with os.scandir('.') as outs: + for entry in outs: + if not entry.is_file(): + continue + if "." in entry.name: + _, ext = os.path.splitext(entry.name) + if ext in [".yml", ".xml", ".yaml"]: + newname = f"{entry.name.replace('.','_')}.txt" + else: + newname = entry.name + else: + newname = f"{entry.name}.txt" + dest = os.path.join(self.repdir, newname) + src =entry.name + shutil.copyfile(src, dest) + if True or self.args.include_tests: + with os.scandir(self.testdir) as outs: + for entry in outs: + if (not entry.is_file()) or entry.name.endswith( + "_planemo_test_report.html" + ): + continue + if "." in entry.name: + _, ext = os.path.splitext(entry.name) + if ext in [".tgz", ".json"]: + continue + if ext in [".yml", ".xml", ".yaml"]: + newname = f"{entry.name.replace('.','_')}.txt" + else: + newname = entry.name + else: + newname = f"{entry.name}.txt" + dest = os.path.join(self.repdir, newname) + src = os.path.join(self.testdir, entry.name) + shutil.copyfile(src, dest) + + + def update_tests(self,ourdir): + for xmlf in self.ourxmls: + capture = self.call_planemo(xmlf,ourdir) + #sys.stderr.write('%s, stdout=%s, stderr=%s' % (xmlf, capture.stdout, capture.stdout)) + #print('%s, stdout=%s, stderr=%s' % (capture.stdout, capture.stdout,xmlf)) + +def main(): + """ + This is a Galaxy wrapper. + It expects to be called by a special purpose tool.xml + + """ + parser = argparse.ArgumentParser() + a = parser.add_argument + a("--in_tool_archive", default=None) + a("--new_tested_tool_archive", default=None) + a("--galaxy_root", default="/home/ross/gal21/") + args = parser.parse_args() + print('Hello from',os.getcwd()) + tt = ToolTester(args=args, in_tool_archive=args.in_tool_archive, new_tool_archive=args.new_tested_tool_archive) + +if __name__ == "__main__": + main() + + +#end raw]]></configfile> + </configfiles> + <inputs> + <param name="new_tool_name" value="" type="hidden"/> + <param name="in_tool_archive" type="data" optional="false" label="Select a no_test tarfile to test and update for a toolshed" help="" format="toolshed.gz" multiple="false"/> + <param name="galaxyroot" type="text" value="/home/ross/gal21" label="Galaxy root for planemo to use - MUST be made available in the Galaxy job runner configuration" help=""/> + </inputs> + <outputs> + <data name="new_tested_tool_archive" format="toolshed.gz" label="${in_tool_archive.name.split('_')[0]}_tested_toolshed.gz" hidden="false"/> + <data name="tf_archive_tester_log" format="txt" label="${in_tool_archive.name}_test_log" hidden="false"/> + <collection name="TF_run_report" type="list" label="${in_tool_archive.name} test Run reports"> + <discover_datasets pattern="__name_and_ext__" directory="TF_run_report" visible="false"/> + </collection> + </outputs> + <tests> + <test> + <output name="new_tested_tool_archive" value="new_tested_tool_archive_sample" compare="sim_size" delta_frac="0.5"/> + <output name="tf_archive_tester_log" value="tf_archive_tester_log_sample" compare="sim_size" delta_frac="0.1"/> + <param name="in_tool_archive" value="in_tool_archive_sample"/> + <param name="galaxyroot" value="/home/ross/gal21"/> + <output_collection name="TF_run_report"/> + </test> + </tests> + <help><![CDATA[ + +**What it Does** + +------ + +Script:: + + import argparse + import copy + import os + import subprocess + import shutil + import sys + import tarfile + import tempfile + import time + import xml.etree.ElementTree as ET + myversion = "V2.2 April 2021" + verbose = True + debug = True + toolFactoryURL = "https://github.com/fubar2/toolfactory" + def timenow(): + """return current time as a string""" + return time.strftime("%d/%m/%Y %H:%M:%S", time.localtime(time.time())) + + class ToolTester(): + # requires highly insecure docker settings - like write to tool_conf.xml and to tools ! + # if in a container possibly not so courageous. + # Fine on your own laptop but security red flag for most production instances + # uncompress passed tar, run planemo and rebuild a new tarball with tests + def __init__(self, args=None, in_tool_archive='/galaxy-central/tools/newtool/newtool_toolshed.gz', new_tool_archive=None): + self.args = args + self.new_tool_archive = new_tool_archive + assert tarfile.is_tarfile(in_tool_archive) + # this is not going to go well with arbitrary names. + tff = tarfile.open(in_tool_archive, "r:*") + flist = tff.getnames() + ourdir = os.path.commonpath(flist) # eg pyrevpos + self.tool_name = ourdir + ourxmls = [x for x in flist if x.lower().endswith('.xml') and os.path.split(x)[0] == ourdir] + # planemo_test/planemo_test.xml + assert len(ourxmls) > 0 + self.ourxmls = ourxmls # [os.path.join(tool_path,x) for x in ourxmls] + res = tff.extractall() + self.update_tests(ourdir) + tff.close() + self.tooloutdir = "./tfout" + self.repdir = "./TF_run_report" + self.testdir = os.path.join(self.tooloutdir, "test-data") + if not os.path.exists(self.tooloutdir): + os.mkdir(self.tooloutdir) + if not os.path.exists(self.testdir): + os.mkdir(self.testdir) + if not os.path.exists(self.repdir): + os.mkdir(self.repdir) + self.makeTool() + self.moveRunOutputs() + self.makeToolTar() + + def call_planemo(self,xmlpath,ourdir): + penv = os.environ + penv['HOME'] = '/home/ross/galaxy-release_21.01' + toolfile = os.path.split(xmlpath)[1] + tool_name = self.tool_name + tool_test_output = f"{tool_name}_planemo_test_report.html" + cll = [ + "planemo", + "test", + "--test_output", + os.path.abspath(tool_test_output), + "--galaxy_root", + self.args.galaxy_root, + "--update_test_data", + os.path.abspath(xmlpath), + ] + print(cll) + p = subprocess.run( + cll, + capture_output=True, + encoding='utf8', + env = penv, + shell=False, + ) + return p + + def makeTool(self): + """write xmls and input samples into place""" + for xreal in self.ourxmls: + x = os.path.split(xreal)[1] + xout = os.path.join(self.tooloutdir,x) + shutil.copyfile(xreal, xout) + # for p in self.infiles: + # pth = p["name"] + # dest = os.path.join(self.testdir, "%s_sample" % p["infilename"]) + # shutil.copyfile(pth, dest) + # dest = os.path.join(self.repdir, "%s_sample" % p["infilename"]) + # shutil.copyfile(pth, dest) + + def makeToolTar(self): + """move outputs into test-data and prepare the tarball""" + excludeme = "_planemo_test_report.html" + def exclude_function(tarinfo): + filename = tarinfo.name + return None if filename.endswith(excludeme) else tarinfo + newtar = 'new_%s_toolshed.gz' % self.tool_name + ttf = tarfile.open(newtar, "w:gz") + ttf.add(name=self.tooloutdir, + arcname=self.tool_name, + filter=exclude_function) + ttf.close() + shutil.copyfile(newtar, self.new_tool_archive) + + def moveRunOutputs(self): + """need to move planemo or run outputs into toolfactory collection""" + with os.scandir(self.tooloutdir) as outs: + for entry in outs: + if not entry.is_file(): + continue + if "." in entry.name: + _, ext = os.path.splitext(entry.name) + if ext in [".tgz", ".json"]: + continue + if ext in [".yml", ".xml", ".yaml"]: + newname = f"{entry.name.replace('.','_')}.txt" + else: + newname = entry.name + else: + newname = f"{entry.name}.txt" + dest = os.path.join(self.repdir, newname) + src = os.path.join(self.tooloutdir, entry.name) + shutil.copyfile(src, dest) + with os.scandir('.') as outs: + for entry in outs: + if not entry.is_file(): + continue + if "." in entry.name: + _, ext = os.path.splitext(entry.name) + if ext in [".yml", ".xml", ".yaml"]: + newname = f"{entry.name.replace('.','_')}.txt" + else: + newname = entry.name + else: + newname = f"{entry.name}.txt" + dest = os.path.join(self.repdir, newname) + src =entry.name + shutil.copyfile(src, dest) + if True or self.args.include_tests: + with os.scandir(self.testdir) as outs: + for entry in outs: + if (not entry.is_file()) or entry.name.endswith( + "_planemo_test_report.html" + ): + continue + if "." in entry.name: + _, ext = os.path.splitext(entry.name) + if ext in [".tgz", ".json"]: + continue + if ext in [".yml", ".xml", ".yaml"]: + newname = f"{entry.name.replace('.','_')}.txt" + else: + newname = entry.name + else: + newname = f"{entry.name}.txt" + dest = os.path.join(self.repdir, newname) + src = os.path.join(self.testdir, entry.name) + shutil.copyfile(src, dest) + + def update_tests(self,ourdir): + for xmlf in self.ourxmls: + capture = self.call_planemo(xmlf,ourdir) + #sys.stderr.write('%s, stdout=%s, stderr=%s' % (xmlf, capture.stdout, capture.stdout)) + print('%s, stdout=%s, stderr=%s' % (capture.stdout, capture.stdout,xmlf)) + + def main(): + """ + This is a Galaxy wrapper. + It expects to be called by a special purpose tool.xml + """ + parser = argparse.ArgumentParser() + a = parser.add_argument + a("--in_tool_archive", default=None) + a("--new_tested_tool_archive", default=None) + a("--galaxy_root", default="/home/ross/gal21/") + args = parser.parse_args() + print('Hello from',os.getcwd()) + tt = ToolTester(args=args, in_tool_archive=args.in_tool_archive, new_tool_archive=args.new_tested_tool_archive) + if __name__ == "__main__": + main() + +]]></help> + <citations> + <citation type="doi">10.1093/bioinformatics/bts573</citation> + </citations> +</tool> +