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