| 84 | 1 # replace with shebang for biocontainer | 
| 48 | 2 # see https://github.com/fubar2/toolfactory | 
|  | 3 # | 
|  | 4 # copyright ross lazarus (ross stop lazarus at gmail stop com) May 2012 | 
|  | 5 # | 
|  | 6 # all rights reserved | 
|  | 7 # Licensed under the LGPL | 
| 49 | 8 # suggestions for improvement and bug fixes welcome at | 
|  | 9 # https://github.com/fubar2/toolfactory | 
| 48 | 10 # | 
|  | 11 # July 2020: BCC was fun and I feel like rip van winkle after 5 years. | 
|  | 12 # Decided to | 
|  | 13 # 1. Fix the toolfactory so it works - done for simplest case | 
|  | 14 # 2. Fix planemo so the toolfactory function works | 
|  | 15 # 3. Rewrite bits using galaxyxml functions where that makes sense - done | 
|  | 16 | 
|  | 17 import argparse | 
| 101 | 18 import copy | 
| 48 | 19 import logging | 
|  | 20 import os | 
|  | 21 import re | 
|  | 22 import shutil | 
|  | 23 import subprocess | 
|  | 24 import sys | 
|  | 25 import tarfile | 
|  | 26 import tempfile | 
|  | 27 import time | 
|  | 28 | 
| 100 | 29 from bioblend import ConnectionError | 
| 63 | 30 from bioblend import toolshed | 
|  | 31 | 
| 48 | 32 import galaxyxml.tool as gxt | 
|  | 33 import galaxyxml.tool.parameters as gxtp | 
|  | 34 | 
|  | 35 import lxml | 
|  | 36 | 
|  | 37 import yaml | 
|  | 38 | 
|  | 39 myversion = "V2.1 July 2020" | 
|  | 40 verbose = True | 
|  | 41 debug = True | 
|  | 42 toolFactoryURL = "https://github.com/fubar2/toolfactory" | 
|  | 43 ourdelim = "~~~" | 
|  | 44 | 
| 119 | 45 # --input_files="$intab.input_files~~~$intab.input_CL~~~ | 
|  | 46 # $intab.input_formats# ~~~$intab.input_label | 
|  | 47 # ~~~$intab.input_help" | 
| 48 | 48 IPATHPOS = 0 | 
|  | 49 ICLPOS = 1 | 
|  | 50 IFMTPOS = 2 | 
|  | 51 ILABPOS = 3 | 
|  | 52 IHELPOS = 4 | 
|  | 53 IOCLPOS = 5 | 
|  | 54 | 
| 119 | 55 # --output_files "$otab.history_name~~~$otab.history_format~~~ | 
|  | 56 # $otab.history_CL~~~$otab.history_test" | 
| 48 | 57 ONAMEPOS = 0 | 
|  | 58 OFMTPOS = 1 | 
|  | 59 OCLPOS = 2 | 
| 49 | 60 OTESTPOS = 3 | 
|  | 61 OOCLPOS = 4 | 
|  | 62 | 
| 48 | 63 | 
|  | 64 # --additional_parameters="$i.param_name~~~$i.param_value~~~ | 
| 119 | 65 # $i.param_label~~~$i.param_help~~~$i.param_type | 
|  | 66 # ~~~$i.CL~~~i$.param_CLoverride" | 
| 48 | 67 ANAMEPOS = 0 | 
|  | 68 AVALPOS = 1 | 
|  | 69 ALABPOS = 2 | 
|  | 70 AHELPPOS = 3 | 
|  | 71 ATYPEPOS = 4 | 
|  | 72 ACLPOS = 5 | 
|  | 73 AOVERPOS = 6 | 
|  | 74 AOCLPOS = 7 | 
|  | 75 | 
|  | 76 | 
|  | 77 foo = len(lxml.__version__) | 
|  | 78 # fug you, flake8. Say my name! | 
| 49 | 79 FAKEEXE = "~~~REMOVE~~~ME~~~" | 
|  | 80 # need this until a PR/version bump to fix galaxyxml prepending the exe even | 
|  | 81 # with override. | 
|  | 82 | 
| 48 | 83 | 
|  | 84 def timenow(): | 
| 75 | 85     """return current time as a string""" | 
| 48 | 86     return time.strftime("%d/%m/%Y %H:%M:%S", time.localtime(time.time())) | 
|  | 87 | 
|  | 88 | 
|  | 89 def quote_non_numeric(s): | 
|  | 90     """return a prequoted string for non-numerics | 
|  | 91     useful for perl and Rscript parameter passing? | 
|  | 92     """ | 
|  | 93     try: | 
|  | 94         _ = float(s) | 
|  | 95         return s | 
|  | 96     except ValueError: | 
|  | 97         return '"%s"' % s | 
|  | 98 | 
|  | 99 | 
| 119 | 100 html_escape_table = { | 
|  | 101     "&": "&", | 
|  | 102     ">": ">", | 
|  | 103     "<": "<", | 
|  | 104     "#": "#", | 
|  | 105     "$": "$", | 
|  | 106 } | 
|  | 107 cheetah_escape_table = {"$": "\\$", "#": "\\#"} | 
|  | 108 | 
| 48 | 109 | 
|  | 110 def html_escape(text): | 
|  | 111     """Produce entities within text.""" | 
| 110 | 112     return "".join([html_escape_table.get(c, c) for c in text]) | 
| 48 | 113 | 
| 119 | 114 | 
| 108 | 115 def cheetah_escape(text): | 
|  | 116     """Produce entities within text.""" | 
| 110 | 117     return "".join([cheetah_escape_table.get(c, c) for c in text]) | 
| 108 | 118 | 
| 48 | 119 | 
|  | 120 def html_unescape(text): | 
|  | 121     """Revert entities within text. Multiple character targets so use replace""" | 
|  | 122     t = text.replace("&", "&") | 
|  | 123     t = t.replace(">", ">") | 
|  | 124     t = t.replace("<", "<") | 
|  | 125     t = t.replace("\\$", "$") | 
| 119 | 126     t = t.replace("$", "$") | 
|  | 127     t = t.replace("#", "#") | 
| 48 | 128     return t | 
|  | 129 | 
|  | 130 | 
|  | 131 def parse_citations(citations_text): | 
| 75 | 132     """""" | 
| 48 | 133     citations = [c for c in citations_text.split("**ENTRY**") if c.strip()] | 
|  | 134     citation_tuples = [] | 
|  | 135     for citation in citations: | 
|  | 136         if citation.startswith("doi"): | 
|  | 137             citation_tuples.append(("doi", citation[len("doi") :].strip())) | 
|  | 138         else: | 
| 119 | 139             citation_tuples.append( | 
|  | 140                 ("bibtex", citation[len("bibtex") :].strip()) | 
|  | 141             ) | 
| 48 | 142     return citation_tuples | 
|  | 143 | 
|  | 144 | 
|  | 145 class ScriptRunner: | 
|  | 146     """Wrapper for an arbitrary script | 
|  | 147     uses galaxyxml | 
|  | 148 | 
|  | 149     """ | 
|  | 150 | 
|  | 151     def __init__(self, args=None): | 
|  | 152         """ | 
|  | 153         prepare command line cl for running the tool here | 
|  | 154         and prepare elements needed for galaxyxml tool generation | 
|  | 155         """ | 
| 101 | 156         self.ourcwd = os.getcwd() | 
|  | 157         self.ourenv = copy.deepcopy(os.environ) | 
| 48 | 158         self.infiles = [x.split(ourdelim) for x in args.input_files] | 
|  | 159         self.outfiles = [x.split(ourdelim) for x in args.output_files] | 
|  | 160         self.addpar = [x.split(ourdelim) for x in args.additional_parameters] | 
|  | 161         self.args = args | 
|  | 162         self.cleanuppar() | 
|  | 163         self.lastclredirect = None | 
|  | 164         self.lastxclredirect = None | 
|  | 165         self.cl = [] | 
|  | 166         self.xmlcl = [] | 
|  | 167         self.is_positional = self.args.parampass == "positional" | 
| 63 | 168         if self.args.sysexe: | 
| 49 | 169             self.executeme = self.args.sysexe | 
| 63 | 170         else: | 
|  | 171             if self.args.packages: | 
| 119 | 172                 self.executeme = ( | 
|  | 173                     self.args.packages.split(",")[0].split(":")[0].strip() | 
|  | 174                 ) | 
| 63 | 175             else: | 
|  | 176                 self.executeme = None | 
| 48 | 177         aCL = self.cl.append | 
| 49 | 178         aXCL = self.xmlcl.append | 
| 48 | 179         assert args.parampass in [ | 
|  | 180             "0", | 
|  | 181             "argparse", | 
|  | 182             "positional", | 
| 49 | 183         ], 'args.parampass must be "0","positional" or "argparse"' | 
| 48 | 184         self.tool_name = re.sub("[^a-zA-Z0-9_]+", "", args.tool_name) | 
|  | 185         self.tool_id = self.tool_name | 
| 50 | 186         self.newtool = gxt.Tool( | 
| 101 | 187             self.tool_name, | 
| 48 | 188             self.tool_id, | 
|  | 189             self.args.tool_version, | 
|  | 190             self.args.tool_desc, | 
| 50 | 191             FAKEEXE, | 
| 48 | 192         ) | 
| 76 | 193         self.newtarpath = "toolfactory_%s.tgz" % self.tool_name | 
| 98 | 194         self.tooloutdir = "./tfout" | 
|  | 195         self.repdir = "./TF_run_report_tempdir" | 
| 48 | 196         self.testdir = os.path.join(self.tooloutdir, "test-data") | 
|  | 197         if not os.path.exists(self.tooloutdir): | 
|  | 198             os.mkdir(self.tooloutdir) | 
|  | 199         if not os.path.exists(self.testdir): | 
| 113 | 200             os.mkdir(self.testdir) | 
| 48 | 201         if not os.path.exists(self.repdir): | 
|  | 202             os.mkdir(self.repdir) | 
|  | 203         self.tinputs = gxtp.Inputs() | 
|  | 204         self.toutputs = gxtp.Outputs() | 
|  | 205         self.testparam = [] | 
| 49 | 206         if self.args.script_path: | 
|  | 207             self.prepScript() | 
|  | 208         if self.args.command_override: | 
|  | 209             scos = open(self.args.command_override, "r").readlines() | 
|  | 210             self.command_override = [x.rstrip() for x in scos] | 
|  | 211         else: | 
|  | 212             self.command_override = None | 
|  | 213         if self.args.test_override: | 
|  | 214             stos = open(self.args.test_override, "r").readlines() | 
|  | 215             self.test_override = [x.rstrip() for x in stos] | 
|  | 216         else: | 
|  | 217             self.test_override = None | 
| 50 | 218         if self.args.cl_prefix:  # DIY CL start | 
| 49 | 219             clp = self.args.cl_prefix.split(" ") | 
|  | 220             for c in clp: | 
|  | 221                 aCL(c) | 
|  | 222                 aXCL(c) | 
|  | 223         else: | 
| 56 | 224             if self.args.script_path: | 
|  | 225                 aCL(self.executeme) | 
|  | 226                 aCL(self.sfile) | 
|  | 227                 aXCL(self.executeme) | 
|  | 228                 aXCL("$runme") | 
| 48 | 229             else: | 
| 113 | 230                 aCL(self.executeme) | 
| 56 | 231                 aXCL(self.executeme) | 
| 119 | 232         self.elog = os.path.join( | 
|  | 233             self.repdir, "%s_error_log.txt" % self.tool_name | 
|  | 234         ) | 
|  | 235         self.tlog = os.path.join( | 
|  | 236             self.repdir, "%s_runner_log.txt" % self.tool_name | 
|  | 237         ) | 
| 48 | 238 | 
|  | 239         if self.args.parampass == "0": | 
|  | 240             self.clsimple() | 
|  | 241         else: | 
|  | 242             clsuffix = [] | 
|  | 243             xclsuffix = [] | 
|  | 244             for i, p in enumerate(self.infiles): | 
| 119 | 245                 if p[IOCLPOS].upper() == "STDIN": | 
| 48 | 246                     appendme = [ | 
| 119 | 247                         p[ICLPOS], | 
| 48 | 248                         p[ICLPOS], | 
|  | 249                         p[IPATHPOS], | 
|  | 250                         "< %s" % p[IPATHPOS], | 
|  | 251                     ] | 
|  | 252                     xappendme = [ | 
| 119 | 253                         p[ICLPOS], | 
| 48 | 254                         p[ICLPOS], | 
|  | 255                         p[IPATHPOS], | 
|  | 256                         "< $%s" % p[ICLPOS], | 
|  | 257                     ] | 
|  | 258                 else: | 
|  | 259                     appendme = [p[IOCLPOS], p[ICLPOS], p[IPATHPOS], ""] | 
|  | 260                     xappendme = [p[IOCLPOS], p[ICLPOS], "$%s" % p[ICLPOS], ""] | 
|  | 261                 clsuffix.append(appendme) | 
|  | 262                 xclsuffix.append(xappendme) | 
|  | 263             for i, p in enumerate(self.outfiles): | 
| 112 | 264                 if p[OOCLPOS] == "STDOUT": | 
| 48 | 265                     self.lastclredirect = [">", p[ONAMEPOS]] | 
|  | 266                     self.lastxclredirect = [">", "$%s" % p[OCLPOS]] | 
| 113 | 267                 else: | 
| 119 | 268                     clsuffix.append([p[OCLPOS], p[ONAMEPOS], p[ONAMEPOS], ""]) | 
|  | 269                     xclsuffix.append( | 
|  | 270                         [p[OCLPOS], p[ONAMEPOS], "$%s" % p[ONAMEPOS], ""] | 
|  | 271                     ) | 
| 48 | 272             for p in self.addpar: | 
| 119 | 273                 clsuffix.append( | 
|  | 274                     [p[AOCLPOS], p[ACLPOS], p[AVALPOS], p[AOVERPOS]] | 
|  | 275                 ) | 
| 48 | 276                 xclsuffix.append( | 
|  | 277                     [p[AOCLPOS], p[ACLPOS], '"$%s"' % p[ANAMEPOS], p[AOVERPOS]] | 
|  | 278                 ) | 
|  | 279             clsuffix.sort() | 
|  | 280             xclsuffix.sort() | 
|  | 281             self.xclsuffix = xclsuffix | 
|  | 282             self.clsuffix = clsuffix | 
|  | 283             if self.args.parampass == "positional": | 
|  | 284                 self.clpositional() | 
|  | 285             else: | 
|  | 286                 self.clargparse() | 
|  | 287 | 
|  | 288     def prepScript(self): | 
|  | 289         rx = open(self.args.script_path, "r").readlines() | 
|  | 290         rx = [x.rstrip() for x in rx] | 
|  | 291         rxcheck = [x.strip() for x in rx if x.strip() > ""] | 
|  | 292         assert len(rxcheck) > 0, "Supplied script is empty. Cannot run" | 
|  | 293         self.script = "\n".join(rx) | 
|  | 294         fhandle, self.sfile = tempfile.mkstemp( | 
| 49 | 295             prefix=self.tool_name, suffix="_%s" % (self.executeme) | 
| 48 | 296         ) | 
|  | 297         tscript = open(self.sfile, "w") | 
|  | 298         tscript.write(self.script) | 
|  | 299         tscript.close() | 
| 109 | 300         self.escapedScript = [cheetah_escape(x) for x in rx] | 
| 112 | 301         self.spacedScript = [f"    {x}" for x in rx if x.strip() > ""] | 
| 49 | 302         art = "%s.%s" % (self.tool_name, self.executeme) | 
| 48 | 303         artifact = open(art, "wb") | 
| 119 | 304         artifact.write(bytes("\n".join(self.escapedScript), "utf8")) | 
| 48 | 305         artifact.close() | 
|  | 306 | 
|  | 307     def cleanuppar(self): | 
|  | 308         """ positional parameters are complicated by their numeric ordinal""" | 
| 119 | 309         if self.args.parampass == "positional": | 
|  | 310             for i, p in enumerate(self.infiles): | 
|  | 311                 assert ( | 
|  | 312                     p[ICLPOS].isdigit() or p[ICLPOS].strip().upper() == "STDIN" | 
|  | 313                 ), "Positional parameters must be ordinal integers - got %s for %s" % ( | 
|  | 314                     p[ICLPOS], | 
|  | 315                     p[ILABPOS], | 
| 48 | 316                 ) | 
| 119 | 317             for i, p in enumerate(self.outfiles): | 
|  | 318                 assert ( | 
|  | 319                     p[OCLPOS].isdigit() | 
|  | 320                     or p[OCLPOS].strip().upper() == "STDOUT" | 
|  | 321                 ), "Positional parameters must be ordinal integers - got %s for %s" % ( | 
| 75 | 322                     p[OCLPOS], | 
|  | 323                     p[ONAMEPOS], | 
| 48 | 324                 ) | 
| 119 | 325             for i, p in enumerate(self.addpar): | 
| 75 | 326                 assert p[ | 
|  | 327                     ACLPOS | 
|  | 328                 ].isdigit(), "Positional parameters must be ordinal integers - got %s for %s" % ( | 
|  | 329                     p[ACLPOS], | 
|  | 330                     p[ANAMEPOS], | 
| 48 | 331                 ) | 
| 119 | 332         for i, p in enumerate(self.infiles): | 
|  | 333             infp = copy.copy(p) | 
|  | 334             icl = infp[ICLPOS] | 
|  | 335             infp.append(icl) | 
|  | 336             if ( | 
|  | 337                 infp[ICLPOS].isdigit() | 
|  | 338                 or self.args.parampass == "0" | 
|  | 339                 or infp[ICLPOS].strip().upper() == "STDOUT" | 
|  | 340             ): | 
|  | 341                 scl = "input%d" % (i + 1) | 
|  | 342                 infp[ICLPOS] = scl | 
|  | 343             self.infiles[i] = infp | 
|  | 344         for i, p in enumerate(self.outfiles): | 
|  | 345             p.append(p[OCLPOS])  # keep copy | 
|  | 346             if ( | 
|  | 347                 p[OOCLPOS].isdigit() and self.args.parampass != "positional" | 
|  | 348             ) or p[OOCLPOS].strip().upper() == "STDOUT": | 
|  | 349                 scl = p[ONAMEPOS] | 
|  | 350                 p[OCLPOS] = scl | 
|  | 351             self.outfiles[i] = p | 
|  | 352         for i, p in enumerate(self.addpar): | 
| 48 | 353             p.append(p[ACLPOS]) | 
|  | 354             if p[ACLPOS].isdigit(): | 
| 119 | 355                 scl = "param%s" % p[ACLPOS] | 
| 48 | 356                 p[ACLPOS] = scl | 
|  | 357             self.addpar[i] = p | 
|  | 358 | 
|  | 359     def clsimple(self): | 
| 75 | 360         """no parameters - uses < and > for i/o""" | 
| 48 | 361         aCL = self.cl.append | 
|  | 362         aXCL = self.xmlcl.append | 
| 62 | 363 | 
|  | 364         if len(self.infiles) > 0: | 
|  | 365             aCL("<") | 
|  | 366             aCL(self.infiles[0][IPATHPOS]) | 
|  | 367             aXCL("<") | 
|  | 368             aXCL("$%s" % self.infiles[0][ICLPOS]) | 
|  | 369         if len(self.outfiles) > 0: | 
|  | 370             aCL(">") | 
|  | 371             aCL(self.outfiles[0][OCLPOS]) | 
|  | 372             aXCL(">") | 
|  | 373             aXCL("$%s" % self.outfiles[0][ONAMEPOS]) | 
| 48 | 374 | 
|  | 375     def clpositional(self): | 
|  | 376         # inputs in order then params | 
|  | 377         aCL = self.cl.append | 
|  | 378         for (o_v, k, v, koverride) in self.clsuffix: | 
|  | 379             if " " in v: | 
|  | 380                 aCL("%s" % v) | 
|  | 381             else: | 
|  | 382                 aCL(v) | 
|  | 383         aXCL = self.xmlcl.append | 
|  | 384         for (o_v, k, v, koverride) in self.xclsuffix: | 
|  | 385             aXCL(v) | 
|  | 386         if self.lastxclredirect: | 
|  | 387             aXCL(self.lastxclredirect[0]) | 
|  | 388             aXCL(self.lastxclredirect[1]) | 
| 112 | 389 | 
| 48 | 390     def clargparse(self): | 
| 75 | 391         """argparse style""" | 
| 48 | 392         aCL = self.cl.append | 
|  | 393         aXCL = self.xmlcl.append | 
|  | 394         # inputs then params in argparse named form | 
| 112 | 395 | 
| 48 | 396         for (o_v, k, v, koverride) in self.xclsuffix: | 
|  | 397             if koverride > "": | 
|  | 398                 k = koverride | 
|  | 399             elif len(k.strip()) == 1: | 
|  | 400                 k = "-%s" % k | 
|  | 401             else: | 
|  | 402                 k = "--%s" % k | 
|  | 403             aXCL(k) | 
|  | 404             aXCL(v) | 
|  | 405         for (o_v, k, v, koverride) in self.clsuffix: | 
|  | 406             if koverride > "": | 
|  | 407                 k = koverride | 
|  | 408             elif len(k.strip()) == 1: | 
|  | 409                 k = "-%s" % k | 
|  | 410             else: | 
|  | 411                 k = "--%s" % k | 
|  | 412             aCL(k) | 
|  | 413             aCL(v) | 
| 112 | 414 | 
| 48 | 415     def getNdash(self, newname): | 
|  | 416         if self.is_positional: | 
|  | 417             ndash = 0 | 
|  | 418         else: | 
|  | 419             ndash = 2 | 
|  | 420             if len(newname) < 2: | 
|  | 421                 ndash = 1 | 
|  | 422         return ndash | 
|  | 423 | 
|  | 424     def doXMLparam(self): | 
|  | 425         """flake8 made me do this...""" | 
| 119 | 426         for ( | 
|  | 427             p | 
|  | 428         ) in ( | 
|  | 429             self.outfiles | 
|  | 430         ):  # --output_files "$otab.history_name~~~$otab.history_format~~~$otab.history_CL~~~$otab.history_test" | 
| 49 | 431             newname, newfmt, newcl, test, oldcl = p | 
| 108 | 432             test = test.strip() | 
| 48 | 433             ndash = self.getNdash(newcl) | 
| 119 | 434             aparm = gxtp.OutputData( | 
|  | 435                 name=newname, format=newfmt, num_dashes=ndash, label=newcl | 
|  | 436             ) | 
| 48 | 437             aparm.positional = self.is_positional | 
|  | 438             if self.is_positional: | 
| 113 | 439                 if oldcl.upper() == "STDOUT": | 
| 48 | 440                     aparm.positional = 9999999 | 
| 111 | 441                     aparm.command_line_override = "> $%s" % newname | 
| 48 | 442                 else: | 
|  | 443                     aparm.positional = int(oldcl) | 
| 111 | 444                     aparm.command_line_override = "$%s" % newname | 
| 48 | 445             self.toutputs.append(aparm) | 
| 49 | 446             ld = None | 
| 108 | 447             if test.strip() > "": | 
| 50 | 448                 if test.startswith("diff"): | 
| 108 | 449                     c = "diff" | 
|  | 450                     ld = 0 | 
| 50 | 451                     if test.split(":")[1].isdigit: | 
|  | 452                         ld = int(test.split(":")[1]) | 
| 108 | 453                     tp = gxtp.TestOutput( | 
| 119 | 454                         name=newname, | 
|  | 455                         value="%s_sample" % newname, | 
|  | 456                         format=newfmt, | 
|  | 457                         compare=c, | 
|  | 458                         lines_diff=ld, | 
|  | 459                     ) | 
| 108 | 460                 elif test.startswith("sim_size"): | 
|  | 461                     c = "sim_size" | 
|  | 462                     tn = test.split(":")[1].strip() | 
| 119 | 463                     if tn > "": | 
|  | 464                         if "." in tn: | 
| 108 | 465                             delta = None | 
| 119 | 466                             delta_frac = min(1.0, float(tn)) | 
| 108 | 467                         else: | 
|  | 468                             delta = int(tn) | 
|  | 469                             delta_frac = None | 
|  | 470                     tp = gxtp.TestOutput( | 
| 119 | 471                         name=newname, | 
|  | 472                         value="%s_sample" % newname, | 
|  | 473                         format=newfmt, | 
|  | 474                         compare=c, | 
|  | 475                         delta=delta, | 
|  | 476                         delta_frac=delta_frac, | 
|  | 477                     ) | 
| 108 | 478                 self.testparam.append(tp) | 
| 48 | 479         for p in self.infiles: | 
|  | 480             newname = p[ICLPOS] | 
|  | 481             newfmt = p[IFMTPOS] | 
|  | 482             ndash = self.getNdash(newname) | 
|  | 483             if not len(p[ILABPOS]) > 0: | 
|  | 484                 alab = p[ICLPOS] | 
|  | 485             else: | 
|  | 486                 alab = p[ILABPOS] | 
|  | 487             aninput = gxtp.DataParam( | 
|  | 488                 newname, | 
|  | 489                 optional=False, | 
|  | 490                 label=alab, | 
|  | 491                 help=p[IHELPOS], | 
|  | 492                 format=newfmt, | 
|  | 493                 multiple=False, | 
|  | 494                 num_dashes=ndash, | 
|  | 495             ) | 
|  | 496             aninput.positional = self.is_positional | 
|  | 497             self.tinputs.append(aninput) | 
|  | 498             tparm = gxtp.TestParam(name=newname, value="%s_sample" % newname) | 
|  | 499             self.testparam.append(tparm) | 
|  | 500         for p in self.addpar: | 
| 119 | 501             ( | 
|  | 502                 newname, | 
|  | 503                 newval, | 
|  | 504                 newlabel, | 
|  | 505                 newhelp, | 
|  | 506                 newtype, | 
|  | 507                 newcl, | 
|  | 508                 override, | 
|  | 509                 oldcl, | 
|  | 510             ) = p | 
| 48 | 511             if not len(newlabel) > 0: | 
|  | 512                 newlabel = newname | 
|  | 513             ndash = self.getNdash(newname) | 
|  | 514             if newtype == "text": | 
|  | 515                 aparm = gxtp.TextParam( | 
|  | 516                     newname, | 
|  | 517                     label=newlabel, | 
|  | 518                     help=newhelp, | 
|  | 519                     value=newval, | 
|  | 520                     num_dashes=ndash, | 
|  | 521                 ) | 
|  | 522             elif newtype == "integer": | 
|  | 523                 aparm = gxtp.IntegerParam( | 
|  | 524                     newname, | 
|  | 525                     label=newname, | 
|  | 526                     help=newhelp, | 
|  | 527                     value=newval, | 
|  | 528                     num_dashes=ndash, | 
|  | 529                 ) | 
|  | 530             elif newtype == "float": | 
|  | 531                 aparm = gxtp.FloatParam( | 
|  | 532                     newname, | 
|  | 533                     label=newname, | 
|  | 534                     help=newhelp, | 
|  | 535                     value=newval, | 
|  | 536                     num_dashes=ndash, | 
|  | 537                 ) | 
|  | 538             else: | 
|  | 539                 raise ValueError( | 
|  | 540                     'Unrecognised parameter type "%s" for\ | 
|  | 541                  additional parameter %s in makeXML' | 
|  | 542                     % (newtype, newname) | 
|  | 543                 ) | 
|  | 544             aparm.positional = self.is_positional | 
|  | 545             if self.is_positional: | 
| 63 | 546                 aparm.positional = int(oldcl) | 
| 48 | 547             self.tinputs.append(aparm) | 
| 63 | 548             tparm = gxtp.TestParam(newname, value=newval) | 
| 48 | 549             self.testparam.append(tparm) | 
|  | 550 | 
|  | 551     def doNoXMLparam(self): | 
| 49 | 552         """filter style package - stdin to stdout""" | 
| 62 | 553         if len(self.infiles) > 0: | 
|  | 554             alab = self.infiles[0][ILABPOS] | 
|  | 555             if len(alab) == 0: | 
|  | 556                 alab = self.infiles[0][ICLPOS] | 
|  | 557             max1s = ( | 
|  | 558                 "Maximum one input if parampass is 0 but multiple input files supplied - %s" | 
|  | 559                 % str(self.infiles) | 
|  | 560             ) | 
|  | 561             assert len(self.infiles) == 1, max1s | 
|  | 562             newname = self.infiles[0][ICLPOS] | 
|  | 563             aninput = gxtp.DataParam( | 
|  | 564                 newname, | 
|  | 565                 optional=False, | 
|  | 566                 label=alab, | 
|  | 567                 help=self.infiles[0][IHELPOS], | 
|  | 568                 format=self.infiles[0][IFMTPOS], | 
|  | 569                 multiple=False, | 
|  | 570                 num_dashes=0, | 
|  | 571             ) | 
|  | 572             aninput.command_line_override = "< $%s" % newname | 
|  | 573             aninput.positional = self.is_positional | 
|  | 574             self.tinputs.append(aninput) | 
|  | 575             tp = gxtp.TestParam(name=newname, value="%s_sample" % newname) | 
|  | 576             self.testparam.append(tp) | 
| 63 | 577         if len(self.outfiles) > 0: | 
| 62 | 578             newname = self.outfiles[0][OCLPOS] | 
|  | 579             newfmt = self.outfiles[0][OFMTPOS] | 
|  | 580             anout = gxtp.OutputData(newname, format=newfmt, num_dashes=0) | 
|  | 581             anout.command_line_override = "> $%s" % newname | 
|  | 582             anout.positional = self.is_positional | 
|  | 583             self.toutputs.append(anout) | 
| 75 | 584             tp = gxtp.TestOutput( | 
|  | 585                 name=newname, value="%s_sample" % newname, format=newfmt | 
|  | 586             ) | 
| 62 | 587             self.testparam.append(tp) | 
| 48 | 588 | 
|  | 589     def makeXML(self): | 
|  | 590         """ | 
|  | 591         Create a Galaxy xml tool wrapper for the new script | 
|  | 592         Uses galaxyhtml | 
|  | 593         Hmmm. How to get the command line into correct order... | 
|  | 594         """ | 
| 49 | 595         if self.command_override: | 
| 119 | 596             self.newtool.command_override = ( | 
|  | 597                 self.command_override | 
|  | 598             )  # config file | 
| 48 | 599         else: | 
| 56 | 600             self.newtool.command_override = self.xmlcl | 
| 48 | 601         if self.args.help_text: | 
|  | 602             helptext = open(self.args.help_text, "r").readlines() | 
| 108 | 603             safertext = "\n".join([cheetah_escape(x) for x in helptext]) | 
|  | 604             if self.args.script_path: | 
| 110 | 605                 scr = [x for x in self.spacedScript if x.strip() > ""] | 
| 119 | 606                 scr.insert(0, "\n------\n\n\nScript::\n") | 
| 110 | 607                 if len(scr) > 300: | 
|  | 608                     scr = ( | 
|  | 609                         scr[:100] | 
| 118 | 610                         + ["    >300 lines - stuff deleted", "    ......"] | 
| 110 | 611                         + scr[-100:] | 
| 75 | 612                     ) | 
| 119 | 613                 scr.append("\n") | 
| 110 | 614                 safertext = safertext + "\n".join(scr) | 
| 108 | 615             self.newtool.help = safertext | 
| 48 | 616         else: | 
| 50 | 617             self.newtool.help = ( | 
| 48 | 618                 "Please ask the tool author (%s) for help \ | 
|  | 619               as none was supplied at tool generation\n" | 
|  | 620                 % (self.args.user_email) | 
|  | 621             ) | 
| 50 | 622         self.newtool.version_command = None  # do not want | 
| 48 | 623         requirements = gxtp.Requirements() | 
| 49 | 624         if self.args.packages: | 
|  | 625             for d in self.args.packages.split(","): | 
| 119 | 626                 ver = "" | 
|  | 627                 d = d.replace("==", ":") | 
|  | 628                 d = d.replace("=", ":") | 
| 49 | 629                 if ":" in d: | 
|  | 630                     packg, ver = d.split(":") | 
|  | 631                 else: | 
|  | 632                     packg = d | 
| 50 | 633                 requirements.append( | 
|  | 634                     gxtp.Requirement("package", packg.strip(), ver.strip()) | 
|  | 635                 ) | 
|  | 636         self.newtool.requirements = requirements | 
| 48 | 637         if self.args.parampass == "0": | 
|  | 638             self.doNoXMLparam() | 
|  | 639         else: | 
|  | 640             self.doXMLparam() | 
| 50 | 641         self.newtool.outputs = self.toutputs | 
|  | 642         self.newtool.inputs = self.tinputs | 
|  | 643         if self.args.script_path: | 
| 48 | 644             configfiles = gxtp.Configfiles() | 
| 119 | 645             configfiles.append( | 
|  | 646                 gxtp.Configfile( | 
|  | 647                     name="runme", text="\n".join(self.escapedScript) | 
|  | 648                 ) | 
|  | 649             ) | 
| 50 | 650             self.newtool.configfiles = configfiles | 
| 48 | 651         tests = gxtp.Tests() | 
|  | 652         test_a = gxtp.Test() | 
|  | 653         for tp in self.testparam: | 
|  | 654             test_a.append(tp) | 
|  | 655         tests.append(test_a) | 
| 50 | 656         self.newtool.tests = tests | 
|  | 657         self.newtool.add_comment( | 
| 48 | 658             "Created by %s at %s using the Galaxy Tool Factory." | 
|  | 659             % (self.args.user_email, timenow()) | 
|  | 660         ) | 
| 50 | 661         self.newtool.add_comment("Source in git at: %s" % (toolFactoryURL)) | 
|  | 662         self.newtool.add_comment( | 
| 108 | 663             "Cite: Creating re-usable tools from scripts doi:10.1093/bioinformatics/bts573" | 
| 48 | 664         ) | 
| 50 | 665         exml0 = self.newtool.export() | 
| 119 | 666         exml = exml0.replace( | 
|  | 667             FAKEEXE, "" | 
|  | 668         )  # temporary work around until PR accepted | 
| 50 | 669         if ( | 
|  | 670             self.test_override | 
|  | 671         ):  # cannot do this inside galaxyxml as it expects lxml objects for tests | 
|  | 672             part1 = exml.split("<tests>")[0] | 
|  | 673             part2 = exml.split("</tests>")[1] | 
|  | 674             fixed = "%s\n%s\n%s" % (part1, self.test_override, part2) | 
| 49 | 675             exml = fixed | 
| 119 | 676         # exml = exml.replace('range="1:"', 'range="1000:"') | 
| 49 | 677         xf = open("%s.xml" % self.tool_name, "w") | 
| 48 | 678         xf.write(exml) | 
|  | 679         xf.write("\n") | 
|  | 680         xf.close() | 
|  | 681         # ready for the tarball | 
|  | 682 | 
|  | 683     def run(self): | 
|  | 684         """ | 
| 50 | 685         generate test outputs by running a command line | 
| 56 | 686         won't work if command or test override in play - planemo is the | 
| 50 | 687         easiest way to generate test outputs for that case so is | 
|  | 688         automagically selected | 
| 48 | 689         """ | 
|  | 690         scl = " ".join(self.cl) | 
|  | 691         err = None | 
|  | 692         if self.args.parampass != "0": | 
| 56 | 693             if os.path.exists(self.elog): | 
|  | 694                 ste = open(self.elog, "a") | 
|  | 695             else: | 
|  | 696                 ste = open(self.elog, "w") | 
| 48 | 697             if self.lastclredirect: | 
| 119 | 698                 sto = open( | 
|  | 699                     self.lastclredirect[1], "wb" | 
|  | 700                 )  # is name of an output file | 
| 48 | 701             else: | 
| 56 | 702                 if os.path.exists(self.tlog): | 
|  | 703                     sto = open(self.tlog, "a") | 
|  | 704                 else: | 
|  | 705                     sto = open(self.tlog, "w") | 
| 48 | 706                 sto.write( | 
| 119 | 707                     "## Executing Toolfactory generated command line = %s\n" | 
|  | 708                     % scl | 
| 48 | 709                 ) | 
|  | 710             sto.flush() | 
| 106 | 711             subp = subprocess.run( | 
|  | 712                 self.cl, env=self.ourenv, shell=False, stdout=sto, stderr=ste | 
|  | 713             ) | 
| 48 | 714             sto.close() | 
|  | 715             ste.close() | 
| 98 | 716             retval = subp.returncode | 
| 49 | 717         else:  # work around special case - stdin and write to stdout | 
| 62 | 718             if len(self.infiles) > 0: | 
|  | 719                 sti = open(self.infiles[0][IPATHPOS], "rb") | 
|  | 720             else: | 
| 63 | 721                 sti = sys.stdin | 
| 62 | 722             if len(self.outfiles) > 0: | 
|  | 723                 sto = open(self.outfiles[0][ONAMEPOS], "wb") | 
|  | 724             else: | 
|  | 725                 sto = sys.stdout | 
| 106 | 726             subp = subprocess.run( | 
|  | 727                 self.cl, env=self.ourenv, shell=False, stdout=sto, stdin=sti | 
|  | 728             ) | 
| 119 | 729             sto.write( | 
|  | 730                 "## Executing Toolfactory generated command line = %s\n" % scl | 
|  | 731             ) | 
| 98 | 732             retval = subp.returncode | 
| 48 | 733             sto.close() | 
|  | 734             sti.close() | 
|  | 735         if os.path.isfile(self.tlog) and os.stat(self.tlog).st_size == 0: | 
|  | 736             os.unlink(self.tlog) | 
|  | 737         if os.path.isfile(self.elog) and os.stat(self.elog).st_size == 0: | 
|  | 738             os.unlink(self.elog) | 
|  | 739         if retval != 0 and err:  # problem | 
|  | 740             sys.stderr.write(err) | 
|  | 741         logging.debug("run done") | 
|  | 742         return retval | 
|  | 743 | 
| 63 | 744     def shedLoad(self): | 
| 48 | 745         """ | 
| 113 | 746         use bioblend to create new repository | 
|  | 747         or update existing | 
| 63 | 748 | 
| 48 | 749         """ | 
| 49 | 750         if os.path.exists(self.tlog): | 
| 63 | 751             sto = open(self.tlog, "a") | 
| 48 | 752         else: | 
| 63 | 753             sto = open(self.tlog, "w") | 
| 48 | 754 | 
| 75 | 755         ts = toolshed.ToolShedInstance( | 
| 119 | 756             url=self.args.toolshed_url, | 
|  | 757             key=self.args.toolshed_api_key, | 
|  | 758             verify=False, | 
| 75 | 759         ) | 
| 63 | 760         repos = ts.repositories.get_repositories() | 
| 75 | 761         rnames = [x.get("name", "?") for x in repos] | 
|  | 762         rids = [x.get("id", "?") for x in repos] | 
| 98 | 763         tfcat = "ToolFactory generated tools" | 
| 101 | 764         if self.tool_name not in rnames: | 
| 63 | 765             tscat = ts.categories.get_categories() | 
| 98 | 766             cnames = [x.get("name", "?").strip() for x in tscat] | 
| 75 | 767             cids = [x.get("id", "?") for x in tscat] | 
| 63 | 768             catID = None | 
| 98 | 769             if tfcat.strip() in cnames: | 
|  | 770                 ci = cnames.index(tfcat) | 
| 63 | 771                 catID = cids[ci] | 
| 75 | 772             res = ts.repositories.create_repository( | 
|  | 773                 name=self.args.tool_name, | 
|  | 774                 synopsis="Synopsis:%s" % self.args.tool_desc, | 
|  | 775                 description=self.args.tool_desc, | 
|  | 776                 type="unrestricted", | 
|  | 777                 remote_repository_url=self.args.toolshed_url, | 
|  | 778                 homepage_url=None, | 
|  | 779                 category_ids=catID, | 
|  | 780             ) | 
|  | 781             tid = res.get("id", None) | 
| 119 | 782             sto.write( | 
|  | 783                 f"#create_repository {self.args.tool_name} tid={tid} res={res}\n" | 
|  | 784             ) | 
| 49 | 785         else: | 
| 101 | 786             i = rnames.index(self.tool_name) | 
| 75 | 787             tid = rids[i] | 
| 100 | 788         try: | 
|  | 789             res = ts.repositories.update_repository( | 
| 106 | 790                 id=tid, tar_ball_path=self.newtarpath, commit_message=None | 
|  | 791             ) | 
| 113 | 792             sto.write(f"#update res id {id} ={res}\n") | 
| 100 | 793         except ConnectionError: | 
| 106 | 794             sto.write( | 
| 113 | 795                 "####### Is the toolshed running and the API key correct? Bioblend shed upload failed\n" | 
| 106 | 796             ) | 
| 63 | 797         sto.close() | 
|  | 798 | 
| 48 | 799     def eph_galaxy_load(self): | 
| 113 | 800         """ | 
|  | 801         use ephemeris to load the new tool from the local toolshed after planemo uploads it | 
|  | 802         """ | 
| 49 | 803         if os.path.exists(self.tlog): | 
| 50 | 804             tout = open(self.tlog, "a") | 
| 49 | 805         else: | 
| 50 | 806             tout = open(self.tlog, "w") | 
| 49 | 807         cll = [ | 
|  | 808             "shed-tools", | 
|  | 809             "install", | 
|  | 810             "-g", | 
|  | 811             self.args.galaxy_url, | 
|  | 812             "--latest", | 
|  | 813             "-a", | 
|  | 814             self.args.galaxy_api_key, | 
|  | 815             "--name", | 
| 101 | 816             self.tool_name, | 
| 49 | 817             "--owner", | 
|  | 818             "fubar", | 
|  | 819             "--toolshed", | 
|  | 820             self.args.toolshed_url, | 
| 75 | 821             "--section_label", | 
| 63 | 822             "ToolFactory", | 
| 49 | 823         ] | 
| 63 | 824         tout.write("running\n%s\n" % " ".join(cll)) | 
| 106 | 825         subp = subprocess.run( | 
| 119 | 826             cll, | 
|  | 827             env=self.ourenv, | 
|  | 828             cwd=self.ourcwd, | 
|  | 829             shell=False, | 
|  | 830             stderr=tout, | 
|  | 831             stdout=tout, | 
| 106 | 832         ) | 
| 75 | 833         tout.write( | 
| 119 | 834             "installed %s - got retcode %d\n" | 
|  | 835             % (self.tool_name, subp.returncode) | 
| 75 | 836         ) | 
| 63 | 837         tout.close() | 
| 98 | 838         return subp.returncode | 
| 63 | 839 | 
| 48 | 840     def writeShedyml(self): | 
| 75 | 841         """for planemo""" | 
| 49 | 842         yuser = self.args.user_email.split("@")[0] | 
|  | 843         yfname = os.path.join(self.tooloutdir, ".shed.yml") | 
|  | 844         yamlf = open(yfname, "w") | 
|  | 845         odict = { | 
|  | 846             "name": self.tool_name, | 
|  | 847             "owner": yuser, | 
|  | 848             "type": "unrestricted", | 
|  | 849             "description": self.args.tool_desc, | 
| 50 | 850             "synopsis": self.args.tool_desc, | 
|  | 851             "category": "TF Generated Tools", | 
| 49 | 852         } | 
| 48 | 853         yaml.dump(odict, yamlf, allow_unicode=True) | 
|  | 854         yamlf.close() | 
|  | 855 | 
| 50 | 856     def makeTool(self): | 
| 75 | 857         """write xmls and input samples into place""" | 
| 50 | 858         self.makeXML() | 
|  | 859         if self.args.script_path: | 
|  | 860             stname = os.path.join(self.tooloutdir, "%s" % (self.sfile)) | 
|  | 861             if not os.path.exists(stname): | 
|  | 862                 shutil.copyfile(self.sfile, stname) | 
|  | 863         xreal = "%s.xml" % self.tool_name | 
|  | 864         xout = os.path.join(self.tooloutdir, xreal) | 
|  | 865         shutil.copyfile(xreal, xout) | 
|  | 866         for p in self.infiles: | 
|  | 867             pth = p[IPATHPOS] | 
|  | 868             dest = os.path.join(self.testdir, "%s_sample" % p[ICLPOS]) | 
|  | 869             shutil.copyfile(pth, dest) | 
| 49 | 870 | 
| 50 | 871     def makeToolTar(self): | 
| 75 | 872         """move outputs into test-data and prepare the tarball""" | 
| 101 | 873         excludeme = "_planemo_test_report.html" | 
| 75 | 874 | 
| 66 | 875         def exclude_function(tarinfo): | 
| 75 | 876             filename = tarinfo.name | 
| 106 | 877             return None if filename.endswith(excludeme) else tarinfo | 
| 66 | 878 | 
| 117 | 879         if os.path.exists(self.tlog): | 
|  | 880             tout = open(self.tlog, "a") | 
|  | 881         else: | 
|  | 882             tout = open(self.tlog, "w") | 
| 50 | 883         for p in self.outfiles: | 
| 96 | 884             oname = p[ONAMEPOS] | 
| 99 | 885             tdest = os.path.join(self.testdir, "%s_sample" % oname) | 
|  | 886             if not os.path.isfile(tdest): | 
| 106 | 887                 src = os.path.join(self.testdir, oname) | 
| 99 | 888                 if os.path.isfile(src): | 
|  | 889                     shutil.copyfile(src, tdest) | 
|  | 890                     dest = os.path.join(self.repdir, "%s.sample" % (oname)) | 
|  | 891                     shutil.copyfile(src, dest) | 
|  | 892                 else: | 
| 117 | 893                     tout.write( | 
|  | 894                         "###Output file %s not found in testdir %s. This is normal during the first Planemo run that generates test outputs" | 
| 99 | 895                         % (tdest, self.testdir) | 
|  | 896                     ) | 
| 50 | 897         tf = tarfile.open(self.newtarpath, "w:gz") | 
| 119 | 898         tf.add( | 
|  | 899             name=self.tooloutdir, | 
|  | 900             arcname=self.tool_name, | 
|  | 901             filter=exclude_function, | 
|  | 902         ) | 
| 50 | 903         tf.close() | 
|  | 904         shutil.copyfile(self.newtarpath, self.args.new_tool) | 
|  | 905 | 
|  | 906     def moveRunOutputs(self): | 
| 75 | 907         """need to move planemo or run outputs into toolfactory collection""" | 
| 50 | 908         with os.scandir(self.tooloutdir) as outs: | 
|  | 909             for entry in outs: | 
| 80 | 910                 if not entry.is_file(): | 
|  | 911                     continue | 
|  | 912                 if "." in entry.name: | 
|  | 913                     nayme, ext = os.path.splitext(entry.name) | 
| 106 | 914                     if ext in [".yml", ".xml", ".json", ".yaml"]: | 
|  | 915                         ext = f"{ext}.txt" | 
| 80 | 916                 else: | 
|  | 917                     ext = ".txt" | 
|  | 918                 ofn = "%s%s" % (entry.name.replace(".", "_"), ext) | 
|  | 919                 dest = os.path.join(self.repdir, ofn) | 
|  | 920                 src = os.path.join(self.tooloutdir, entry.name) | 
|  | 921                 shutil.copyfile(src, dest) | 
|  | 922         with os.scandir(self.testdir) as outs: | 
|  | 923             for entry in outs: | 
| 106 | 924                 if ( | 
|  | 925                     (not entry.is_file()) | 
|  | 926                     or entry.name.endswith("_sample") | 
|  | 927                     or entry.name.endswith("_planemo_test_report.html") | 
|  | 928                 ): | 
| 50 | 929                     continue | 
|  | 930                 if "." in entry.name: | 
|  | 931                     nayme, ext = os.path.splitext(entry.name) | 
|  | 932                 else: | 
|  | 933                     ext = ".txt" | 
| 80 | 934                 newname = f"{entry.name}{ext}" | 
|  | 935                 dest = os.path.join(self.repdir, newname) | 
|  | 936                 src = os.path.join(self.testdir, entry.name) | 
| 50 | 937                 shutil.copyfile(src, dest) | 
|  | 938 | 
| 49 | 939 | 
| 48 | 940 def main(): | 
|  | 941     """ | 
| 119 | 942     This is a Galaxy wrapper. | 
|  | 943     It expects to be called by a special purpose tool.xml | 
| 118 | 944 | 
| 48 | 945     """ | 
|  | 946     parser = argparse.ArgumentParser() | 
|  | 947     a = parser.add_argument | 
| 49 | 948     a("--script_path", default=None) | 
|  | 949     a("--history_test", default=None) | 
|  | 950     a("--cl_prefix", default=None) | 
|  | 951     a("--sysexe", default=None) | 
|  | 952     a("--packages", default=None) | 
| 76 | 953     a("--tool_name", default="newtool") | 
| 72 | 954     a("--tool_dir", default=None) | 
| 48 | 955     a("--input_files", default=[], action="append") | 
|  | 956     a("--output_files", default=[], action="append") | 
|  | 957     a("--user_email", default="Unknown") | 
|  | 958     a("--bad_user", default=None) | 
| 49 | 959     a("--make_Tool", default="runonly") | 
| 48 | 960     a("--help_text", default=None) | 
|  | 961     a("--tool_desc", default=None) | 
|  | 962     a("--tool_version", default=None) | 
|  | 963     a("--citations", default=None) | 
| 49 | 964     a("--command_override", default=None) | 
|  | 965     a("--test_override", default=None) | 
| 48 | 966     a("--additional_parameters", action="append", default=[]) | 
|  | 967     a("--edit_additional_parameters", action="store_true", default=False) | 
|  | 968     a("--parampass", default="positional") | 
|  | 969     a("--tfout", default="./tfout") | 
|  | 970     a("--new_tool", default="new_tool") | 
| 49 | 971     a("--galaxy_url", default="http://localhost:8080") | 
| 106 | 972     a("--toolshed_url", default="http://localhost:9009") | 
| 119 | 973     # make sure this is identical to tool_sheds_conf.xml | 
|  | 974     # localhost != 127.0.0.1 so validation fails | 
| 63 | 975     a("--toolshed_api_key", default="fakekey") | 
| 50 | 976     a("--galaxy_api_key", default="fakekey") | 
|  | 977     a("--galaxy_root", default="/galaxy-central") | 
| 101 | 978     a("--galaxy_venv", default="/galaxy_venv") | 
| 48 | 979     args = parser.parse_args() | 
|  | 980     assert not args.bad_user, ( | 
| 119 | 981         'UNAUTHORISED: %s is NOT authorized to use this tool until Galaxy \ | 
|  | 982 admin adds %s to "admin_users" in the galaxy.yml Galaxy configuration file' | 
| 48 | 983         % (args.bad_user, args.bad_user) | 
|  | 984     ) | 
| 119 | 985     assert ( | 
|  | 986         args.tool_name | 
|  | 987     ), "## Tool Factory expects a tool name - eg --tool_name=DESeq" | 
| 48 | 988     assert ( | 
| 49 | 989         args.sysexe or args.packages | 
| 119 | 990     ), "## Tool Factory wrapper expects an interpreter \ | 
|  | 991 or an executable package in --sysexe or --packages" | 
|  | 992     args.input_files = [ | 
|  | 993         x.replace('"', "").replace("'", "") for x in args.input_files | 
|  | 994     ] | 
| 48 | 995     # remove quotes we need to deal with spaces in CL params | 
|  | 996     for i, x in enumerate(args.additional_parameters): | 
| 119 | 997         args.additional_parameters[i] = args.additional_parameters[i].replace( | 
|  | 998             '"', "" | 
|  | 999         ) | 
| 48 | 1000     r = ScriptRunner(args) | 
| 49 | 1001     r.writeShedyml() | 
|  | 1002     r.makeTool() | 
| 66 | 1003     if args.make_Tool == "generate": | 
| 119 | 1004         retcode = r.run() | 
| 66 | 1005         r.moveRunOutputs() | 
|  | 1006         r.makeToolTar() | 
|  | 1007     else: | 
| 119 | 1008         retcode = r.planemo_test(genoutputs=True)  # this fails :( - see PR | 
| 66 | 1009         r.moveRunOutputs() | 
|  | 1010         r.makeToolTar() | 
| 119 | 1011         retcode = r.planemo_test(genoutputs=False) | 
|  | 1012         r.moveRunOutputs() | 
|  | 1013         r.makeToolTar() | 
|  | 1014         print(f"second planemo_test returned {retcode}") | 
| 101 | 1015         if args.make_Tool == "gentestinstall": | 
|  | 1016             r.shedLoad() | 
|  | 1017             r.eph_galaxy_load() | 
| 63 | 1018 | 
| 48 | 1019 | 
|  | 1020 if __name__ == "__main__": | 
|  | 1021     main() |