diff toolfactory/ToolFactory.py @ 5:e2c8c2fa192d draft

Uploaded
author fubar
date Tue, 27 Apr 2021 23:33:49 +0000
parents 2a46da701dde
children efefe43f23c8
line wrap: on
line diff
--- a/toolfactory/ToolFactory.py	Mon Apr 26 05:25:26 2021 +0000
+++ b/toolfactory/ToolFactory.py	Tue Apr 27 23:33:49 2021 +0000
@@ -70,146 +70,41 @@
             citation_tuples.append(("bibtex", citation[len("bibtex") :].strip()))
     return citation_tuples
 
-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, report_dir, in_tool_archive, new_tool_archive, include_tests, galaxy_root):
-        self.new_tool_archive = new_tool_archive
-        self.include_tests = include_tests
-        self.galaxy_root = galaxy_root
-        self.repdir = report_dir
-        assert in_tool_archive and tarfile.is_tarfile(in_tool_archive)
-        # this is not going to go well with arbitrary names. TODO introspect tool xml!
-        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()
-        tff.close()
-        self.update_tests(ourdir)
-        self.tooloutdir = ourdir
-        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)
-        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.moveRunOutputs()
-        self.makeToolTar()
-
-    def call_planemo(self,xmlpath,ourdir):
-        penv = os.environ
-        penv['HOME'] = os.path.join(self.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.galaxy_root,'pipcache')
-        toolfile = os.path.split(xmlpath)[1]
-        tool_name = self.tool_name
-        tool_test_output = os.path.join(self.repdir, f"{tool_name}_planemo_test_report.html")
-        cll = ["planemo",
-            "test",
-            #"--job_config_file",
-            # os.path.join(self.galaxy_root,"config","job_conf.xml"),
-            #"--galaxy_python_version",
-            #"3.9",
-            "--test_output",
-            os.path.abspath(tool_test_output),
-            "--galaxy_root",
-            self.galaxy_root,
-            "--update_test_data",
-            os.path.abspath(xmlpath),
-        ]
-        print("Call planemo cl =", cll)
-        p = subprocess.run(
-            cll,
-            capture_output=True,
-            encoding='utf8',
-            env = penv,
-            shell=False,
-        )
-        return p
-
-    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 move_One(self,scandir):
-        with os.scandir('.') as outs:
-            for entry in outs:
-                newname = entry.name
-                if not entry.is_file() or entry.name.endswith('_sample'):
-                    continue
-                if not (entry.name.endswith('.html') or entry.name.endswith('.gz') or entry.name.endswith(".tgz")):
-                    fname, ext = os.path.splitext(entry.name)
-                    if len(ext) > 1:
-                        newname = f"{fname}_{ext[1:]}.txt"
-                    else:
-                        newname = f"{fname}.txt"
-                dest = os.path.join(self.repdir, newname)
-                src = entry.name
-                shutil.copyfile(src, dest)
-
-    def moveRunOutputs(self):
-        """need to move planemo or run outputs into toolfactory collection"""
-        self.move_One(self.tooloutdir)
-        self.move_One('.')
-        if self.include_tests:
-            self.move_One(self.testdir)
-
-    def update_tests(self,ourdir):
-        for xmlf in self.ourxmls:
-            capture = self.call_planemo(xmlf,ourdir)
-            logf = open(f"%s_run_report" % (self.tool_name),'w')
-            logf.write("stdout:")
-            logf.write(capture.stdout)
-            logf.write("stderr:")
-            logf.write(capture.stderr)
-
-
 class ToolConfUpdater():
     # update config/tool_conf.xml with a new tool unpacked in /tools
     # 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
 
-    def __init__(self, args, tool_conf_path, new_tool_archive_path, new_tool_name, tool_dir):
+  def __init__(self, args, tool_conf_path, new_tool_archive_path, new_tool_name, tool_dir):
         self.args = args
-        self.tool_conf_path = tool_conf_path
+        self.tool_conf_path = os.path.join(args.galaxy_root,tool_conf_path)
+        self.tool_dir = os.path.join(args.galaxy_root, tool_dir)
         self.our_name = 'ToolFactory'
         tff = tarfile.open(new_tool_archive_path, "r:*")
         flist = tff.getnames()
         ourdir = os.path.commonpath(flist) # eg pyrevpos
         self.tool_id = ourdir # they are the same for TF tools
         ourxml = [x for x in flist if x.lower().endswith('.xml')]
-        res = tff.extractall(tool_dir)
+        res = tff.extractall()
         tff.close()
+        self.run_rsync(ourdir, self.tool_dir)
         self.update_toolconf(ourdir,ourxml)
 
+    def run_rsync(self, srcf, dstf):
+        src = os.path.abspath(srcf)
+        dst = os.path.abspath(dstf)
+        if os.path.isdir(src):
+            cll = ['rsync', '-vr', src, dst]
+        else:
+            cll = ['rsync', '-v', src, dst]
+        p = subprocess.run(
+            cll,
+            capture_output=False,
+            encoding='utf8',
+            shell=False,
+        )
+
     def install_deps(self):
         gi = galaxy.GalaxyInstance(url=self.args.galaxy_url, key=self.args.galaxy_api_key)
         x = gi.tools.install_dependencies(self.tool_id)
@@ -217,7 +112,9 @@
 
     def update_toolconf(self,ourdir,ourxml): # path is relative to tools
         updated = False
-        tree = ET.parse(self.tool_conf_path)
+        localconf = './local_tool_conf.xml'
+        self.run_rsync(self.tool_conf_path,localconf)
+        tree = ET.parse(localconf)
         root = tree.getroot()
         hasTF = False
         TFsection = None
@@ -235,7 +132,9 @@
                 updated = True
                 ET.SubElement(TFsection, 'tool', {'file':xml})
         ET.indent(tree)
-        tree.write(self.tool_conf_path, pretty_print=True)
+        newconf = f"{self.tool_id}_conf"
+        tree.write(newconf, pretty_print=True)
+        self.run_rsync(newconf,self.tool_conf_path)
         if False and self.args.packages and self.args.packages > '':
             self.install_deps()
 
@@ -1171,8 +1070,8 @@
     a("--include_tests", default=False, action="store_true")
     a("--install", default=False, action="store_true")
     a("--run_test", default=False, action="store_true")
-    a("--local_tools", default='tools') # relative to galaxy_root
-    a("--tool_conf_path", default='/galaxy_root/config/tool_conf.xml')
+    a("--local_tools", default='tools') # relative to $__root_dir__
+    a("--tool_conf_path", default='config/tool_conf.xml') # relative to $__root_dir__
     a("--galaxy_url", default="http://localhost:8080")
     a("--toolshed_url", default="http://localhost:9009")
     # make sure this is identical to tool_sheds_conf.xml
@@ -1203,8 +1102,8 @@
             tt = ToolTester(report_dir=r.repdir, in_tool_archive=r.newtarpath, new_tool_archive=r.args.new_tool, galaxy_root=args.galaxy_root, include_tests=False)
     if args.install:
         #try:
-        tcu = ToolConfUpdater(args=args, tool_dir=os.path.join(args.galaxy_root,args.local_tools),
-        new_tool_archive_path=r.newtarpath, tool_conf_path=os.path.join(args.galaxy_root,'config','tool_conf.xml'),
+        tcu = ToolConfUpdater(args=args, tool_dir=args.local_tools,
+        new_tool_archive_path=r.newtarpath, tool_conf_path=args.tool_conf_path,
         new_tool_name=r.tool_name)
         #except Exception:
         #   print("### Unable to install the new tool. Are you sure you have all the required special settings?")