# HG changeset patch
# User fubar
# Date 1708598881 0
# Node ID 0183cad9d13be1acb94da25cd4d1a050f0a8450d
# Parent 2beaae16651e96d48555d805134bd9da51b6c757
planemo upload
diff -r 2beaae16651e -r 0183cad9d13b abslen_bed/abslen_bed.python.txt
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/abslen_bed/abslen_bed.python.txt Thu Feb 22 10:48:01 2024 +0000
@@ -0,0 +1,14 @@
+#raw
+import sys
+inp = []
+for line in sys.stdin:
+ if line.strip() > '':
+ ls = line.split()
+ if len(ls) > 2:
+ x = abs(int(ls[2]) - int(ls[1]))
+ ls.append((str(x)))
+ inp.append('\t'.join(ls))
+ else:
+ break
+sys.stdout.write('\n'.join(inp))
+#end raw
diff -r 2beaae16651e -r 0183cad9d13b abslen_bed/abslen_bed.xml
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/abslen_bed/abslen_bed.xml Thu Feb 22 10:48:01 2024 +0000
@@ -0,0 +1,56 @@
+
+
+
+ Returns a file of absolute values from differences
+
+ python
+
+
+
+$absout]]>
+
+ '':
+ ls = line.split()
+ if len(ls) > 2:
+ x = abs(int(ls[2]) - int(ls[1]))
+ ls.append((str(x)))
+ inp.append('\t'.join(ls))
+ else:
+ break
+sys.stdout.write('\n'.join(inp))
+#end raw]]>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 10.1093/bioinformatics/bts573
+
+
+
diff -r 2beaae16651e -r 0183cad9d13b abslen_bed/test-data/absin_sample
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/abslen_bed/test-data/absin_sample Thu Feb 22 10:48:01 2024 +0000
@@ -0,0 +1,4 @@
+mm10_knownGene_uc008xda.1 900 959
+mm10_knownGene_uc008xda.1 1009 1038
+mm10_knownGene_uc008xda.1 1088 1166
+mm10_knownGene_uc008xda.1 1216 1252
diff -r 2beaae16651e -r 0183cad9d13b abslen_bed/test-data/absout_sample
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/abslen_bed/test-data/absout_sample Thu Feb 22 10:48:01 2024 +0000
@@ -0,0 +1,4 @@
+mm10_knownGene_uc008xda.1 900 959 59
+mm10_knownGene_uc008xda.1 1009 1038 29
+mm10_knownGene_uc008xda.1 1088 1166 78
+mm10_knownGene_uc008xda.1 1216 1252 36
\ No newline at end of file
diff -r 2beaae16651e -r 0183cad9d13b hictk/hictk.bash.txt
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hictk/hictk.bash.txt Thu Feb 22 10:48:01 2024 +0000
@@ -0,0 +1,1 @@
+hictk convert -f --output-fmt 'hic' '$incool' '$outhic'
diff -r 2beaae16651e -r 0183cad9d13b hictk/hictk.xml
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hictk/hictk.xml Thu Feb 22 10:48:01 2024 +0000
@@ -0,0 +1,70 @@
+
+
+
+ cool to hic binary
+
+ hictk
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ License: MIT
+
+ **hictk**
+
+ ----
+
+ hictk is a blazing fast toolkit to work with .hic and .cool files.
+
+ This repository hosts `hictk`: a set of CLI tools to work with Cooler, as well as `libhictk`: the C++ library underlying `hictk`.
+
+ Python bindings for `libhictk` are available at https://github.com/paulsengroup/hictkpy.
+
+ hictk is capable of reading files in `.cool`, `.mcool`, `.scool` and `.juicebox_hic` format (including hic v9) as well as writing `.cool` and `.mcool` files.
+
+ **Installing hictk**
+
+ hictk is developed on Linux and tested on Linux, MacOS and Windows.
+
+ hictk can be installed using containers, bioconda or directly from source.
+ Refer to https://hictk.readthedocs.io/en/latest/installation.html for more information.
+
+ **Running hictk**
+
+ hictk provides the following subcommands but this tool implements only *convert*
+
+ Refer to https://hictk.readthedocs.io/en/latest/cli_reference.html for more details.
+
+ ]]>
+
+ @article{hictk,
+author = {Roberto Rossini},
+year = {2023},
+url = {https://github.com/paulsengroup/hictk},
+title = {hictk: blazing fast toolkit to work with .hic and .cool files}
+}
+ 10.1093/bioinformatics/bts573
+
+
+
diff -r 2beaae16651e -r 0183cad9d13b hictk/test-data/incool_sample
Binary file hictk/test-data/incool_sample has changed
diff -r 2beaae16651e -r 0183cad9d13b hictk/test-data/outhic_sample
Binary file hictk/test-data/outhic_sample has changed
diff -r 2beaae16651e -r 0183cad9d13b jb2.tar.gz
Binary file jb2.tar.gz has changed
diff -r 2beaae16651e -r 0183cad9d13b local_tool_conf.xml
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/local_tool_conf.xml Thu Feb 22 10:48:01 2024 +0000
@@ -0,0 +1,14 @@
+
+
+
diff -r 2beaae16651e -r 0183cad9d13b mashmap.tgz
Binary file mashmap.tgz has changed
diff -r 2beaae16651e -r 0183cad9d13b mashmap/.shed.yml
--- a/mashmap/.shed.yml Thu Feb 22 07:24:04 2024 +0000
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,6 +0,0 @@
-category: ToolFactory generated Tools
-description: ToolFactory autogenerated tool
-name: mashmap
-owner: fubar2
-synopsis: Fast local alignment boundaries
-type: unrestricted
diff -r 2beaae16651e -r 0183cad9d13b mashmap/mashmap.xml
--- a/mashmap/mashmap.xml Thu Feb 22 07:24:04 2024 +0000
+++ b/mashmap/mashmap.xml Thu Feb 22 10:48:01 2024 +0000
@@ -1,6 +1,6 @@
-
+
Fast local alignment boundaries
mashmap
@@ -16,19 +16,19 @@
--dense \
#end if
#if len($reflist) == 1:
- -r $reflist -q '$query'
+ -r '$reflist' -q '$query'
#else
rm -rf 'reflist'
#for i, mash in enumerate($reflist):
#if i == 0:
- echo $mash > 'reflist'
+ echo '$mash' > 'reflist'
#else:
- echo $mash >> 'reflist'
+ echo '$mash' >> 'reflist'
#end if
#end for
--rl 'reflist' -q '$query'
#end if
-cp 'mashmap.out' $mashout]]>
+cp 'mashmap.out' '$mashout']]>
diff -r 2beaae16651e -r 0183cad9d13b planemo_lint/planemo_lint.bash.txt
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/planemo_lint/planemo_lint.bash.txt Thu Feb 22 10:48:01 2024 +0000
@@ -0,0 +1,7 @@
+#raw
+cp $1 foo.tar
+tar -xvf foo.tar
+TOOLNAME=`find . -name "*.xml"`
+echo "$$$$$TOOLNAME = $TOOLNAME" > $2
+planemo lint $TOOLNAME >> $2
+#end raw
diff -r 2beaae16651e -r 0183cad9d13b planemo_lint/planemo_lint.xml
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/planemo_lint/planemo_lint.xml Thu Feb 22 10:48:01 2024 +0000
@@ -0,0 +1,41 @@
+
+
+
+
+
+ planemo
+
+
+
+
+ $2
+planemo lint $TOOLNAME >> $2
+#end raw]]>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 10.1093/bioinformatics/bts573
+
+
+
diff -r 2beaae16651e -r 0183cad9d13b planemo_lint/test-data/Toolshed_archive_to_be_linted_sample
Binary file planemo_lint/test-data/Toolshed_archive_to_be_linted_sample has changed
diff -r 2beaae16651e -r 0183cad9d13b planemotest/planemotest.xml
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/planemotest/planemotest.xml Thu Feb 22 10:48:01 2024 +0000
@@ -0,0 +1,77 @@
+
+
+
+ Tests a ToolFactory archive containing a new tool
+
+ planemo
+
+
+
+
+
+
+
+ STDOUT
+cp $REP $2
+
+#end raw]]>
+
+
+
+
+
+
+
+
+
+
+
+
+
+ $LOG
+ planemo test --update_test_data --test_output $REP $TOOLNAME >> $LOG
+ cp $REP $2
+
+]]>
+
+ 10.1093/bioinformatics/bts573
+
+
+
diff -r 2beaae16651e -r 0183cad9d13b planemotest/test-data/Toolshed_archive_to_be_tested_sample
Binary file planemotest/test-data/Toolshed_archive_to_be_tested_sample has changed
diff -r 2beaae16651e -r 0183cad9d13b planemotest/test-data/test_output_sample
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/planemotest/test-data/test_output_sample Thu Feb 22 10:48:01 2024 +0000
@@ -0,0 +1,291 @@
+
+
+
+
+
+
+ Test Results (powered by Planemo)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff -r 2beaae16651e -r 0183cad9d13b plants.sh
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/plants.sh Thu Feb 22 10:48:01 2024 +0000
@@ -0,0 +1,1 @@
+planemo shed_update --shed_target toolshed --owner fubar --name mashmap --shed_key bbfaa3d1d522066d41a4250dc419cc6f ./
diff -r 2beaae16651e -r 0183cad9d13b pyrev_pos_test/pyrev_pos_test.python.txt
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/pyrev_pos_test/pyrev_pos_test.python.txt Thu Feb 22 10:48:01 2024 +0000
@@ -0,0 +1,17 @@
+#raw
+## reverse order of text by row
+## ToolFactory demonstration
+## positional parameters
+import sys
+inp = sys.argv[1]
+outp = sys.argv[2]
+i = open(inp,'r').readlines()
+o = open(outp,'w')
+for row in i:
+ rs = row.rstrip()
+ rs = list(rs)
+ rs.reverse()
+ o.write(''.join(rs))
+ o.write('\n')
+o.close()
+#end raw
diff -r 2beaae16651e -r 0183cad9d13b pyrev_pos_test/pyrev_pos_test.xml
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/pyrev_pos_test/pyrev_pos_test.xml Thu Feb 22 10:48:01 2024 +0000
@@ -0,0 +1,49 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 10.1093/bioinformatics/bts573
+
+
+
diff -r 2beaae16651e -r 0183cad9d13b pyrev_pos_test/test-data/Input_text_file_to_be_reversed_sample
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/pyrev_pos_test/test-data/Input_text_file_to_be_reversed_sample Thu Feb 22 10:48:01 2024 +0000
@@ -0,0 +1,1210 @@
+# see https://github.com/fubar2/toolfactory
+#
+# copyright ross lazarus (ross stop lazarus at gmail stop com) May 2012
+#
+# all rights reserved
+# Licensed under the LGPL
+# suggestions for improvement and bug fixes welcome at
+# https://github.com/fubar2/toolfactory
+#
+# march 2022: Refactored into two tools - generate and test/install
+# as part of GTN tutorial development and biocontainer adoption
+# The tester runs planemo on a non-tested archive, creates the test outputs
+# and returns a new proper tool with test.
+
+
+
+import argparse
+import copy
+import fcntl
+import json
+import os
+import re
+import shlex
+import shutil
+import subprocess
+import sys
+import tarfile
+import tempfile
+import time
+
+from bioblend import galaxy
+
+import galaxyxml.tool as gxt
+import galaxyxml.tool.parameters as gxtp
+
+import lxml.etree as ET
+
+import yaml
+
+myversion = "V2.4 March 2022"
+verbose = True
+debug = True
+toolFactoryURL = "https://github.com/fubar2/toolfactory"
+FAKEEXE = "~~~REMOVE~~~ME~~~"
+# need this until a PR/version bump to fix galaxyxml prepending the exe even
+# with override.
+
+
+def timenow():
+ """return current time as a string"""
+ return time.strftime("%d/%m/%Y %H:%M:%S", time.localtime(time.time()))
+
+
+cheetah_escape_table = {"$": "\\$", "#": "\\#"}
+
+
+def cheetah_escape(text):
+ """Produce entities within text."""
+ return "".join([cheetah_escape_table.get(c, c) for c in text])
+
+
+def parse_citations(citations_text):
+ """"""
+ citations = [c for c in citations_text.split("**ENTRY**") if c.strip()]
+ citation_tuples = []
+ for citation in citations:
+ if citation.startswith("doi"):
+ citation_tuples.append(("doi", citation[len("doi") :].strip()))
+ else:
+ citation_tuples.append(("bibtex", citation[len("bibtex") :].strip()))
+ return citation_tuples
+
+
+class Tool_Factory:
+ """Wrapper for an arbitrary script
+ uses galaxyxml
+
+ """
+
+ def __init__(self, args=None): # noqa
+ """
+ prepare command line cl for running the tool here
+ and prepare elements needed for galaxyxml tool generation
+ """
+ self.local_tools = os.path.join(args.galaxy_root,'local_tools')
+ self.ourcwd = os.getcwd()
+ self.collections = []
+ if len(args.collection) > 0:
+ try:
+ self.collections = [
+ json.loads(x) for x in args.collection if len(x.strip()) > 1
+ ]
+ except Exception:
+ print(
+ f"--collections parameter {str(args.collection)} is malformed - should be a dictionary"
+ )
+ try:
+ self.infiles = [
+ json.loads(x) for x in args.input_files if len(x.strip()) > 1
+ ]
+ except Exception:
+ print(
+ f"--input_files parameter {str(args.input_files)} is malformed - should be a dictionary"
+ )
+ try:
+ self.outfiles = [
+ json.loads(x) for x in args.output_files if len(x.strip()) > 1
+ ]
+ except Exception:
+ print(
+ f"--output_files parameter {args.output_files} is malformed - should be a dictionary"
+ )
+ assert (len(self.outfiles) + len(self.collections)) > 0, 'No outfiles or output collections specified. The Galaxy job runner will fail without an output of some sort'
+ try:
+ self.addpar = [
+ json.loads(x) for x in args.additional_parameters if len(x.strip()) > 1
+ ]
+ except Exception:
+ print(
+ f"--additional_parameters {args.additional_parameters} is malformed - should be a dictionary"
+ )
+ try:
+ self.selpar = [
+ json.loads(x) for x in args.selecttext_parameters if len(x.strip()) > 1
+ ]
+ except Exception:
+ print(
+ f"--selecttext_parameters {args.selecttext_parameters} is malformed - should be a dictionary"
+ )
+ self.args = args
+ self.cleanuppar()
+ self.lastxclredirect = None
+ self.xmlcl = []
+ self.is_positional = self.args.parampass == "positional"
+ if self.args.sysexe:
+ if " " in self.args.sysexe:
+ self.executeme = shlex.split(self.args.sysexe)
+ else:
+ self.executeme = [
+ self.args.sysexe,
+ ]
+ else:
+ if self.args.packages:
+ self.executeme = [
+ self.args.packages.split(",")[0].split(":")[0].strip(),
+ ]
+ else:
+ self.executeme = None
+ aXCL = self.xmlcl.append
+ assert args.parampass in [
+ "0",
+ "argparse",
+ "positional",
+ ], 'args.parampass must be "0","positional" or "argparse"'
+ self.tool_name = re.sub("[^a-zA-Z0-9_]+", "", args.tool_name)
+ self.tool_id = self.tool_name
+ self.newtool = gxt.Tool(
+ self.tool_name,
+ self.tool_id,
+ self.args.tool_version,
+ self.args.tool_desc,
+ FAKEEXE,
+ )
+ self.tooloutdir = "./tfout"
+ self.repdir = "./toolgen"
+ self.newtarpath = args.untested_tool_out # os.path.join(self.tooloutdir, "%s_not_tested_toolshed.gz" % self.tool_name)
+ self.testdir = os.path.join(self.tooloutdir, "test-data")
+ if not os.path.exists(self.tooloutdir):
+ os.mkdir(self.tooloutdir)
+ if not os.path.exists(self.testdir):
+ os.mkdir(self.testdir)
+ if not os.path.exists(self.repdir):
+ os.mkdir(self.repdir)
+ self.tlog = os.path.join(self.repdir,'%s_TF_run_log.txt' % self.tool_name)
+ self.tinputs = gxtp.Inputs()
+ self.toutputs = gxtp.Outputs()
+ self.testparam = []
+ if self.args.script_path:
+ self.prepScript()
+ if self.args.command_override:
+ scos = open(self.args.command_override, "r").readlines()
+ self.command_override = [x.rstrip() for x in scos]
+ else:
+ self.command_override = None
+ if self.args.test_override:
+ stos = open(self.args.test_override, "r").readlines()
+ self.test_override = [x.rstrip() for x in stos]
+ else:
+ self.test_override = None
+ if self.args.script_path:
+ for ex in self.executeme:
+ aXCL(ex)
+ aXCL("$runme")
+ else:
+ for ex in self.executeme:
+ aXCL(ex)
+
+ if self.args.parampass == "0":
+ self.clsimple()
+ else:
+ if self.args.parampass == "positional":
+ self.prepclpos()
+ self.clpositional()
+ else:
+ self.prepargp()
+ self.clargparse()
+
+ def clsimple(self):
+ """no parameters or repeats - uses < and > for i/o"""
+ aXCL = self.xmlcl.append
+ if len(self.infiles) > 0:
+ aXCL("<")
+ aXCL("$%s" % self.infiles[0]["infilename"])
+ if len(self.outfiles) > 0:
+ aXCL(">")
+ aXCL("$%s" % self.outfiles[0]["name"])
+ if self.args.cl_user_suffix: # DIY CL end
+ clp = shlex.split(self.args.cl_user_suffix)
+ for c in clp:
+ aXCL(c)
+
+ def prepargp(self):
+ xclsuffix = []
+ for i, p in enumerate(self.infiles):
+ nam = p["infilename"]
+ if p["origCL"].strip().upper() == "STDIN":
+ xappendme = [
+ nam,
+ nam,
+ "< $%s" % nam,
+ ]
+ else:
+ rep = p["repeat"] == "1"
+ over = ""
+ if rep:
+ over = f'#for $rep in $R_{nam}:\n--{nam} "$rep.{nam}"\n#end for'
+ xappendme = [p["CL"], "$%s" % p["CL"], over]
+ xclsuffix.append(xappendme)
+ for i, p in enumerate(self.outfiles):
+ if p["origCL"].strip().upper() == "STDOUT":
+ self.lastxclredirect = [">", "$%s" % p["name"]]
+ else:
+ xclsuffix.append([p["name"], "$%s" % p["name"], ""])
+ for p in self.addpar:
+ nam = p["name"]
+ rep = p["repeat"] == "1"
+ if rep:
+ over = f'#for $rep in $R_{nam}:\n--{nam} "$rep.{nam}"\n#end for'
+ else:
+ over = p["override"]
+ xclsuffix.append([p["CL"], '"$%s"' % nam, over])
+ for p in self.selpar:
+ xclsuffix.append([p["CL"], '"$%s"' % p["name"], p["override"]])
+ self.xclsuffix = xclsuffix
+
+ def prepclpos(self):
+ xclsuffix = []
+ for i, p in enumerate(self.infiles):
+ if p["origCL"].strip().upper() == "STDIN":
+ xappendme = [
+ "999",
+ p["infilename"],
+ "< $%s" % p["infilename"],
+ ]
+ else:
+ xappendme = [p["CL"], "$%s" % p["infilename"], ""]
+ xclsuffix.append(xappendme)
+ for i, p in enumerate(self.outfiles):
+ if p["origCL"].strip().upper() == "STDOUT":
+ self.lastxclredirect = [">", "$%s" % p["name"]]
+ else:
+ xclsuffix.append([p["CL"], "$%s" % p["name"], ""])
+ for p in self.addpar:
+ nam = p["name"]
+ rep = p["repeat"] == "1" # repeats make NO sense
+ if rep:
+ print(
+ f"### warning. Repeats for {nam} ignored - not permitted in positional parameter command lines!"
+ )
+ over = p["override"]
+ xclsuffix.append([p["CL"], '"$%s"' % nam, over])
+ for p in self.selpar:
+ xclsuffix.append([p["CL"], '"$%s"' % p["name"], p["override"]])
+ xclsuffix.sort()
+ self.xclsuffix = xclsuffix
+
+ def prepScript(self):
+ rx = open(self.args.script_path, "r").readlines()
+ rx = [x.rstrip() for x in rx]
+ rxcheck = [x.strip() for x in rx if x.strip() > ""]
+ assert len(rxcheck) > 0, "Supplied script is empty. Cannot run"
+ self.script = "\n".join(rx)
+ fhandle, self.sfile = tempfile.mkstemp(
+ prefix=self.tool_name, suffix="_%s" % (self.executeme[0])
+ )
+ tscript = open(self.sfile, "w")
+ tscript.write(self.script)
+ tscript.close()
+ self.spacedScript = [f" {x}" for x in rx if x.strip() > ""]
+ rx.insert(0, "#raw")
+ rx.append("#end raw")
+ self.escapedScript = rx
+ art = "%s.%s" % (self.tool_name, self.executeme[0])
+ artifact = open(art, "wb")
+ artifact.write(bytes(self.script, "utf8"))
+ artifact.close()
+
+ def cleanuppar(self):
+ """ positional parameters are complicated by their numeric ordinal"""
+ if self.args.parampass == "positional":
+ for i, p in enumerate(self.infiles):
+ assert (
+ p["CL"].isdigit() or p["CL"].strip().upper() == "STDIN"
+ ), "Positional parameters must be ordinal integers - got %s for %s" % (
+ p["CL"],
+ p["label"],
+ )
+ for i, p in enumerate(self.outfiles):
+ assert (
+ p["CL"].isdigit() or p["CL"].strip().upper() == "STDOUT"
+ ), "Positional parameters must be ordinal integers - got %s for %s" % (
+ p["CL"],
+ p["name"],
+ )
+ for i, p in enumerate(self.addpar):
+ assert p[
+ "CL"
+ ].isdigit(), "Positional parameters must be ordinal integers - got %s for %s" % (
+ p["CL"],
+ p["name"],
+ )
+ for i, p in enumerate(self.infiles):
+ infp = copy.copy(p)
+ infp["origCL"] = infp["CL"]
+ if self.args.parampass in ["positional", "0"]:
+ infp["infilename"] = infp["label"].replace(" ", "_")
+ else:
+ infp["infilename"] = infp["CL"]
+ self.infiles[i] = infp
+ for i, p in enumerate(self.outfiles):
+ outfp = copy.copy(p)
+ outfp["origCL"] = outfp["CL"] # keep copy
+ self.outfiles[i] = outfp
+ for i, p in enumerate(self.addpar):
+ addp = copy.copy(p)
+ addp["origCL"] = addp["CL"]
+ self.addpar[i] = addp
+
+ def clpositional(self):
+ # inputs in order then params
+ aXCL = self.xmlcl.append
+ for (k, v, koverride) in self.xclsuffix:
+ aXCL(v)
+ if self.lastxclredirect:
+ for cl in self.lastxclredirect:
+ aXCL(cl)
+ if self.args.cl_user_suffix: # DIY CL end
+ clp = shlex.split(self.args.cl_user_suffix)
+ for c in clp:
+ aXCL(c)
+
+ def clargparse(self):
+ """argparse style"""
+ aXCL = self.xmlcl.append
+ # inputs then params in argparse named form
+
+ for (k, v, koverride) in self.xclsuffix:
+ if koverride > "":
+ k = koverride
+ aXCL(k)
+ else:
+ if len(k.strip()) == 1:
+ k = "-%s" % k
+ else:
+ k = "--%s" % k
+ aXCL(k)
+ aXCL(v)
+ if self.lastxclredirect:
+ for cl in self.lastxclredirect:
+ aXCL(cl)
+ if self.args.cl_user_suffix: # DIY CL end
+ clp = shlex.split(self.args.cl_user_suffix)
+ for c in clp:
+ aXCL(c)
+
+ def getNdash(self, newname):
+ if self.is_positional:
+ ndash = 0
+ else:
+ ndash = 2
+ if len(newname) < 2:
+ ndash = 1
+ return ndash
+
+ def doXMLparam(self): # noqa
+ """Add all needed elements to tool"""
+ for p in self.outfiles:
+ newname = p["name"]
+ newfmt = p["format"]
+ newcl = p["CL"]
+ test = p["test"]
+ oldcl = p["origCL"]
+ test = test.strip()
+ ndash = self.getNdash(newcl)
+ aparm = gxtp.OutputData(
+ name=newname, format=newfmt, num_dashes=ndash, label=newname
+ )
+ aparm.positional = self.is_positional
+ if self.is_positional:
+ if oldcl.upper() == "STDOUT":
+ aparm.positional = 9999999
+ aparm.command_line_override = "> $%s" % newname
+ else:
+ aparm.positional = int(oldcl)
+ aparm.command_line_override = "$%s" % newname
+ self.toutputs.append(aparm)
+ ld = None
+ if test.strip() > "":
+ if test.strip().startswith("diff"):
+ c = "diff"
+ ld = 0
+ if test.split(":")[1].isdigit:
+ ld = int(test.split(":")[1])
+ tp = gxtp.TestOutput(
+ name=newname,
+ value="%s_sample" % newname,
+ compare=c,
+ lines_diff=ld,
+ )
+ elif test.startswith("sim_size"):
+ c = "sim_size"
+ tn = test.split(":")[1].strip()
+ if tn > "":
+ if "." in tn:
+ delta = None
+ delta_frac = min(1.0, float(tn))
+ else:
+ delta = int(tn)
+ delta_frac = None
+ tp = gxtp.TestOutput(
+ name=newname,
+ value="%s_sample" % newname,
+ compare=c,
+ delta=delta,
+ delta_frac=delta_frac,
+ )
+ else:
+ c = test
+ tp = gxtp.TestOutput(
+ name=newname,
+ value="%s_sample" % newname,
+ compare=c,
+ )
+ self.testparam.append(tp)
+ for p in self.infiles:
+ newname = p["infilename"]
+ newfmt = p["format"]
+ ndash = self.getNdash(newname)
+ reps = p.get("repeat", "0") == "1"
+ if not len(p["label"]) > 0:
+ alab = p["CL"]
+ else:
+ alab = p["label"]
+ aninput = gxtp.DataParam(
+ newname,
+ optional=False,
+ label=alab,
+ help=p["help"],
+ format=newfmt,
+ multiple=False,
+ num_dashes=ndash,
+ )
+ aninput.positional = self.is_positional
+ if self.is_positional:
+ if p["origCL"].upper() == "STDIN":
+ aninput.positional = 9999998
+ aninput.command_line_override = "< $%s" % newname
+ else:
+ aninput.positional = int(p["origCL"])
+ aninput.command_line_override = "$%s" % newname
+ if reps:
+ repe = gxtp.Repeat(
+ name=f"R_{newname}", title=f"Add as many {alab} as needed"
+ )
+ repe.append(aninput)
+ self.tinputs.append(repe)
+ tparm = gxtp.TestRepeat(name=f"R_{newname}")
+ tparm2 = gxtp.TestParam(newname, value="%s_sample" % newname)
+ tparm.append(tparm2)
+ self.testparam.append(tparm)
+ else:
+ self.tinputs.append(aninput)
+ tparm = gxtp.TestParam(newname, value="%s_sample" % newname)
+ self.testparam.append(tparm)
+ for p in self.addpar:
+ newname = p["name"]
+ newval = p["value"]
+ newlabel = p["label"]
+ newhelp = p["help"]
+ newtype = p["type"]
+ newcl = p["CL"]
+ oldcl = p["origCL"]
+ reps = p["repeat"] == "1"
+ if not len(newlabel) > 0:
+ newlabel = newname
+ ndash = self.getNdash(newname)
+ if newtype == "text":
+ aparm = gxtp.TextParam(
+ newname,
+ label=newlabel,
+ help=newhelp,
+ value=newval,
+ num_dashes=ndash,
+ )
+ elif newtype == "integer":
+ aparm = gxtp.IntegerParam(
+ newname,
+ label=newlabel,
+ help=newhelp,
+ value=newval,
+ num_dashes=ndash,
+ )
+ elif newtype == "float":
+ aparm = gxtp.FloatParam(
+ newname,
+ label=newlabel,
+ help=newhelp,
+ value=newval,
+ num_dashes=ndash,
+ )
+ elif newtype == "boolean":
+ aparm = gxtp.BooleanParam(
+ newname,
+ label=newlabel,
+ help=newhelp,
+ value=newval,
+ num_dashes=ndash,
+ )
+ else:
+ raise ValueError(
+ 'Unrecognised parameter type "%s" for\
+ additional parameter %s in makeXML'
+ % (newtype, newname)
+ )
+ aparm.positional = self.is_positional
+ if self.is_positional:
+ aparm.positional = int(oldcl)
+ if reps:
+ repe = gxtp.Repeat(
+ name=f"R_{newname}", title=f"Add as many {newlabel} as needed"
+ )
+ repe.append(aparm)
+ self.tinputs.append(repe)
+ tparm = gxtp.TestRepeat(name=f"R_{newname}")
+ tparm2 = gxtp.TestParam(newname, value=newval)
+ tparm.append(tparm2)
+ self.testparam.append(tparm)
+ else:
+ self.tinputs.append(aparm)
+ tparm = gxtp.TestParam(newname, value=newval)
+ self.testparam.append(tparm)
+ for p in self.selpar:
+ newname = p["name"]
+ newval = p["value"]
+ newlabel = p["label"]
+ newhelp = p["help"]
+ newtype = p["type"]
+ newcl = p["CL"]
+ if not len(newlabel) > 0:
+ newlabel = newname
+ ndash = self.getNdash(newname)
+ if newtype == "selecttext":
+ newtext = p["texts"]
+ aparm = gxtp.SelectParam(
+ newname,
+ label=newlabel,
+ help=newhelp,
+ num_dashes=ndash,
+ )
+ for i in range(len(newval)):
+ anopt = gxtp.SelectOption(
+ value=newval[i],
+ text=newtext[i],
+ )
+ aparm.append(anopt)
+ aparm.positional = self.is_positional
+ if self.is_positional:
+ aparm.positional = int(newcl)
+ self.tinputs.append(aparm)
+ tparm = gxtp.TestParam(newname, value=newval)
+ self.testparam.append(tparm)
+ else:
+ raise ValueError(
+ 'Unrecognised parameter type "%s" for\
+ selecttext parameter %s in makeXML'
+ % (newtype, newname)
+ )
+ for p in self.collections:
+ newkind = p["kind"]
+ newname = p["name"]
+ newlabel = p["label"]
+ newdisc = p["discover"]
+ collect = gxtp.OutputCollection(newname, label=newlabel, type=newkind)
+ disc = gxtp.DiscoverDatasets(
+ pattern=newdisc, directory=f"{newname}", visible="false"
+ )
+ collect.append(disc)
+ self.toutputs.append(collect)
+ try:
+ tparm = gxtp.TestOutputCollection(newname) # broken until PR merged.
+ self.testparam.append(tparm)
+ except Exception:
+ print(
+ "#### WARNING: Galaxyxml version does not have the PR merged yet - tests for collections must be over-ridden until then!"
+ )
+
+ def doNoXMLparam(self):
+ """filter style package - stdin to stdout"""
+ if len(self.infiles) > 0:
+ alab = self.infiles[0]["label"]
+ if len(alab) == 0:
+ alab = self.infiles[0]["infilename"]
+ max1s = (
+ "Maximum one input if parampass is 0 but multiple input files supplied - %s"
+ % str(self.infiles)
+ )
+ assert len(self.infiles) == 1, max1s
+ newname = self.infiles[0]["infilename"]
+ aninput = gxtp.DataParam(
+ newname,
+ optional=False,
+ label=alab,
+ help=self.infiles[0]["help"],
+ format=self.infiles[0]["format"],
+ multiple=False,
+ num_dashes=0,
+ )
+ aninput.command_line_override = "< $%s" % newname
+ aninput.positional = True
+ self.tinputs.append(aninput)
+ tp = gxtp.TestParam(name=newname, value="%s_sample" % newname)
+ self.testparam.append(tp)
+ if len(self.outfiles) > 0:
+ newname = self.outfiles[0]["name"]
+ newfmt = self.outfiles[0]["format"]
+ anout = gxtp.OutputData(newname, format=newfmt, num_dashes=0)
+ anout.command_line_override = "> $%s" % newname
+ anout.positional = self.is_positional
+ self.toutputs.append(anout)
+ tp = gxtp.TestOutput(name=newname, value="%s_sample" % newname)
+ self.testparam.append(tp)
+
+ def makeXML(self): # noqa
+ """
+ Create a Galaxy xml tool wrapper for the new script
+ Uses galaxyhtml
+ Hmmm. How to get the command line into correct order...
+ """
+ if self.command_override:
+ self.newtool.command_override = self.command_override # config file
+ else:
+ self.newtool.command_override = self.xmlcl
+ cite = gxtp.Citations()
+ acite = gxtp.Citation(type="doi", value="10.1093/bioinformatics/bts573")
+ cite.append(acite)
+ self.newtool.citations = cite
+ safertext = ""
+ if self.args.help_text:
+ helptext = open(self.args.help_text, "r").readlines()
+ safertext = "\n".join([cheetah_escape(x) for x in helptext])
+ if len(safertext.strip()) == 0:
+ safertext = (
+ "Ask the tool author (%s) to rebuild with help text please\n"
+ % (self.args.user_email)
+ )
+ if self.args.script_path:
+ if len(safertext) > 0:
+ safertext = safertext + "\n\n------\n" # transition allowed!
+ scr = [x for x in self.spacedScript if x.strip() > ""]
+ scr.insert(0, "\n\nScript::\n")
+ if len(scr) > 300:
+ scr = (
+ scr[:100]
+ + [" >300 lines - stuff deleted", " ......"]
+ + scr[-100:]
+ )
+ scr.append("\n")
+ safertext = safertext + "\n".join(scr)
+ self.newtool.help = safertext
+ self.newtool.version_command = f'echo "{self.args.tool_version}"'
+ std = gxtp.Stdios()
+ std1 = gxtp.Stdio()
+ std.append(std1)
+ self.newtool.stdios = std
+ requirements = gxtp.Requirements()
+ self.condaenv = []
+ if self.args.packages:
+ try:
+ for d in self.args.packages.split(","):
+ ver = None
+ packg = None
+ d = d.replace("==", ":")
+ d = d.replace("=", ":")
+ if ":" in d:
+ packg, ver = d.split(":")
+ ver = ver.strip()
+ packg = packg.strip()
+ else:
+ packg = d.strip()
+ ver = None
+ if ver == "":
+ ver = None
+ if packg:
+ requirements.append(
+ gxtp.Requirement("package", packg.strip(), ver)
+ )
+ self.condaenv.append(d)
+ except Exception:
+ print(
+ "### malformed packages string supplied - cannot parse =",
+ self.args.packages,
+ )
+ sys.exit(2)
+ self.newtool.requirements = requirements
+ if self.args.parampass == "0":
+ self.doNoXMLparam()
+ else:
+ self.doXMLparam()
+ self.newtool.outputs = self.toutputs
+ self.newtool.inputs = self.tinputs
+ if self.args.script_path:
+ configfiles = gxtp.Configfiles()
+ configfiles.append(
+ gxtp.Configfile(name="runme", text="\n".join(self.escapedScript))
+ )
+ self.newtool.configfiles = configfiles
+ tests = gxtp.Tests()
+ test_a = gxtp.Test()
+ for tp in self.testparam:
+ test_a.append(tp)
+ tests.append(test_a)
+ self.newtool.tests = tests
+ self.newtool.add_comment(
+ "Created by %s at %s using the Galaxy Tool Factory."
+ % (self.args.user_email, timenow())
+ )
+ self.newtool.add_comment("Source in git at: %s" % (toolFactoryURL))
+ exml0 = self.newtool.export()
+ exml = exml0.replace(FAKEEXE, "") # temporary work around until PR accepted
+ if (
+ self.test_override
+ ): # cannot do this inside galaxyxml as it expects lxml objects for tests
+ part1 = exml.split("")[0]
+ part2 = exml.split("")[1]
+ fixed = "%s\n%s\n%s" % (part1, "\n".join(self.test_override), part2)
+ exml = fixed
+ with open("%s.xml" % self.tool_name, "w") as xf:
+ xf.write(exml)
+ xf.write("\n")
+ # galaxy history item
+
+ def writeShedyml(self):
+ """for planemo"""
+ yuser = self.args.user_email.split("@")[0]
+ yfname = os.path.join(self.tooloutdir, ".shed.yml")
+ yamlf = open(yfname, "w")
+ odict = {
+ "name": self.tool_name,
+ "owner": yuser,
+ "type": "unrestricted",
+ "description": self.args.tool_desc,
+ "synopsis": self.args.tool_desc,
+ "category": "TF Generated Tools",
+ }
+ yaml.dump(odict, yamlf, allow_unicode=True)
+ yamlf.close()
+
+ def makeTool(self):
+ """write xmls and input samples into place"""
+ if self.args.parampass == 0:
+ self.doNoXMLparam()
+ else:
+ self.makeXML()
+ if self.args.script_path:
+ stname = os.path.join(self.tooloutdir, self.sfile)
+ if not os.path.exists(stname):
+ shutil.copyfile(self.sfile, stname)
+ xreal = "%s.xml" % self.tool_name
+ xout = os.path.join(self.tooloutdir, xreal)
+ shutil.copyfile(xreal, xout)
+ xout = os.path.join(self.repdir, xreal)
+ shutil.copyfile(xreal, xout)
+ for p in self.infiles:
+ pth = p["name"]
+ dest = os.path.join(self.testdir, "%s_sample" % p["infilename"])
+ shutil.copyfile(pth, dest)
+ dest = os.path.join(
+ self.repdir, "%s_sample.%s" % (p["infilename"], p["format"])
+ )
+ shutil.copyfile(pth, dest)
+ dest = os.path.join(self.local_tools, self.tool_name)
+ shutil.copytree(self.tooloutdir,dest, dirs_exist_ok=True)
+
+ def makeToolTar(self, report_fail=False):
+ """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
+
+ for p in self.outfiles:
+ oname = p["name"]
+ tdest = os.path.join(self.testdir, "%s_sample" % oname)
+ src = os.path.join(self.testdir, oname)
+ if not os.path.isfile(tdest):
+ if os.path.isfile(src):
+ shutil.copyfile(src, tdest)
+ dest = os.path.join(self.repdir, "%s.sample.%s" % (oname,p['format']))
+ shutil.copyfile(src, dest)
+ else:
+ if report_fail:
+ print(
+ "###Tool may have failed - output file %s not found in testdir after planemo run %s."
+ % (tdest, self.testdir)
+ )
+ tf = tarfile.open(self.newtarpath, "w:gz")
+ tf.add(
+ name=self.tooloutdir,
+ arcname=self.tool_name,
+ filter=exclude_function,
+ )
+ shutil.copy(self.newtarpath, os.path.join(self.tooloutdir, f"{self.tool_name}_untested_toolshed.gz"))
+ tf.close()
+
+
+ def planemo_test_update(self):
+ """planemo is a requirement so is available for testing
+ """
+ xreal = "%s.xml" % self.tool_name
+ tool_test_path = os.path.join(
+ self.repdir, f"{self.tool_name}_planemo_test_report.html"
+ )
+ if os.path.exists(self.tlog):
+ tout = open(self.tlog, "a")
+ else:
+ tout = open(self.tlog, "w")
+ cll = [
+ "planemo",
+ "test",
+ "--conda_auto_init",
+ "--biocontainers",
+ "--test_data",
+ os.path.abspath(self.testdir),
+ "--test_output",
+ os.path.abspath(tool_test_path),
+ "--galaxy_root",
+ self.args.galaxy_root,
+ "--update_test_data",
+ os.path.abspath(xreal),
+ ]
+ p = subprocess.run(
+ cll,
+ shell=False,
+ cwd=self.tooloutdir,
+ stderr=tout,
+ stdout=tout,
+ )
+ tout.close()
+ return p.returncode
+
+
+ def update_toolconf(self ):
+
+ def sortchildrenby(parent, attr):
+ parent[:] = sorted(parent, key=lambda child: child.get(attr))
+
+ tcpath = os.path.join(self.args.galaxy_root,'config/local_tool_conf.xml')
+ xmlfile = os.path.join(self.local_tools, self.tool_name, '%s.xml' % self.tool_name)
+ parser = ET.XMLParser(remove_blank_text=True)
+ tree = ET.parse(tcpath, parser)
+ root = tree.getroot()
+ hasTF = False
+ e = root.findall("section")
+ if len(e) > 0:
+ hasTF = True
+ TFsection = e[0]
+ if not hasTF:
+ TFsection = ET.Element("section", {"id":"localtools", "name":"Local Tools"})
+ root.insert(0, TFsection) # at the top!
+ our_tools = TFsection.findall("tool")
+ conf_tools = [x.attrib["file"] for x in our_tools]
+ if xmlfile not in conf_tools: # new
+ ET.SubElement(TFsection, "tool", {"file": xmlfile})
+ sortchildrenby(TFsection,"file")
+ tree.write(tcpath, pretty_print=True)
+
+
+
+
+
+
+ def shedLoad(self):
+ """
+ use bioblend to create new repository
+ or update existing
+
+ """
+ if os.path.exists(self.tlog):
+ sto = open(self.tlog, "a")
+ else:
+ sto = open(self.tlog, "w")
+
+ ts = toolshed.ToolShedInstance(
+ url=self.args.toolshed_url,
+ key=self.args.toolshed_api_key,
+ verify=False,
+ )
+ repos = ts.repositories.get_repositories()
+ rnames = [x.get("name", "?") for x in repos]
+ rids = [x.get("id", "?") for x in repos]
+ tfcat = "ToolFactory generated tools"
+ if self.tool_name not in rnames:
+ tscat = ts.categories.get_categories()
+ cnames = [x.get("name", "?").strip() for x in tscat]
+ cids = [x.get("id", "?") for x in tscat]
+ catID = None
+ if tfcat.strip() in cnames:
+ ci = cnames.index(tfcat)
+ catID = cids[ci]
+ res = ts.repositories.create_repository(
+ name=self.args.tool_name,
+ synopsis="Synopsis:%s" % self.args.tool_desc,
+ description=self.args.tool_desc,
+ type="unrestricted",
+ remote_repository_url=self.args.toolshed_url,
+ homepage_url=None,
+ category_ids=catID,
+ )
+ tid = res.get("id", None)
+ sto.write(f"#create_repository {self.args.tool_name} tid={tid} res={res}\n")
+ else:
+ i = rnames.index(self.tool_name)
+ tid = rids[i]
+ try:
+ res = ts.repositories.update_repository(
+ id=tid, tar_ball_path=self.newtarpath, commit_message=None
+ )
+ sto.write(f"#update res id {id} ={res}\n")
+ except ConnectionError:
+ sto.write(
+ "####### Is the toolshed running and the API key correct? Bioblend shed upload failed\n"
+ )
+ sto.close()
+
+ def eph_galaxy_load(self):
+ """
+ use ephemeris to load the new tool from the local toolshed after planemo uploads it
+ """
+ if os.path.exists(self.tlog):
+ tout = open(self.tlog, "a")
+ else:
+ tout = open(self.tlog, "w")
+ cll = [
+ "shed-tools",
+ "install",
+ "-g",
+ self.args.galaxy_url,
+ "--latest",
+ "-a",
+ self.args.galaxy_api_key,
+ "--name",
+ self.tool_name,
+ "--owner",
+ "fubar",
+ "--toolshed",
+ self.args.toolshed_url,
+ "--section_label",
+ "ToolFactory",
+ ]
+ tout.write("running\n%s\n" % " ".join(cll))
+ subp = subprocess.run(
+ cll,
+ env=self.ourenv,
+ cwd=self.ourcwd,
+ shell=False,
+ stderr=tout,
+ stdout=tout,
+ )
+ tout.write(
+ "installed %s - got retcode %d\n" % (self.tool_name, subp.returncode)
+ )
+ tout.close()
+ return subp.returncode
+
+ def planemo_biodocker_test(self):
+ """planemo currently leaks dependencies if used in the same container and gets unhappy after a
+ first successful run. https://github.com/galaxyproject/planemo/issues/1078#issuecomment-731476930
+
+ Docker biocontainer has planemo with caches filled to save repeated downloads
+
+
+ """
+
+ def prun(container, tout, cl, user="biodocker"):
+ rlog = container.exec_run(cl, user=user)
+ slogl = str(rlog).split("\\n")
+ slog = "\n".join(slogl)
+ tout.write(f"## got rlog {slog} from {cl}\n")
+
+ if os.path.exists(self.tlog):
+ tout = open(self.tlog, "a")
+ else:
+ tout = open(self.tlog, "w")
+ planemoimage = "quay.io/fubar2/planemo-biocontainer"
+ xreal = "%s.xml" % self.tool_name
+ repname = f"{self.tool_name}_planemo_test_report.html"
+ ptestrep_path = os.path.join(self.repdir, repname)
+ client = docker.from_env()
+ tvol = client.volumes.create()
+ tvolname = tvol.name
+ destdir = "/toolfactory/ptest"
+ imrep = os.path.join(destdir, repname)
+ # need to keep the container running so keep it open with sleep
+ # will stop and destroy it when we are done
+ container = client.containers.run(
+ planemoimage,
+ "sleep 120m",
+ detach=True,
+ user="biodocker",
+ volumes={f"{tvolname}": {"bind": "/toolfactory", "mode": "rw"}},
+ )
+ cl = f"mkdir -p {destdir}"
+ prun(container, tout, cl, user="root")
+ # that's how hard it is to get root on a biodocker container :(
+ cl = f"rm -rf {destdir}/*"
+ prun(container, tout, cl, user="root")
+ ptestpath = os.path.join(destdir, "tfout", xreal)
+ self.copy_to_container(self.tooloutdir, destdir, container)
+ cl = "chown -R biodocker /toolfactory"
+ prun(container, tout, cl, user="root")
+ _ = container.exec_run(f"ls -la {destdir}")
+ ptestcl = f"planemo test --test_output {imrep} --update_test_data --no_cleanup --test_data {destdir}/tfout/test-data --galaxy_root /home/biodocker/galaxy-central {ptestpath}"
+ try:
+ _ = container.exec_run(ptestcl)
+ # fails because test outputs missing but updates the test-data directory
+ except Exception:
+ e = sys.exc_info()[0]
+ tout.write(f"#### error: {e} from {ptestcl}\n")
+ cl = f"planemo test --test_output {imrep} --no_cleanup --test_data {destdir}/tfout/test-data --galaxy_root /home/biodocker/galaxy-central {ptestpath}"
+ try:
+ prun(container, tout, cl)
+ except Exception:
+ e = sys.exc_info()[0]
+ tout.write(f"#### error: {e} from {ptestcl}\n")
+ testouts = tempfile.mkdtemp(suffix=None, prefix="tftemp", dir=".")
+ self.copy_from_container(destdir, testouts, container)
+ src = os.path.join(testouts, "ptest")
+ if os.path.isdir(src):
+ shutil.copytree(src, ".", dirs_exist_ok=True)
+ src = repname
+ if os.path.isfile(repname):
+ shutil.copyfile(src, ptestrep_path)
+ else:
+ tout.write(f"No output from run to shutil.copytree in {src}\n")
+ tout.close()
+ container.stop()
+ container.remove()
+ tvol.remove()
+ shutil.rmtree(testouts) # leave for debugging
+
+
+ # def run(self):
+ # """
+ # scripts must be small enough not to fill the pipe!
+ # """
+ # if self.treatbashSpecial and self.opts.interpreter in ['bash','sh']:
+ # retval = self.runBash()
+ # else:
+ # if self.opts.output_dir:
+ # ste = open(self.elog,'w')
+ # sto = open(self.tlog,'w')
+ # sto.write('## Toolfactory generated command line = %s\n' % ' '.join(self.cl))
+ # sto.flush()
+ # p = subprocess.Popen(self.cl,shell=False,stdout=sto,stderr=ste,stdin=subprocess.PIPE,cwd=self.opts.output_dir)
+ # else:
+ # p = subprocess.Popen(self.cl,shell=False,stdin=subprocess.PIPE)
+ # p.stdin.write(self.script)
+ # p.stdin.close()
+ # retval = p.wait()
+ # if self.opts.output_dir:
+ # sto.close()
+ # ste.close()
+ # err = open(self.elog,'r').read()
+ # if retval <> 0 and err: # problem
+ # print >> sys.stderr, '## error code %d returned with:\n%s' % (retval,err)
+ # if self.opts.make_HTML:
+ # self.makeHtml()
+ # return retval
+
+ # def runBash(self):
+ # """
+ # cannot use - for bash so use self.sfile
+ # """
+ # if self.opts.output_dir:
+ # s = '## Toolfactory generated command line = %s\n' % ' '.join(self.cl)
+ # sto = open(self.tlog,'w')
+ # sto.write(s)
+ # sto.flush()
+ # p = subprocess.Popen(self.cl,shell=False,stdout=sto,stderr=sto,cwd=self.opts.output_dir)
+ # else:
+ # p = subprocess.Popen(self.cl,shell=False)
+ # retval = p.wait()
+ # if self.opts.output_dir:
+ # sto.close()
+ # if self.opts.make_HTML:
+ # self.makeHtml()
+ # return retval
+
+ # def make_conda_env(self, dep_list):
+ # """
+# (venv) galaxy@ross-newgrt:/evol/galaxy$ mulled-hash bioblend=0.17.0,galaxyxml=0.4.14
+# mulled-v2-37438395e15c3d0bed4e02d66d5b05ca3d18b389:1d0b008b65909163243b3fdddd9aa20605f8a005
+
+# conda create -n myenv python=3.9 scipy=0.17.3 astroid babel
+
+
+ # """
+ # dep_list.sort()
+ # self.env_name = '-'.join(dep_list)
+ # for e in self.xmlcl +
+
+ # for e in self.xclsuffix:
+ # # xappendme = ["999", p["infilename"], "< $%s" % p["infilename"]]
+ # else:
+ # xappendme = [p["CL"], "$%s" % p["infilename"], ""]
+ # xclsuffix.append(xappendme)
+ # if os.path.exists(self.tlog):
+ # tout = open(self.tlog, "a")
+ # else:
+ # tout = open(self.tlog, "w")
+ # cli = ["conda", "create", "-n", self.env_name, ' '.join(dep_list)]
+ # p = subprocess.run(
+ # cll,
+ # shell=False,
+ # cwd=self.tooloutdir,
+ # stderr=tout,
+ # stdout=tout,
+ # )
+ # cli = ["conda", "activate", self.env_name, " && "]
+ # cli.append(run_cmd)
+ # tout.close()
+
+def main():
+ """
+ This is a Galaxy wrapper.
+ It expects to be called by a special purpose tool.xml
+
+ """
+ parser = argparse.ArgumentParser()
+ a = parser.add_argument
+ a("--script_path", default=None)
+ a("--history_test", default=None)
+ a("--cl_user_suffix", default=None)
+ a("--sysexe", default=None)
+ a("--packages", default=None)
+ a("--tool_name", default="newtool")
+ a("--tool_dir", default=None)
+ a("--input_files", default=[], action="append")
+ a("--output_files", default=[], action="append")
+ a("--user_email", default="Unknown")
+ a("--bad_user", default=None)
+ a("--help_text", default=None)
+ a("--tool_desc", default=None)
+ a("--tool_version", default="0.01")
+ a("--citations", default=None)
+ a("--command_override", default=None)
+ a("--test_override", default=None)
+ a("--additional_parameters", action="append", default=[])
+ a("--selecttext_parameters", action="append", default=[])
+ a("--edit_additional_parameters", action="store_true", default=False)
+ a("--parampass", default="positional")
+ a("--tfout", default="./tfout")
+ a("--galaxy_root", default="/galaxy-central")
+ a("--galaxy_venv", default="/galaxy_venv")
+ a("--collection", action="append", default=[])
+ a("--include_tests", default=False, action="store_true")
+ a("--install_flag", action = "store_true", default=False)
+ a("--admin_only", default=True, action="store_true")
+ a("--untested_tool_out", default=None)
+ a("--local_tools", default="tools") # relative to $__root_dir__
+ a("--tool_conf_path", default="config/tool_conf.xml") # relative to $__root_dir__
+ args = parser.parse_args()
+ if args.admin_only:
+ assert not args.bad_user, (
+ 'UNAUTHORISED: %s is NOT authorized to use this tool until Galaxy \
+admin adds %s to "admin_users" in the galaxy.yml Galaxy configuration file'
+ % (args.bad_user, args.bad_user)
+ )
+ assert args.tool_name, "## This ToolFactory cannot build a tool without a tool name. Please supply one."
+ tf = Tool_Factory(args)
+ tf.writeShedyml()
+ tf.makeTool()
+ tf.planemo_test_update()
+ tf.makeToolTar()
+ tf.update_toolconf()
+
+
+if __name__ == "__main__":
+ main()
diff -r 2beaae16651e -r 0183cad9d13b pyrev_pos_test/test-data/pyrev_positionalparse_output_sample
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/pyrev_pos_test/test-data/pyrev_positionalparse_output_sample Thu Feb 22 10:48:01 2024 +0000
@@ -0,0 +1,1210 @@
+yrotcafloot/2rabuf/moc.buhtig//:sptth ees #
+#
+2102 yaM )moc pots liamg ta surazal pots ssor( surazal ssor thgirypoc #
+#
+devreser sthgir lla #
+LPGL eht rednu desneciL #
+ta emoclew sexif gub dna tnemevorpmi rof snoitseggus #
+yrotcafloot/2rabuf/moc.buhtig//:sptth #
+#
+llatsni/tset dna etareneg - sloot owt otni derotcafeR :2202 hcram #
+noitpoda reniatnocoib dna tnempoleved lairotut NTG fo trap sa #
+stuptuo tset eht setaerc ,evihcra detset-non a no omenalp snur retset ehT #
+.tset htiw loot reporp wen a snruter dna #
+
+
+
+esrapgra tropmi
+ypoc tropmi
+ltncf tropmi
+nosj tropmi
+so tropmi
+er tropmi
+xelhs tropmi
+lituhs tropmi
+ssecorpbus tropmi
+sys tropmi
+elifrat tropmi
+elifpmet tropmi
+emit tropmi
+
+yxalag tropmi dnelboib morf
+
+txg sa loot.lmxyxalag tropmi
+ptxg sa sretemarap.loot.lmxyxalag tropmi
+
+TE sa eerte.lmxl tropmi
+
+lmay tropmi
+
+"2202 hcraM 4.2V" = noisrevym
+eurT = esobrev
+eurT = gubed
+"yrotcafloot/2rabuf/moc.buhtig//:sptth" = LRUyrotcaFloot
+"~~~EM~~~EVOMER~~~" = EXEEKAF
+neve exe eht gnidneperp lmxyxalag xif ot pmub noisrev/RP a litnu siht deen #
+.edirrevo htiw #
+
+
+:)(wonemit fed
+"""gnirts a sa emit tnerruc nruter"""
+)))(emit.emit(emitlacol.emit ,"S%:M%:H% Y%/m%/d%"(emitfrts.emit nruter
+
+
+}"#\\" :"#" ,"$\\" :"$"{ = elbat_epacse_hateehc
+
+
+:)txet(epacse_hateehc fed
+""".txet nihtiw seititne ecudorP"""
+)]txet ni c rof )c ,c(teg.elbat_epacse_hateehc[(nioj."" nruter
+
+
+:)txet_snoitatic(snoitatic_esrap fed
+""""""
+])(pirts.c fi )"**YRTNE**"(tilps.txet_snoitatic ni c rof c[ = snoitatic
+][ = selput_noitatic
+:snoitatic ni noitatic rof
+:)"iod"(htiwstrats.noitatic fi
+)))(pirts.]: )"iod"(nel[noitatic ,"iod"((dneppa.selput_noitatic
+:esle
+)))(pirts.]: )"xetbib"(nel[noitatic ,"xetbib"((dneppa.selput_noitatic
+selput_noitatic nruter
+
+
+:yrotcaF_looT ssalc
+tpircs yrartibra na rof repparW"""
+lmxyxalag sesu
+
+"""
+
+aqon # :)enoN=sgra ,fles(__tini__ fed
+"""
+ereh loot eht gninnur rof lc enil dnammoc eraperp
+noitareneg loot lmxyxalag rof dedeen stnemele eraperp dna
+"""
+)'sloot_lacol',toor_yxalag.sgra(nioj.htap.so = sloot_lacol.fles
+)(dwcteg.so = dwcruo.fles
+][ = snoitcelloc.fles
+:0 > )noitcelloc.sgra(nel fi
+:yrt
+[ = snoitcelloc.fles
+1 > ))(pirts.x(nel fi noitcelloc.sgra ni x rof )x(sdaol.nosj
+]
+:noitpecxE tpecxe
+(tnirp
+"yranoitcid a eb dluohs - demroflam si })noitcelloc.sgra(rts{ retemarap snoitcelloc--"f
+)
+:yrt
+[ = selifni.fles
+1 > ))(pirts.x(nel fi selif_tupni.sgra ni x rof )x(sdaol.nosj
+]
+:noitpecxE tpecxe
+(tnirp
+"yranoitcid a eb dluohs - demroflam si })selif_tupni.sgra(rts{ retemarap selif_tupni--"f
+)
+:yrt
+[ = seliftuo.fles
+1 > ))(pirts.x(nel fi selif_tuptuo.sgra ni x rof )x(sdaol.nosj
+]
+:noitpecxE tpecxe
+(tnirp
+"yranoitcid a eb dluohs - demroflam si }selif_tuptuo.sgra{ retemarap selif_tuptuo--"f
+)
+'tros emos fo tuptuo na tuohtiw liaf lliw rennur boj yxalaG ehT .deificeps snoitcelloc tuptuo ro seliftuo oN' ,0 > ))snoitcelloc.fles(nel + )seliftuo.fles(nel( tressa
+:yrt
+[ = rapdda.fles
+1 > ))(pirts.x(nel fi sretemarap_lanoitidda.sgra ni x rof )x(sdaol.nosj
+]
+:noitpecxE tpecxe
+(tnirp
+"yranoitcid a eb dluohs - demroflam si }sretemarap_lanoitidda.sgra{ sretemarap_lanoitidda--"f
+)
+:yrt
+[ = raples.fles
+1 > ))(pirts.x(nel fi sretemarap_txettceles.sgra ni x rof )x(sdaol.nosj
+]
+:noitpecxE tpecxe
+(tnirp
+"yranoitcid a eb dluohs - demroflam si }sretemarap_txettceles.sgra{ sretemarap_txettceles--"f
+)
+sgra = sgra.fles
+)(rappunaelc.fles
+enoN = tceriderlcxtsal.fles
+][ = lclmx.fles
+"lanoitisop" == ssapmarap.sgra.fles = lanoitisop_si.fles
+:exesys.sgra.fles fi
+:exesys.sgra.fles ni " " fi
+)exesys.sgra.fles(tilps.xelhs = emetucexe.fles
+:esle
+[ = emetucexe.fles
+,exesys.sgra.fles
+]
+:esle
+:segakcap.sgra.fles fi
+[ = emetucexe.fles
+,)(pirts.]0[)":"(tilps.]0[)","(tilps.segakcap.sgra.fles
+]
+:esle
+enoN = emetucexe.fles
+dneppa.lclmx.fles = LCXa
+[ ni ssapmarap.sgra tressa
+,"0"
+,"esrapgra"
+,"lanoitisop"
+'"esrapgra" ro "lanoitisop","0" eb tsum ssapmarap.sgra' ,]
+)eman_loot.sgra ,"" ,"+]_9-0Z-Az-a^["(bus.er = eman_loot.fles
+eman_loot.fles = di_loot.fles
+(looT.txg = lootwen.fles
+,eman_loot.fles
+,di_loot.fles
+,noisrev_loot.sgra.fles
+,csed_loot.sgra.fles
+,EXEEKAF
+)
+"tuoft/." = ridtuoloot.fles
+"negloot/." = ridper.fles
+)eman_loot.fles % "zg.dehsloot_detset_ton_s%" ,ridtuoloot.fles(nioj.htap.so # tuo_loot_detsetnu.sgra = htapratwen.fles
+)"atad-tset" ,ridtuoloot.fles(nioj.htap.so = ridtset.fles
+:)ridtuoloot.fles(stsixe.htap.so ton fi
+)ridtuoloot.fles(ridkm.so
+:)ridtset.fles(stsixe.htap.so ton fi
+)ridtset.fles(ridkm.so
+:)ridper.fles(stsixe.htap.so ton fi
+)ridper.fles(ridkm.so
+)eman_loot.fles % 'txt.gol_nur_FT_s%',ridper.fles(nioj.htap.so = golt.fles
+)(stupnI.ptxg = stupnit.fles
+)(stuptuO.ptxg = stuptuot.fles
+][ = maraptset.fles
+:htap_tpircs.sgra.fles fi
+)(tpircSperp.fles
+:edirrevo_dnammoc.sgra.fles fi
+)(senildaer.)"r" ,edirrevo_dnammoc.sgra.fles(nepo = socs
+]socs ni x rof )(pirtsr.x[ = edirrevo_dnammoc.fles
+:esle
+enoN = edirrevo_dnammoc.fles
+:edirrevo_tset.sgra.fles fi
+)(senildaer.)"r" ,edirrevo_tset.sgra.fles(nepo = sots
+]sots ni x rof )(pirtsr.x[ = edirrevo_tset.fles
+:esle
+enoN = edirrevo_tset.fles
+:htap_tpircs.sgra.fles fi
+:emetucexe.fles ni xe rof
+)xe(LCXa
+)"emnur$"(LCXa
+:esle
+:emetucexe.fles ni xe rof
+)xe(LCXa
+
+:"0" == ssapmarap.sgra.fles fi
+)(elpmislc.fles
+:esle
+:"lanoitisop" == ssapmarap.sgra.fles fi
+)(soplcperp.fles
+)(lanoitisoplc.fles
+:esle
+)(pgraperp.fles
+)(esrapgralc.fles
+
+:)fles(elpmislc fed
+"""o/i rof > dna < sesu - staeper ro sretemarap on"""
+dneppa.lclmx.fles = LCXa
+:0 > )selifni.fles(nel fi
+)"<"(LCXa
+)]"emanelifni"[]0[selifni.fles % "s%$"(LCXa
+:0 > )seliftuo.fles(nel fi
+)">"(LCXa
+)]"eman"[]0[seliftuo.fles % "s%$"(LCXa
+dne LC YID # :xiffus_resu_lc.sgra.fles fi
+)xiffus_resu_lc.sgra.fles(tilps.xelhs = plc
+:plc ni c rof
+)c(LCXa
+
+:)fles(pgraperp fed
+][ = xiffuslcx
+:)selifni.fles(etaremune ni p ,i rof
+]"emanelifni"[p = man
+:"NIDTS" == )(reppu.)(pirts.]"LCgiro"[p fi
+[ = emdneppax
+,man
+,man
+,man % "s%$ <"
+]
+:esle
+"1" == ]"taeper"[p = per
+"" = revo
+:per fi
+'rof dne#n\"}man{.per$" }man{--n\:}man{_R$ ni per$ rof#'f = revo
+]revo ,]"LC"[p % "s%$" ,]"LC"[p[ = emdneppax
+)emdneppax(dneppa.xiffuslcx
+:)seliftuo.fles(etaremune ni p ,i rof
+:"TUODTS" == )(reppu.)(pirts.]"LCgiro"[p fi
+]]"eman"[p % "s%$" ,">"[ = tceriderlcxtsal.fles
+:esle
+)]"" ,]"eman"[p % "s%$" ,]"eman"[p[(dneppa.xiffuslcx
+:rapdda.fles ni p rof
+]"eman"[p = man
+"1" == ]"taeper"[p = per
+:per fi
+'rof dne#n\"}man{.per$" }man{--n\:}man{_R$ ni per$ rof#'f = revo
+:esle
+]"edirrevo"[p = revo
+)]revo ,man % '"s%$"' ,]"LC"[p[(dneppa.xiffuslcx
+:raples.fles ni p rof
+)]]"edirrevo"[p ,]"eman"[p % '"s%$"' ,]"LC"[p[(dneppa.xiffuslcx
+xiffuslcx = xiffuslcx.fles
+
+:)fles(soplcperp fed
+][ = xiffuslcx
+:)selifni.fles(etaremune ni p ,i rof
+:"NIDTS" == )(reppu.)(pirts.]"LCgiro"[p fi
+[ = emdneppax
+,"999"
+,]"emanelifni"[p
+,]"emanelifni"[p % "s%$ <"
+]
+:esle
+]"" ,]"emanelifni"[p % "s%$" ,]"LC"[p[ = emdneppax
+)emdneppax(dneppa.xiffuslcx
+:)seliftuo.fles(etaremune ni p ,i rof
+:"TUODTS" == )(reppu.)(pirts.]"LCgiro"[p fi
+]]"eman"[p % "s%$" ,">"[ = tceriderlcxtsal.fles
+:esle
+)]"" ,]"eman"[p % "s%$" ,]"LC"[p[(dneppa.xiffuslcx
+:rapdda.fles ni p rof
+]"eman"[p = man
+esnes ON ekam staeper # "1" == ]"taeper"[p = per
+:per fi
+(tnirp
+"!senil dnammoc retemarap lanoitisop ni dettimrep ton - derongi }man{ rof staepeR .gninraw ###"f
+)
+]"edirrevo"[p = revo
+)]revo ,man % '"s%$"' ,]"LC"[p[(dneppa.xiffuslcx
+:raples.fles ni p rof
+)]]"edirrevo"[p ,]"eman"[p % '"s%$"' ,]"LC"[p[(dneppa.xiffuslcx
+)(tros.xiffuslcx
+xiffuslcx = xiffuslcx.fles
+
+:)fles(tpircSperp fed
+)(senildaer.)"r" ,htap_tpircs.sgra.fles(nepo = xr
+]xr ni x rof )(pirtsr.x[ = xr
+]"" > )(pirts.x fi xr ni x rof )(pirts.x[ = kcehcxr
+"nur tonnaC .ytpme si tpircs deilppuS" ,0 > )kcehcxr(nel tressa
+)xr(nioj."n\" = tpircs.fles
+(pmetskm.elifpmet = elifs.fles ,eldnahf
+)]0[emetucexe.fles( % "s%_"=xiffus ,eman_loot.fles=xiferp
+)
+)"w" ,elifs.fles(nepo = tpircst
+)tpircs.fles(etirw.tpircst
+)(esolc.tpircst
+]"" > )(pirts.x fi xr ni x rof "}x{ "f[ = tpircSdecaps.fles
+)"war#" ,0(tresni.xr
+)"war dne#"(dneppa.xr
+xr = tpircSdepacse.fles
+)]0[emetucexe.fles ,eman_loot.fles( % "s%.s%" = tra
+)"bw" ,tra(nepo = tcafitra
+))"8ftu" ,tpircs.fles(setyb(etirw.tcafitra
+)(esolc.tcafitra
+
+:)fles(rappunaelc fed
+"""lanidro ciremun rieht yb detacilpmoc era sretemarap lanoitisop """
+:"lanoitisop" == ssapmarap.sgra.fles fi
+:)selifni.fles(etaremune ni p ,i rof
+( tressa
+"NIDTS" == )(reppu.)(pirts.]"LC"[p ro )(tigidsi.]"LC"[p
+( % "s% rof s% tog - sregetni lanidro eb tsum sretemarap lanoitisoP" ,)
+,]"LC"[p
+,]"lebal"[p
+)
+:)seliftuo.fles(etaremune ni p ,i rof
+( tressa
+"TUODTS" == )(reppu.)(pirts.]"LC"[p ro )(tigidsi.]"LC"[p
+( % "s% rof s% tog - sregetni lanidro eb tsum sretemarap lanoitisoP" ,)
+,]"LC"[p
+,]"eman"[p
+)
+:)rapdda.fles(etaremune ni p ,i rof
+[p tressa
+"LC"
+( % "s% rof s% tog - sregetni lanidro eb tsum sretemarap lanoitisoP" ,)(tigidsi.]
+,]"LC"[p
+,]"eman"[p
+)
+:)selifni.fles(etaremune ni p ,i rof
+)p(ypoc.ypoc = pfni
+]"LC"[pfni = ]"LCgiro"[pfni
+:]"0" ,"lanoitisop"[ ni ssapmarap.sgra.fles fi
+)"_" ," "(ecalper.]"lebal"[pfni = ]"emanelifni"[pfni
+:esle
+]"LC"[pfni = ]"emanelifni"[pfni
+pfni = ]i[selifni.fles
+:)seliftuo.fles(etaremune ni p ,i rof
+)p(ypoc.ypoc = pftuo
+ypoc peek # ]"LC"[pftuo = ]"LCgiro"[pftuo
+pftuo = ]i[seliftuo.fles
+:)rapdda.fles(etaremune ni p ,i rof
+)p(ypoc.ypoc = pdda
+]"LC"[pdda = ]"LCgiro"[pdda
+pdda = ]i[rapdda.fles
+
+:)fles(lanoitisoplc fed
+smarap neht redro ni stupni #
+dneppa.lclmx.fles = LCXa
+:xiffuslcx.fles ni )edirrevok ,v ,k( rof
+)v(LCXa
+:tceriderlcxtsal.fles fi
+:tceriderlcxtsal.fles ni lc rof
+)lc(LCXa
+dne LC YID # :xiffus_resu_lc.sgra.fles fi
+)xiffus_resu_lc.sgra.fles(tilps.xelhs = plc
+:plc ni c rof
+)c(LCXa
+
+:)fles(esrapgralc fed
+"""elyts esrapgra"""
+dneppa.lclmx.fles = LCXa
+mrof deman esrapgra ni smarap neht stupni #
+
+:xiffuslcx.fles ni )edirrevok ,v ,k( rof
+:"" > edirrevok fi
+edirrevok = k
+)k(LCXa
+:esle
+:1 == ))(pirts.k(nel fi
+k % "s%-" = k
+:esle
+k % "s%--" = k
+)k(LCXa
+)v(LCXa
+:tceriderlcxtsal.fles fi
+:tceriderlcxtsal.fles ni lc rof
+)lc(LCXa
+dne LC YID # :xiffus_resu_lc.sgra.fles fi
+)xiffus_resu_lc.sgra.fles(tilps.xelhs = plc
+:plc ni c rof
+)c(LCXa
+
+:)emanwen ,fles(hsadNteg fed
+:lanoitisop_si.fles fi
+0 = hsadn
+:esle
+2 = hsadn
+:2 < )emanwen(nel fi
+1 = hsadn
+hsadn nruter
+
+aqon # :)fles(marapLMXod fed
+"""loot ot stnemele dedeen lla ddA"""
+:seliftuo.fles ni p rof
+]"eman"[p = emanwen
+]"tamrof"[p = tmfwen
+]"LC"[p = lcwen
+]"tset"[p = tset
+]"LCgiro"[p = lcdlo
+)(pirts.tset = tset
+)lcwen(hsadNteg.fles = hsadn
+(ataDtuptuO.ptxg = mrapa
+emanwen=lebal ,hsadn=sehsad_mun ,tmfwen=tamrof ,emanwen=eman
+)
+lanoitisop_si.fles = lanoitisop.mrapa
+:lanoitisop_si.fles fi
+:"TUODTS" == )(reppu.lcdlo fi
+9999999 = lanoitisop.mrapa
+emanwen % "s%$ >" = edirrevo_enil_dnammoc.mrapa
+:esle
+)lcdlo(tni = lanoitisop.mrapa
+emanwen % "s%$" = edirrevo_enil_dnammoc.mrapa
+)mrapa(dneppa.stuptuot.fles
+enoN = dl
+:"" > )(pirts.tset fi
+:)"ffid"(htiwstrats.)(pirts.tset fi
+"ffid" = c
+0 = dl
+:tigidsi.]1[)":"(tilps.tset fi
+)]1[)":"(tilps.tset(tni = dl
+(tuptuOtseT.ptxg = pt
+,emanwen=eman
+,emanwen % "elpmas_s%"=eulav
+,c=erapmoc
+,dl=ffid_senil
+)
+:)"ezis_mis"(htiwstrats.tset file
+"ezis_mis" = c
+)(pirts.]1[)":"(tilps.tset = nt
+:"" > nt fi
+:nt ni "." fi
+enoN = atled
+))nt(taolf ,0.1(nim = carf_atled
+:esle
+)nt(tni = atled
+enoN = carf_atled
+(tuptuOtseT.ptxg = pt
+,emanwen=eman
+,emanwen % "elpmas_s%"=eulav
+,c=erapmoc
+,atled=atled
+,carf_atled=carf_atled
+)
+:esle
+tset = c
+(tuptuOtseT.ptxg = pt
+,emanwen=eman
+,emanwen % "elpmas_s%"=eulav
+,c=erapmoc
+)
+)pt(dneppa.maraptset.fles
+:selifni.fles ni p rof
+]"emanelifni"[p = emanwen
+]"tamrof"[p = tmfwen
+)emanwen(hsadNteg.fles = hsadn
+"1" == )"0" ,"taeper"(teg.p = sper
+:0 > )]"lebal"[p(nel ton fi
+]"LC"[p = bala
+:esle
+]"lebal"[p = bala
+(maraPataD.ptxg = tupnina
+,emanwen
+,eslaF=lanoitpo
+,bala=lebal
+,]"pleh"[p=pleh
+,tmfwen=tamrof
+,eslaF=elpitlum
+,hsadn=sehsad_mun
+)
+lanoitisop_si.fles = lanoitisop.tupnina
+:lanoitisop_si.fles fi
+:"NIDTS" == )(reppu.]"LCgiro"[p fi
+8999999 = lanoitisop.tupnina
+emanwen % "s%$ <" = edirrevo_enil_dnammoc.tupnina
+:esle
+)]"LCgiro"[p(tni = lanoitisop.tupnina
+emanwen % "s%$" = edirrevo_enil_dnammoc.tupnina
+:sper fi
+(taepeR.ptxg = eper
+"dedeen sa }bala{ ynam sa ddA"f=eltit ,"}emanwen{_R"f=eman
+)
+)tupnina(dneppa.eper
+)eper(dneppa.stupnit.fles
+)"}emanwen{_R"f=eman(taepeRtseT.ptxg = mrapt
+)emanwen % "elpmas_s%"=eulav ,emanwen(maraPtseT.ptxg = 2mrapt
+)2mrapt(dneppa.mrapt
+)mrapt(dneppa.maraptset.fles
+:esle
+)tupnina(dneppa.stupnit.fles
+)emanwen % "elpmas_s%"=eulav ,emanwen(maraPtseT.ptxg = mrapt
+)mrapt(dneppa.maraptset.fles
+:rapdda.fles ni p rof
+]"eman"[p = emanwen
+]"eulav"[p = lavwen
+]"lebal"[p = lebalwen
+]"pleh"[p = plehwen
+]"epyt"[p = epytwen
+]"LC"[p = lcwen
+]"LCgiro"[p = lcdlo
+"1" == ]"taeper"[p = sper
+:0 > )lebalwen(nel ton fi
+emanwen = lebalwen
+)emanwen(hsadNteg.fles = hsadn
+:"txet" == epytwen fi
+(maraPtxeT.ptxg = mrapa
+,emanwen
+,lebalwen=lebal
+,plehwen=pleh
+,lavwen=eulav
+,hsadn=sehsad_mun
+)
+:"regetni" == epytwen file
+(maraPregetnI.ptxg = mrapa
+,emanwen
+,lebalwen=lebal
+,plehwen=pleh
+,lavwen=eulav
+,hsadn=sehsad_mun
+)
+:"taolf" == epytwen file
+(maraPtaolF.ptxg = mrapa
+,emanwen
+,lebalwen=lebal
+,plehwen=pleh
+,lavwen=eulav
+,hsadn=sehsad_mun
+)
+:"naeloob" == epytwen file
+(maraPnaelooB.ptxg = mrapa
+,emanwen
+,lebalwen=lebal
+,plehwen=pleh
+,lavwen=eulav
+,hsadn=sehsad_mun
+)
+:esle
+(rorrEeulaV esiar
+\rof "s%" epyt retemarap desingocernU'
+'LMXekam ni s% retemarap lanoitidda
+)emanwen ,epytwen( %
+)
+lanoitisop_si.fles = lanoitisop.mrapa
+:lanoitisop_si.fles fi
+)lcdlo(tni = lanoitisop.mrapa
+:sper fi
+(taepeR.ptxg = eper
+"dedeen sa }lebalwen{ ynam sa ddA"f=eltit ,"}emanwen{_R"f=eman
+)
+)mrapa(dneppa.eper
+)eper(dneppa.stupnit.fles
+)"}emanwen{_R"f=eman(taepeRtseT.ptxg = mrapt
+)lavwen=eulav ,emanwen(maraPtseT.ptxg = 2mrapt
+)2mrapt(dneppa.mrapt
+)mrapt(dneppa.maraptset.fles
+:esle
+)mrapa(dneppa.stupnit.fles
+)lavwen=eulav ,emanwen(maraPtseT.ptxg = mrapt
+)mrapt(dneppa.maraptset.fles
+:raples.fles ni p rof
+]"eman"[p = emanwen
+]"eulav"[p = lavwen
+]"lebal"[p = lebalwen
+]"pleh"[p = plehwen
+]"epyt"[p = epytwen
+]"LC"[p = lcwen
+:0 > )lebalwen(nel ton fi
+emanwen = lebalwen
+)emanwen(hsadNteg.fles = hsadn
+:"txettceles" == epytwen fi
+]"stxet"[p = txetwen
+(maraPtceleS.ptxg = mrapa
+,emanwen
+,lebalwen=lebal
+,plehwen=pleh
+,hsadn=sehsad_mun
+)
+:))lavwen(nel(egnar ni i rof
+(noitpOtceleS.ptxg = tpona
+,]i[lavwen=eulav
+,]i[txetwen=txet
+)
+)tpona(dneppa.mrapa
+lanoitisop_si.fles = lanoitisop.mrapa
+:lanoitisop_si.fles fi
+)lcwen(tni = lanoitisop.mrapa
+)mrapa(dneppa.stupnit.fles
+)lavwen=eulav ,emanwen(maraPtseT.ptxg = mrapt
+)mrapt(dneppa.maraptset.fles
+:esle
+(rorrEeulaV esiar
+\rof "s%" epyt retemarap desingocernU'
+'LMXekam ni s% retemarap txettceles
+)emanwen ,epytwen( %
+)
+:snoitcelloc.fles ni p rof
+]"dnik"[p = dnikwen
+]"eman"[p = emanwen
+]"lebal"[p = lebalwen
+]"revocsid"[p = csidwen
+)dnikwen=epyt ,lebalwen=lebal ,emanwen(noitcelloCtuptuO.ptxg = tcelloc
+(stesataDrevocsiD.ptxg = csid
+"eslaf"=elbisiv ,"}emanwen{"f=yrotcerid ,csidwen=nrettap
+)
+)csid(dneppa.tcelloc
+)tcelloc(dneppa.stuptuot.fles
+:yrt
+.degrem RP litnu nekorb # )emanwen(noitcelloCtuptuOtseT.ptxg = mrapt
+)mrapt(dneppa.maraptset.fles
+:noitpecxE tpecxe
+(tnirp
+"!neht litnu neddir-revo eb tsum snoitcelloc rof stset - tey degrem RP eht evah ton seod noisrev lmxyxalaG :GNINRAW ####"
+)
+
+:)fles(marapLMXoNod fed
+"""tuodts ot nidts - egakcap elyts retlif"""
+:0 > )selifni.fles(nel fi
+]"lebal"[]0[selifni.fles = bala
+:0 == )bala(nel fi
+]"emanelifni"[]0[selifni.fles = bala
+( = s1xam
+"s% - deilppus selif tupni elpitlum tub 0 si ssapmarap fi tupni eno mumixaM"
+)selifni.fles(rts %
+)
+s1xam ,1 == )selifni.fles(nel tressa
+]"emanelifni"[]0[selifni.fles = emanwen
+(maraPataD.ptxg = tupnina
+,emanwen
+,eslaF=lanoitpo
+,bala=lebal
+,]"pleh"[]0[selifni.fles=pleh
+,]"tamrof"[]0[selifni.fles=tamrof
+,eslaF=elpitlum
+,0=sehsad_mun
+)
+emanwen % "s%$ <" = edirrevo_enil_dnammoc.tupnina
+eurT = lanoitisop.tupnina
+)tupnina(dneppa.stupnit.fles
+)emanwen % "elpmas_s%"=eulav ,emanwen=eman(maraPtseT.ptxg = pt
+)pt(dneppa.maraptset.fles
+:0 > )seliftuo.fles(nel fi
+]"eman"[]0[seliftuo.fles = emanwen
+]"tamrof"[]0[seliftuo.fles = tmfwen
+)0=sehsad_mun ,tmfwen=tamrof ,emanwen(ataDtuptuO.ptxg = tuona
+emanwen % "s%$ >" = edirrevo_enil_dnammoc.tuona
+lanoitisop_si.fles = lanoitisop.tuona
+)tuona(dneppa.stuptuot.fles
+)emanwen % "elpmas_s%"=eulav ,emanwen=eman(tuptuOtseT.ptxg = pt
+)pt(dneppa.maraptset.fles
+
+aqon # :)fles(LMXekam fed
+"""
+tpircs wen eht rof repparw loot lmx yxalaG a etaerC
+lmthyxalag sesU
+...redro tcerroc otni enil dnammoc eht teg ot woH .mmmH
+"""
+:edirrevo_dnammoc.fles fi
+elif gifnoc # edirrevo_dnammoc.fles = edirrevo_dnammoc.lootwen.fles
+:esle
+lclmx.fles = edirrevo_dnammoc.lootwen.fles
+)(snoitatiC.ptxg = etic
+)"375stb/scitamrofnioib/3901.01"=eulav ,"iod"=epyt(noitatiC.ptxg = etica
+)etica(dneppa.etic
+etic = snoitatic.lootwen.fles
+"" = txetrefas
+:txet_pleh.sgra.fles fi
+)(senildaer.)"r" ,txet_pleh.sgra.fles(nepo = txetpleh
+)]txetpleh ni x rof )x(epacse_hateehc[(nioj."n\" = txetrefas
+:0 == ))(pirts.txetrefas(nel fi
+( = txetrefas
+"n\esaelp txet pleh htiw dliuber ot )s%( rohtua loot eht ksA"
+)liame_resu.sgra.fles( %
+)
+:htap_tpircs.sgra.fles fi
+:0 > )txetrefas(nel fi
+!dewolla noitisnart # "n\------n\n\" + txetrefas = txetrefas
+]"" > )(pirts.x fi tpircSdecaps.fles ni x rof x[ = rcs
+)"n\::tpircSn\n\" ,0(tresni.rcs
+:003 > )rcs(nel fi
+( = rcs
+]001:[rcs
+]"...... " ,"deteled ffuts - senil 003> "[ +
+]:001-[rcs +
+)
+)"n\"(dneppa.rcs
+)rcs(nioj."n\" + txetrefas = txetrefas
+txetrefas = pleh.lootwen.fles
+'"}noisrev_loot.sgra.fles{" ohce'f = dnammoc_noisrev.lootwen.fles
+)(soidtS.ptxg = dts
+)(oidtS.ptxg = 1dts
+)1dts(dneppa.dts
+dts = soidts.lootwen.fles
+)(stnemeriuqeR.ptxg = stnemeriuqer
+][ = vneadnoc.fles
+:segakcap.sgra.fles fi
+:yrt
+:)","(tilps.segakcap.sgra.fles ni d rof
+enoN = rev
+enoN = gkcap
+)":" ,"=="(ecalper.d = d
+)":" ,"="(ecalper.d = d
+:d ni ":" fi
+)":"(tilps.d = rev ,gkcap
+)(pirts.rev = rev
+)(pirts.gkcap = gkcap
+:esle
+)(pirts.d = gkcap
+enoN = rev
+:"" == rev fi
+enoN = rev
+:gkcap fi
+(dneppa.stnemeriuqer
+)rev ,)(pirts.gkcap ,"egakcap"(tnemeriuqeR.ptxg
+)
+)d(dneppa.vneadnoc.fles
+:noitpecxE tpecxe
+(tnirp
+,"= esrap tonnac - deilppus gnirts segakcap demroflam ###"
+,segakcap.sgra.fles
+)
+)2(tixe.sys
+stnemeriuqer = stnemeriuqer.lootwen.fles
+:"0" == ssapmarap.sgra.fles fi
+)(marapLMXoNod.fles
+:esle
+)(marapLMXod.fles
+stuptuot.fles = stuptuo.lootwen.fles
+stupnit.fles = stupni.lootwen.fles
+:htap_tpircs.sgra.fles fi
+)(selifgifnoC.ptxg = selifgifnoc
+(dneppa.selifgifnoc
+))tpircSdepacse.fles(nioj."n\"=txet ,"emnur"=eman(elifgifnoC.ptxg
+)
+selifgifnoc = selifgifnoc.lootwen.fles
+)(stseT.ptxg = stset
+)(tseT.ptxg = a_tset
+:maraptset.fles ni pt rof
+)pt(dneppa.a_tset
+)a_tset(dneppa.stset
+stset = stset.lootwen.fles
+(tnemmoc_dda.lootwen.fles
+".yrotcaF looT yxalaG eht gnisu s% ta s% yb detaerC"
+))(wonemit ,liame_resu.sgra.fles( %
+)
+))LRUyrotcaFloot( % "s% :ta tig ni ecruoS"(tnemmoc_dda.lootwen.fles
+)(tropxe.lootwen.fles = 0lmxe
+detpecca RP litnu dnuora krow yraropmet # )"" ,EXEEKAF(ecalper.0lmxe = lmxe
+( fi
+edirrevo_tset.fles
+stset rof stcejbo lmxl stcepxe ti sa lmxyxalag edisni siht od tonnac # :)
+]0[)">stset<"(tilps.lmxe = 1trap
+]1[)">stset/<"(tilps.lmxe = 2trap
+)2trap ,)edirrevo_tset.fles(nioj."n\" ,1trap( % "s%n\s%n\s%" = dexif
+dexif = lmxe
+:fx sa )"w" ,eman_loot.fles % "lmx.s%"(nepo htiw
+)lmxe(etirw.fx
+)"n\"(etirw.fx
+meti yrotsih yxalag #
+
+:)fles(lmydehSetirw fed
+"""omenalp rof"""
+]0[)"@"(tilps.liame_resu.sgra.fles = resuy
+)"lmy.dehs." ,ridtuoloot.fles(nioj.htap.so = emanfy
+)"w" ,emanfy(nepo = flmay
+{ = tcido
+,eman_loot.fles :"eman"
+,resuy :"renwo"
+,"detcirtsernu" :"epyt"
+,csed_loot.sgra.fles :"noitpircsed"
+,csed_loot.sgra.fles :"sisponys"
+,"slooT detareneG FT" :"yrogetac"
+}
+)eurT=edocinu_wolla ,flmay ,tcido(pmud.lmay
+)(esolc.flmay
+
+:)fles(looTekam fed
+"""ecalp otni selpmas tupni dna slmx etirw"""
+:0 == ssapmarap.sgra.fles fi
+)(marapLMXoNod.fles
+:esle
+)(LMXekam.fles
+:htap_tpircs.sgra.fles fi
+)elifs.fles ,ridtuoloot.fles(nioj.htap.so = emants
+:)emants(stsixe.htap.so ton fi
+)emants ,elifs.fles(elifypoc.lituhs
+eman_loot.fles % "lmx.s%" = laerx
+)laerx ,ridtuoloot.fles(nioj.htap.so = tuox
+)tuox ,laerx(elifypoc.lituhs
+)laerx ,ridper.fles(nioj.htap.so = tuox
+)tuox ,laerx(elifypoc.lituhs
+:selifni.fles ni p rof
+]"eman"[p = htp
+)]"emanelifni"[p % "elpmas_s%" ,ridtset.fles(nioj.htap.so = tsed
+)tsed ,htp(elifypoc.lituhs
+(nioj.htap.so = tsed
+)]"tamrof"[p ,]"emanelifni"[p( % "s%.elpmas_s%" ,ridper.fles
+)
+)tsed ,htp(elifypoc.lituhs
+)eman_loot.fles ,sloot_lacol.fles(nioj.htap.so = tsed
+)eurT=ko_tsixe_srid ,tsed,ridtuoloot.fles(eertypoc.lituhs
+
+:)eslaF=liaf_troper ,fles(raTlooTekam fed
+"""llabrat eht eraperp dna atad-tset otni stuptuo evom"""
+"lmth.troper_tset_omenalp_" = emedulcxe
+
+:)ofnirat(noitcnuf_edulcxe fed
+eman.ofnirat = emanelif
+ofnirat esle )emedulcxe(htiwsdne.emanelif fi enoN nruter
+
+:seliftuo.fles ni p rof
+]"eman"[p = emano
+)emano % "elpmas_s%" ,ridtset.fles(nioj.htap.so = tsedt
+)emano ,ridtset.fles(nioj.htap.so = crs
+:)tsedt(elifsi.htap.so ton fi
+:)crs(elifsi.htap.so fi
+)tsedt ,crs(elifypoc.lituhs
+))]'tamrof'[p,emano( % "s%.elpmas.s%" ,ridper.fles(nioj.htap.so = tsed
+)tsed ,crs(elifypoc.lituhs
+:esle
+:liaf_troper fi
+(tnirp
+".s% nur omenalp retfa ridtset ni dnuof ton s% elif tuptuo - deliaf evah yam looT###"
+)ridtset.fles ,tsedt( %
+)
+)"zg:w" ,htapratwen.fles(nepo.elifrat = ft
+(dda.ft
+,ridtuoloot.fles=eman
+,eman_loot.fles=emancra
+,noitcnuf_edulcxe=retlif
+)
+))"zg.dehsloot_detsetnu_}eman_loot.fles{"f ,ridtuoloot.fles(nioj.htap.so ,htapratwen.fles(ypoc.lituhs
+)(esolc.ft
+
+
+:)fles(etadpu_tset_omenalp fed
+gnitset rof elbaliava si os tnemeriuqer a si omenalp"""
+"""
+eman_loot.fles % "lmx.s%" = laerx
+(nioj.htap.so = htap_tset_loot
+"lmth.troper_tset_omenalp_}eman_loot.fles{"f ,ridper.fles
+)
+:)golt.fles(stsixe.htap.so fi
+)"a" ,golt.fles(nepo = tuot
+:esle
+)"w" ,golt.fles(nepo = tuot
+[ = llc
+,"omenalp"
+,"tset"
+,"tini_otua_adnoc--"
+,"sreniatnocoib--"
+,"atad_tset--"
+,)ridtset.fles(htapsba.htap.so
+,"tuptuo_tset--"
+,)htap_tset_loot(htapsba.htap.so
+,"toor_yxalag--"
+,toor_yxalag.sgra.fles
+,"atad_tset_etadpu--"
+,)laerx(htapsba.htap.so
+]
+(nur.ssecorpbus = p
+,llc
+,eslaF=llehs
+,ridtuoloot.fles=dwc
+,tuot=rredts
+,tuot=tuodts
+)
+)(esolc.tuot
+edocnruter.p nruter
+
+
+:) fles(fnocloot_etadpu fed
+
+:)rtta ,tnerap(ybnerdlihctros fed
+))rtta(teg.dlihc :dlihc adbmal=yek ,tnerap(detros = ]:[tnerap
+
+)'lmx.fnoc_loot_lacol/gifnoc',toor_yxalag.sgra.fles(nioj.htap.so = htapct
+)eman_loot.fles % 'lmx.s%' ,eman_loot.fles ,sloot_lacol.fles(nioj.htap.so = eliflmx
+)eurT=txet_knalb_evomer(resraPLMX.TE = resrap
+)resrap ,htapct(esrap.TE = eert
+)(toorteg.eert = toor
+eslaF = FTsah
+)"noitces"(lladnif.toor = e
+:0 > )e(nel fi
+eurT = FTsah
+]0[e = noitcesFT
+:FTsah ton fi
+)}"slooT lacoL":"eman" ,"slootlacol":"di"{ ,"noitces"(tnemelE.TE = noitcesFT
+!pot eht ta # )noitcesFT ,0(tresni.toor
+)"loot"(lladnif.noitcesFT = sloot_ruo
+]sloot_ruo ni x rof ]"elif"[birtta.x[ = sloot_fnoc
+wen # :sloot_fnoc ni ton eliflmx fi
+)}eliflmx :"elif"{ ,"loot" ,noitcesFT(tnemelEbuS.TE
+)"elif",noitcesFT(ybnerdlihctros
+)eurT=tnirp_ytterp ,htapct(etirw.eert
+
+
+
+
+
+
+:)fles(daoLdehs fed
+"""
+yrotisoper wen etaerc ot dnelboib esu
+gnitsixe etadpu ro
+
+"""
+:)golt.fles(stsixe.htap.so fi
+)"a" ,golt.fles(nepo = ots
+:esle
+)"w" ,golt.fles(nepo = ots
+
+(ecnatsnIdehSlooT.dehsloot = st
+,lru_dehsloot.sgra.fles=lru
+,yek_ipa_dehsloot.sgra.fles=yek
+,eslaF=yfirev
+)
+)(seirotisoper_teg.seirotisoper.st = soper
+]soper ni x rof )"?" ,"eman"(teg.x[ = semanr
+]soper ni x rof )"?" ,"di"(teg.x[ = sdir
+"sloot detareneg yrotcaFlooT" = tacft
+:semanr ni ton eman_loot.fles fi
+)(seirogetac_teg.seirogetac.st = tacst
+]tacst ni x rof )(pirts.)"?" ,"eman"(teg.x[ = semanc
+]tacst ni x rof )"?" ,"di"(teg.x[ = sdic
+enoN = DItac
+:semanc ni )(pirts.tacft fi
+)tacft(xedni.semanc = ic
+]ic[sdic = DItac
+(yrotisoper_etaerc.seirotisoper.st = ser
+,eman_loot.sgra.fles=eman
+,csed_loot.sgra.fles % "s%:sisponyS"=sisponys
+,csed_loot.sgra.fles=noitpircsed
+,"detcirtsernu"=epyt
+,lru_dehsloot.sgra.fles=lru_yrotisoper_etomer
+,enoN=lru_egapemoh
+,DItac=sdi_yrogetac
+)
+)enoN ,"di"(teg.ser = dit
+)"n\}ser{=ser }dit{=dit }eman_loot.sgra.fles{ yrotisoper_etaerc#"f(etirw.ots
+:esle
+)eman_loot.fles(xedni.semanr = i
+]i[sdir = dit
+:yrt
+(yrotisoper_etadpu.seirotisoper.st = ser
+enoN=egassem_timmoc ,htapratwen.fles=htap_llab_rat ,dit=di
+)
+)"n\}ser{= }di{ di ser etadpu#"f(etirw.ots
+:rorrEnoitcennoC tpecxe
+(etirw.ots
+"n\deliaf daolpu dehs dnelboiB ?tcerroc yek IPA eht dna gninnur dehsloot eht sI #######"
+)
+)(esolc.ots
+
+:)fles(daol_yxalag_hpe fed
+"""
+ti sdaolpu omenalp retfa dehsloot lacol eht morf loot wen eht daol ot siremehpe esu
+"""
+:)golt.fles(stsixe.htap.so fi
+)"a" ,golt.fles(nepo = tuot
+:esle
+)"w" ,golt.fles(nepo = tuot
+[ = llc
+,"sloot-dehs"
+,"llatsni"
+,"g-"
+,lru_yxalag.sgra.fles
+,"tsetal--"
+,"a-"
+,yek_ipa_yxalag.sgra.fles
+,"eman--"
+,eman_loot.fles
+,"renwo--"
+,"rabuf"
+,"dehsloot--"
+,lru_dehsloot.sgra.fles
+,"lebal_noitces--"
+,"yrotcaFlooT"
+]
+))llc(nioj." " % "n\s%n\gninnur"(etirw.tuot
+(nur.ssecorpbus = pbus
+,llc
+,vneruo.fles=vne
+,dwcruo.fles=dwc
+,eslaF=llehs
+,tuot=rredts
+,tuot=tuodts
+)
+(etirw.tuot
+)edocnruter.pbus ,eman_loot.fles( % "n\d% edocter tog - s% dellatsni"
+)
+)(esolc.tuot
+edocnruter.pbus nruter
+
+:)fles(tset_rekcodoib_omenalp fed
+a retfa yppahnu steg dna reniatnoc emas eht ni desu fi seicnedneped skael yltnerruc omenalp"""
+039674137-tnemmoceussi#8701/seussi/omenalp/tcejorpyxalag/moc.buhtig//:sptth .nur lufsseccus tsrif
+
+sdaolnwod detaeper evas ot dellif sehcac htiw omenalp sah reniatnocoib rekcoD
+
+
+"""
+
+:)"rekcodoib"=resu ,lc ,tuot ,reniatnoc(nurp fed
+)resu=resu ,lc(nur_cexe.reniatnoc = golr
+)"n\\"(tilps.)golr(rts = lgols
+)lgols(nioj."n\" = gols
+)"n\}lc{ morf }gols{ golr tog ##"f(etirw.tuot
+
+:)golt.fles(stsixe.htap.so fi
+)"a" ,golt.fles(nepo = tuot
+:esle
+)"w" ,golt.fles(nepo = tuot
+"reniatnocoib-omenalp/2rabuf/oi.yauq" = egamiomenalp
+eman_loot.fles % "lmx.s%" = laerx
+"lmth.troper_tset_omenalp_}eman_loot.fles{"f = emanper
+)emanper ,ridper.fles(nioj.htap.so = htap_pertsetp
+)(vne_morf.rekcod = tneilc
+)(etaerc.semulov.tneilc = lovt
+eman.lovt = emanlovt
+"tsetp/yrotcafloot/" = ridtsed
+)emanper ,ridtsed(nioj.htap.so = permi
+peels htiw nepo ti peek os gninnur reniatnoc eht peek ot deen #
+enod era ew nehw ti yortsed dna pots lliw #
+(nur.sreniatnoc.tneilc = reniatnoc
+,egamiomenalp
+,"m021 peels"
+,eurT=hcated
+,"rekcodoib"=resu
+,}}"wr" :"edom" ,"yrotcafloot/" :"dnib"{ :"}emanlovt{"f{=semulov
+)
+"}ridtsed{ p- ridkm"f = lc
+)"toor"=resu ,lc ,tuot ,reniatnoc(nurp
+(: reniatnoc rekcodoib a no toor teg ot si ti drah woh s'taht #
+"*/}ridtsed{ fr- mr"f = lc
+)"toor"=resu ,lc ,tuot ,reniatnoc(nurp
+)laerx ,"tuoft" ,ridtsed(nioj.htap.so = htaptsetp
+)reniatnoc ,ridtsed ,ridtuoloot.fles(reniatnoc_ot_ypoc.fles
+"yrotcafloot/ rekcodoib R- nwohc" = lc
+)"toor"=resu ,lc ,tuot ,reniatnoc(nurp
+)"}ridtsed{ al- sl"f(nur_cexe.reniatnoc = _
+"}htaptsetp{ lartnec-yxalag/rekcodoib/emoh/ toor_yxalag-- atad-tset/tuoft/}ridtsed{ atad_tset-- punaelc_on-- atad_tset_etadpu-- }permi{ tuptuo_tset-- tset omenalp"f = lctsetp
+:yrt
+)lctsetp(nur_cexe.reniatnoc = _
+yrotcerid atad-tset eht setadpu tub gnissim stuptuo tset esuaceb sliaf #
+:noitpecxE tpecxe
+]0[)(ofni_cxe.sys = e
+)"n\}lctsetp{ morf }e{ :rorre ####"f(etirw.tuot
+"}htaptsetp{ lartnec-yxalag/rekcodoib/emoh/ toor_yxalag-- atad-tset/tuoft/}ridtsed{ atad_tset-- punaelc_on-- }permi{ tuptuo_tset-- tset omenalp"f = lc
+:yrt
+)lc ,tuot ,reniatnoc(nurp
+:noitpecxE tpecxe
+]0[)(ofni_cxe.sys = e
+)"n\}lctsetp{ morf }e{ :rorre ####"f(etirw.tuot
+)"."=rid ,"pmetft"=xiferp ,enoN=xiffus(pmetdkm.elifpmet = stuotset
+)reniatnoc ,stuotset ,ridtsed(reniatnoc_morf_ypoc.fles
+)"tsetp" ,stuotset(nioj.htap.so = crs
+:)crs(ridsi.htap.so fi
+)eurT=ko_tsixe_srid ,"." ,crs(eertypoc.lituhs
+emanper = crs
+:)emanper(elifsi.htap.so fi
+)htap_pertsetp ,crs(elifypoc.lituhs
+:esle
+)"n\}crs{ ni eertypoc.lituhs ot nur morf tuptuo oN"f(etirw.tuot
+)(esolc.tuot
+)(pots.reniatnoc
+)(evomer.reniatnoc
+)(evomer.lovt
+gniggubed rof evael # )stuotset(eertmr.lituhs
+
+
+:)fles(nur fed #
+""" #
+!epip eht llif ot ton hguone llams eb tsum stpircs #
+""" #
+:]'hs','hsab'[ ni reterpretni.stpo.fles dna laicepShsabtaert.fles fi #
+)(hsaBnur.fles = lavter #
+:esle #
+:rid_tuptuo.stpo.fles fi #
+)'w',gole.fles(nepo = ets #
+)'w',golt.fles(nepo = ots #
+))lc.fles(nioj.' ' % 'n\s% = enil dnammoc detareneg yrotcaflooT ##'(etirw.ots #
+)(hsulf.ots #
+)rid_tuptuo.stpo.fles=dwc,EPIP.ssecorpbus=nidts,ets=rredts,ots=tuodts,eslaF=llehs,lc.fles(nepoP.ssecorpbus = p #
+:esle #
+)EPIP.ssecorpbus=nidts,eslaF=llehs,lc.fles(nepoP.ssecorpbus = p #
+)tpircs.fles(etirw.nidts.p #
+)(esolc.nidts.p #
+)(tiaw.p = lavter #
+:rid_tuptuo.stpo.fles fi #
+)(esolc.ots #
+)(esolc.ets #
+)(daer.)'r',gole.fles(nepo = rre #
+melborp # :rre dna 0 >< lavter fi #
+)rre,lavter( % 's%n\:htiw denruter d% edoc rorre ##' ,rredts.sys >> tnirp #
+:LMTH_ekam.stpo.fles fi #
+)(lmtHekam.fles #
+lavter nruter #
+
+:)fles(hsaBnur fed #
+""" #
+elifs.fles esu os hsab rof - esu tonnac #
+""" #
+:rid_tuptuo.stpo.fles fi #
+)lc.fles(nioj.' ' % 'n\s% = enil dnammoc detareneg yrotcaflooT ##' = s #
+)'w',golt.fles(nepo = ots #
+)s(etirw.ots #
+)(hsulf.ots #
+)rid_tuptuo.stpo.fles=dwc,ots=rredts,ots=tuodts,eslaF=llehs,lc.fles(nepoP.ssecorpbus = p #
+:esle #
+)eslaF=llehs,lc.fles(nepoP.ssecorpbus = p #
+)(tiaw.p = lavter #
+:rid_tuptuo.stpo.fles fi #
+)(esolc.ots #
+:LMTH_ekam.stpo.fles fi #
+)(lmtHekam.fles #
+lavter nruter #
+
+:)tsil_ped ,fles(vne_adnoc_ekam fed #
+""" #
+41.4.0=lmxyxalag,0.71.0=dnelboib hsah-dellum $yxalag/love/:trgwen-ssor@yxalag )vnev( #
+500a8f50602aa9ddddf3b34236190956b800b0d1:983b81d3ac50b5d66d20e4deb0d3c51e59383473-2v-dellum #
+
+lebab diortsa 3.71.0=ypics 9.3=nohtyp vneym n- etaerc adnoc #
+
+
+""" #
+)(tros.tsil_ped #
+)tsil_ped(nioj.'-' = eman_vne.fles #
++ lclmx.fles ni e rof #
+
+:xiffuslcx.fles ni e rof #
+]]"emanelifni"[p % "s%$ <" ,]"emanelifni"[p ,"999"[ = emdneppax # #
+:esle #
+]"" ,]"emanelifni"[p % "s%$" ,]"LC"[p[ = emdneppax #
+)emdneppax(dneppa.xiffuslcx #
+:)golt.fles(stsixe.htap.so fi #
+)"a" ,golt.fles(nepo = tuot #
+:esle #
+)"w" ,golt.fles(nepo = tuot #
+])tsil_ped(nioj.' ' ,eman_vne.fles ,"n-" ,"etaerc" ,"adnoc"[ = ilc #
+(nur.ssecorpbus = p #
+,llc #
+,eslaF=llehs #
+,ridtuoloot.fles=dwc #
+,tuot=rredts #
+,tuot=tuodts #
+) #
+]" && " ,eman_vne.fles ,"etavitca" ,"adnoc"[ = ilc #
+)dmc_nur(dneppa.ilc #
+)(esolc.tuot #
+
+:)(niam fed
+"""
+.repparw yxalaG a si sihT
+lmx.loot esoprup laiceps a yb dellac eb ot stcepxe tI
+
+"""
+)(resraPtnemugrA.esrapgra = resrap
+tnemugra_dda.resrap = a
+)enoN=tluafed ,"htap_tpircs--"(a
+)enoN=tluafed ,"tset_yrotsih--"(a
+)enoN=tluafed ,"xiffus_resu_lc--"(a
+)enoN=tluafed ,"exesys--"(a
+)enoN=tluafed ,"segakcap--"(a
+)"lootwen"=tluafed ,"eman_loot--"(a
+)enoN=tluafed ,"rid_loot--"(a
+)"dneppa"=noitca ,][=tluafed ,"selif_tupni--"(a
+)"dneppa"=noitca ,][=tluafed ,"selif_tuptuo--"(a
+)"nwonknU"=tluafed ,"liame_resu--"(a
+)enoN=tluafed ,"resu_dab--"(a
+)enoN=tluafed ,"txet_pleh--"(a
+)enoN=tluafed ,"csed_loot--"(a
+)"10.0"=tluafed ,"noisrev_loot--"(a
+)enoN=tluafed ,"snoitatic--"(a
+)enoN=tluafed ,"edirrevo_dnammoc--"(a
+)enoN=tluafed ,"edirrevo_tset--"(a
+)][=tluafed ,"dneppa"=noitca ,"sretemarap_lanoitidda--"(a
+)][=tluafed ,"dneppa"=noitca ,"sretemarap_txettceles--"(a
+)eslaF=tluafed ,"eurt_erots"=noitca ,"sretemarap_lanoitidda_tide--"(a
+)"lanoitisop"=tluafed ,"ssapmarap--"(a
+)"tuoft/."=tluafed ,"tuoft--"(a
+)"lartnec-yxalag/"=tluafed ,"toor_yxalag--"(a
+)"vnev_yxalag/"=tluafed ,"vnev_yxalag--"(a
+)][=tluafed ,"dneppa"=noitca ,"noitcelloc--"(a
+)"eurt_erots"=noitca ,eslaF=tluafed ,"stset_edulcni--"(a
+)eslaF=tluafed ,"eurt_erots" = noitca ,"galf_llatsni--"(a
+)"eurt_erots"=noitca ,eurT=tluafed ,"ylno_nimda--"(a
+)enoN=tluafed ,"tuo_loot_detsetnu--"(a
+__rid_toor__$ ot evitaler # )"sloot"=tluafed ,"sloot_lacol--"(a
+__rid_toor__$ ot evitaler # )"lmx.fnoc_loot/gifnoc"=tluafed ,"htap_fnoc_loot--"(a
+)(sgra_esrap.resrap = sgra
+:ylno_nimda.sgra fi
+( ,resu_dab.sgra ton tressa
+\ yxalaG litnu loot siht esu ot dezirohtua TON si s% :DESIROHTUANU'
+'elif noitarugifnoc yxalaG lmy.yxalag eht ni "sresu_nimda" ot s% sdda nimda
+)resu_dab.sgra ,resu_dab.sgra( %
+)
+".eno ylppus esaelP .eman loot a tuohtiw loot a dliub tonnac yrotcaFlooT sihT ##" ,eman_loot.sgra tressa
+)sgra(yrotcaF_looT = ft
+)(lmydehSetirw.ft
+)(looTekam.ft
+)(etadpu_tset_omenalp.ft
+)(raTlooTekam.ft
+)(fnocloot_etadpu.ft
+
+
+:"__niam__" == __eman__ fi
+)(niam
diff -r 2beaae16651e -r 0183cad9d13b seqtk_telo/seqtk_telo.seqtk=1.4.txt
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/seqtk_telo/seqtk_telo.seqtk=1.4.txt Thu Feb 22 10:48:01 2024 +0000
@@ -0,0 +1,1 @@
+seqtk $infa > $out_bed 2> $out_count
diff -r 2beaae16651e -r 0183cad9d13b seqtk_telo/seqtk_telo.xml
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/seqtk_telo/seqtk_telo.xml Thu Feb 22 10:48:01 2024 +0000
@@ -0,0 +1,32 @@
+
+
+
+
+
+ seqtk
+
+
+
+
+ $out_bed ]]>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 10.1093/bioinformatics/bts573
+
+
+
diff -r 2beaae16651e -r 0183cad9d13b seqtk_telo/test-data/infa_sample
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/seqtk_telo/test-data/infa_sample Thu Feb 22 10:48:01 2024 +0000
@@ -0,0 +1,163 @@
+>test
+CCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAA
+CCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAA
+CCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAA
+CCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAA
+CCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAA
+CCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAA
+CCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAA
+CCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAA
+CCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAA
+CCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAA
+CCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAA
+CCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAA
+CCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAA
+CCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAA
+CCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAA
+CCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAA
+CCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAA
+CCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAA
+CCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAA
+CCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAA
+CCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAA
+CCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAA
+CCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAA
+CCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAA
+CCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAA
+CCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAA
+CCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAA
+CCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAA
+CCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAA
+CCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAA
+CCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAA
+CCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAA
+GCACTCGCCGCGAGGGTTGCCGGGACGGGCCCAAGATGGCTGAGCGCCTT
+GGTTCCGCTTCTGCCTGCCGCGCAGAGCCCCATTCATTGCCTTGCTGCTA
+AGTGGCGCCGCGTAGTGCCAGTAGGCTCCAAGTCTTCAGGGTCTGTCCCA
+TCGGGCAGGAAGCCGTCATGGCAACCCTGGAAAAGCTGATGAAGGCTTTC
+GAGTCGCTCAAGTCGTTTCAGCAGCAACAGCAGCAGCAGCCACCGCCGCA
+GGCGCCGCCGCCACCGCCGCCGCCGCCTCCGCCTCAACCCCCTCAGCCGC
+CGCCTCAGGGGCAGCCGCCGCCGCCACCACCGCCGCTGCCAGGTCCGGCA
+GAGGAACCGCTGCACCGACCGTGAGTCCGGGCGCCGCAGCTCCCGCCCGG
+GCCCCGCGCCCCTGGCCTGCGTGCTGGGCATGGCCAACACTGTTCCCTGT
+CCAGAGGGTCGCGGTACCTCCCTGAGGCCAGGCTTTCCCGGCCCGGGCCC
+TCGTCTTGCGGGGTCTCTGGCCTCCCTCAGAGGAGACAGAGCCGGGTCAG
+GCCAGCCAGGGACTCGCTGAGGGGCGTCACGACTCCAGTGCCTTCGCCGT
+TCCCAGTTTGCGAAGTTAGGGAACGAACTTGTTTCTCTCTTCTGGAGAAA
+CTGGGGCGGTGGCGCACATGACTGTTGTGAAGAGAACTTGGAGAGGCAGA
+GATCTCTAGGGTTACCTCCTCATCAGGCCTAAGAGCTGGGAGTGCAGGAC
+AGCGTGAGAGATGTGCGGGTAGTGGATGACATAATGCTTTTAGGAGGTCT
+CGGCGGGAGTGCTGAGGGCGGGGGAGTGTGAACGCATCCAATGGGATATT
+CTTTTTCCAAGTGACACTTGAAGCAGCCTGTGACTCGAGGCACTTCGTAC
+TCTCCTGGCGTTTCATTTAGTTTGTGGTGTAGTGTAGTTAAACCAGGTTT
+TAAGCATAGCCAGAGAGGTGTGCTTCTGTGTGTCTGCAGGCAGTTGGATG
+AGTTGTATTTGTCAAGTACATGGTGAGTTACTTAGGTGTGATTATTAATA
+AAAAACTATATGTGTGCATATATATGAAAGAGTCGACTTATACTTAACTG
+CCTATCGATTTTTTGTTCTATATAAAACGGATACATTGGTGGTGCTCAGT
+TTTCACCGGGGAATGAATTTTACTAGTGTTGCAGACAGGCTTGTTTTAGA
+ACATAGGCCACTCTGACTCTGACTTTGTGCCAGTAAAAGTTCCTGTTTAG
+TTCTTTGCTGACATCTTATAGATCTTTGGAAGCTAGCTGCTTGTGACTGG
+AGAGAATATTGAAACAGAAGAGAGACCATGAGTCACAGTGCTCTAAGAGA
+AAAGAGACGCTCAAAACATTTCCTGGAAATCCATGCTGAGTGTTGAGCCC
+TGTGCTCTCTTGCAGCTCAGTCCTTTCTCTCAACTCTGGGCATTTTATTT
+CTAATCTGGATTTGTATAATTAATAAGGAGAACTTTTGGGAACAACCTAC
+TAAAGAATGTCATCATTAAAACTCACTTAGAAAATAAGTGTTCTGGTGAT
+ATCATTGAGCTATGTTCCCAGTCCTGAGAGTTTGTTTTTTTTTTTTTTTT
+TAAATAAAGATTTGGGGAGAAAAGGTGGCTTACTTGATAGAACAAAATAT
+AGGAATAAAATTTCCTTCTATAAGGTGAAAAGTGTGAATAGAAAACTTCT
+TATCCTCTAGATAAGTAGTTTCTTTTTGCTTTTGAGAGTCTCACTATGTA
+ACTCTTGACCTGAACTCAGAGAGATCCATCCTCCTGCCTCTGCCTCCTCT
+CTCTGGGATTAAAGGCATGTGGCACCATGCTGGGCTGTCCAAGTATGCCA
+CAGACCCTCTAGGTCCCTGGTCTTCGAGGAACGGGATTTCTTAGGCAGAT
+GGGTAAGGAGTCGGATGAAAATGACAATCAGCCACACACAAGAGAGGTGT
+TGAATCTGAATGTAATGTTCTGGTTGAGCTTCAGACTTATATAACAACGA
+ATTATCAGAGGATACAAATCACAAAAAGACAAGATACACTGAAATTCACC
+AGTTACAGCAGAAAGGAATTTGCAGGGACTAATTAAATGTTTACATTAGG
+GATAACAAGCCCTGCCTAGGATCAGCCTAATGCCAGGCAAGAATTTCACA
+CTTTAAGGTTAAAAGCATCAGGGGGTTGTTAACTCTTGACAGGCCTTAAG
+AGTAATGTGCTATCACTGAGCTCTAAATTCTTAGGTCTAGTAAAACTTAT
+CCTGTCTGGAGAGTTCCCCCTTATCAGGGTAGTATATCAACTTATACTTG
+ACATGGAATGAAGCCTGTAGTAAAACATTTCTATCTCAGTGAGACTTTTA
+GTCTCTATCTGTAAACAGCTGAGTAAAATGGCAAGTGCTTAATTGTTTAC
+TGAATGGGTTAAGCTCCTTGCTGCTATCTGGAATCTAAGAACACTGGGGA
+AAGGCTTTAGCTATGTTAGAATACAATATTAAAAGGCATTTACTATAAGG
+TGATGCTTAATAGAGTGCACGTGAATCTATACACTAGATTAATGTGGTGG
+AAATTTGAATATAATGGGTTAGGGAAAGAGATGCCATAACTCTGGGAGGA
+AAATTTCCCTGGACTCTTATCCTCGTGAAACAGCTTCCAGGCTTTTCGCC
+TGACAAACCGATCCAAACTGGAGAGTTGGCTTTCGCCAGAATATCCAGGA
+GGAGAGTCCTAGAAATTCATTTCTCATGAGCAGCTTTTTGGCATTTTTGC
+CTCACAAGCTGACTCCACCAGAGTACCCTGACACAAGTATTGTCTAGTTA
+TTTTGATTATTACCATGACTCTGCCTCTGGGTGAGAGGAATTGTGGAAGT
+TTACATATTCCCCATATCTTCTATAAACCTCTGTGTGTGTGTGTGTGTGT
+GTGTGTGTGTGTGTGTGTGTGTGTATGAGGGAGAGAGAGGGAGAGAGAGA
+GAGGGAGGGAGGAAGAGAGAGAGAGAGATTGTTCTGTGCCTGCTTCGAAC
+ACAAATTAGTTTGCAAAAGTAATTCATTAACATGATACAGTCCCAAAGAT
+AAAAATGGTTAAATAATGAAAACATCTCCCTCCCCATTTTCCTAACTTTG
+TACCCAGGAGCAAGCTCTGTTACACTTCATTTGTCCTTCCAGATAAAATT
+TGGGCATATGTTAGGACAGAATTTTAAATTATTTACAAACAAAAGTATTT
+TGGAACAAAAGCTTTTAAAAGCTTTTATTTTAATAAAATAACTTGTTACT
+ACACTGTATATAACTAACTAACATTTTCCAAAATTAGCTCCATTAGCATC
+TATCTCATATTTCTATGTACTTTGCTGTTGAAAAACCAAGTGTTCATTAA
+TAATAAGTAACAAACTCACTGCTTGGAAGCTTTGATTTTTGGCATTTTGT
+CCACTTGACTCAGTTAAAAGTCCTTTTTTTCGAAATGAGAACAGCCAAAA
+CAGTTTTAGAATGAGTCTGTTCTGCTTTTGTGACTCTCATTGTGTTCTGT
+AGAACCAGTGTCACAGCCATATGTGGGCCTCTGTTGAAGTAGCTGAGAAC
+TTGTTCTCTGCTCTGCTAGCTGCTGTCGATCTGATAGGCCTTGAACAGTT
+GACATTCACCCTTAATAGTCCTCATTAGTCTTCCTGAGCATAGTCATTCA
+TTTATCAATATTTGCTGATCATCTCCTATGTGCCTAGCATTGTTCTAGTT
+GCAGGTTTTAGCAGGGAACAAAGTCATGTCTCATGAAGCTAAAATTCTTG
+GGAGAGACATAGACAGTAAGCAGAATAGTTTGTTCATAGTGAGTGATGAG
+GCGCATGCAGTAAAGTAGGGAAGGGGATTAGGAAATGCCAGGGCTTGACA
+TGTTTTAGACAGGGTGTTTAAATAATATCTGCTTAGTTGAAGGCTTATTT
+TTGAATAAATATCTGAAGAGTCAGAAATCTACCAGGAGGGTGTATGGAAG
+AGGAGTATTCCTGCAAGGGGAAGTTGTCAAAGGCTTTCCTGTGTGGGGAT
+TAGTGATGTCATGTTTTTGCTGGATGAAATGAGTGACGGTAAGAGTTGTA
+GTGGGGGTGAAGCAAAGGGTTGAGGGAGGCTTCATTGGTGTTATCAGTTA
+CTGCATTTATCTCCAAATAGAGAACGTAGCAATGAAAGCTACAGAGAACG
+GGAAAGGTGAGGATTTATTCTAAGACAAAATAAGTGTAGGAAGTTTAACA
+ATTAGATCAGGAGCACAGACTCCAAGTCTAAGTCTTCATTCTTGCACATT
+TTTTAAAAATTTTGTTATGTGTTCTGGATACTATTTCCTTATGAGATATA
+AGTTTAAAAGCCTTTCTGTGGATTGCCTTGCCTTTGTTGTTGTTGTTTGT
+TTTGTTTTGTTTTGTTGAGACAGGTCTCTCTATGTAGCCTTGACTGTCCT
+GAAAATCACTCTGTAGACCAGGCTGGCCTGGAACTCAGAGATCTGCCTGC
+TTCTGCTTTTCAAGTGCTGATATTAAATGTATGTGCCACCACTGCCAGGC
+TAAGATTGTTCTTTCAATTTCTTTTTTTGTTTTCTTTTGAGATCAAAGTT
+TGCTATGTACTTTTGGCTGGCCTGGTATATTGTGTAGTCTAAGTTGGCTT
+CAAATCTTCATGGCACAGATTCCCAAGTACTGGGACCATAGGTATGGCCC
+ATCACAGTGGGGGGTTGGGGGGGCCAGTACATCTATCTCTTGAATGGTGT
+GGAGTGTATATATGTGTTAGGGGTTTGCAGAGGCCAAAAGAATATTGAGT
+GTCTTCCTCTATTGCTCGCCACTTCTCTGAATAAACCTAAAGTTACCAAT
+GGATTTCTAGTAAGCTGACTGACCAGCAAATATTGGGGATCTGTCTGTCC
+CTGTTCACCATAGTGAGGTTACAGACGTGAATAACCACACCCAGTTTTAA
+CCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAA
+CCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAA
+CCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAA
+CCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAA
+CCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAA
+CCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAA
+CCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAA
+CCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAA
+CCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAA
+CCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAA
+CCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAA
+CCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAA
+CCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAA
+CCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAA
+CCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAA
+CCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAA
+CCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAA
+CCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAA
+CCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAA
+CCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAA
+CCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAA
+CCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAA
+CCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAA
+CCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAA
+CCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAA
+CCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAA
+CCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAA
+CCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAA
+CCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAA
+CCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAA
+CCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAA
+CCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAA
diff -r 2beaae16651e -r 0183cad9d13b seqtk_telo/test-data/out_bed_sample
diff -r 2beaae16651e -r 0183cad9d13b tacrev/tacrev.bash.txt
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tacrev/tacrev.bash.txt Thu Feb 22 10:48:01 2024 +0000
@@ -0,0 +1,3 @@
+#raw
+tac | rev
+#end raw
diff -r 2beaae16651e -r 0183cad9d13b tacrev/tacrev.xml
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tacrev/tacrev.xml Thu Feb 22 10:48:01 2024 +0000
@@ -0,0 +1,37 @@
+
+
+
+
+
+
+
+$tacrev_reversed_output]]>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 10.1093/bioinformatics/bts573
+
+
+
diff -r 2beaae16651e -r 0183cad9d13b tacrev/tacrev_reversed_output_sample
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tacrev/tacrev_reversed_output_sample Thu Feb 22 10:48:01 2024 +0000
@@ -0,0 +1,1210 @@
+)(niam
+:"__niam__" == __eman__ fi
+
+
+)(fnocloot_etadpu.ft
+)(raTlooTekam.ft
+)(etadpu_tset_omenalp.ft
+)(looTekam.ft
+)(lmydehSetirw.ft
+)sgra(yrotcaF_looT = ft
+".eno ylppus esaelP .eman loot a tuohtiw loot a dliub tonnac yrotcaFlooT sihT ##" ,eman_loot.sgra tressa
+)
+)resu_dab.sgra ,resu_dab.sgra( %
+'elif noitarugifnoc yxalaG lmy.yxalag eht ni "sresu_nimda" ot s% sdda nimda
+\ yxalaG litnu loot siht esu ot dezirohtua TON si s% :DESIROHTUANU'
+( ,resu_dab.sgra ton tressa
+:ylno_nimda.sgra fi
+)(sgra_esrap.resrap = sgra
+__rid_toor__$ ot evitaler # )"lmx.fnoc_loot/gifnoc"=tluafed ,"htap_fnoc_loot--"(a
+__rid_toor__$ ot evitaler # )"sloot"=tluafed ,"sloot_lacol--"(a
+)enoN=tluafed ,"tuo_loot_detsetnu--"(a
+)"eurt_erots"=noitca ,eurT=tluafed ,"ylno_nimda--"(a
+)eslaF=tluafed ,"eurt_erots" = noitca ,"galf_llatsni--"(a
+)"eurt_erots"=noitca ,eslaF=tluafed ,"stset_edulcni--"(a
+)][=tluafed ,"dneppa"=noitca ,"noitcelloc--"(a
+)"vnev_yxalag/"=tluafed ,"vnev_yxalag--"(a
+)"lartnec-yxalag/"=tluafed ,"toor_yxalag--"(a
+)"tuoft/."=tluafed ,"tuoft--"(a
+)"lanoitisop"=tluafed ,"ssapmarap--"(a
+)eslaF=tluafed ,"eurt_erots"=noitca ,"sretemarap_lanoitidda_tide--"(a
+)][=tluafed ,"dneppa"=noitca ,"sretemarap_txettceles--"(a
+)][=tluafed ,"dneppa"=noitca ,"sretemarap_lanoitidda--"(a
+)enoN=tluafed ,"edirrevo_tset--"(a
+)enoN=tluafed ,"edirrevo_dnammoc--"(a
+)enoN=tluafed ,"snoitatic--"(a
+)"10.0"=tluafed ,"noisrev_loot--"(a
+)enoN=tluafed ,"csed_loot--"(a
+)enoN=tluafed ,"txet_pleh--"(a
+)enoN=tluafed ,"resu_dab--"(a
+)"nwonknU"=tluafed ,"liame_resu--"(a
+)"dneppa"=noitca ,][=tluafed ,"selif_tuptuo--"(a
+)"dneppa"=noitca ,][=tluafed ,"selif_tupni--"(a
+)enoN=tluafed ,"rid_loot--"(a
+)"lootwen"=tluafed ,"eman_loot--"(a
+)enoN=tluafed ,"segakcap--"(a
+)enoN=tluafed ,"exesys--"(a
+)enoN=tluafed ,"xiffus_resu_lc--"(a
+)enoN=tluafed ,"tset_yrotsih--"(a
+)enoN=tluafed ,"htap_tpircs--"(a
+tnemugra_dda.resrap = a
+)(resraPtnemugrA.esrapgra = resrap
+"""
+
+lmx.loot esoprup laiceps a yb dellac eb ot stcepxe tI
+.repparw yxalaG a si sihT
+"""
+:)(niam fed
+
+)(esolc.tuot #
+)dmc_nur(dneppa.ilc #
+]" && " ,eman_vne.fles ,"etavitca" ,"adnoc"[ = ilc #
+) #
+,tuot=tuodts #
+,tuot=rredts #
+,ridtuoloot.fles=dwc #
+,eslaF=llehs #
+,llc #
+(nur.ssecorpbus = p #
+])tsil_ped(nioj.' ' ,eman_vne.fles ,"n-" ,"etaerc" ,"adnoc"[ = ilc #
+)"w" ,golt.fles(nepo = tuot #
+:esle #
+)"a" ,golt.fles(nepo = tuot #
+:)golt.fles(stsixe.htap.so fi #
+)emdneppax(dneppa.xiffuslcx #
+]"" ,]"emanelifni"[p % "s%$" ,]"LC"[p[ = emdneppax #
+:esle #
+]]"emanelifni"[p % "s%$ <" ,]"emanelifni"[p ,"999"[ = emdneppax # #
+:xiffuslcx.fles ni e rof #
+
++ lclmx.fles ni e rof #
+)tsil_ped(nioj.'-' = eman_vne.fles #
+)(tros.tsil_ped #
+""" #
+
+
+lebab diortsa 3.71.0=ypics 9.3=nohtyp vneym n- etaerc adnoc #
+
+500a8f50602aa9ddddf3b34236190956b800b0d1:983b81d3ac50b5d66d20e4deb0d3c51e59383473-2v-dellum #
+41.4.0=lmxyxalag,0.71.0=dnelboib hsah-dellum $yxalag/love/:trgwen-ssor@yxalag )vnev( #
+""" #
+:)tsil_ped ,fles(vne_adnoc_ekam fed #
+
+lavter nruter #
+)(lmtHekam.fles #
+:LMTH_ekam.stpo.fles fi #
+)(esolc.ots #
+:rid_tuptuo.stpo.fles fi #
+)(tiaw.p = lavter #
+)eslaF=llehs,lc.fles(nepoP.ssecorpbus = p #
+:esle #
+)rid_tuptuo.stpo.fles=dwc,ots=rredts,ots=tuodts,eslaF=llehs,lc.fles(nepoP.ssecorpbus = p #
+)(hsulf.ots #
+)s(etirw.ots #
+)'w',golt.fles(nepo = ots #
+)lc.fles(nioj.' ' % 'n\s% = enil dnammoc detareneg yrotcaflooT ##' = s #
+:rid_tuptuo.stpo.fles fi #
+""" #
+elifs.fles esu os hsab rof - esu tonnac #
+""" #
+:)fles(hsaBnur fed #
+
+lavter nruter #
+)(lmtHekam.fles #
+:LMTH_ekam.stpo.fles fi #
+)rre,lavter( % 's%n\:htiw denruter d% edoc rorre ##' ,rredts.sys >> tnirp #
+melborp # :rre dna 0 >< lavter fi #
+)(daer.)'r',gole.fles(nepo = rre #
+)(esolc.ets #
+)(esolc.ots #
+:rid_tuptuo.stpo.fles fi #
+)(tiaw.p = lavter #
+)(esolc.nidts.p #
+)tpircs.fles(etirw.nidts.p #
+)EPIP.ssecorpbus=nidts,eslaF=llehs,lc.fles(nepoP.ssecorpbus = p #
+:esle #
+)rid_tuptuo.stpo.fles=dwc,EPIP.ssecorpbus=nidts,ets=rredts,ots=tuodts,eslaF=llehs,lc.fles(nepoP.ssecorpbus = p #
+)(hsulf.ots #
+))lc.fles(nioj.' ' % 'n\s% = enil dnammoc detareneg yrotcaflooT ##'(etirw.ots #
+)'w',golt.fles(nepo = ots #
+)'w',gole.fles(nepo = ets #
+:rid_tuptuo.stpo.fles fi #
+:esle #
+)(hsaBnur.fles = lavter #
+:]'hs','hsab'[ ni reterpretni.stpo.fles dna laicepShsabtaert.fles fi #
+""" #
+!epip eht llif ot ton hguone llams eb tsum stpircs #
+""" #
+:)fles(nur fed #
+
+
+gniggubed rof evael # )stuotset(eertmr.lituhs
+)(evomer.lovt
+)(evomer.reniatnoc
+)(pots.reniatnoc
+)(esolc.tuot
+)"n\}crs{ ni eertypoc.lituhs ot nur morf tuptuo oN"f(etirw.tuot
+:esle
+)htap_pertsetp ,crs(elifypoc.lituhs
+:)emanper(elifsi.htap.so fi
+emanper = crs
+)eurT=ko_tsixe_srid ,"." ,crs(eertypoc.lituhs
+:)crs(ridsi.htap.so fi
+)"tsetp" ,stuotset(nioj.htap.so = crs
+)reniatnoc ,stuotset ,ridtsed(reniatnoc_morf_ypoc.fles
+)"."=rid ,"pmetft"=xiferp ,enoN=xiffus(pmetdkm.elifpmet = stuotset
+)"n\}lctsetp{ morf }e{ :rorre ####"f(etirw.tuot
+]0[)(ofni_cxe.sys = e
+:noitpecxE tpecxe
+)lc ,tuot ,reniatnoc(nurp
+:yrt
+"}htaptsetp{ lartnec-yxalag/rekcodoib/emoh/ toor_yxalag-- atad-tset/tuoft/}ridtsed{ atad_tset-- punaelc_on-- }permi{ tuptuo_tset-- tset omenalp"f = lc
+)"n\}lctsetp{ morf }e{ :rorre ####"f(etirw.tuot
+]0[)(ofni_cxe.sys = e
+:noitpecxE tpecxe
+yrotcerid atad-tset eht setadpu tub gnissim stuptuo tset esuaceb sliaf #
+)lctsetp(nur_cexe.reniatnoc = _
+:yrt
+"}htaptsetp{ lartnec-yxalag/rekcodoib/emoh/ toor_yxalag-- atad-tset/tuoft/}ridtsed{ atad_tset-- punaelc_on-- atad_tset_etadpu-- }permi{ tuptuo_tset-- tset omenalp"f = lctsetp
+)"}ridtsed{ al- sl"f(nur_cexe.reniatnoc = _
+)"toor"=resu ,lc ,tuot ,reniatnoc(nurp
+"yrotcafloot/ rekcodoib R- nwohc" = lc
+)reniatnoc ,ridtsed ,ridtuoloot.fles(reniatnoc_ot_ypoc.fles
+)laerx ,"tuoft" ,ridtsed(nioj.htap.so = htaptsetp
+)"toor"=resu ,lc ,tuot ,reniatnoc(nurp
+"*/}ridtsed{ fr- mr"f = lc
+(: reniatnoc rekcodoib a no toor teg ot si ti drah woh s'taht #
+)"toor"=resu ,lc ,tuot ,reniatnoc(nurp
+"}ridtsed{ p- ridkm"f = lc
+)
+,}}"wr" :"edom" ,"yrotcafloot/" :"dnib"{ :"}emanlovt{"f{=semulov
+,"rekcodoib"=resu
+,eurT=hcated
+,"m021 peels"
+,egamiomenalp
+(nur.sreniatnoc.tneilc = reniatnoc
+enod era ew nehw ti yortsed dna pots lliw #
+peels htiw nepo ti peek os gninnur reniatnoc eht peek ot deen #
+)emanper ,ridtsed(nioj.htap.so = permi
+"tsetp/yrotcafloot/" = ridtsed
+eman.lovt = emanlovt
+)(etaerc.semulov.tneilc = lovt
+)(vne_morf.rekcod = tneilc
+)emanper ,ridper.fles(nioj.htap.so = htap_pertsetp
+"lmth.troper_tset_omenalp_}eman_loot.fles{"f = emanper
+eman_loot.fles % "lmx.s%" = laerx
+"reniatnocoib-omenalp/2rabuf/oi.yauq" = egamiomenalp
+)"w" ,golt.fles(nepo = tuot
+:esle
+)"a" ,golt.fles(nepo = tuot
+:)golt.fles(stsixe.htap.so fi
+
+)"n\}lc{ morf }gols{ golr tog ##"f(etirw.tuot
+)lgols(nioj."n\" = gols
+)"n\\"(tilps.)golr(rts = lgols
+)resu=resu ,lc(nur_cexe.reniatnoc = golr
+:)"rekcodoib"=resu ,lc ,tuot ,reniatnoc(nurp fed
+
+"""
+
+
+sdaolnwod detaeper evas ot dellif sehcac htiw omenalp sah reniatnocoib rekcoD
+
+039674137-tnemmoceussi#8701/seussi/omenalp/tcejorpyxalag/moc.buhtig//:sptth .nur lufsseccus tsrif
+a retfa yppahnu steg dna reniatnoc emas eht ni desu fi seicnedneped skael yltnerruc omenalp"""
+:)fles(tset_rekcodoib_omenalp fed
+
+edocnruter.pbus nruter
+)(esolc.tuot
+)
+)edocnruter.pbus ,eman_loot.fles( % "n\d% edocter tog - s% dellatsni"
+(etirw.tuot
+)
+,tuot=tuodts
+,tuot=rredts
+,eslaF=llehs
+,dwcruo.fles=dwc
+,vneruo.fles=vne
+,llc
+(nur.ssecorpbus = pbus
+))llc(nioj." " % "n\s%n\gninnur"(etirw.tuot
+]
+,"yrotcaFlooT"
+,"lebal_noitces--"
+,lru_dehsloot.sgra.fles
+,"dehsloot--"
+,"rabuf"
+,"renwo--"
+,eman_loot.fles
+,"eman--"
+,yek_ipa_yxalag.sgra.fles
+,"a-"
+,"tsetal--"
+,lru_yxalag.sgra.fles
+,"g-"
+,"llatsni"
+,"sloot-dehs"
+[ = llc
+)"w" ,golt.fles(nepo = tuot
+:esle
+)"a" ,golt.fles(nepo = tuot
+:)golt.fles(stsixe.htap.so fi
+"""
+ti sdaolpu omenalp retfa dehsloot lacol eht morf loot wen eht daol ot siremehpe esu
+"""
+:)fles(daol_yxalag_hpe fed
+
+)(esolc.ots
+)
+"n\deliaf daolpu dehs dnelboiB ?tcerroc yek IPA eht dna gninnur dehsloot eht sI #######"
+(etirw.ots
+:rorrEnoitcennoC tpecxe
+)"n\}ser{= }di{ di ser etadpu#"f(etirw.ots
+)
+enoN=egassem_timmoc ,htapratwen.fles=htap_llab_rat ,dit=di
+(yrotisoper_etadpu.seirotisoper.st = ser
+:yrt
+]i[sdir = dit
+)eman_loot.fles(xedni.semanr = i
+:esle
+)"n\}ser{=ser }dit{=dit }eman_loot.sgra.fles{ yrotisoper_etaerc#"f(etirw.ots
+)enoN ,"di"(teg.ser = dit
+)
+,DItac=sdi_yrogetac
+,enoN=lru_egapemoh
+,lru_dehsloot.sgra.fles=lru_yrotisoper_etomer
+,"detcirtsernu"=epyt
+,csed_loot.sgra.fles=noitpircsed
+,csed_loot.sgra.fles % "s%:sisponyS"=sisponys
+,eman_loot.sgra.fles=eman
+(yrotisoper_etaerc.seirotisoper.st = ser
+]ic[sdic = DItac
+)tacft(xedni.semanc = ic
+:semanc ni )(pirts.tacft fi
+enoN = DItac
+]tacst ni x rof )"?" ,"di"(teg.x[ = sdic
+]tacst ni x rof )(pirts.)"?" ,"eman"(teg.x[ = semanc
+)(seirogetac_teg.seirogetac.st = tacst
+:semanr ni ton eman_loot.fles fi
+"sloot detareneg yrotcaFlooT" = tacft
+]soper ni x rof )"?" ,"di"(teg.x[ = sdir
+]soper ni x rof )"?" ,"eman"(teg.x[ = semanr
+)(seirotisoper_teg.seirotisoper.st = soper
+)
+,eslaF=yfirev
+,yek_ipa_dehsloot.sgra.fles=yek
+,lru_dehsloot.sgra.fles=lru
+(ecnatsnIdehSlooT.dehsloot = st
+
+)"w" ,golt.fles(nepo = ots
+:esle
+)"a" ,golt.fles(nepo = ots
+:)golt.fles(stsixe.htap.so fi
+"""
+
+gnitsixe etadpu ro
+yrotisoper wen etaerc ot dnelboib esu
+"""
+:)fles(daoLdehs fed
+
+
+
+
+
+
+)eurT=tnirp_ytterp ,htapct(etirw.eert
+)"elif",noitcesFT(ybnerdlihctros
+)}eliflmx :"elif"{ ,"loot" ,noitcesFT(tnemelEbuS.TE
+wen # :sloot_fnoc ni ton eliflmx fi
+]sloot_ruo ni x rof ]"elif"[birtta.x[ = sloot_fnoc
+)"loot"(lladnif.noitcesFT = sloot_ruo
+!pot eht ta # )noitcesFT ,0(tresni.toor
+)}"slooT lacoL":"eman" ,"slootlacol":"di"{ ,"noitces"(tnemelE.TE = noitcesFT
+:FTsah ton fi
+]0[e = noitcesFT
+eurT = FTsah
+:0 > )e(nel fi
+)"noitces"(lladnif.toor = e
+eslaF = FTsah
+)(toorteg.eert = toor
+)resrap ,htapct(esrap.TE = eert
+)eurT=txet_knalb_evomer(resraPLMX.TE = resrap
+)eman_loot.fles % 'lmx.s%' ,eman_loot.fles ,sloot_lacol.fles(nioj.htap.so = eliflmx
+)'lmx.fnoc_loot_lacol/gifnoc',toor_yxalag.sgra.fles(nioj.htap.so = htapct
+
+))rtta(teg.dlihc :dlihc adbmal=yek ,tnerap(detros = ]:[tnerap
+:)rtta ,tnerap(ybnerdlihctros fed
+
+:) fles(fnocloot_etadpu fed
+
+
+edocnruter.p nruter
+)(esolc.tuot
+)
+,tuot=tuodts
+,tuot=rredts
+,ridtuoloot.fles=dwc
+,eslaF=llehs
+,llc
+(nur.ssecorpbus = p
+]
+,)laerx(htapsba.htap.so
+,"atad_tset_etadpu--"
+,toor_yxalag.sgra.fles
+,"toor_yxalag--"
+,)htap_tset_loot(htapsba.htap.so
+,"tuptuo_tset--"
+,)ridtset.fles(htapsba.htap.so
+,"atad_tset--"
+,"sreniatnocoib--"
+,"tini_otua_adnoc--"
+,"tset"
+,"omenalp"
+[ = llc
+)"w" ,golt.fles(nepo = tuot
+:esle
+)"a" ,golt.fles(nepo = tuot
+:)golt.fles(stsixe.htap.so fi
+)
+"lmth.troper_tset_omenalp_}eman_loot.fles{"f ,ridper.fles
+(nioj.htap.so = htap_tset_loot
+eman_loot.fles % "lmx.s%" = laerx
+"""
+gnitset rof elbaliava si os tnemeriuqer a si omenalp"""
+:)fles(etadpu_tset_omenalp fed
+
+
+)(esolc.ft
+))"zg.dehsloot_detsetnu_}eman_loot.fles{"f ,ridtuoloot.fles(nioj.htap.so ,htapratwen.fles(ypoc.lituhs
+)
+,noitcnuf_edulcxe=retlif
+,eman_loot.fles=emancra
+,ridtuoloot.fles=eman
+(dda.ft
+)"zg:w" ,htapratwen.fles(nepo.elifrat = ft
+)
+)ridtset.fles ,tsedt( %
+".s% nur omenalp retfa ridtset ni dnuof ton s% elif tuptuo - deliaf evah yam looT###"
+(tnirp
+:liaf_troper fi
+:esle
+)tsed ,crs(elifypoc.lituhs
+))]'tamrof'[p,emano( % "s%.elpmas.s%" ,ridper.fles(nioj.htap.so = tsed
+)tsedt ,crs(elifypoc.lituhs
+:)crs(elifsi.htap.so fi
+:)tsedt(elifsi.htap.so ton fi
+)emano ,ridtset.fles(nioj.htap.so = crs
+)emano % "elpmas_s%" ,ridtset.fles(nioj.htap.so = tsedt
+]"eman"[p = emano
+:seliftuo.fles ni p rof
+
+ofnirat esle )emedulcxe(htiwsdne.emanelif fi enoN nruter
+eman.ofnirat = emanelif
+:)ofnirat(noitcnuf_edulcxe fed
+
+"lmth.troper_tset_omenalp_" = emedulcxe
+"""llabrat eht eraperp dna atad-tset otni stuptuo evom"""
+:)eslaF=liaf_troper ,fles(raTlooTekam fed
+
+)eurT=ko_tsixe_srid ,tsed,ridtuoloot.fles(eertypoc.lituhs
+)eman_loot.fles ,sloot_lacol.fles(nioj.htap.so = tsed
+)tsed ,htp(elifypoc.lituhs
+)
+)]"tamrof"[p ,]"emanelifni"[p( % "s%.elpmas_s%" ,ridper.fles
+(nioj.htap.so = tsed
+)tsed ,htp(elifypoc.lituhs
+)]"emanelifni"[p % "elpmas_s%" ,ridtset.fles(nioj.htap.so = tsed
+]"eman"[p = htp
+:selifni.fles ni p rof
+)tuox ,laerx(elifypoc.lituhs
+)laerx ,ridper.fles(nioj.htap.so = tuox
+)tuox ,laerx(elifypoc.lituhs
+)laerx ,ridtuoloot.fles(nioj.htap.so = tuox
+eman_loot.fles % "lmx.s%" = laerx
+)emants ,elifs.fles(elifypoc.lituhs
+:)emants(stsixe.htap.so ton fi
+)elifs.fles ,ridtuoloot.fles(nioj.htap.so = emants
+:htap_tpircs.sgra.fles fi
+)(LMXekam.fles
+:esle
+)(marapLMXoNod.fles
+:0 == ssapmarap.sgra.fles fi
+"""ecalp otni selpmas tupni dna slmx etirw"""
+:)fles(looTekam fed
+
+)(esolc.flmay
+)eurT=edocinu_wolla ,flmay ,tcido(pmud.lmay
+}
+,"slooT detareneG FT" :"yrogetac"
+,csed_loot.sgra.fles :"sisponys"
+,csed_loot.sgra.fles :"noitpircsed"
+,"detcirtsernu" :"epyt"
+,resuy :"renwo"
+,eman_loot.fles :"eman"
+{ = tcido
+)"w" ,emanfy(nepo = flmay
+)"lmy.dehs." ,ridtuoloot.fles(nioj.htap.so = emanfy
+]0[)"@"(tilps.liame_resu.sgra.fles = resuy
+"""omenalp rof"""
+:)fles(lmydehSetirw fed
+
+meti yrotsih yxalag #
+)"n\"(etirw.fx
+)lmxe(etirw.fx
+:fx sa )"w" ,eman_loot.fles % "lmx.s%"(nepo htiw
+dexif = lmxe
+)2trap ,)edirrevo_tset.fles(nioj."n\" ,1trap( % "s%n\s%n\s%" = dexif
+]1[)">stset/<"(tilps.lmxe = 2trap
+]0[)">stset<"(tilps.lmxe = 1trap
+stset rof stcejbo lmxl stcepxe ti sa lmxyxalag edisni siht od tonnac # :)
+edirrevo_tset.fles
+( fi
+detpecca RP litnu dnuora krow yraropmet # )"" ,EXEEKAF(ecalper.0lmxe = lmxe
+)(tropxe.lootwen.fles = 0lmxe
+))LRUyrotcaFloot( % "s% :ta tig ni ecruoS"(tnemmoc_dda.lootwen.fles
+)
+))(wonemit ,liame_resu.sgra.fles( %
+".yrotcaF looT yxalaG eht gnisu s% ta s% yb detaerC"
+(tnemmoc_dda.lootwen.fles
+stset = stset.lootwen.fles
+)a_tset(dneppa.stset
+)pt(dneppa.a_tset
+:maraptset.fles ni pt rof
+)(tseT.ptxg = a_tset
+)(stseT.ptxg = stset
+selifgifnoc = selifgifnoc.lootwen.fles
+)
+))tpircSdepacse.fles(nioj."n\"=txet ,"emnur"=eman(elifgifnoC.ptxg
+(dneppa.selifgifnoc
+)(selifgifnoC.ptxg = selifgifnoc
+:htap_tpircs.sgra.fles fi
+stupnit.fles = stupni.lootwen.fles
+stuptuot.fles = stuptuo.lootwen.fles
+)(marapLMXod.fles
+:esle
+)(marapLMXoNod.fles
+:"0" == ssapmarap.sgra.fles fi
+stnemeriuqer = stnemeriuqer.lootwen.fles
+)2(tixe.sys
+)
+,segakcap.sgra.fles
+,"= esrap tonnac - deilppus gnirts segakcap demroflam ###"
+(tnirp
+:noitpecxE tpecxe
+)d(dneppa.vneadnoc.fles
+)
+)rev ,)(pirts.gkcap ,"egakcap"(tnemeriuqeR.ptxg
+(dneppa.stnemeriuqer
+:gkcap fi
+enoN = rev
+:"" == rev fi
+enoN = rev
+)(pirts.d = gkcap
+:esle
+)(pirts.gkcap = gkcap
+)(pirts.rev = rev
+)":"(tilps.d = rev ,gkcap
+:d ni ":" fi
+)":" ,"="(ecalper.d = d
+)":" ,"=="(ecalper.d = d
+enoN = gkcap
+enoN = rev
+:)","(tilps.segakcap.sgra.fles ni d rof
+:yrt
+:segakcap.sgra.fles fi
+][ = vneadnoc.fles
+)(stnemeriuqeR.ptxg = stnemeriuqer
+dts = soidts.lootwen.fles
+)1dts(dneppa.dts
+)(oidtS.ptxg = 1dts
+)(soidtS.ptxg = dts
+'"}noisrev_loot.sgra.fles{" ohce'f = dnammoc_noisrev.lootwen.fles
+txetrefas = pleh.lootwen.fles
+)rcs(nioj."n\" + txetrefas = txetrefas
+)"n\"(dneppa.rcs
+)
+]:001-[rcs +
+]"...... " ,"deteled ffuts - senil 003> "[ +
+]001:[rcs
+( = rcs
+:003 > )rcs(nel fi
+)"n\::tpircSn\n\" ,0(tresni.rcs
+]"" > )(pirts.x fi tpircSdecaps.fles ni x rof x[ = rcs
+!dewolla noitisnart # "n\------n\n\" + txetrefas = txetrefas
+:0 > )txetrefas(nel fi
+:htap_tpircs.sgra.fles fi
+)
+)liame_resu.sgra.fles( %
+"n\esaelp txet pleh htiw dliuber ot )s%( rohtua loot eht ksA"
+( = txetrefas
+:0 == ))(pirts.txetrefas(nel fi
+)]txetpleh ni x rof )x(epacse_hateehc[(nioj."n\" = txetrefas
+)(senildaer.)"r" ,txet_pleh.sgra.fles(nepo = txetpleh
+:txet_pleh.sgra.fles fi
+"" = txetrefas
+etic = snoitatic.lootwen.fles
+)etica(dneppa.etic
+)"375stb/scitamrofnioib/3901.01"=eulav ,"iod"=epyt(noitatiC.ptxg = etica
+)(snoitatiC.ptxg = etic
+lclmx.fles = edirrevo_dnammoc.lootwen.fles
+:esle
+elif gifnoc # edirrevo_dnammoc.fles = edirrevo_dnammoc.lootwen.fles
+:edirrevo_dnammoc.fles fi
+"""
+...redro tcerroc otni enil dnammoc eht teg ot woH .mmmH
+lmthyxalag sesU
+tpircs wen eht rof repparw loot lmx yxalaG a etaerC
+"""
+aqon # :)fles(LMXekam fed
+
+)pt(dneppa.maraptset.fles
+)emanwen % "elpmas_s%"=eulav ,emanwen=eman(tuptuOtseT.ptxg = pt
+)tuona(dneppa.stuptuot.fles
+lanoitisop_si.fles = lanoitisop.tuona
+emanwen % "s%$ >" = edirrevo_enil_dnammoc.tuona
+)0=sehsad_mun ,tmfwen=tamrof ,emanwen(ataDtuptuO.ptxg = tuona
+]"tamrof"[]0[seliftuo.fles = tmfwen
+]"eman"[]0[seliftuo.fles = emanwen
+:0 > )seliftuo.fles(nel fi
+)pt(dneppa.maraptset.fles
+)emanwen % "elpmas_s%"=eulav ,emanwen=eman(maraPtseT.ptxg = pt
+)tupnina(dneppa.stupnit.fles
+eurT = lanoitisop.tupnina
+emanwen % "s%$ <" = edirrevo_enil_dnammoc.tupnina
+)
+,0=sehsad_mun
+,eslaF=elpitlum
+,]"tamrof"[]0[selifni.fles=tamrof
+,]"pleh"[]0[selifni.fles=pleh
+,bala=lebal
+,eslaF=lanoitpo
+,emanwen
+(maraPataD.ptxg = tupnina
+]"emanelifni"[]0[selifni.fles = emanwen
+s1xam ,1 == )selifni.fles(nel tressa
+)
+)selifni.fles(rts %
+"s% - deilppus selif tupni elpitlum tub 0 si ssapmarap fi tupni eno mumixaM"
+( = s1xam
+]"emanelifni"[]0[selifni.fles = bala
+:0 == )bala(nel fi
+]"lebal"[]0[selifni.fles = bala
+:0 > )selifni.fles(nel fi
+"""tuodts ot nidts - egakcap elyts retlif"""
+:)fles(marapLMXoNod fed
+
+)
+"!neht litnu neddir-revo eb tsum snoitcelloc rof stset - tey degrem RP eht evah ton seod noisrev lmxyxalaG :GNINRAW ####"
+(tnirp
+:noitpecxE tpecxe
+)mrapt(dneppa.maraptset.fles
+.degrem RP litnu nekorb # )emanwen(noitcelloCtuptuOtseT.ptxg = mrapt
+:yrt
+)tcelloc(dneppa.stuptuot.fles
+)csid(dneppa.tcelloc
+)
+"eslaf"=elbisiv ,"}emanwen{"f=yrotcerid ,csidwen=nrettap
+(stesataDrevocsiD.ptxg = csid
+)dnikwen=epyt ,lebalwen=lebal ,emanwen(noitcelloCtuptuO.ptxg = tcelloc
+]"revocsid"[p = csidwen
+]"lebal"[p = lebalwen
+]"eman"[p = emanwen
+]"dnik"[p = dnikwen
+:snoitcelloc.fles ni p rof
+)
+)emanwen ,epytwen( %
+'LMXekam ni s% retemarap txettceles
+\rof "s%" epyt retemarap desingocernU'
+(rorrEeulaV esiar
+:esle
+)mrapt(dneppa.maraptset.fles
+)lavwen=eulav ,emanwen(maraPtseT.ptxg = mrapt
+)mrapa(dneppa.stupnit.fles
+)lcwen(tni = lanoitisop.mrapa
+:lanoitisop_si.fles fi
+lanoitisop_si.fles = lanoitisop.mrapa
+)tpona(dneppa.mrapa
+)
+,]i[txetwen=txet
+,]i[lavwen=eulav
+(noitpOtceleS.ptxg = tpona
+:))lavwen(nel(egnar ni i rof
+)
+,hsadn=sehsad_mun
+,plehwen=pleh
+,lebalwen=lebal
+,emanwen
+(maraPtceleS.ptxg = mrapa
+]"stxet"[p = txetwen
+:"txettceles" == epytwen fi
+)emanwen(hsadNteg.fles = hsadn
+emanwen = lebalwen
+:0 > )lebalwen(nel ton fi
+]"LC"[p = lcwen
+]"epyt"[p = epytwen
+]"pleh"[p = plehwen
+]"lebal"[p = lebalwen
+]"eulav"[p = lavwen
+]"eman"[p = emanwen
+:raples.fles ni p rof
+)mrapt(dneppa.maraptset.fles
+)lavwen=eulav ,emanwen(maraPtseT.ptxg = mrapt
+)mrapa(dneppa.stupnit.fles
+:esle
+)mrapt(dneppa.maraptset.fles
+)2mrapt(dneppa.mrapt
+)lavwen=eulav ,emanwen(maraPtseT.ptxg = 2mrapt
+)"}emanwen{_R"f=eman(taepeRtseT.ptxg = mrapt
+)eper(dneppa.stupnit.fles
+)mrapa(dneppa.eper
+)
+"dedeen sa }lebalwen{ ynam sa ddA"f=eltit ,"}emanwen{_R"f=eman
+(taepeR.ptxg = eper
+:sper fi
+)lcdlo(tni = lanoitisop.mrapa
+:lanoitisop_si.fles fi
+lanoitisop_si.fles = lanoitisop.mrapa
+)
+)emanwen ,epytwen( %
+'LMXekam ni s% retemarap lanoitidda
+\rof "s%" epyt retemarap desingocernU'
+(rorrEeulaV esiar
+:esle
+)
+,hsadn=sehsad_mun
+,lavwen=eulav
+,plehwen=pleh
+,lebalwen=lebal
+,emanwen
+(maraPnaelooB.ptxg = mrapa
+:"naeloob" == epytwen file
+)
+,hsadn=sehsad_mun
+,lavwen=eulav
+,plehwen=pleh
+,lebalwen=lebal
+,emanwen
+(maraPtaolF.ptxg = mrapa
+:"taolf" == epytwen file
+)
+,hsadn=sehsad_mun
+,lavwen=eulav
+,plehwen=pleh
+,lebalwen=lebal
+,emanwen
+(maraPregetnI.ptxg = mrapa
+:"regetni" == epytwen file
+)
+,hsadn=sehsad_mun
+,lavwen=eulav
+,plehwen=pleh
+,lebalwen=lebal
+,emanwen
+(maraPtxeT.ptxg = mrapa
+:"txet" == epytwen fi
+)emanwen(hsadNteg.fles = hsadn
+emanwen = lebalwen
+:0 > )lebalwen(nel ton fi
+"1" == ]"taeper"[p = sper
+]"LCgiro"[p = lcdlo
+]"LC"[p = lcwen
+]"epyt"[p = epytwen
+]"pleh"[p = plehwen
+]"lebal"[p = lebalwen
+]"eulav"[p = lavwen
+]"eman"[p = emanwen
+:rapdda.fles ni p rof
+)mrapt(dneppa.maraptset.fles
+)emanwen % "elpmas_s%"=eulav ,emanwen(maraPtseT.ptxg = mrapt
+)tupnina(dneppa.stupnit.fles
+:esle
+)mrapt(dneppa.maraptset.fles
+)2mrapt(dneppa.mrapt
+)emanwen % "elpmas_s%"=eulav ,emanwen(maraPtseT.ptxg = 2mrapt
+)"}emanwen{_R"f=eman(taepeRtseT.ptxg = mrapt
+)eper(dneppa.stupnit.fles
+)tupnina(dneppa.eper
+)
+"dedeen sa }bala{ ynam sa ddA"f=eltit ,"}emanwen{_R"f=eman
+(taepeR.ptxg = eper
+:sper fi
+emanwen % "s%$" = edirrevo_enil_dnammoc.tupnina
+)]"LCgiro"[p(tni = lanoitisop.tupnina
+:esle
+emanwen % "s%$ <" = edirrevo_enil_dnammoc.tupnina
+8999999 = lanoitisop.tupnina
+:"NIDTS" == )(reppu.]"LCgiro"[p fi
+:lanoitisop_si.fles fi
+lanoitisop_si.fles = lanoitisop.tupnina
+)
+,hsadn=sehsad_mun
+,eslaF=elpitlum
+,tmfwen=tamrof
+,]"pleh"[p=pleh
+,bala=lebal
+,eslaF=lanoitpo
+,emanwen
+(maraPataD.ptxg = tupnina
+]"lebal"[p = bala
+:esle
+]"LC"[p = bala
+:0 > )]"lebal"[p(nel ton fi
+"1" == )"0" ,"taeper"(teg.p = sper
+)emanwen(hsadNteg.fles = hsadn
+]"tamrof"[p = tmfwen
+]"emanelifni"[p = emanwen
+:selifni.fles ni p rof
+)pt(dneppa.maraptset.fles
+)
+,c=erapmoc
+,emanwen % "elpmas_s%"=eulav
+,emanwen=eman
+(tuptuOtseT.ptxg = pt
+tset = c
+:esle
+)
+,carf_atled=carf_atled
+,atled=atled
+,c=erapmoc
+,emanwen % "elpmas_s%"=eulav
+,emanwen=eman
+(tuptuOtseT.ptxg = pt
+enoN = carf_atled
+)nt(tni = atled
+:esle
+))nt(taolf ,0.1(nim = carf_atled
+enoN = atled
+:nt ni "." fi
+:"" > nt fi
+)(pirts.]1[)":"(tilps.tset = nt
+"ezis_mis" = c
+:)"ezis_mis"(htiwstrats.tset file
+)
+,dl=ffid_senil
+,c=erapmoc
+,emanwen % "elpmas_s%"=eulav
+,emanwen=eman
+(tuptuOtseT.ptxg = pt
+)]1[)":"(tilps.tset(tni = dl
+:tigidsi.]1[)":"(tilps.tset fi
+0 = dl
+"ffid" = c
+:)"ffid"(htiwstrats.)(pirts.tset fi
+:"" > )(pirts.tset fi
+enoN = dl
+)mrapa(dneppa.stuptuot.fles
+emanwen % "s%$" = edirrevo_enil_dnammoc.mrapa
+)lcdlo(tni = lanoitisop.mrapa
+:esle
+emanwen % "s%$ >" = edirrevo_enil_dnammoc.mrapa
+9999999 = lanoitisop.mrapa
+:"TUODTS" == )(reppu.lcdlo fi
+:lanoitisop_si.fles fi
+lanoitisop_si.fles = lanoitisop.mrapa
+)
+emanwen=lebal ,hsadn=sehsad_mun ,tmfwen=tamrof ,emanwen=eman
+(ataDtuptuO.ptxg = mrapa
+)lcwen(hsadNteg.fles = hsadn
+)(pirts.tset = tset
+]"LCgiro"[p = lcdlo
+]"tset"[p = tset
+]"LC"[p = lcwen
+]"tamrof"[p = tmfwen
+]"eman"[p = emanwen
+:seliftuo.fles ni p rof
+"""loot ot stnemele dedeen lla ddA"""
+aqon # :)fles(marapLMXod fed
+
+hsadn nruter
+1 = hsadn
+:2 < )emanwen(nel fi
+2 = hsadn
+:esle
+0 = hsadn
+:lanoitisop_si.fles fi
+:)emanwen ,fles(hsadNteg fed
+
+)c(LCXa
+:plc ni c rof
+)xiffus_resu_lc.sgra.fles(tilps.xelhs = plc
+dne LC YID # :xiffus_resu_lc.sgra.fles fi
+)lc(LCXa
+:tceriderlcxtsal.fles ni lc rof
+:tceriderlcxtsal.fles fi
+)v(LCXa
+)k(LCXa
+k % "s%--" = k
+:esle
+k % "s%-" = k
+:1 == ))(pirts.k(nel fi
+:esle
+)k(LCXa
+edirrevok = k
+:"" > edirrevok fi
+:xiffuslcx.fles ni )edirrevok ,v ,k( rof
+
+mrof deman esrapgra ni smarap neht stupni #
+dneppa.lclmx.fles = LCXa
+"""elyts esrapgra"""
+:)fles(esrapgralc fed
+
+)c(LCXa
+:plc ni c rof
+)xiffus_resu_lc.sgra.fles(tilps.xelhs = plc
+dne LC YID # :xiffus_resu_lc.sgra.fles fi
+)lc(LCXa
+:tceriderlcxtsal.fles ni lc rof
+:tceriderlcxtsal.fles fi
+)v(LCXa
+:xiffuslcx.fles ni )edirrevok ,v ,k( rof
+dneppa.lclmx.fles = LCXa
+smarap neht redro ni stupni #
+:)fles(lanoitisoplc fed
+
+pdda = ]i[rapdda.fles
+]"LC"[pdda = ]"LCgiro"[pdda
+)p(ypoc.ypoc = pdda
+:)rapdda.fles(etaremune ni p ,i rof
+pftuo = ]i[seliftuo.fles
+ypoc peek # ]"LC"[pftuo = ]"LCgiro"[pftuo
+)p(ypoc.ypoc = pftuo
+:)seliftuo.fles(etaremune ni p ,i rof
+pfni = ]i[selifni.fles
+]"LC"[pfni = ]"emanelifni"[pfni
+:esle
+)"_" ," "(ecalper.]"lebal"[pfni = ]"emanelifni"[pfni
+:]"0" ,"lanoitisop"[ ni ssapmarap.sgra.fles fi
+]"LC"[pfni = ]"LCgiro"[pfni
+)p(ypoc.ypoc = pfni
+:)selifni.fles(etaremune ni p ,i rof
+)
+,]"eman"[p
+,]"LC"[p
+( % "s% rof s% tog - sregetni lanidro eb tsum sretemarap lanoitisoP" ,)(tigidsi.]
+"LC"
+[p tressa
+:)rapdda.fles(etaremune ni p ,i rof
+)
+,]"eman"[p
+,]"LC"[p
+( % "s% rof s% tog - sregetni lanidro eb tsum sretemarap lanoitisoP" ,)
+"TUODTS" == )(reppu.)(pirts.]"LC"[p ro )(tigidsi.]"LC"[p
+( tressa
+:)seliftuo.fles(etaremune ni p ,i rof
+)
+,]"lebal"[p
+,]"LC"[p
+( % "s% rof s% tog - sregetni lanidro eb tsum sretemarap lanoitisoP" ,)
+"NIDTS" == )(reppu.)(pirts.]"LC"[p ro )(tigidsi.]"LC"[p
+( tressa
+:)selifni.fles(etaremune ni p ,i rof
+:"lanoitisop" == ssapmarap.sgra.fles fi
+"""lanidro ciremun rieht yb detacilpmoc era sretemarap lanoitisop """
+:)fles(rappunaelc fed
+
+)(esolc.tcafitra
+))"8ftu" ,tpircs.fles(setyb(etirw.tcafitra
+)"bw" ,tra(nepo = tcafitra
+)]0[emetucexe.fles ,eman_loot.fles( % "s%.s%" = tra
+xr = tpircSdepacse.fles
+)"war dne#"(dneppa.xr
+)"war#" ,0(tresni.xr
+]"" > )(pirts.x fi xr ni x rof "}x{ "f[ = tpircSdecaps.fles
+)(esolc.tpircst
+)tpircs.fles(etirw.tpircst
+)"w" ,elifs.fles(nepo = tpircst
+)
+)]0[emetucexe.fles( % "s%_"=xiffus ,eman_loot.fles=xiferp
+(pmetskm.elifpmet = elifs.fles ,eldnahf
+)xr(nioj."n\" = tpircs.fles
+"nur tonnaC .ytpme si tpircs deilppuS" ,0 > )kcehcxr(nel tressa
+]"" > )(pirts.x fi xr ni x rof )(pirts.x[ = kcehcxr
+]xr ni x rof )(pirtsr.x[ = xr
+)(senildaer.)"r" ,htap_tpircs.sgra.fles(nepo = xr
+:)fles(tpircSperp fed
+
+xiffuslcx = xiffuslcx.fles
+)(tros.xiffuslcx
+)]]"edirrevo"[p ,]"eman"[p % '"s%$"' ,]"LC"[p[(dneppa.xiffuslcx
+:raples.fles ni p rof
+)]revo ,man % '"s%$"' ,]"LC"[p[(dneppa.xiffuslcx
+]"edirrevo"[p = revo
+)
+"!senil dnammoc retemarap lanoitisop ni dettimrep ton - derongi }man{ rof staepeR .gninraw ###"f
+(tnirp
+:per fi
+esnes ON ekam staeper # "1" == ]"taeper"[p = per
+]"eman"[p = man
+:rapdda.fles ni p rof
+)]"" ,]"eman"[p % "s%$" ,]"LC"[p[(dneppa.xiffuslcx
+:esle
+]]"eman"[p % "s%$" ,">"[ = tceriderlcxtsal.fles
+:"TUODTS" == )(reppu.)(pirts.]"LCgiro"[p fi
+:)seliftuo.fles(etaremune ni p ,i rof
+)emdneppax(dneppa.xiffuslcx
+]"" ,]"emanelifni"[p % "s%$" ,]"LC"[p[ = emdneppax
+:esle
+]
+,]"emanelifni"[p % "s%$ <"
+,]"emanelifni"[p
+,"999"
+[ = emdneppax
+:"NIDTS" == )(reppu.)(pirts.]"LCgiro"[p fi
+:)selifni.fles(etaremune ni p ,i rof
+][ = xiffuslcx
+:)fles(soplcperp fed
+
+xiffuslcx = xiffuslcx.fles
+)]]"edirrevo"[p ,]"eman"[p % '"s%$"' ,]"LC"[p[(dneppa.xiffuslcx
+:raples.fles ni p rof
+)]revo ,man % '"s%$"' ,]"LC"[p[(dneppa.xiffuslcx
+]"edirrevo"[p = revo
+:esle
+'rof dne#n\"}man{.per$" }man{--n\:}man{_R$ ni per$ rof#'f = revo
+:per fi
+"1" == ]"taeper"[p = per
+]"eman"[p = man
+:rapdda.fles ni p rof
+)]"" ,]"eman"[p % "s%$" ,]"eman"[p[(dneppa.xiffuslcx
+:esle
+]]"eman"[p % "s%$" ,">"[ = tceriderlcxtsal.fles
+:"TUODTS" == )(reppu.)(pirts.]"LCgiro"[p fi
+:)seliftuo.fles(etaremune ni p ,i rof
+)emdneppax(dneppa.xiffuslcx
+]revo ,]"LC"[p % "s%$" ,]"LC"[p[ = emdneppax
+'rof dne#n\"}man{.per$" }man{--n\:}man{_R$ ni per$ rof#'f = revo
+:per fi
+"" = revo
+"1" == ]"taeper"[p = per
+:esle
+]
+,man % "s%$ <"
+,man
+,man
+[ = emdneppax
+:"NIDTS" == )(reppu.)(pirts.]"LCgiro"[p fi
+]"emanelifni"[p = man
+:)selifni.fles(etaremune ni p ,i rof
+][ = xiffuslcx
+:)fles(pgraperp fed
+
+)c(LCXa
+:plc ni c rof
+)xiffus_resu_lc.sgra.fles(tilps.xelhs = plc
+dne LC YID # :xiffus_resu_lc.sgra.fles fi
+)]"eman"[]0[seliftuo.fles % "s%$"(LCXa
+)">"(LCXa
+:0 > )seliftuo.fles(nel fi
+)]"emanelifni"[]0[selifni.fles % "s%$"(LCXa
+)"<"(LCXa
+:0 > )selifni.fles(nel fi
+dneppa.lclmx.fles = LCXa
+"""o/i rof > dna < sesu - staeper ro sretemarap on"""
+:)fles(elpmislc fed
+
+)(esrapgralc.fles
+)(pgraperp.fles
+:esle
+)(lanoitisoplc.fles
+)(soplcperp.fles
+:"lanoitisop" == ssapmarap.sgra.fles fi
+:esle
+)(elpmislc.fles
+:"0" == ssapmarap.sgra.fles fi
+
+)xe(LCXa
+:emetucexe.fles ni xe rof
+:esle
+)"emnur$"(LCXa
+)xe(LCXa
+:emetucexe.fles ni xe rof
+:htap_tpircs.sgra.fles fi
+enoN = edirrevo_tset.fles
+:esle
+]sots ni x rof )(pirtsr.x[ = edirrevo_tset.fles
+)(senildaer.)"r" ,edirrevo_tset.sgra.fles(nepo = sots
+:edirrevo_tset.sgra.fles fi
+enoN = edirrevo_dnammoc.fles
+:esle
+]socs ni x rof )(pirtsr.x[ = edirrevo_dnammoc.fles
+)(senildaer.)"r" ,edirrevo_dnammoc.sgra.fles(nepo = socs
+:edirrevo_dnammoc.sgra.fles fi
+)(tpircSperp.fles
+:htap_tpircs.sgra.fles fi
+][ = maraptset.fles
+)(stuptuO.ptxg = stuptuot.fles
+)(stupnI.ptxg = stupnit.fles
+)eman_loot.fles % 'txt.gol_nur_FT_s%',ridper.fles(nioj.htap.so = golt.fles
+)ridper.fles(ridkm.so
+:)ridper.fles(stsixe.htap.so ton fi
+)ridtset.fles(ridkm.so
+:)ridtset.fles(stsixe.htap.so ton fi
+)ridtuoloot.fles(ridkm.so
+:)ridtuoloot.fles(stsixe.htap.so ton fi
+)"atad-tset" ,ridtuoloot.fles(nioj.htap.so = ridtset.fles
+)eman_loot.fles % "zg.dehsloot_detset_ton_s%" ,ridtuoloot.fles(nioj.htap.so # tuo_loot_detsetnu.sgra = htapratwen.fles
+"negloot/." = ridper.fles
+"tuoft/." = ridtuoloot.fles
+)
+,EXEEKAF
+,csed_loot.sgra.fles
+,noisrev_loot.sgra.fles
+,di_loot.fles
+,eman_loot.fles
+(looT.txg = lootwen.fles
+eman_loot.fles = di_loot.fles
+)eman_loot.sgra ,"" ,"+]_9-0Z-Az-a^["(bus.er = eman_loot.fles
+'"esrapgra" ro "lanoitisop","0" eb tsum ssapmarap.sgra' ,]
+,"lanoitisop"
+,"esrapgra"
+,"0"
+[ ni ssapmarap.sgra tressa
+dneppa.lclmx.fles = LCXa
+enoN = emetucexe.fles
+:esle
+]
+,)(pirts.]0[)":"(tilps.]0[)","(tilps.segakcap.sgra.fles
+[ = emetucexe.fles
+:segakcap.sgra.fles fi
+:esle
+]
+,exesys.sgra.fles
+[ = emetucexe.fles
+:esle
+)exesys.sgra.fles(tilps.xelhs = emetucexe.fles
+:exesys.sgra.fles ni " " fi
+:exesys.sgra.fles fi
+"lanoitisop" == ssapmarap.sgra.fles = lanoitisop_si.fles
+][ = lclmx.fles
+enoN = tceriderlcxtsal.fles
+)(rappunaelc.fles
+sgra = sgra.fles
+)
+"yranoitcid a eb dluohs - demroflam si }sretemarap_txettceles.sgra{ sretemarap_txettceles--"f
+(tnirp
+:noitpecxE tpecxe
+]
+1 > ))(pirts.x(nel fi sretemarap_txettceles.sgra ni x rof )x(sdaol.nosj
+[ = raples.fles
+:yrt
+)
+"yranoitcid a eb dluohs - demroflam si }sretemarap_lanoitidda.sgra{ sretemarap_lanoitidda--"f
+(tnirp
+:noitpecxE tpecxe
+]
+1 > ))(pirts.x(nel fi sretemarap_lanoitidda.sgra ni x rof )x(sdaol.nosj
+[ = rapdda.fles
+:yrt
+'tros emos fo tuptuo na tuohtiw liaf lliw rennur boj yxalaG ehT .deificeps snoitcelloc tuptuo ro seliftuo oN' ,0 > ))snoitcelloc.fles(nel + )seliftuo.fles(nel( tressa
+)
+"yranoitcid a eb dluohs - demroflam si }selif_tuptuo.sgra{ retemarap selif_tuptuo--"f
+(tnirp
+:noitpecxE tpecxe
+]
+1 > ))(pirts.x(nel fi selif_tuptuo.sgra ni x rof )x(sdaol.nosj
+[ = seliftuo.fles
+:yrt
+)
+"yranoitcid a eb dluohs - demroflam si })selif_tupni.sgra(rts{ retemarap selif_tupni--"f
+(tnirp
+:noitpecxE tpecxe
+]
+1 > ))(pirts.x(nel fi selif_tupni.sgra ni x rof )x(sdaol.nosj
+[ = selifni.fles
+:yrt
+)
+"yranoitcid a eb dluohs - demroflam si })noitcelloc.sgra(rts{ retemarap snoitcelloc--"f
+(tnirp
+:noitpecxE tpecxe
+]
+1 > ))(pirts.x(nel fi noitcelloc.sgra ni x rof )x(sdaol.nosj
+[ = snoitcelloc.fles
+:yrt
+:0 > )noitcelloc.sgra(nel fi
+][ = snoitcelloc.fles
+)(dwcteg.so = dwcruo.fles
+)'sloot_lacol',toor_yxalag.sgra(nioj.htap.so = sloot_lacol.fles
+"""
+noitareneg loot lmxyxalag rof dedeen stnemele eraperp dna
+ereh loot eht gninnur rof lc enil dnammoc eraperp
+"""
+aqon # :)enoN=sgra ,fles(__tini__ fed
+
+"""
+
+lmxyxalag sesu
+tpircs yrartibra na rof repparW"""
+:yrotcaF_looT ssalc
+
+
+selput_noitatic nruter
+)))(pirts.]: )"xetbib"(nel[noitatic ,"xetbib"((dneppa.selput_noitatic
+:esle
+)))(pirts.]: )"iod"(nel[noitatic ,"iod"((dneppa.selput_noitatic
+:)"iod"(htiwstrats.noitatic fi
+:snoitatic ni noitatic rof
+][ = selput_noitatic
+])(pirts.c fi )"**YRTNE**"(tilps.txet_snoitatic ni c rof c[ = snoitatic
+""""""
+:)txet_snoitatic(snoitatic_esrap fed
+
+
+)]txet ni c rof )c ,c(teg.elbat_epacse_hateehc[(nioj."" nruter
+""".txet nihtiw seititne ecudorP"""
+:)txet(epacse_hateehc fed
+
+
+}"#\\" :"#" ,"$\\" :"$"{ = elbat_epacse_hateehc
+
+
+)))(emit.emit(emitlacol.emit ,"S%:M%:H% Y%/m%/d%"(emitfrts.emit nruter
+"""gnirts a sa emit tnerruc nruter"""
+:)(wonemit fed
+
+
+.edirrevo htiw #
+neve exe eht gnidneperp lmxyxalag xif ot pmub noisrev/RP a litnu siht deen #
+"~~~EM~~~EVOMER~~~" = EXEEKAF
+"yrotcafloot/2rabuf/moc.buhtig//:sptth" = LRUyrotcaFloot
+eurT = gubed
+eurT = esobrev
+"2202 hcraM 4.2V" = noisrevym
+
+lmay tropmi
+
+TE sa eerte.lmxl tropmi
+
+ptxg sa sretemarap.loot.lmxyxalag tropmi
+txg sa loot.lmxyxalag tropmi
+
+yxalag tropmi dnelboib morf
+
+emit tropmi
+elifpmet tropmi
+elifrat tropmi
+sys tropmi
+ssecorpbus tropmi
+lituhs tropmi
+xelhs tropmi
+er tropmi
+so tropmi
+nosj tropmi
+ltncf tropmi
+ypoc tropmi
+esrapgra tropmi
+
+
+
+.tset htiw loot reporp wen a snruter dna #
+stuptuo tset eht setaerc ,evihcra detset-non a no omenalp snur retset ehT #
+noitpoda reniatnocoib dna tnempoleved lairotut NTG fo trap sa #
+llatsni/tset dna etareneg - sloot owt otni derotcafeR :2202 hcram #
+#
+yrotcafloot/2rabuf/moc.buhtig//:sptth #
+ta emoclew sexif gub dna tnemevorpmi rof snoitseggus #
+LPGL eht rednu desneciL #
+devreser sthgir lla #
+#
+2102 yaM )moc pots liamg ta surazal pots ssor( surazal ssor thgirypoc #
+#
+yrotcafloot/2rabuf/moc.buhtig//:sptth ees #
diff -r 2beaae16651e -r 0183cad9d13b tacrev/test-data/Input_text_file_to_be_reversed_sample
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tacrev/test-data/Input_text_file_to_be_reversed_sample Thu Feb 22 10:48:01 2024 +0000
@@ -0,0 +1,1210 @@
+# see https://github.com/fubar2/toolfactory
+#
+# copyright ross lazarus (ross stop lazarus at gmail stop com) May 2012
+#
+# all rights reserved
+# Licensed under the LGPL
+# suggestions for improvement and bug fixes welcome at
+# https://github.com/fubar2/toolfactory
+#
+# march 2022: Refactored into two tools - generate and test/install
+# as part of GTN tutorial development and biocontainer adoption
+# The tester runs planemo on a non-tested archive, creates the test outputs
+# and returns a new proper tool with test.
+
+
+
+import argparse
+import copy
+import fcntl
+import json
+import os
+import re
+import shlex
+import shutil
+import subprocess
+import sys
+import tarfile
+import tempfile
+import time
+
+from bioblend import galaxy
+
+import galaxyxml.tool as gxt
+import galaxyxml.tool.parameters as gxtp
+
+import lxml.etree as ET
+
+import yaml
+
+myversion = "V2.4 March 2022"
+verbose = True
+debug = True
+toolFactoryURL = "https://github.com/fubar2/toolfactory"
+FAKEEXE = "~~~REMOVE~~~ME~~~"
+# need this until a PR/version bump to fix galaxyxml prepending the exe even
+# with override.
+
+
+def timenow():
+ """return current time as a string"""
+ return time.strftime("%d/%m/%Y %H:%M:%S", time.localtime(time.time()))
+
+
+cheetah_escape_table = {"$": "\\$", "#": "\\#"}
+
+
+def cheetah_escape(text):
+ """Produce entities within text."""
+ return "".join([cheetah_escape_table.get(c, c) for c in text])
+
+
+def parse_citations(citations_text):
+ """"""
+ citations = [c for c in citations_text.split("**ENTRY**") if c.strip()]
+ citation_tuples = []
+ for citation in citations:
+ if citation.startswith("doi"):
+ citation_tuples.append(("doi", citation[len("doi") :].strip()))
+ else:
+ citation_tuples.append(("bibtex", citation[len("bibtex") :].strip()))
+ return citation_tuples
+
+
+class Tool_Factory:
+ """Wrapper for an arbitrary script
+ uses galaxyxml
+
+ """
+
+ def __init__(self, args=None): # noqa
+ """
+ prepare command line cl for running the tool here
+ and prepare elements needed for galaxyxml tool generation
+ """
+ self.local_tools = os.path.join(args.galaxy_root,'local_tools')
+ self.ourcwd = os.getcwd()
+ self.collections = []
+ if len(args.collection) > 0:
+ try:
+ self.collections = [
+ json.loads(x) for x in args.collection if len(x.strip()) > 1
+ ]
+ except Exception:
+ print(
+ f"--collections parameter {str(args.collection)} is malformed - should be a dictionary"
+ )
+ try:
+ self.infiles = [
+ json.loads(x) for x in args.input_files if len(x.strip()) > 1
+ ]
+ except Exception:
+ print(
+ f"--input_files parameter {str(args.input_files)} is malformed - should be a dictionary"
+ )
+ try:
+ self.outfiles = [
+ json.loads(x) for x in args.output_files if len(x.strip()) > 1
+ ]
+ except Exception:
+ print(
+ f"--output_files parameter {args.output_files} is malformed - should be a dictionary"
+ )
+ assert (len(self.outfiles) + len(self.collections)) > 0, 'No outfiles or output collections specified. The Galaxy job runner will fail without an output of some sort'
+ try:
+ self.addpar = [
+ json.loads(x) for x in args.additional_parameters if len(x.strip()) > 1
+ ]
+ except Exception:
+ print(
+ f"--additional_parameters {args.additional_parameters} is malformed - should be a dictionary"
+ )
+ try:
+ self.selpar = [
+ json.loads(x) for x in args.selecttext_parameters if len(x.strip()) > 1
+ ]
+ except Exception:
+ print(
+ f"--selecttext_parameters {args.selecttext_parameters} is malformed - should be a dictionary"
+ )
+ self.args = args
+ self.cleanuppar()
+ self.lastxclredirect = None
+ self.xmlcl = []
+ self.is_positional = self.args.parampass == "positional"
+ if self.args.sysexe:
+ if " " in self.args.sysexe:
+ self.executeme = shlex.split(self.args.sysexe)
+ else:
+ self.executeme = [
+ self.args.sysexe,
+ ]
+ else:
+ if self.args.packages:
+ self.executeme = [
+ self.args.packages.split(",")[0].split(":")[0].strip(),
+ ]
+ else:
+ self.executeme = None
+ aXCL = self.xmlcl.append
+ assert args.parampass in [
+ "0",
+ "argparse",
+ "positional",
+ ], 'args.parampass must be "0","positional" or "argparse"'
+ self.tool_name = re.sub("[^a-zA-Z0-9_]+", "", args.tool_name)
+ self.tool_id = self.tool_name
+ self.newtool = gxt.Tool(
+ self.tool_name,
+ self.tool_id,
+ self.args.tool_version,
+ self.args.tool_desc,
+ FAKEEXE,
+ )
+ self.tooloutdir = "./tfout"
+ self.repdir = "./toolgen"
+ self.newtarpath = args.untested_tool_out # os.path.join(self.tooloutdir, "%s_not_tested_toolshed.gz" % self.tool_name)
+ self.testdir = os.path.join(self.tooloutdir, "test-data")
+ if not os.path.exists(self.tooloutdir):
+ os.mkdir(self.tooloutdir)
+ if not os.path.exists(self.testdir):
+ os.mkdir(self.testdir)
+ if not os.path.exists(self.repdir):
+ os.mkdir(self.repdir)
+ self.tlog = os.path.join(self.repdir,'%s_TF_run_log.txt' % self.tool_name)
+ self.tinputs = gxtp.Inputs()
+ self.toutputs = gxtp.Outputs()
+ self.testparam = []
+ if self.args.script_path:
+ self.prepScript()
+ if self.args.command_override:
+ scos = open(self.args.command_override, "r").readlines()
+ self.command_override = [x.rstrip() for x in scos]
+ else:
+ self.command_override = None
+ if self.args.test_override:
+ stos = open(self.args.test_override, "r").readlines()
+ self.test_override = [x.rstrip() for x in stos]
+ else:
+ self.test_override = None
+ if self.args.script_path:
+ for ex in self.executeme:
+ aXCL(ex)
+ aXCL("$runme")
+ else:
+ for ex in self.executeme:
+ aXCL(ex)
+
+ if self.args.parampass == "0":
+ self.clsimple()
+ else:
+ if self.args.parampass == "positional":
+ self.prepclpos()
+ self.clpositional()
+ else:
+ self.prepargp()
+ self.clargparse()
+
+ def clsimple(self):
+ """no parameters or repeats - uses < and > for i/o"""
+ aXCL = self.xmlcl.append
+ if len(self.infiles) > 0:
+ aXCL("<")
+ aXCL("$%s" % self.infiles[0]["infilename"])
+ if len(self.outfiles) > 0:
+ aXCL(">")
+ aXCL("$%s" % self.outfiles[0]["name"])
+ if self.args.cl_user_suffix: # DIY CL end
+ clp = shlex.split(self.args.cl_user_suffix)
+ for c in clp:
+ aXCL(c)
+
+ def prepargp(self):
+ xclsuffix = []
+ for i, p in enumerate(self.infiles):
+ nam = p["infilename"]
+ if p["origCL"].strip().upper() == "STDIN":
+ xappendme = [
+ nam,
+ nam,
+ "< $%s" % nam,
+ ]
+ else:
+ rep = p["repeat"] == "1"
+ over = ""
+ if rep:
+ over = f'#for $rep in $R_{nam}:\n--{nam} "$rep.{nam}"\n#end for'
+ xappendme = [p["CL"], "$%s" % p["CL"], over]
+ xclsuffix.append(xappendme)
+ for i, p in enumerate(self.outfiles):
+ if p["origCL"].strip().upper() == "STDOUT":
+ self.lastxclredirect = [">", "$%s" % p["name"]]
+ else:
+ xclsuffix.append([p["name"], "$%s" % p["name"], ""])
+ for p in self.addpar:
+ nam = p["name"]
+ rep = p["repeat"] == "1"
+ if rep:
+ over = f'#for $rep in $R_{nam}:\n--{nam} "$rep.{nam}"\n#end for'
+ else:
+ over = p["override"]
+ xclsuffix.append([p["CL"], '"$%s"' % nam, over])
+ for p in self.selpar:
+ xclsuffix.append([p["CL"], '"$%s"' % p["name"], p["override"]])
+ self.xclsuffix = xclsuffix
+
+ def prepclpos(self):
+ xclsuffix = []
+ for i, p in enumerate(self.infiles):
+ if p["origCL"].strip().upper() == "STDIN":
+ xappendme = [
+ "999",
+ p["infilename"],
+ "< $%s" % p["infilename"],
+ ]
+ else:
+ xappendme = [p["CL"], "$%s" % p["infilename"], ""]
+ xclsuffix.append(xappendme)
+ for i, p in enumerate(self.outfiles):
+ if p["origCL"].strip().upper() == "STDOUT":
+ self.lastxclredirect = [">", "$%s" % p["name"]]
+ else:
+ xclsuffix.append([p["CL"], "$%s" % p["name"], ""])
+ for p in self.addpar:
+ nam = p["name"]
+ rep = p["repeat"] == "1" # repeats make NO sense
+ if rep:
+ print(
+ f"### warning. Repeats for {nam} ignored - not permitted in positional parameter command lines!"
+ )
+ over = p["override"]
+ xclsuffix.append([p["CL"], '"$%s"' % nam, over])
+ for p in self.selpar:
+ xclsuffix.append([p["CL"], '"$%s"' % p["name"], p["override"]])
+ xclsuffix.sort()
+ self.xclsuffix = xclsuffix
+
+ def prepScript(self):
+ rx = open(self.args.script_path, "r").readlines()
+ rx = [x.rstrip() for x in rx]
+ rxcheck = [x.strip() for x in rx if x.strip() > ""]
+ assert len(rxcheck) > 0, "Supplied script is empty. Cannot run"
+ self.script = "\n".join(rx)
+ fhandle, self.sfile = tempfile.mkstemp(
+ prefix=self.tool_name, suffix="_%s" % (self.executeme[0])
+ )
+ tscript = open(self.sfile, "w")
+ tscript.write(self.script)
+ tscript.close()
+ self.spacedScript = [f" {x}" for x in rx if x.strip() > ""]
+ rx.insert(0, "#raw")
+ rx.append("#end raw")
+ self.escapedScript = rx
+ art = "%s.%s" % (self.tool_name, self.executeme[0])
+ artifact = open(art, "wb")
+ artifact.write(bytes(self.script, "utf8"))
+ artifact.close()
+
+ def cleanuppar(self):
+ """ positional parameters are complicated by their numeric ordinal"""
+ if self.args.parampass == "positional":
+ for i, p in enumerate(self.infiles):
+ assert (
+ p["CL"].isdigit() or p["CL"].strip().upper() == "STDIN"
+ ), "Positional parameters must be ordinal integers - got %s for %s" % (
+ p["CL"],
+ p["label"],
+ )
+ for i, p in enumerate(self.outfiles):
+ assert (
+ p["CL"].isdigit() or p["CL"].strip().upper() == "STDOUT"
+ ), "Positional parameters must be ordinal integers - got %s for %s" % (
+ p["CL"],
+ p["name"],
+ )
+ for i, p in enumerate(self.addpar):
+ assert p[
+ "CL"
+ ].isdigit(), "Positional parameters must be ordinal integers - got %s for %s" % (
+ p["CL"],
+ p["name"],
+ )
+ for i, p in enumerate(self.infiles):
+ infp = copy.copy(p)
+ infp["origCL"] = infp["CL"]
+ if self.args.parampass in ["positional", "0"]:
+ infp["infilename"] = infp["label"].replace(" ", "_")
+ else:
+ infp["infilename"] = infp["CL"]
+ self.infiles[i] = infp
+ for i, p in enumerate(self.outfiles):
+ outfp = copy.copy(p)
+ outfp["origCL"] = outfp["CL"] # keep copy
+ self.outfiles[i] = outfp
+ for i, p in enumerate(self.addpar):
+ addp = copy.copy(p)
+ addp["origCL"] = addp["CL"]
+ self.addpar[i] = addp
+
+ def clpositional(self):
+ # inputs in order then params
+ aXCL = self.xmlcl.append
+ for (k, v, koverride) in self.xclsuffix:
+ aXCL(v)
+ if self.lastxclredirect:
+ for cl in self.lastxclredirect:
+ aXCL(cl)
+ if self.args.cl_user_suffix: # DIY CL end
+ clp = shlex.split(self.args.cl_user_suffix)
+ for c in clp:
+ aXCL(c)
+
+ def clargparse(self):
+ """argparse style"""
+ aXCL = self.xmlcl.append
+ # inputs then params in argparse named form
+
+ for (k, v, koverride) in self.xclsuffix:
+ if koverride > "":
+ k = koverride
+ aXCL(k)
+ else:
+ if len(k.strip()) == 1:
+ k = "-%s" % k
+ else:
+ k = "--%s" % k
+ aXCL(k)
+ aXCL(v)
+ if self.lastxclredirect:
+ for cl in self.lastxclredirect:
+ aXCL(cl)
+ if self.args.cl_user_suffix: # DIY CL end
+ clp = shlex.split(self.args.cl_user_suffix)
+ for c in clp:
+ aXCL(c)
+
+ def getNdash(self, newname):
+ if self.is_positional:
+ ndash = 0
+ else:
+ ndash = 2
+ if len(newname) < 2:
+ ndash = 1
+ return ndash
+
+ def doXMLparam(self): # noqa
+ """Add all needed elements to tool"""
+ for p in self.outfiles:
+ newname = p["name"]
+ newfmt = p["format"]
+ newcl = p["CL"]
+ test = p["test"]
+ oldcl = p["origCL"]
+ test = test.strip()
+ ndash = self.getNdash(newcl)
+ aparm = gxtp.OutputData(
+ name=newname, format=newfmt, num_dashes=ndash, label=newname
+ )
+ aparm.positional = self.is_positional
+ if self.is_positional:
+ if oldcl.upper() == "STDOUT":
+ aparm.positional = 9999999
+ aparm.command_line_override = "> $%s" % newname
+ else:
+ aparm.positional = int(oldcl)
+ aparm.command_line_override = "$%s" % newname
+ self.toutputs.append(aparm)
+ ld = None
+ if test.strip() > "":
+ if test.strip().startswith("diff"):
+ c = "diff"
+ ld = 0
+ if test.split(":")[1].isdigit:
+ ld = int(test.split(":")[1])
+ tp = gxtp.TestOutput(
+ name=newname,
+ value="%s_sample" % newname,
+ compare=c,
+ lines_diff=ld,
+ )
+ elif test.startswith("sim_size"):
+ c = "sim_size"
+ tn = test.split(":")[1].strip()
+ if tn > "":
+ if "." in tn:
+ delta = None
+ delta_frac = min(1.0, float(tn))
+ else:
+ delta = int(tn)
+ delta_frac = None
+ tp = gxtp.TestOutput(
+ name=newname,
+ value="%s_sample" % newname,
+ compare=c,
+ delta=delta,
+ delta_frac=delta_frac,
+ )
+ else:
+ c = test
+ tp = gxtp.TestOutput(
+ name=newname,
+ value="%s_sample" % newname,
+ compare=c,
+ )
+ self.testparam.append(tp)
+ for p in self.infiles:
+ newname = p["infilename"]
+ newfmt = p["format"]
+ ndash = self.getNdash(newname)
+ reps = p.get("repeat", "0") == "1"
+ if not len(p["label"]) > 0:
+ alab = p["CL"]
+ else:
+ alab = p["label"]
+ aninput = gxtp.DataParam(
+ newname,
+ optional=False,
+ label=alab,
+ help=p["help"],
+ format=newfmt,
+ multiple=False,
+ num_dashes=ndash,
+ )
+ aninput.positional = self.is_positional
+ if self.is_positional:
+ if p["origCL"].upper() == "STDIN":
+ aninput.positional = 9999998
+ aninput.command_line_override = "< $%s" % newname
+ else:
+ aninput.positional = int(p["origCL"])
+ aninput.command_line_override = "$%s" % newname
+ if reps:
+ repe = gxtp.Repeat(
+ name=f"R_{newname}", title=f"Add as many {alab} as needed"
+ )
+ repe.append(aninput)
+ self.tinputs.append(repe)
+ tparm = gxtp.TestRepeat(name=f"R_{newname}")
+ tparm2 = gxtp.TestParam(newname, value="%s_sample" % newname)
+ tparm.append(tparm2)
+ self.testparam.append(tparm)
+ else:
+ self.tinputs.append(aninput)
+ tparm = gxtp.TestParam(newname, value="%s_sample" % newname)
+ self.testparam.append(tparm)
+ for p in self.addpar:
+ newname = p["name"]
+ newval = p["value"]
+ newlabel = p["label"]
+ newhelp = p["help"]
+ newtype = p["type"]
+ newcl = p["CL"]
+ oldcl = p["origCL"]
+ reps = p["repeat"] == "1"
+ if not len(newlabel) > 0:
+ newlabel = newname
+ ndash = self.getNdash(newname)
+ if newtype == "text":
+ aparm = gxtp.TextParam(
+ newname,
+ label=newlabel,
+ help=newhelp,
+ value=newval,
+ num_dashes=ndash,
+ )
+ elif newtype == "integer":
+ aparm = gxtp.IntegerParam(
+ newname,
+ label=newlabel,
+ help=newhelp,
+ value=newval,
+ num_dashes=ndash,
+ )
+ elif newtype == "float":
+ aparm = gxtp.FloatParam(
+ newname,
+ label=newlabel,
+ help=newhelp,
+ value=newval,
+ num_dashes=ndash,
+ )
+ elif newtype == "boolean":
+ aparm = gxtp.BooleanParam(
+ newname,
+ label=newlabel,
+ help=newhelp,
+ value=newval,
+ num_dashes=ndash,
+ )
+ else:
+ raise ValueError(
+ 'Unrecognised parameter type "%s" for\
+ additional parameter %s in makeXML'
+ % (newtype, newname)
+ )
+ aparm.positional = self.is_positional
+ if self.is_positional:
+ aparm.positional = int(oldcl)
+ if reps:
+ repe = gxtp.Repeat(
+ name=f"R_{newname}", title=f"Add as many {newlabel} as needed"
+ )
+ repe.append(aparm)
+ self.tinputs.append(repe)
+ tparm = gxtp.TestRepeat(name=f"R_{newname}")
+ tparm2 = gxtp.TestParam(newname, value=newval)
+ tparm.append(tparm2)
+ self.testparam.append(tparm)
+ else:
+ self.tinputs.append(aparm)
+ tparm = gxtp.TestParam(newname, value=newval)
+ self.testparam.append(tparm)
+ for p in self.selpar:
+ newname = p["name"]
+ newval = p["value"]
+ newlabel = p["label"]
+ newhelp = p["help"]
+ newtype = p["type"]
+ newcl = p["CL"]
+ if not len(newlabel) > 0:
+ newlabel = newname
+ ndash = self.getNdash(newname)
+ if newtype == "selecttext":
+ newtext = p["texts"]
+ aparm = gxtp.SelectParam(
+ newname,
+ label=newlabel,
+ help=newhelp,
+ num_dashes=ndash,
+ )
+ for i in range(len(newval)):
+ anopt = gxtp.SelectOption(
+ value=newval[i],
+ text=newtext[i],
+ )
+ aparm.append(anopt)
+ aparm.positional = self.is_positional
+ if self.is_positional:
+ aparm.positional = int(newcl)
+ self.tinputs.append(aparm)
+ tparm = gxtp.TestParam(newname, value=newval)
+ self.testparam.append(tparm)
+ else:
+ raise ValueError(
+ 'Unrecognised parameter type "%s" for\
+ selecttext parameter %s in makeXML'
+ % (newtype, newname)
+ )
+ for p in self.collections:
+ newkind = p["kind"]
+ newname = p["name"]
+ newlabel = p["label"]
+ newdisc = p["discover"]
+ collect = gxtp.OutputCollection(newname, label=newlabel, type=newkind)
+ disc = gxtp.DiscoverDatasets(
+ pattern=newdisc, directory=f"{newname}", visible="false"
+ )
+ collect.append(disc)
+ self.toutputs.append(collect)
+ try:
+ tparm = gxtp.TestOutputCollection(newname) # broken until PR merged.
+ self.testparam.append(tparm)
+ except Exception:
+ print(
+ "#### WARNING: Galaxyxml version does not have the PR merged yet - tests for collections must be over-ridden until then!"
+ )
+
+ def doNoXMLparam(self):
+ """filter style package - stdin to stdout"""
+ if len(self.infiles) > 0:
+ alab = self.infiles[0]["label"]
+ if len(alab) == 0:
+ alab = self.infiles[0]["infilename"]
+ max1s = (
+ "Maximum one input if parampass is 0 but multiple input files supplied - %s"
+ % str(self.infiles)
+ )
+ assert len(self.infiles) == 1, max1s
+ newname = self.infiles[0]["infilename"]
+ aninput = gxtp.DataParam(
+ newname,
+ optional=False,
+ label=alab,
+ help=self.infiles[0]["help"],
+ format=self.infiles[0]["format"],
+ multiple=False,
+ num_dashes=0,
+ )
+ aninput.command_line_override = "< $%s" % newname
+ aninput.positional = True
+ self.tinputs.append(aninput)
+ tp = gxtp.TestParam(name=newname, value="%s_sample" % newname)
+ self.testparam.append(tp)
+ if len(self.outfiles) > 0:
+ newname = self.outfiles[0]["name"]
+ newfmt = self.outfiles[0]["format"]
+ anout = gxtp.OutputData(newname, format=newfmt, num_dashes=0)
+ anout.command_line_override = "> $%s" % newname
+ anout.positional = self.is_positional
+ self.toutputs.append(anout)
+ tp = gxtp.TestOutput(name=newname, value="%s_sample" % newname)
+ self.testparam.append(tp)
+
+ def makeXML(self): # noqa
+ """
+ Create a Galaxy xml tool wrapper for the new script
+ Uses galaxyhtml
+ Hmmm. How to get the command line into correct order...
+ """
+ if self.command_override:
+ self.newtool.command_override = self.command_override # config file
+ else:
+ self.newtool.command_override = self.xmlcl
+ cite = gxtp.Citations()
+ acite = gxtp.Citation(type="doi", value="10.1093/bioinformatics/bts573")
+ cite.append(acite)
+ self.newtool.citations = cite
+ safertext = ""
+ if self.args.help_text:
+ helptext = open(self.args.help_text, "r").readlines()
+ safertext = "\n".join([cheetah_escape(x) for x in helptext])
+ if len(safertext.strip()) == 0:
+ safertext = (
+ "Ask the tool author (%s) to rebuild with help text please\n"
+ % (self.args.user_email)
+ )
+ if self.args.script_path:
+ if len(safertext) > 0:
+ safertext = safertext + "\n\n------\n" # transition allowed!
+ scr = [x for x in self.spacedScript if x.strip() > ""]
+ scr.insert(0, "\n\nScript::\n")
+ if len(scr) > 300:
+ scr = (
+ scr[:100]
+ + [" >300 lines - stuff deleted", " ......"]
+ + scr[-100:]
+ )
+ scr.append("\n")
+ safertext = safertext + "\n".join(scr)
+ self.newtool.help = safertext
+ self.newtool.version_command = f'echo "{self.args.tool_version}"'
+ std = gxtp.Stdios()
+ std1 = gxtp.Stdio()
+ std.append(std1)
+ self.newtool.stdios = std
+ requirements = gxtp.Requirements()
+ self.condaenv = []
+ if self.args.packages:
+ try:
+ for d in self.args.packages.split(","):
+ ver = None
+ packg = None
+ d = d.replace("==", ":")
+ d = d.replace("=", ":")
+ if ":" in d:
+ packg, ver = d.split(":")
+ ver = ver.strip()
+ packg = packg.strip()
+ else:
+ packg = d.strip()
+ ver = None
+ if ver == "":
+ ver = None
+ if packg:
+ requirements.append(
+ gxtp.Requirement("package", packg.strip(), ver)
+ )
+ self.condaenv.append(d)
+ except Exception:
+ print(
+ "### malformed packages string supplied - cannot parse =",
+ self.args.packages,
+ )
+ sys.exit(2)
+ self.newtool.requirements = requirements
+ if self.args.parampass == "0":
+ self.doNoXMLparam()
+ else:
+ self.doXMLparam()
+ self.newtool.outputs = self.toutputs
+ self.newtool.inputs = self.tinputs
+ if self.args.script_path:
+ configfiles = gxtp.Configfiles()
+ configfiles.append(
+ gxtp.Configfile(name="runme", text="\n".join(self.escapedScript))
+ )
+ self.newtool.configfiles = configfiles
+ tests = gxtp.Tests()
+ test_a = gxtp.Test()
+ for tp in self.testparam:
+ test_a.append(tp)
+ tests.append(test_a)
+ self.newtool.tests = tests
+ self.newtool.add_comment(
+ "Created by %s at %s using the Galaxy Tool Factory."
+ % (self.args.user_email, timenow())
+ )
+ self.newtool.add_comment("Source in git at: %s" % (toolFactoryURL))
+ exml0 = self.newtool.export()
+ exml = exml0.replace(FAKEEXE, "") # temporary work around until PR accepted
+ if (
+ self.test_override
+ ): # cannot do this inside galaxyxml as it expects lxml objects for tests
+ part1 = exml.split("")[0]
+ part2 = exml.split("")[1]
+ fixed = "%s\n%s\n%s" % (part1, "\n".join(self.test_override), part2)
+ exml = fixed
+ with open("%s.xml" % self.tool_name, "w") as xf:
+ xf.write(exml)
+ xf.write("\n")
+ # galaxy history item
+
+ def writeShedyml(self):
+ """for planemo"""
+ yuser = self.args.user_email.split("@")[0]
+ yfname = os.path.join(self.tooloutdir, ".shed.yml")
+ yamlf = open(yfname, "w")
+ odict = {
+ "name": self.tool_name,
+ "owner": yuser,
+ "type": "unrestricted",
+ "description": self.args.tool_desc,
+ "synopsis": self.args.tool_desc,
+ "category": "TF Generated Tools",
+ }
+ yaml.dump(odict, yamlf, allow_unicode=True)
+ yamlf.close()
+
+ def makeTool(self):
+ """write xmls and input samples into place"""
+ if self.args.parampass == 0:
+ self.doNoXMLparam()
+ else:
+ self.makeXML()
+ if self.args.script_path:
+ stname = os.path.join(self.tooloutdir, self.sfile)
+ if not os.path.exists(stname):
+ shutil.copyfile(self.sfile, stname)
+ xreal = "%s.xml" % self.tool_name
+ xout = os.path.join(self.tooloutdir, xreal)
+ shutil.copyfile(xreal, xout)
+ xout = os.path.join(self.repdir, xreal)
+ shutil.copyfile(xreal, xout)
+ for p in self.infiles:
+ pth = p["name"]
+ dest = os.path.join(self.testdir, "%s_sample" % p["infilename"])
+ shutil.copyfile(pth, dest)
+ dest = os.path.join(
+ self.repdir, "%s_sample.%s" % (p["infilename"], p["format"])
+ )
+ shutil.copyfile(pth, dest)
+ dest = os.path.join(self.local_tools, self.tool_name)
+ shutil.copytree(self.tooloutdir,dest, dirs_exist_ok=True)
+
+ def makeToolTar(self, report_fail=False):
+ """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
+
+ for p in self.outfiles:
+ oname = p["name"]
+ tdest = os.path.join(self.testdir, "%s_sample" % oname)
+ src = os.path.join(self.testdir, oname)
+ if not os.path.isfile(tdest):
+ if os.path.isfile(src):
+ shutil.copyfile(src, tdest)
+ dest = os.path.join(self.repdir, "%s.sample.%s" % (oname,p['format']))
+ shutil.copyfile(src, dest)
+ else:
+ if report_fail:
+ print(
+ "###Tool may have failed - output file %s not found in testdir after planemo run %s."
+ % (tdest, self.testdir)
+ )
+ tf = tarfile.open(self.newtarpath, "w:gz")
+ tf.add(
+ name=self.tooloutdir,
+ arcname=self.tool_name,
+ filter=exclude_function,
+ )
+ shutil.copy(self.newtarpath, os.path.join(self.tooloutdir, f"{self.tool_name}_untested_toolshed.gz"))
+ tf.close()
+
+
+ def planemo_test_update(self):
+ """planemo is a requirement so is available for testing
+ """
+ xreal = "%s.xml" % self.tool_name
+ tool_test_path = os.path.join(
+ self.repdir, f"{self.tool_name}_planemo_test_report.html"
+ )
+ if os.path.exists(self.tlog):
+ tout = open(self.tlog, "a")
+ else:
+ tout = open(self.tlog, "w")
+ cll = [
+ "planemo",
+ "test",
+ "--conda_auto_init",
+ "--biocontainers",
+ "--test_data",
+ os.path.abspath(self.testdir),
+ "--test_output",
+ os.path.abspath(tool_test_path),
+ "--galaxy_root",
+ self.args.galaxy_root,
+ "--update_test_data",
+ os.path.abspath(xreal),
+ ]
+ p = subprocess.run(
+ cll,
+ shell=False,
+ cwd=self.tooloutdir,
+ stderr=tout,
+ stdout=tout,
+ )
+ tout.close()
+ return p.returncode
+
+
+ def update_toolconf(self ):
+
+ def sortchildrenby(parent, attr):
+ parent[:] = sorted(parent, key=lambda child: child.get(attr))
+
+ tcpath = os.path.join(self.args.galaxy_root,'config/local_tool_conf.xml')
+ xmlfile = os.path.join(self.local_tools, self.tool_name, '%s.xml' % self.tool_name)
+ parser = ET.XMLParser(remove_blank_text=True)
+ tree = ET.parse(tcpath, parser)
+ root = tree.getroot()
+ hasTF = False
+ e = root.findall("section")
+ if len(e) > 0:
+ hasTF = True
+ TFsection = e[0]
+ if not hasTF:
+ TFsection = ET.Element("section", {"id":"localtools", "name":"Local Tools"})
+ root.insert(0, TFsection) # at the top!
+ our_tools = TFsection.findall("tool")
+ conf_tools = [x.attrib["file"] for x in our_tools]
+ if xmlfile not in conf_tools: # new
+ ET.SubElement(TFsection, "tool", {"file": xmlfile})
+ sortchildrenby(TFsection,"file")
+ tree.write(tcpath, pretty_print=True)
+
+
+
+
+
+
+ def shedLoad(self):
+ """
+ use bioblend to create new repository
+ or update existing
+
+ """
+ if os.path.exists(self.tlog):
+ sto = open(self.tlog, "a")
+ else:
+ sto = open(self.tlog, "w")
+
+ ts = toolshed.ToolShedInstance(
+ url=self.args.toolshed_url,
+ key=self.args.toolshed_api_key,
+ verify=False,
+ )
+ repos = ts.repositories.get_repositories()
+ rnames = [x.get("name", "?") for x in repos]
+ rids = [x.get("id", "?") for x in repos]
+ tfcat = "ToolFactory generated tools"
+ if self.tool_name not in rnames:
+ tscat = ts.categories.get_categories()
+ cnames = [x.get("name", "?").strip() for x in tscat]
+ cids = [x.get("id", "?") for x in tscat]
+ catID = None
+ if tfcat.strip() in cnames:
+ ci = cnames.index(tfcat)
+ catID = cids[ci]
+ res = ts.repositories.create_repository(
+ name=self.args.tool_name,
+ synopsis="Synopsis:%s" % self.args.tool_desc,
+ description=self.args.tool_desc,
+ type="unrestricted",
+ remote_repository_url=self.args.toolshed_url,
+ homepage_url=None,
+ category_ids=catID,
+ )
+ tid = res.get("id", None)
+ sto.write(f"#create_repository {self.args.tool_name} tid={tid} res={res}\n")
+ else:
+ i = rnames.index(self.tool_name)
+ tid = rids[i]
+ try:
+ res = ts.repositories.update_repository(
+ id=tid, tar_ball_path=self.newtarpath, commit_message=None
+ )
+ sto.write(f"#update res id {id} ={res}\n")
+ except ConnectionError:
+ sto.write(
+ "####### Is the toolshed running and the API key correct? Bioblend shed upload failed\n"
+ )
+ sto.close()
+
+ def eph_galaxy_load(self):
+ """
+ use ephemeris to load the new tool from the local toolshed after planemo uploads it
+ """
+ if os.path.exists(self.tlog):
+ tout = open(self.tlog, "a")
+ else:
+ tout = open(self.tlog, "w")
+ cll = [
+ "shed-tools",
+ "install",
+ "-g",
+ self.args.galaxy_url,
+ "--latest",
+ "-a",
+ self.args.galaxy_api_key,
+ "--name",
+ self.tool_name,
+ "--owner",
+ "fubar",
+ "--toolshed",
+ self.args.toolshed_url,
+ "--section_label",
+ "ToolFactory",
+ ]
+ tout.write("running\n%s\n" % " ".join(cll))
+ subp = subprocess.run(
+ cll,
+ env=self.ourenv,
+ cwd=self.ourcwd,
+ shell=False,
+ stderr=tout,
+ stdout=tout,
+ )
+ tout.write(
+ "installed %s - got retcode %d\n" % (self.tool_name, subp.returncode)
+ )
+ tout.close()
+ return subp.returncode
+
+ def planemo_biodocker_test(self):
+ """planemo currently leaks dependencies if used in the same container and gets unhappy after a
+ first successful run. https://github.com/galaxyproject/planemo/issues/1078#issuecomment-731476930
+
+ Docker biocontainer has planemo with caches filled to save repeated downloads
+
+
+ """
+
+ def prun(container, tout, cl, user="biodocker"):
+ rlog = container.exec_run(cl, user=user)
+ slogl = str(rlog).split("\\n")
+ slog = "\n".join(slogl)
+ tout.write(f"## got rlog {slog} from {cl}\n")
+
+ if os.path.exists(self.tlog):
+ tout = open(self.tlog, "a")
+ else:
+ tout = open(self.tlog, "w")
+ planemoimage = "quay.io/fubar2/planemo-biocontainer"
+ xreal = "%s.xml" % self.tool_name
+ repname = f"{self.tool_name}_planemo_test_report.html"
+ ptestrep_path = os.path.join(self.repdir, repname)
+ client = docker.from_env()
+ tvol = client.volumes.create()
+ tvolname = tvol.name
+ destdir = "/toolfactory/ptest"
+ imrep = os.path.join(destdir, repname)
+ # need to keep the container running so keep it open with sleep
+ # will stop and destroy it when we are done
+ container = client.containers.run(
+ planemoimage,
+ "sleep 120m",
+ detach=True,
+ user="biodocker",
+ volumes={f"{tvolname}": {"bind": "/toolfactory", "mode": "rw"}},
+ )
+ cl = f"mkdir -p {destdir}"
+ prun(container, tout, cl, user="root")
+ # that's how hard it is to get root on a biodocker container :(
+ cl = f"rm -rf {destdir}/*"
+ prun(container, tout, cl, user="root")
+ ptestpath = os.path.join(destdir, "tfout", xreal)
+ self.copy_to_container(self.tooloutdir, destdir, container)
+ cl = "chown -R biodocker /toolfactory"
+ prun(container, tout, cl, user="root")
+ _ = container.exec_run(f"ls -la {destdir}")
+ ptestcl = f"planemo test --test_output {imrep} --update_test_data --no_cleanup --test_data {destdir}/tfout/test-data --galaxy_root /home/biodocker/galaxy-central {ptestpath}"
+ try:
+ _ = container.exec_run(ptestcl)
+ # fails because test outputs missing but updates the test-data directory
+ except Exception:
+ e = sys.exc_info()[0]
+ tout.write(f"#### error: {e} from {ptestcl}\n")
+ cl = f"planemo test --test_output {imrep} --no_cleanup --test_data {destdir}/tfout/test-data --galaxy_root /home/biodocker/galaxy-central {ptestpath}"
+ try:
+ prun(container, tout, cl)
+ except Exception:
+ e = sys.exc_info()[0]
+ tout.write(f"#### error: {e} from {ptestcl}\n")
+ testouts = tempfile.mkdtemp(suffix=None, prefix="tftemp", dir=".")
+ self.copy_from_container(destdir, testouts, container)
+ src = os.path.join(testouts, "ptest")
+ if os.path.isdir(src):
+ shutil.copytree(src, ".", dirs_exist_ok=True)
+ src = repname
+ if os.path.isfile(repname):
+ shutil.copyfile(src, ptestrep_path)
+ else:
+ tout.write(f"No output from run to shutil.copytree in {src}\n")
+ tout.close()
+ container.stop()
+ container.remove()
+ tvol.remove()
+ shutil.rmtree(testouts) # leave for debugging
+
+
+ # def run(self):
+ # """
+ # scripts must be small enough not to fill the pipe!
+ # """
+ # if self.treatbashSpecial and self.opts.interpreter in ['bash','sh']:
+ # retval = self.runBash()
+ # else:
+ # if self.opts.output_dir:
+ # ste = open(self.elog,'w')
+ # sto = open(self.tlog,'w')
+ # sto.write('## Toolfactory generated command line = %s\n' % ' '.join(self.cl))
+ # sto.flush()
+ # p = subprocess.Popen(self.cl,shell=False,stdout=sto,stderr=ste,stdin=subprocess.PIPE,cwd=self.opts.output_dir)
+ # else:
+ # p = subprocess.Popen(self.cl,shell=False,stdin=subprocess.PIPE)
+ # p.stdin.write(self.script)
+ # p.stdin.close()
+ # retval = p.wait()
+ # if self.opts.output_dir:
+ # sto.close()
+ # ste.close()
+ # err = open(self.elog,'r').read()
+ # if retval <> 0 and err: # problem
+ # print >> sys.stderr, '## error code %d returned with:\n%s' % (retval,err)
+ # if self.opts.make_HTML:
+ # self.makeHtml()
+ # return retval
+
+ # def runBash(self):
+ # """
+ # cannot use - for bash so use self.sfile
+ # """
+ # if self.opts.output_dir:
+ # s = '## Toolfactory generated command line = %s\n' % ' '.join(self.cl)
+ # sto = open(self.tlog,'w')
+ # sto.write(s)
+ # sto.flush()
+ # p = subprocess.Popen(self.cl,shell=False,stdout=sto,stderr=sto,cwd=self.opts.output_dir)
+ # else:
+ # p = subprocess.Popen(self.cl,shell=False)
+ # retval = p.wait()
+ # if self.opts.output_dir:
+ # sto.close()
+ # if self.opts.make_HTML:
+ # self.makeHtml()
+ # return retval
+
+ # def make_conda_env(self, dep_list):
+ # """
+# (venv) galaxy@ross-newgrt:/evol/galaxy$ mulled-hash bioblend=0.17.0,galaxyxml=0.4.14
+# mulled-v2-37438395e15c3d0bed4e02d66d5b05ca3d18b389:1d0b008b65909163243b3fdddd9aa20605f8a005
+
+# conda create -n myenv python=3.9 scipy=0.17.3 astroid babel
+
+
+ # """
+ # dep_list.sort()
+ # self.env_name = '-'.join(dep_list)
+ # for e in self.xmlcl +
+
+ # for e in self.xclsuffix:
+ # # xappendme = ["999", p["infilename"], "< $%s" % p["infilename"]]
+ # else:
+ # xappendme = [p["CL"], "$%s" % p["infilename"], ""]
+ # xclsuffix.append(xappendme)
+ # if os.path.exists(self.tlog):
+ # tout = open(self.tlog, "a")
+ # else:
+ # tout = open(self.tlog, "w")
+ # cli = ["conda", "create", "-n", self.env_name, ' '.join(dep_list)]
+ # p = subprocess.run(
+ # cll,
+ # shell=False,
+ # cwd=self.tooloutdir,
+ # stderr=tout,
+ # stdout=tout,
+ # )
+ # cli = ["conda", "activate", self.env_name, " && "]
+ # cli.append(run_cmd)
+ # tout.close()
+
+def main():
+ """
+ This is a Galaxy wrapper.
+ It expects to be called by a special purpose tool.xml
+
+ """
+ parser = argparse.ArgumentParser()
+ a = parser.add_argument
+ a("--script_path", default=None)
+ a("--history_test", default=None)
+ a("--cl_user_suffix", default=None)
+ a("--sysexe", default=None)
+ a("--packages", default=None)
+ a("--tool_name", default="newtool")
+ a("--tool_dir", default=None)
+ a("--input_files", default=[], action="append")
+ a("--output_files", default=[], action="append")
+ a("--user_email", default="Unknown")
+ a("--bad_user", default=None)
+ a("--help_text", default=None)
+ a("--tool_desc", default=None)
+ a("--tool_version", default="0.01")
+ a("--citations", default=None)
+ a("--command_override", default=None)
+ a("--test_override", default=None)
+ a("--additional_parameters", action="append", default=[])
+ a("--selecttext_parameters", action="append", default=[])
+ a("--edit_additional_parameters", action="store_true", default=False)
+ a("--parampass", default="positional")
+ a("--tfout", default="./tfout")
+ a("--galaxy_root", default="/galaxy-central")
+ a("--galaxy_venv", default="/galaxy_venv")
+ a("--collection", action="append", default=[])
+ a("--include_tests", default=False, action="store_true")
+ a("--install_flag", action = "store_true", default=False)
+ a("--admin_only", default=True, action="store_true")
+ a("--untested_tool_out", default=None)
+ a("--local_tools", default="tools") # relative to $__root_dir__
+ a("--tool_conf_path", default="config/tool_conf.xml") # relative to $__root_dir__
+ args = parser.parse_args()
+ if args.admin_only:
+ assert not args.bad_user, (
+ 'UNAUTHORISED: %s is NOT authorized to use this tool until Galaxy \
+admin adds %s to "admin_users" in the galaxy.yml Galaxy configuration file'
+ % (args.bad_user, args.bad_user)
+ )
+ assert args.tool_name, "## This ToolFactory cannot build a tool without a tool name. Please supply one."
+ tf = Tool_Factory(args)
+ tf.writeShedyml()
+ tf.makeTool()
+ tf.planemo_test_update()
+ tf.makeToolTar()
+ tf.update_toolconf()
+
+
+if __name__ == "__main__":
+ main()
diff -r 2beaae16651e -r 0183cad9d13b tacrev/test-data/tacrev_reversed_output_sample
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tacrev/test-data/tacrev_reversed_output_sample Thu Feb 22 10:48:01 2024 +0000
@@ -0,0 +1,1210 @@
+)(niam
+:"__niam__" == __eman__ fi
+
+
+)(fnocloot_etadpu.ft
+)(raTlooTekam.ft
+)(etadpu_tset_omenalp.ft
+)(looTekam.ft
+)(lmydehSetirw.ft
+)sgra(yrotcaF_looT = ft
+".eno ylppus esaelP .eman loot a tuohtiw loot a dliub tonnac yrotcaFlooT sihT ##" ,eman_loot.sgra tressa
+)
+)resu_dab.sgra ,resu_dab.sgra( %
+'elif noitarugifnoc yxalaG lmy.yxalag eht ni "sresu_nimda" ot s% sdda nimda
+\ yxalaG litnu loot siht esu ot dezirohtua TON si s% :DESIROHTUANU'
+( ,resu_dab.sgra ton tressa
+:ylno_nimda.sgra fi
+)(sgra_esrap.resrap = sgra
+__rid_toor__$ ot evitaler # )"lmx.fnoc_loot/gifnoc"=tluafed ,"htap_fnoc_loot--"(a
+__rid_toor__$ ot evitaler # )"sloot"=tluafed ,"sloot_lacol--"(a
+)enoN=tluafed ,"tuo_loot_detsetnu--"(a
+)"eurt_erots"=noitca ,eurT=tluafed ,"ylno_nimda--"(a
+)eslaF=tluafed ,"eurt_erots" = noitca ,"galf_llatsni--"(a
+)"eurt_erots"=noitca ,eslaF=tluafed ,"stset_edulcni--"(a
+)][=tluafed ,"dneppa"=noitca ,"noitcelloc--"(a
+)"vnev_yxalag/"=tluafed ,"vnev_yxalag--"(a
+)"lartnec-yxalag/"=tluafed ,"toor_yxalag--"(a
+)"tuoft/."=tluafed ,"tuoft--"(a
+)"lanoitisop"=tluafed ,"ssapmarap--"(a
+)eslaF=tluafed ,"eurt_erots"=noitca ,"sretemarap_lanoitidda_tide--"(a
+)][=tluafed ,"dneppa"=noitca ,"sretemarap_txettceles--"(a
+)][=tluafed ,"dneppa"=noitca ,"sretemarap_lanoitidda--"(a
+)enoN=tluafed ,"edirrevo_tset--"(a
+)enoN=tluafed ,"edirrevo_dnammoc--"(a
+)enoN=tluafed ,"snoitatic--"(a
+)"10.0"=tluafed ,"noisrev_loot--"(a
+)enoN=tluafed ,"csed_loot--"(a
+)enoN=tluafed ,"txet_pleh--"(a
+)enoN=tluafed ,"resu_dab--"(a
+)"nwonknU"=tluafed ,"liame_resu--"(a
+)"dneppa"=noitca ,][=tluafed ,"selif_tuptuo--"(a
+)"dneppa"=noitca ,][=tluafed ,"selif_tupni--"(a
+)enoN=tluafed ,"rid_loot--"(a
+)"lootwen"=tluafed ,"eman_loot--"(a
+)enoN=tluafed ,"segakcap--"(a
+)enoN=tluafed ,"exesys--"(a
+)enoN=tluafed ,"xiffus_resu_lc--"(a
+)enoN=tluafed ,"tset_yrotsih--"(a
+)enoN=tluafed ,"htap_tpircs--"(a
+tnemugra_dda.resrap = a
+)(resraPtnemugrA.esrapgra = resrap
+"""
+
+lmx.loot esoprup laiceps a yb dellac eb ot stcepxe tI
+.repparw yxalaG a si sihT
+"""
+:)(niam fed
+
+)(esolc.tuot #
+)dmc_nur(dneppa.ilc #
+]" && " ,eman_vne.fles ,"etavitca" ,"adnoc"[ = ilc #
+) #
+,tuot=tuodts #
+,tuot=rredts #
+,ridtuoloot.fles=dwc #
+,eslaF=llehs #
+,llc #
+(nur.ssecorpbus = p #
+])tsil_ped(nioj.' ' ,eman_vne.fles ,"n-" ,"etaerc" ,"adnoc"[ = ilc #
+)"w" ,golt.fles(nepo = tuot #
+:esle #
+)"a" ,golt.fles(nepo = tuot #
+:)golt.fles(stsixe.htap.so fi #
+)emdneppax(dneppa.xiffuslcx #
+]"" ,]"emanelifni"[p % "s%$" ,]"LC"[p[ = emdneppax #
+:esle #
+]]"emanelifni"[p % "s%$ <" ,]"emanelifni"[p ,"999"[ = emdneppax # #
+:xiffuslcx.fles ni e rof #
+
++ lclmx.fles ni e rof #
+)tsil_ped(nioj.'-' = eman_vne.fles #
+)(tros.tsil_ped #
+""" #
+
+
+lebab diortsa 3.71.0=ypics 9.3=nohtyp vneym n- etaerc adnoc #
+
+500a8f50602aa9ddddf3b34236190956b800b0d1:983b81d3ac50b5d66d20e4deb0d3c51e59383473-2v-dellum #
+41.4.0=lmxyxalag,0.71.0=dnelboib hsah-dellum $yxalag/love/:trgwen-ssor@yxalag )vnev( #
+""" #
+:)tsil_ped ,fles(vne_adnoc_ekam fed #
+
+lavter nruter #
+)(lmtHekam.fles #
+:LMTH_ekam.stpo.fles fi #
+)(esolc.ots #
+:rid_tuptuo.stpo.fles fi #
+)(tiaw.p = lavter #
+)eslaF=llehs,lc.fles(nepoP.ssecorpbus = p #
+:esle #
+)rid_tuptuo.stpo.fles=dwc,ots=rredts,ots=tuodts,eslaF=llehs,lc.fles(nepoP.ssecorpbus = p #
+)(hsulf.ots #
+)s(etirw.ots #
+)'w',golt.fles(nepo = ots #
+)lc.fles(nioj.' ' % 'n\s% = enil dnammoc detareneg yrotcaflooT ##' = s #
+:rid_tuptuo.stpo.fles fi #
+""" #
+elifs.fles esu os hsab rof - esu tonnac #
+""" #
+:)fles(hsaBnur fed #
+
+lavter nruter #
+)(lmtHekam.fles #
+:LMTH_ekam.stpo.fles fi #
+)rre,lavter( % 's%n\:htiw denruter d% edoc rorre ##' ,rredts.sys >> tnirp #
+melborp # :rre dna 0 >< lavter fi #
+)(daer.)'r',gole.fles(nepo = rre #
+)(esolc.ets #
+)(esolc.ots #
+:rid_tuptuo.stpo.fles fi #
+)(tiaw.p = lavter #
+)(esolc.nidts.p #
+)tpircs.fles(etirw.nidts.p #
+)EPIP.ssecorpbus=nidts,eslaF=llehs,lc.fles(nepoP.ssecorpbus = p #
+:esle #
+)rid_tuptuo.stpo.fles=dwc,EPIP.ssecorpbus=nidts,ets=rredts,ots=tuodts,eslaF=llehs,lc.fles(nepoP.ssecorpbus = p #
+)(hsulf.ots #
+))lc.fles(nioj.' ' % 'n\s% = enil dnammoc detareneg yrotcaflooT ##'(etirw.ots #
+)'w',golt.fles(nepo = ots #
+)'w',gole.fles(nepo = ets #
+:rid_tuptuo.stpo.fles fi #
+:esle #
+)(hsaBnur.fles = lavter #
+:]'hs','hsab'[ ni reterpretni.stpo.fles dna laicepShsabtaert.fles fi #
+""" #
+!epip eht llif ot ton hguone llams eb tsum stpircs #
+""" #
+:)fles(nur fed #
+
+
+gniggubed rof evael # )stuotset(eertmr.lituhs
+)(evomer.lovt
+)(evomer.reniatnoc
+)(pots.reniatnoc
+)(esolc.tuot
+)"n\}crs{ ni eertypoc.lituhs ot nur morf tuptuo oN"f(etirw.tuot
+:esle
+)htap_pertsetp ,crs(elifypoc.lituhs
+:)emanper(elifsi.htap.so fi
+emanper = crs
+)eurT=ko_tsixe_srid ,"." ,crs(eertypoc.lituhs
+:)crs(ridsi.htap.so fi
+)"tsetp" ,stuotset(nioj.htap.so = crs
+)reniatnoc ,stuotset ,ridtsed(reniatnoc_morf_ypoc.fles
+)"."=rid ,"pmetft"=xiferp ,enoN=xiffus(pmetdkm.elifpmet = stuotset
+)"n\}lctsetp{ morf }e{ :rorre ####"f(etirw.tuot
+]0[)(ofni_cxe.sys = e
+:noitpecxE tpecxe
+)lc ,tuot ,reniatnoc(nurp
+:yrt
+"}htaptsetp{ lartnec-yxalag/rekcodoib/emoh/ toor_yxalag-- atad-tset/tuoft/}ridtsed{ atad_tset-- punaelc_on-- }permi{ tuptuo_tset-- tset omenalp"f = lc
+)"n\}lctsetp{ morf }e{ :rorre ####"f(etirw.tuot
+]0[)(ofni_cxe.sys = e
+:noitpecxE tpecxe
+yrotcerid atad-tset eht setadpu tub gnissim stuptuo tset esuaceb sliaf #
+)lctsetp(nur_cexe.reniatnoc = _
+:yrt
+"}htaptsetp{ lartnec-yxalag/rekcodoib/emoh/ toor_yxalag-- atad-tset/tuoft/}ridtsed{ atad_tset-- punaelc_on-- atad_tset_etadpu-- }permi{ tuptuo_tset-- tset omenalp"f = lctsetp
+)"}ridtsed{ al- sl"f(nur_cexe.reniatnoc = _
+)"toor"=resu ,lc ,tuot ,reniatnoc(nurp
+"yrotcafloot/ rekcodoib R- nwohc" = lc
+)reniatnoc ,ridtsed ,ridtuoloot.fles(reniatnoc_ot_ypoc.fles
+)laerx ,"tuoft" ,ridtsed(nioj.htap.so = htaptsetp
+)"toor"=resu ,lc ,tuot ,reniatnoc(nurp
+"*/}ridtsed{ fr- mr"f = lc
+(: reniatnoc rekcodoib a no toor teg ot si ti drah woh s'taht #
+)"toor"=resu ,lc ,tuot ,reniatnoc(nurp
+"}ridtsed{ p- ridkm"f = lc
+)
+,}}"wr" :"edom" ,"yrotcafloot/" :"dnib"{ :"}emanlovt{"f{=semulov
+,"rekcodoib"=resu
+,eurT=hcated
+,"m021 peels"
+,egamiomenalp
+(nur.sreniatnoc.tneilc = reniatnoc
+enod era ew nehw ti yortsed dna pots lliw #
+peels htiw nepo ti peek os gninnur reniatnoc eht peek ot deen #
+)emanper ,ridtsed(nioj.htap.so = permi
+"tsetp/yrotcafloot/" = ridtsed
+eman.lovt = emanlovt
+)(etaerc.semulov.tneilc = lovt
+)(vne_morf.rekcod = tneilc
+)emanper ,ridper.fles(nioj.htap.so = htap_pertsetp
+"lmth.troper_tset_omenalp_}eman_loot.fles{"f = emanper
+eman_loot.fles % "lmx.s%" = laerx
+"reniatnocoib-omenalp/2rabuf/oi.yauq" = egamiomenalp
+)"w" ,golt.fles(nepo = tuot
+:esle
+)"a" ,golt.fles(nepo = tuot
+:)golt.fles(stsixe.htap.so fi
+
+)"n\}lc{ morf }gols{ golr tog ##"f(etirw.tuot
+)lgols(nioj."n\" = gols
+)"n\\"(tilps.)golr(rts = lgols
+)resu=resu ,lc(nur_cexe.reniatnoc = golr
+:)"rekcodoib"=resu ,lc ,tuot ,reniatnoc(nurp fed
+
+"""
+
+
+sdaolnwod detaeper evas ot dellif sehcac htiw omenalp sah reniatnocoib rekcoD
+
+039674137-tnemmoceussi#8701/seussi/omenalp/tcejorpyxalag/moc.buhtig//:sptth .nur lufsseccus tsrif
+a retfa yppahnu steg dna reniatnoc emas eht ni desu fi seicnedneped skael yltnerruc omenalp"""
+:)fles(tset_rekcodoib_omenalp fed
+
+edocnruter.pbus nruter
+)(esolc.tuot
+)
+)edocnruter.pbus ,eman_loot.fles( % "n\d% edocter tog - s% dellatsni"
+(etirw.tuot
+)
+,tuot=tuodts
+,tuot=rredts
+,eslaF=llehs
+,dwcruo.fles=dwc
+,vneruo.fles=vne
+,llc
+(nur.ssecorpbus = pbus
+))llc(nioj." " % "n\s%n\gninnur"(etirw.tuot
+]
+,"yrotcaFlooT"
+,"lebal_noitces--"
+,lru_dehsloot.sgra.fles
+,"dehsloot--"
+,"rabuf"
+,"renwo--"
+,eman_loot.fles
+,"eman--"
+,yek_ipa_yxalag.sgra.fles
+,"a-"
+,"tsetal--"
+,lru_yxalag.sgra.fles
+,"g-"
+,"llatsni"
+,"sloot-dehs"
+[ = llc
+)"w" ,golt.fles(nepo = tuot
+:esle
+)"a" ,golt.fles(nepo = tuot
+:)golt.fles(stsixe.htap.so fi
+"""
+ti sdaolpu omenalp retfa dehsloot lacol eht morf loot wen eht daol ot siremehpe esu
+"""
+:)fles(daol_yxalag_hpe fed
+
+)(esolc.ots
+)
+"n\deliaf daolpu dehs dnelboiB ?tcerroc yek IPA eht dna gninnur dehsloot eht sI #######"
+(etirw.ots
+:rorrEnoitcennoC tpecxe
+)"n\}ser{= }di{ di ser etadpu#"f(etirw.ots
+)
+enoN=egassem_timmoc ,htapratwen.fles=htap_llab_rat ,dit=di
+(yrotisoper_etadpu.seirotisoper.st = ser
+:yrt
+]i[sdir = dit
+)eman_loot.fles(xedni.semanr = i
+:esle
+)"n\}ser{=ser }dit{=dit }eman_loot.sgra.fles{ yrotisoper_etaerc#"f(etirw.ots
+)enoN ,"di"(teg.ser = dit
+)
+,DItac=sdi_yrogetac
+,enoN=lru_egapemoh
+,lru_dehsloot.sgra.fles=lru_yrotisoper_etomer
+,"detcirtsernu"=epyt
+,csed_loot.sgra.fles=noitpircsed
+,csed_loot.sgra.fles % "s%:sisponyS"=sisponys
+,eman_loot.sgra.fles=eman
+(yrotisoper_etaerc.seirotisoper.st = ser
+]ic[sdic = DItac
+)tacft(xedni.semanc = ic
+:semanc ni )(pirts.tacft fi
+enoN = DItac
+]tacst ni x rof )"?" ,"di"(teg.x[ = sdic
+]tacst ni x rof )(pirts.)"?" ,"eman"(teg.x[ = semanc
+)(seirogetac_teg.seirogetac.st = tacst
+:semanr ni ton eman_loot.fles fi
+"sloot detareneg yrotcaFlooT" = tacft
+]soper ni x rof )"?" ,"di"(teg.x[ = sdir
+]soper ni x rof )"?" ,"eman"(teg.x[ = semanr
+)(seirotisoper_teg.seirotisoper.st = soper
+)
+,eslaF=yfirev
+,yek_ipa_dehsloot.sgra.fles=yek
+,lru_dehsloot.sgra.fles=lru
+(ecnatsnIdehSlooT.dehsloot = st
+
+)"w" ,golt.fles(nepo = ots
+:esle
+)"a" ,golt.fles(nepo = ots
+:)golt.fles(stsixe.htap.so fi
+"""
+
+gnitsixe etadpu ro
+yrotisoper wen etaerc ot dnelboib esu
+"""
+:)fles(daoLdehs fed
+
+
+
+
+
+
+)eurT=tnirp_ytterp ,htapct(etirw.eert
+)"elif",noitcesFT(ybnerdlihctros
+)}eliflmx :"elif"{ ,"loot" ,noitcesFT(tnemelEbuS.TE
+wen # :sloot_fnoc ni ton eliflmx fi
+]sloot_ruo ni x rof ]"elif"[birtta.x[ = sloot_fnoc
+)"loot"(lladnif.noitcesFT = sloot_ruo
+!pot eht ta # )noitcesFT ,0(tresni.toor
+)}"slooT lacoL":"eman" ,"slootlacol":"di"{ ,"noitces"(tnemelE.TE = noitcesFT
+:FTsah ton fi
+]0[e = noitcesFT
+eurT = FTsah
+:0 > )e(nel fi
+)"noitces"(lladnif.toor = e
+eslaF = FTsah
+)(toorteg.eert = toor
+)resrap ,htapct(esrap.TE = eert
+)eurT=txet_knalb_evomer(resraPLMX.TE = resrap
+)eman_loot.fles % 'lmx.s%' ,eman_loot.fles ,sloot_lacol.fles(nioj.htap.so = eliflmx
+)'lmx.fnoc_loot_lacol/gifnoc',toor_yxalag.sgra.fles(nioj.htap.so = htapct
+
+))rtta(teg.dlihc :dlihc adbmal=yek ,tnerap(detros = ]:[tnerap
+:)rtta ,tnerap(ybnerdlihctros fed
+
+:) fles(fnocloot_etadpu fed
+
+
+edocnruter.p nruter
+)(esolc.tuot
+)
+,tuot=tuodts
+,tuot=rredts
+,ridtuoloot.fles=dwc
+,eslaF=llehs
+,llc
+(nur.ssecorpbus = p
+]
+,)laerx(htapsba.htap.so
+,"atad_tset_etadpu--"
+,toor_yxalag.sgra.fles
+,"toor_yxalag--"
+,)htap_tset_loot(htapsba.htap.so
+,"tuptuo_tset--"
+,)ridtset.fles(htapsba.htap.so
+,"atad_tset--"
+,"sreniatnocoib--"
+,"tini_otua_adnoc--"
+,"tset"
+,"omenalp"
+[ = llc
+)"w" ,golt.fles(nepo = tuot
+:esle
+)"a" ,golt.fles(nepo = tuot
+:)golt.fles(stsixe.htap.so fi
+)
+"lmth.troper_tset_omenalp_}eman_loot.fles{"f ,ridper.fles
+(nioj.htap.so = htap_tset_loot
+eman_loot.fles % "lmx.s%" = laerx
+"""
+gnitset rof elbaliava si os tnemeriuqer a si omenalp"""
+:)fles(etadpu_tset_omenalp fed
+
+
+)(esolc.ft
+))"zg.dehsloot_detsetnu_}eman_loot.fles{"f ,ridtuoloot.fles(nioj.htap.so ,htapratwen.fles(ypoc.lituhs
+)
+,noitcnuf_edulcxe=retlif
+,eman_loot.fles=emancra
+,ridtuoloot.fles=eman
+(dda.ft
+)"zg:w" ,htapratwen.fles(nepo.elifrat = ft
+)
+)ridtset.fles ,tsedt( %
+".s% nur omenalp retfa ridtset ni dnuof ton s% elif tuptuo - deliaf evah yam looT###"
+(tnirp
+:liaf_troper fi
+:esle
+)tsed ,crs(elifypoc.lituhs
+))]'tamrof'[p,emano( % "s%.elpmas.s%" ,ridper.fles(nioj.htap.so = tsed
+)tsedt ,crs(elifypoc.lituhs
+:)crs(elifsi.htap.so fi
+:)tsedt(elifsi.htap.so ton fi
+)emano ,ridtset.fles(nioj.htap.so = crs
+)emano % "elpmas_s%" ,ridtset.fles(nioj.htap.so = tsedt
+]"eman"[p = emano
+:seliftuo.fles ni p rof
+
+ofnirat esle )emedulcxe(htiwsdne.emanelif fi enoN nruter
+eman.ofnirat = emanelif
+:)ofnirat(noitcnuf_edulcxe fed
+
+"lmth.troper_tset_omenalp_" = emedulcxe
+"""llabrat eht eraperp dna atad-tset otni stuptuo evom"""
+:)eslaF=liaf_troper ,fles(raTlooTekam fed
+
+)eurT=ko_tsixe_srid ,tsed,ridtuoloot.fles(eertypoc.lituhs
+)eman_loot.fles ,sloot_lacol.fles(nioj.htap.so = tsed
+)tsed ,htp(elifypoc.lituhs
+)
+)]"tamrof"[p ,]"emanelifni"[p( % "s%.elpmas_s%" ,ridper.fles
+(nioj.htap.so = tsed
+)tsed ,htp(elifypoc.lituhs
+)]"emanelifni"[p % "elpmas_s%" ,ridtset.fles(nioj.htap.so = tsed
+]"eman"[p = htp
+:selifni.fles ni p rof
+)tuox ,laerx(elifypoc.lituhs
+)laerx ,ridper.fles(nioj.htap.so = tuox
+)tuox ,laerx(elifypoc.lituhs
+)laerx ,ridtuoloot.fles(nioj.htap.so = tuox
+eman_loot.fles % "lmx.s%" = laerx
+)emants ,elifs.fles(elifypoc.lituhs
+:)emants(stsixe.htap.so ton fi
+)elifs.fles ,ridtuoloot.fles(nioj.htap.so = emants
+:htap_tpircs.sgra.fles fi
+)(LMXekam.fles
+:esle
+)(marapLMXoNod.fles
+:0 == ssapmarap.sgra.fles fi
+"""ecalp otni selpmas tupni dna slmx etirw"""
+:)fles(looTekam fed
+
+)(esolc.flmay
+)eurT=edocinu_wolla ,flmay ,tcido(pmud.lmay
+}
+,"slooT detareneG FT" :"yrogetac"
+,csed_loot.sgra.fles :"sisponys"
+,csed_loot.sgra.fles :"noitpircsed"
+,"detcirtsernu" :"epyt"
+,resuy :"renwo"
+,eman_loot.fles :"eman"
+{ = tcido
+)"w" ,emanfy(nepo = flmay
+)"lmy.dehs." ,ridtuoloot.fles(nioj.htap.so = emanfy
+]0[)"@"(tilps.liame_resu.sgra.fles = resuy
+"""omenalp rof"""
+:)fles(lmydehSetirw fed
+
+meti yrotsih yxalag #
+)"n\"(etirw.fx
+)lmxe(etirw.fx
+:fx sa )"w" ,eman_loot.fles % "lmx.s%"(nepo htiw
+dexif = lmxe
+)2trap ,)edirrevo_tset.fles(nioj."n\" ,1trap( % "s%n\s%n\s%" = dexif
+]1[)">stset/<"(tilps.lmxe = 2trap
+]0[)">stset<"(tilps.lmxe = 1trap
+stset rof stcejbo lmxl stcepxe ti sa lmxyxalag edisni siht od tonnac # :)
+edirrevo_tset.fles
+( fi
+detpecca RP litnu dnuora krow yraropmet # )"" ,EXEEKAF(ecalper.0lmxe = lmxe
+)(tropxe.lootwen.fles = 0lmxe
+))LRUyrotcaFloot( % "s% :ta tig ni ecruoS"(tnemmoc_dda.lootwen.fles
+)
+))(wonemit ,liame_resu.sgra.fles( %
+".yrotcaF looT yxalaG eht gnisu s% ta s% yb detaerC"
+(tnemmoc_dda.lootwen.fles
+stset = stset.lootwen.fles
+)a_tset(dneppa.stset
+)pt(dneppa.a_tset
+:maraptset.fles ni pt rof
+)(tseT.ptxg = a_tset
+)(stseT.ptxg = stset
+selifgifnoc = selifgifnoc.lootwen.fles
+)
+))tpircSdepacse.fles(nioj."n\"=txet ,"emnur"=eman(elifgifnoC.ptxg
+(dneppa.selifgifnoc
+)(selifgifnoC.ptxg = selifgifnoc
+:htap_tpircs.sgra.fles fi
+stupnit.fles = stupni.lootwen.fles
+stuptuot.fles = stuptuo.lootwen.fles
+)(marapLMXod.fles
+:esle
+)(marapLMXoNod.fles
+:"0" == ssapmarap.sgra.fles fi
+stnemeriuqer = stnemeriuqer.lootwen.fles
+)2(tixe.sys
+)
+,segakcap.sgra.fles
+,"= esrap tonnac - deilppus gnirts segakcap demroflam ###"
+(tnirp
+:noitpecxE tpecxe
+)d(dneppa.vneadnoc.fles
+)
+)rev ,)(pirts.gkcap ,"egakcap"(tnemeriuqeR.ptxg
+(dneppa.stnemeriuqer
+:gkcap fi
+enoN = rev
+:"" == rev fi
+enoN = rev
+)(pirts.d = gkcap
+:esle
+)(pirts.gkcap = gkcap
+)(pirts.rev = rev
+)":"(tilps.d = rev ,gkcap
+:d ni ":" fi
+)":" ,"="(ecalper.d = d
+)":" ,"=="(ecalper.d = d
+enoN = gkcap
+enoN = rev
+:)","(tilps.segakcap.sgra.fles ni d rof
+:yrt
+:segakcap.sgra.fles fi
+][ = vneadnoc.fles
+)(stnemeriuqeR.ptxg = stnemeriuqer
+dts = soidts.lootwen.fles
+)1dts(dneppa.dts
+)(oidtS.ptxg = 1dts
+)(soidtS.ptxg = dts
+'"}noisrev_loot.sgra.fles{" ohce'f = dnammoc_noisrev.lootwen.fles
+txetrefas = pleh.lootwen.fles
+)rcs(nioj."n\" + txetrefas = txetrefas
+)"n\"(dneppa.rcs
+)
+]:001-[rcs +
+]"...... " ,"deteled ffuts - senil 003> "[ +
+]001:[rcs
+( = rcs
+:003 > )rcs(nel fi
+)"n\::tpircSn\n\" ,0(tresni.rcs
+]"" > )(pirts.x fi tpircSdecaps.fles ni x rof x[ = rcs
+!dewolla noitisnart # "n\------n\n\" + txetrefas = txetrefas
+:0 > )txetrefas(nel fi
+:htap_tpircs.sgra.fles fi
+)
+)liame_resu.sgra.fles( %
+"n\esaelp txet pleh htiw dliuber ot )s%( rohtua loot eht ksA"
+( = txetrefas
+:0 == ))(pirts.txetrefas(nel fi
+)]txetpleh ni x rof )x(epacse_hateehc[(nioj."n\" = txetrefas
+)(senildaer.)"r" ,txet_pleh.sgra.fles(nepo = txetpleh
+:txet_pleh.sgra.fles fi
+"" = txetrefas
+etic = snoitatic.lootwen.fles
+)etica(dneppa.etic
+)"375stb/scitamrofnioib/3901.01"=eulav ,"iod"=epyt(noitatiC.ptxg = etica
+)(snoitatiC.ptxg = etic
+lclmx.fles = edirrevo_dnammoc.lootwen.fles
+:esle
+elif gifnoc # edirrevo_dnammoc.fles = edirrevo_dnammoc.lootwen.fles
+:edirrevo_dnammoc.fles fi
+"""
+...redro tcerroc otni enil dnammoc eht teg ot woH .mmmH
+lmthyxalag sesU
+tpircs wen eht rof repparw loot lmx yxalaG a etaerC
+"""
+aqon # :)fles(LMXekam fed
+
+)pt(dneppa.maraptset.fles
+)emanwen % "elpmas_s%"=eulav ,emanwen=eman(tuptuOtseT.ptxg = pt
+)tuona(dneppa.stuptuot.fles
+lanoitisop_si.fles = lanoitisop.tuona
+emanwen % "s%$ >" = edirrevo_enil_dnammoc.tuona
+)0=sehsad_mun ,tmfwen=tamrof ,emanwen(ataDtuptuO.ptxg = tuona
+]"tamrof"[]0[seliftuo.fles = tmfwen
+]"eman"[]0[seliftuo.fles = emanwen
+:0 > )seliftuo.fles(nel fi
+)pt(dneppa.maraptset.fles
+)emanwen % "elpmas_s%"=eulav ,emanwen=eman(maraPtseT.ptxg = pt
+)tupnina(dneppa.stupnit.fles
+eurT = lanoitisop.tupnina
+emanwen % "s%$ <" = edirrevo_enil_dnammoc.tupnina
+)
+,0=sehsad_mun
+,eslaF=elpitlum
+,]"tamrof"[]0[selifni.fles=tamrof
+,]"pleh"[]0[selifni.fles=pleh
+,bala=lebal
+,eslaF=lanoitpo
+,emanwen
+(maraPataD.ptxg = tupnina
+]"emanelifni"[]0[selifni.fles = emanwen
+s1xam ,1 == )selifni.fles(nel tressa
+)
+)selifni.fles(rts %
+"s% - deilppus selif tupni elpitlum tub 0 si ssapmarap fi tupni eno mumixaM"
+( = s1xam
+]"emanelifni"[]0[selifni.fles = bala
+:0 == )bala(nel fi
+]"lebal"[]0[selifni.fles = bala
+:0 > )selifni.fles(nel fi
+"""tuodts ot nidts - egakcap elyts retlif"""
+:)fles(marapLMXoNod fed
+
+)
+"!neht litnu neddir-revo eb tsum snoitcelloc rof stset - tey degrem RP eht evah ton seod noisrev lmxyxalaG :GNINRAW ####"
+(tnirp
+:noitpecxE tpecxe
+)mrapt(dneppa.maraptset.fles
+.degrem RP litnu nekorb # )emanwen(noitcelloCtuptuOtseT.ptxg = mrapt
+:yrt
+)tcelloc(dneppa.stuptuot.fles
+)csid(dneppa.tcelloc
+)
+"eslaf"=elbisiv ,"}emanwen{"f=yrotcerid ,csidwen=nrettap
+(stesataDrevocsiD.ptxg = csid
+)dnikwen=epyt ,lebalwen=lebal ,emanwen(noitcelloCtuptuO.ptxg = tcelloc
+]"revocsid"[p = csidwen
+]"lebal"[p = lebalwen
+]"eman"[p = emanwen
+]"dnik"[p = dnikwen
+:snoitcelloc.fles ni p rof
+)
+)emanwen ,epytwen( %
+'LMXekam ni s% retemarap txettceles
+\rof "s%" epyt retemarap desingocernU'
+(rorrEeulaV esiar
+:esle
+)mrapt(dneppa.maraptset.fles
+)lavwen=eulav ,emanwen(maraPtseT.ptxg = mrapt
+)mrapa(dneppa.stupnit.fles
+)lcwen(tni = lanoitisop.mrapa
+:lanoitisop_si.fles fi
+lanoitisop_si.fles = lanoitisop.mrapa
+)tpona(dneppa.mrapa
+)
+,]i[txetwen=txet
+,]i[lavwen=eulav
+(noitpOtceleS.ptxg = tpona
+:))lavwen(nel(egnar ni i rof
+)
+,hsadn=sehsad_mun
+,plehwen=pleh
+,lebalwen=lebal
+,emanwen
+(maraPtceleS.ptxg = mrapa
+]"stxet"[p = txetwen
+:"txettceles" == epytwen fi
+)emanwen(hsadNteg.fles = hsadn
+emanwen = lebalwen
+:0 > )lebalwen(nel ton fi
+]"LC"[p = lcwen
+]"epyt"[p = epytwen
+]"pleh"[p = plehwen
+]"lebal"[p = lebalwen
+]"eulav"[p = lavwen
+]"eman"[p = emanwen
+:raples.fles ni p rof
+)mrapt(dneppa.maraptset.fles
+)lavwen=eulav ,emanwen(maraPtseT.ptxg = mrapt
+)mrapa(dneppa.stupnit.fles
+:esle
+)mrapt(dneppa.maraptset.fles
+)2mrapt(dneppa.mrapt
+)lavwen=eulav ,emanwen(maraPtseT.ptxg = 2mrapt
+)"}emanwen{_R"f=eman(taepeRtseT.ptxg = mrapt
+)eper(dneppa.stupnit.fles
+)mrapa(dneppa.eper
+)
+"dedeen sa }lebalwen{ ynam sa ddA"f=eltit ,"}emanwen{_R"f=eman
+(taepeR.ptxg = eper
+:sper fi
+)lcdlo(tni = lanoitisop.mrapa
+:lanoitisop_si.fles fi
+lanoitisop_si.fles = lanoitisop.mrapa
+)
+)emanwen ,epytwen( %
+'LMXekam ni s% retemarap lanoitidda
+\rof "s%" epyt retemarap desingocernU'
+(rorrEeulaV esiar
+:esle
+)
+,hsadn=sehsad_mun
+,lavwen=eulav
+,plehwen=pleh
+,lebalwen=lebal
+,emanwen
+(maraPnaelooB.ptxg = mrapa
+:"naeloob" == epytwen file
+)
+,hsadn=sehsad_mun
+,lavwen=eulav
+,plehwen=pleh
+,lebalwen=lebal
+,emanwen
+(maraPtaolF.ptxg = mrapa
+:"taolf" == epytwen file
+)
+,hsadn=sehsad_mun
+,lavwen=eulav
+,plehwen=pleh
+,lebalwen=lebal
+,emanwen
+(maraPregetnI.ptxg = mrapa
+:"regetni" == epytwen file
+)
+,hsadn=sehsad_mun
+,lavwen=eulav
+,plehwen=pleh
+,lebalwen=lebal
+,emanwen
+(maraPtxeT.ptxg = mrapa
+:"txet" == epytwen fi
+)emanwen(hsadNteg.fles = hsadn
+emanwen = lebalwen
+:0 > )lebalwen(nel ton fi
+"1" == ]"taeper"[p = sper
+]"LCgiro"[p = lcdlo
+]"LC"[p = lcwen
+]"epyt"[p = epytwen
+]"pleh"[p = plehwen
+]"lebal"[p = lebalwen
+]"eulav"[p = lavwen
+]"eman"[p = emanwen
+:rapdda.fles ni p rof
+)mrapt(dneppa.maraptset.fles
+)emanwen % "elpmas_s%"=eulav ,emanwen(maraPtseT.ptxg = mrapt
+)tupnina(dneppa.stupnit.fles
+:esle
+)mrapt(dneppa.maraptset.fles
+)2mrapt(dneppa.mrapt
+)emanwen % "elpmas_s%"=eulav ,emanwen(maraPtseT.ptxg = 2mrapt
+)"}emanwen{_R"f=eman(taepeRtseT.ptxg = mrapt
+)eper(dneppa.stupnit.fles
+)tupnina(dneppa.eper
+)
+"dedeen sa }bala{ ynam sa ddA"f=eltit ,"}emanwen{_R"f=eman
+(taepeR.ptxg = eper
+:sper fi
+emanwen % "s%$" = edirrevo_enil_dnammoc.tupnina
+)]"LCgiro"[p(tni = lanoitisop.tupnina
+:esle
+emanwen % "s%$ <" = edirrevo_enil_dnammoc.tupnina
+8999999 = lanoitisop.tupnina
+:"NIDTS" == )(reppu.]"LCgiro"[p fi
+:lanoitisop_si.fles fi
+lanoitisop_si.fles = lanoitisop.tupnina
+)
+,hsadn=sehsad_mun
+,eslaF=elpitlum
+,tmfwen=tamrof
+,]"pleh"[p=pleh
+,bala=lebal
+,eslaF=lanoitpo
+,emanwen
+(maraPataD.ptxg = tupnina
+]"lebal"[p = bala
+:esle
+]"LC"[p = bala
+:0 > )]"lebal"[p(nel ton fi
+"1" == )"0" ,"taeper"(teg.p = sper
+)emanwen(hsadNteg.fles = hsadn
+]"tamrof"[p = tmfwen
+]"emanelifni"[p = emanwen
+:selifni.fles ni p rof
+)pt(dneppa.maraptset.fles
+)
+,c=erapmoc
+,emanwen % "elpmas_s%"=eulav
+,emanwen=eman
+(tuptuOtseT.ptxg = pt
+tset = c
+:esle
+)
+,carf_atled=carf_atled
+,atled=atled
+,c=erapmoc
+,emanwen % "elpmas_s%"=eulav
+,emanwen=eman
+(tuptuOtseT.ptxg = pt
+enoN = carf_atled
+)nt(tni = atled
+:esle
+))nt(taolf ,0.1(nim = carf_atled
+enoN = atled
+:nt ni "." fi
+:"" > nt fi
+)(pirts.]1[)":"(tilps.tset = nt
+"ezis_mis" = c
+:)"ezis_mis"(htiwstrats.tset file
+)
+,dl=ffid_senil
+,c=erapmoc
+,emanwen % "elpmas_s%"=eulav
+,emanwen=eman
+(tuptuOtseT.ptxg = pt
+)]1[)":"(tilps.tset(tni = dl
+:tigidsi.]1[)":"(tilps.tset fi
+0 = dl
+"ffid" = c
+:)"ffid"(htiwstrats.)(pirts.tset fi
+:"" > )(pirts.tset fi
+enoN = dl
+)mrapa(dneppa.stuptuot.fles
+emanwen % "s%$" = edirrevo_enil_dnammoc.mrapa
+)lcdlo(tni = lanoitisop.mrapa
+:esle
+emanwen % "s%$ >" = edirrevo_enil_dnammoc.mrapa
+9999999 = lanoitisop.mrapa
+:"TUODTS" == )(reppu.lcdlo fi
+:lanoitisop_si.fles fi
+lanoitisop_si.fles = lanoitisop.mrapa
+)
+emanwen=lebal ,hsadn=sehsad_mun ,tmfwen=tamrof ,emanwen=eman
+(ataDtuptuO.ptxg = mrapa
+)lcwen(hsadNteg.fles = hsadn
+)(pirts.tset = tset
+]"LCgiro"[p = lcdlo
+]"tset"[p = tset
+]"LC"[p = lcwen
+]"tamrof"[p = tmfwen
+]"eman"[p = emanwen
+:seliftuo.fles ni p rof
+"""loot ot stnemele dedeen lla ddA"""
+aqon # :)fles(marapLMXod fed
+
+hsadn nruter
+1 = hsadn
+:2 < )emanwen(nel fi
+2 = hsadn
+:esle
+0 = hsadn
+:lanoitisop_si.fles fi
+:)emanwen ,fles(hsadNteg fed
+
+)c(LCXa
+:plc ni c rof
+)xiffus_resu_lc.sgra.fles(tilps.xelhs = plc
+dne LC YID # :xiffus_resu_lc.sgra.fles fi
+)lc(LCXa
+:tceriderlcxtsal.fles ni lc rof
+:tceriderlcxtsal.fles fi
+)v(LCXa
+)k(LCXa
+k % "s%--" = k
+:esle
+k % "s%-" = k
+:1 == ))(pirts.k(nel fi
+:esle
+)k(LCXa
+edirrevok = k
+:"" > edirrevok fi
+:xiffuslcx.fles ni )edirrevok ,v ,k( rof
+
+mrof deman esrapgra ni smarap neht stupni #
+dneppa.lclmx.fles = LCXa
+"""elyts esrapgra"""
+:)fles(esrapgralc fed
+
+)c(LCXa
+:plc ni c rof
+)xiffus_resu_lc.sgra.fles(tilps.xelhs = plc
+dne LC YID # :xiffus_resu_lc.sgra.fles fi
+)lc(LCXa
+:tceriderlcxtsal.fles ni lc rof
+:tceriderlcxtsal.fles fi
+)v(LCXa
+:xiffuslcx.fles ni )edirrevok ,v ,k( rof
+dneppa.lclmx.fles = LCXa
+smarap neht redro ni stupni #
+:)fles(lanoitisoplc fed
+
+pdda = ]i[rapdda.fles
+]"LC"[pdda = ]"LCgiro"[pdda
+)p(ypoc.ypoc = pdda
+:)rapdda.fles(etaremune ni p ,i rof
+pftuo = ]i[seliftuo.fles
+ypoc peek # ]"LC"[pftuo = ]"LCgiro"[pftuo
+)p(ypoc.ypoc = pftuo
+:)seliftuo.fles(etaremune ni p ,i rof
+pfni = ]i[selifni.fles
+]"LC"[pfni = ]"emanelifni"[pfni
+:esle
+)"_" ," "(ecalper.]"lebal"[pfni = ]"emanelifni"[pfni
+:]"0" ,"lanoitisop"[ ni ssapmarap.sgra.fles fi
+]"LC"[pfni = ]"LCgiro"[pfni
+)p(ypoc.ypoc = pfni
+:)selifni.fles(etaremune ni p ,i rof
+)
+,]"eman"[p
+,]"LC"[p
+( % "s% rof s% tog - sregetni lanidro eb tsum sretemarap lanoitisoP" ,)(tigidsi.]
+"LC"
+[p tressa
+:)rapdda.fles(etaremune ni p ,i rof
+)
+,]"eman"[p
+,]"LC"[p
+( % "s% rof s% tog - sregetni lanidro eb tsum sretemarap lanoitisoP" ,)
+"TUODTS" == )(reppu.)(pirts.]"LC"[p ro )(tigidsi.]"LC"[p
+( tressa
+:)seliftuo.fles(etaremune ni p ,i rof
+)
+,]"lebal"[p
+,]"LC"[p
+( % "s% rof s% tog - sregetni lanidro eb tsum sretemarap lanoitisoP" ,)
+"NIDTS" == )(reppu.)(pirts.]"LC"[p ro )(tigidsi.]"LC"[p
+( tressa
+:)selifni.fles(etaremune ni p ,i rof
+:"lanoitisop" == ssapmarap.sgra.fles fi
+"""lanidro ciremun rieht yb detacilpmoc era sretemarap lanoitisop """
+:)fles(rappunaelc fed
+
+)(esolc.tcafitra
+))"8ftu" ,tpircs.fles(setyb(etirw.tcafitra
+)"bw" ,tra(nepo = tcafitra
+)]0[emetucexe.fles ,eman_loot.fles( % "s%.s%" = tra
+xr = tpircSdepacse.fles
+)"war dne#"(dneppa.xr
+)"war#" ,0(tresni.xr
+]"" > )(pirts.x fi xr ni x rof "}x{ "f[ = tpircSdecaps.fles
+)(esolc.tpircst
+)tpircs.fles(etirw.tpircst
+)"w" ,elifs.fles(nepo = tpircst
+)
+)]0[emetucexe.fles( % "s%_"=xiffus ,eman_loot.fles=xiferp
+(pmetskm.elifpmet = elifs.fles ,eldnahf
+)xr(nioj."n\" = tpircs.fles
+"nur tonnaC .ytpme si tpircs deilppuS" ,0 > )kcehcxr(nel tressa
+]"" > )(pirts.x fi xr ni x rof )(pirts.x[ = kcehcxr
+]xr ni x rof )(pirtsr.x[ = xr
+)(senildaer.)"r" ,htap_tpircs.sgra.fles(nepo = xr
+:)fles(tpircSperp fed
+
+xiffuslcx = xiffuslcx.fles
+)(tros.xiffuslcx
+)]]"edirrevo"[p ,]"eman"[p % '"s%$"' ,]"LC"[p[(dneppa.xiffuslcx
+:raples.fles ni p rof
+)]revo ,man % '"s%$"' ,]"LC"[p[(dneppa.xiffuslcx
+]"edirrevo"[p = revo
+)
+"!senil dnammoc retemarap lanoitisop ni dettimrep ton - derongi }man{ rof staepeR .gninraw ###"f
+(tnirp
+:per fi
+esnes ON ekam staeper # "1" == ]"taeper"[p = per
+]"eman"[p = man
+:rapdda.fles ni p rof
+)]"" ,]"eman"[p % "s%$" ,]"LC"[p[(dneppa.xiffuslcx
+:esle
+]]"eman"[p % "s%$" ,">"[ = tceriderlcxtsal.fles
+:"TUODTS" == )(reppu.)(pirts.]"LCgiro"[p fi
+:)seliftuo.fles(etaremune ni p ,i rof
+)emdneppax(dneppa.xiffuslcx
+]"" ,]"emanelifni"[p % "s%$" ,]"LC"[p[ = emdneppax
+:esle
+]
+,]"emanelifni"[p % "s%$ <"
+,]"emanelifni"[p
+,"999"
+[ = emdneppax
+:"NIDTS" == )(reppu.)(pirts.]"LCgiro"[p fi
+:)selifni.fles(etaremune ni p ,i rof
+][ = xiffuslcx
+:)fles(soplcperp fed
+
+xiffuslcx = xiffuslcx.fles
+)]]"edirrevo"[p ,]"eman"[p % '"s%$"' ,]"LC"[p[(dneppa.xiffuslcx
+:raples.fles ni p rof
+)]revo ,man % '"s%$"' ,]"LC"[p[(dneppa.xiffuslcx
+]"edirrevo"[p = revo
+:esle
+'rof dne#n\"}man{.per$" }man{--n\:}man{_R$ ni per$ rof#'f = revo
+:per fi
+"1" == ]"taeper"[p = per
+]"eman"[p = man
+:rapdda.fles ni p rof
+)]"" ,]"eman"[p % "s%$" ,]"eman"[p[(dneppa.xiffuslcx
+:esle
+]]"eman"[p % "s%$" ,">"[ = tceriderlcxtsal.fles
+:"TUODTS" == )(reppu.)(pirts.]"LCgiro"[p fi
+:)seliftuo.fles(etaremune ni p ,i rof
+)emdneppax(dneppa.xiffuslcx
+]revo ,]"LC"[p % "s%$" ,]"LC"[p[ = emdneppax
+'rof dne#n\"}man{.per$" }man{--n\:}man{_R$ ni per$ rof#'f = revo
+:per fi
+"" = revo
+"1" == ]"taeper"[p = per
+:esle
+]
+,man % "s%$ <"
+,man
+,man
+[ = emdneppax
+:"NIDTS" == )(reppu.)(pirts.]"LCgiro"[p fi
+]"emanelifni"[p = man
+:)selifni.fles(etaremune ni p ,i rof
+][ = xiffuslcx
+:)fles(pgraperp fed
+
+)c(LCXa
+:plc ni c rof
+)xiffus_resu_lc.sgra.fles(tilps.xelhs = plc
+dne LC YID # :xiffus_resu_lc.sgra.fles fi
+)]"eman"[]0[seliftuo.fles % "s%$"(LCXa
+)">"(LCXa
+:0 > )seliftuo.fles(nel fi
+)]"emanelifni"[]0[selifni.fles % "s%$"(LCXa
+)"<"(LCXa
+:0 > )selifni.fles(nel fi
+dneppa.lclmx.fles = LCXa
+"""o/i rof > dna < sesu - staeper ro sretemarap on"""
+:)fles(elpmislc fed
+
+)(esrapgralc.fles
+)(pgraperp.fles
+:esle
+)(lanoitisoplc.fles
+)(soplcperp.fles
+:"lanoitisop" == ssapmarap.sgra.fles fi
+:esle
+)(elpmislc.fles
+:"0" == ssapmarap.sgra.fles fi
+
+)xe(LCXa
+:emetucexe.fles ni xe rof
+:esle
+)"emnur$"(LCXa
+)xe(LCXa
+:emetucexe.fles ni xe rof
+:htap_tpircs.sgra.fles fi
+enoN = edirrevo_tset.fles
+:esle
+]sots ni x rof )(pirtsr.x[ = edirrevo_tset.fles
+)(senildaer.)"r" ,edirrevo_tset.sgra.fles(nepo = sots
+:edirrevo_tset.sgra.fles fi
+enoN = edirrevo_dnammoc.fles
+:esle
+]socs ni x rof )(pirtsr.x[ = edirrevo_dnammoc.fles
+)(senildaer.)"r" ,edirrevo_dnammoc.sgra.fles(nepo = socs
+:edirrevo_dnammoc.sgra.fles fi
+)(tpircSperp.fles
+:htap_tpircs.sgra.fles fi
+][ = maraptset.fles
+)(stuptuO.ptxg = stuptuot.fles
+)(stupnI.ptxg = stupnit.fles
+)eman_loot.fles % 'txt.gol_nur_FT_s%',ridper.fles(nioj.htap.so = golt.fles
+)ridper.fles(ridkm.so
+:)ridper.fles(stsixe.htap.so ton fi
+)ridtset.fles(ridkm.so
+:)ridtset.fles(stsixe.htap.so ton fi
+)ridtuoloot.fles(ridkm.so
+:)ridtuoloot.fles(stsixe.htap.so ton fi
+)"atad-tset" ,ridtuoloot.fles(nioj.htap.so = ridtset.fles
+)eman_loot.fles % "zg.dehsloot_detset_ton_s%" ,ridtuoloot.fles(nioj.htap.so # tuo_loot_detsetnu.sgra = htapratwen.fles
+"negloot/." = ridper.fles
+"tuoft/." = ridtuoloot.fles
+)
+,EXEEKAF
+,csed_loot.sgra.fles
+,noisrev_loot.sgra.fles
+,di_loot.fles
+,eman_loot.fles
+(looT.txg = lootwen.fles
+eman_loot.fles = di_loot.fles
+)eman_loot.sgra ,"" ,"+]_9-0Z-Az-a^["(bus.er = eman_loot.fles
+'"esrapgra" ro "lanoitisop","0" eb tsum ssapmarap.sgra' ,]
+,"lanoitisop"
+,"esrapgra"
+,"0"
+[ ni ssapmarap.sgra tressa
+dneppa.lclmx.fles = LCXa
+enoN = emetucexe.fles
+:esle
+]
+,)(pirts.]0[)":"(tilps.]0[)","(tilps.segakcap.sgra.fles
+[ = emetucexe.fles
+:segakcap.sgra.fles fi
+:esle
+]
+,exesys.sgra.fles
+[ = emetucexe.fles
+:esle
+)exesys.sgra.fles(tilps.xelhs = emetucexe.fles
+:exesys.sgra.fles ni " " fi
+:exesys.sgra.fles fi
+"lanoitisop" == ssapmarap.sgra.fles = lanoitisop_si.fles
+][ = lclmx.fles
+enoN = tceriderlcxtsal.fles
+)(rappunaelc.fles
+sgra = sgra.fles
+)
+"yranoitcid a eb dluohs - demroflam si }sretemarap_txettceles.sgra{ sretemarap_txettceles--"f
+(tnirp
+:noitpecxE tpecxe
+]
+1 > ))(pirts.x(nel fi sretemarap_txettceles.sgra ni x rof )x(sdaol.nosj
+[ = raples.fles
+:yrt
+)
+"yranoitcid a eb dluohs - demroflam si }sretemarap_lanoitidda.sgra{ sretemarap_lanoitidda--"f
+(tnirp
+:noitpecxE tpecxe
+]
+1 > ))(pirts.x(nel fi sretemarap_lanoitidda.sgra ni x rof )x(sdaol.nosj
+[ = rapdda.fles
+:yrt
+'tros emos fo tuptuo na tuohtiw liaf lliw rennur boj yxalaG ehT .deificeps snoitcelloc tuptuo ro seliftuo oN' ,0 > ))snoitcelloc.fles(nel + )seliftuo.fles(nel( tressa
+)
+"yranoitcid a eb dluohs - demroflam si }selif_tuptuo.sgra{ retemarap selif_tuptuo--"f
+(tnirp
+:noitpecxE tpecxe
+]
+1 > ))(pirts.x(nel fi selif_tuptuo.sgra ni x rof )x(sdaol.nosj
+[ = seliftuo.fles
+:yrt
+)
+"yranoitcid a eb dluohs - demroflam si })selif_tupni.sgra(rts{ retemarap selif_tupni--"f
+(tnirp
+:noitpecxE tpecxe
+]
+1 > ))(pirts.x(nel fi selif_tupni.sgra ni x rof )x(sdaol.nosj
+[ = selifni.fles
+:yrt
+)
+"yranoitcid a eb dluohs - demroflam si })noitcelloc.sgra(rts{ retemarap snoitcelloc--"f
+(tnirp
+:noitpecxE tpecxe
+]
+1 > ))(pirts.x(nel fi noitcelloc.sgra ni x rof )x(sdaol.nosj
+[ = snoitcelloc.fles
+:yrt
+:0 > )noitcelloc.sgra(nel fi
+][ = snoitcelloc.fles
+)(dwcteg.so = dwcruo.fles
+)'sloot_lacol',toor_yxalag.sgra(nioj.htap.so = sloot_lacol.fles
+"""
+noitareneg loot lmxyxalag rof dedeen stnemele eraperp dna
+ereh loot eht gninnur rof lc enil dnammoc eraperp
+"""
+aqon # :)enoN=sgra ,fles(__tini__ fed
+
+"""
+
+lmxyxalag sesu
+tpircs yrartibra na rof repparW"""
+:yrotcaF_looT ssalc
+
+
+selput_noitatic nruter
+)))(pirts.]: )"xetbib"(nel[noitatic ,"xetbib"((dneppa.selput_noitatic
+:esle
+)))(pirts.]: )"iod"(nel[noitatic ,"iod"((dneppa.selput_noitatic
+:)"iod"(htiwstrats.noitatic fi
+:snoitatic ni noitatic rof
+][ = selput_noitatic
+])(pirts.c fi )"**YRTNE**"(tilps.txet_snoitatic ni c rof c[ = snoitatic
+""""""
+:)txet_snoitatic(snoitatic_esrap fed
+
+
+)]txet ni c rof )c ,c(teg.elbat_epacse_hateehc[(nioj."" nruter
+""".txet nihtiw seititne ecudorP"""
+:)txet(epacse_hateehc fed
+
+
+}"#\\" :"#" ,"$\\" :"$"{ = elbat_epacse_hateehc
+
+
+)))(emit.emit(emitlacol.emit ,"S%:M%:H% Y%/m%/d%"(emitfrts.emit nruter
+"""gnirts a sa emit tnerruc nruter"""
+:)(wonemit fed
+
+
+.edirrevo htiw #
+neve exe eht gnidneperp lmxyxalag xif ot pmub noisrev/RP a litnu siht deen #
+"~~~EM~~~EVOMER~~~" = EXEEKAF
+"yrotcafloot/2rabuf/moc.buhtig//:sptth" = LRUyrotcaFloot
+eurT = gubed
+eurT = esobrev
+"2202 hcraM 4.2V" = noisrevym
+
+lmay tropmi
+
+TE sa eerte.lmxl tropmi
+
+ptxg sa sretemarap.loot.lmxyxalag tropmi
+txg sa loot.lmxyxalag tropmi
+
+yxalag tropmi dnelboib morf
+
+emit tropmi
+elifpmet tropmi
+elifrat tropmi
+sys tropmi
+ssecorpbus tropmi
+lituhs tropmi
+xelhs tropmi
+er tropmi
+so tropmi
+nosj tropmi
+ltncf tropmi
+ypoc tropmi
+esrapgra tropmi
+
+
+
+.tset htiw loot reporp wen a snruter dna #
+stuptuo tset eht setaerc ,evihcra detset-non a no omenalp snur retset ehT #
+noitpoda reniatnocoib dna tnempoleved lairotut NTG fo trap sa #
+llatsni/tset dna etareneg - sloot owt otni derotcafeR :2202 hcram #
+#
+yrotcafloot/2rabuf/moc.buhtig//:sptth #
+ta emoclew sexif gub dna tnemevorpmi rof snoitseggus #
+LPGL eht rednu desneciL #
+devreser sthgir lla #
+#
+2102 yaM )moc pots liamg ta surazal pots ssor( surazal ssor thgirypoc #
+#
+yrotcafloot/2rabuf/moc.buhtig//:sptth ees #
diff -r 2beaae16651e -r 0183cad9d13b tf_apikey_mutate/tf_apikey_mutate.xml
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tf_apikey_mutate/tf_apikey_mutate.xml Thu Feb 22 10:48:01 2024 +0000
@@ -0,0 +1,186 @@
+
+
+
+ Rotates all API keys in a ToolFactory instance
+
+ bioblend
+ python
+ six
+
+
+
+
+
+
+$APIK_mutate_log]]>
+
+ 0:
+ user = query.first()
+ user.username = username
+ user.set_password_cleartext(password)
+ sa_session.add(user)
+ sa_session.flush()
+ uexists = True
+ else:
+ user = User(email)
+ user.username = username
+ user.set_password_cleartext(password)
+ sa_session.add(user)
+ sa_session.flush()
+
+ security_agent.create_private_user_role(user)
+ if not user.default_permissions:
+ security_agent.user_set_default_permissions(user, history=True, dataset=True)
+
+ if key is not None:
+ query = sa_session.query(APIKeys).filter_by(user_id=user.id).delete()
+ sa_session.flush()
+
+ api_key = APIKeys()
+ api_key.user_id = user.id
+ api_key.key = key
+ sa_session.add(api_key)
+ sa_session.flush()
+ return user, uexists
+
+def run_sed(options):
+ """
+ eg replacement = 'APIK="%s"' % options.key
+ line_start = 'APIK='
+ """
+ fixme = []
+ tool_config_file: "tool_conf.xml,../local_tools/local_tool_conf.xml"
+ # database_connection: "sqlite:////universe.sqlite?isolation_level=IMMEDIATE"
+ tfc = 'tool_conf.xml,%s/local_tools/local_tool_conf.xml' % options.galaxy_root
+ fixfile = "%s/config/galaxy.yml" % options.galaxy_root
+ fixme.append((' virtualenv: ', ' virtualenv: "%s"' % options.galaxy_venv, fixfile))
+ fixme.append((' galaxy_root: ', ' galaxyroot: "%s"' % options.galaxy_root, fixfile))
+ fixme.append((' tool_config_file: ', ' tool_config_file: "%s"' % tfc, fixfile))
+ fixfile = "%s/local_tools/toolfactory/toolfactory.py" % options.galaxy_root
+ fixme.append((' self.GALAXY_ADMIN_KEY =', ' self.GALAXY_ADMIN_KEY = "%s"' % options.key, fixfile ))
+ fixme.append((' self.GALAXY_URL = ' , ' self.GALAXY_URL = "%s"' % options.galaxy_url, fixfile ))
+ fixfile = "%s/local_tools/toolfactory/install_tf_deps.sh" % options.galaxy_root
+ fixme.append(('APIK=', 'APIK="%s"' % options.key, fixfile ))
+ fixme.append(('LOCALTOOLDIR=', 'LOCALTOOLDIR="%s"' % os.path.join(os.path.abspath(options.galaxy_root), "local_tools"), fixfile ))
+ fixfile = "%s/local_tools/toolfactory/localplanemotest.sh" % options.galaxy_root
+ fixme.append(('GALAXY_URL=', 'GALAXY_URL=%s' % options.galaxy_url, fixfile))
+ fixme.append(('API_KEY=', 'API_KEY=%s' % options.key, fixfile))
+ fixfile = "%s/local_tools/toolfactory/toolfactory_fast_test.sh" % options.galaxy_root
+ fixme.append(('GALAXY_URL=', 'GALAXY_URL=%s' % options.galaxy_url, fixfile))
+ fixme.append(('API_KEY=', 'API_KEY=%s' % options.key, fixfile))
+ fixme.append(('GALAXY_VENV=', 'GALAXY_VENV=%s' % options.galaxy_venv, fixfile))
+ fixme.append(('API_KEY_USER=', 'API_KEY_USER=%s' % options.botkey, fixfile))
+ for line_start, line_replacement, file_to_edit in fixme:
+ cmd = ["sed", "-i", "s#.*%s.*#%s#g" % (line_start, line_replacement), file_to_edit]
+ print("## executing", ' '.join(cmd))
+ res = subprocess.run(cmd)
+ if not res.returncode == 0:
+ print('### Non zero %d return code from %s ' % (res.returncode, ''.join(cmd)))
+
+
+if __name__ == "__main__":
+ print('starting!', file=sys.stderr)
+ apikey = "%s" % hash(random.random())
+ apikey2 = "%s" % hash(random.random())
+ parser = argparse.ArgumentParser(description="Create Galaxy Admin User.")
+ parser.add_argument("--galaxy_url", help="Galaxy server URL", default="http://localhost:8080")
+ parser.add_argument("--galaxy_root", help="Galaxy root directory path", default="/work/galaxytf")
+ parser.add_argument("--galaxy_venv", help="Galaxy venv path", default="/work/galaxytf/.venv")
+ parser.add_argument("--user", help="Username - an email address.", default="toolfactory@galaxy.org")
+ parser.add_argument("--password", help="Password", default="ChangeMe!")
+ parser.add_argument("--password2", help="Password", default=apikey2)
+ parser.add_argument("--key", help="API-Key.", default=apikey)
+ parser.add_argument("--botkey", help="bot API-Key.", default=apikey2)
+ parser.add_argument("--username", default="tfadmin")
+ parser.add_argument("args", nargs=argparse.REMAINDER)
+ options = parser.parse_args()
+ sys.path.insert(1, options.galaxy_root)
+ sys.path.insert(1, os.path.join(options.galaxy_root, "lib"))
+ sys.path.insert(1, os.path.join(options.galaxy_venv, "lib", "python3.10", "site-packages"))
+ from galaxy.model import User, APIKeys
+ from galaxy.model.mapping import init
+ from galaxy.model.orm.scripts import get_config
+ cnf = get_config(argv=['-c','galaxy', ],cwd=options.galaxy_root)
+ print('cnf=%s' % cnf, file=sys.stderr)
+ cdb_url = cnf["db_url"]
+ # or perhaps "postgresql:///ubuntu?host=/var/run/postgresql"
+ # this is harder to please get_config(sys.argv, use_argparse=False)["db_url"]
+ print('### Using cdb_url', cdb_url, file=sys.stderr)
+ mapping = init("/tmp/", cdb_url)
+ sa_session = mapping.context
+ security_agent = mapping.security_agent
+ usr, uexists = add_user(
+ sa_session, security_agent, options.user, options.password, key=options.key, username=options.username
+ )
+ print("added user", options.user, "apikey", options.key, file=sys.stderr)
+
+ usr, uexists = add_user(
+ sa_session, security_agent, 'test@bx.psu.edu', options.password2, key=options.botkey, username='bot'
+ )
+ run_sed(options)
+ print('Evil deeds done', file=sys.stderr)
+
+
+#end raw]]>
+
+
+
+
+
+
+
+
+
+
+
+
+ 10.1093/bioinformatics/bts573
+
+
+
diff -r 2beaae16651e -r 0183cad9d13b toolfactory/install_tf_deps.sh
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/toolfactory/install_tf_deps.sh Thu Feb 22 10:48:01 2024 +0000
@@ -0,0 +1,17 @@
+LOCALTOOLDIR="/home/ross/rossgit/galaxytf231/local_tools"
+APIK="1718977735397126400"
+GAL="http://localhost:8080"
+# all unless a single id is passed in as $1
+if [ -z "$1" ]; then
+ for f in $LOCALTOOLDIR/*; do
+ if [ -d "$f" ]; then
+ TOOL=`basename "$f"`
+ install_tool_deps -v -g $GAL -a $APIK -t $LOCALTOOLDIR/$TOOL/$TOOL.xml
+ fi
+ done
+else
+ install_tool_deps -v -g $GAL -a $APIK -t $LOCALTOOLDIR/$1/$1.xml
+fi
+
+
+
diff -r 2beaae16651e -r 0183cad9d13b toolfactory/localplanemotest.sh
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/toolfactory/localplanemotest.sh Thu Feb 22 10:48:01 2024 +0000
@@ -0,0 +1,6 @@
+# pass path to tool as parameter /work/galaxytf/local_tools/tacrev/tacrev.xml
+GALAXY_URL=http://localhost:8080
+API_KEY=1718977735397126400
+# for test@bx.psu.edu user
+# for sed to edit at installation
+planemo test --galaxy_admin_key $API_KEY --engine external_galaxy --galaxy_url $GALAXY_URL --update_test_data $1
diff -r 2beaae16651e -r 0183cad9d13b toolfactory/test-data/input1_sample
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/toolfactory/test-data/input1_sample Thu Feb 22 10:48:01 2024 +0000
@@ -0,0 +1,741 @@
+#!/usr/bin/env python
+# rgToolFactory.py
+# see https://github.com/fubar2/toolfactory
+#
+# copyright ross lazarus (ross stop lazarus at gmail stop com) May 2012
+#
+# all rights reserved
+# Licensed under the LGPL
+# suggestions for improvement and bug fixes welcome at https://github.com/fubar2/toolfactory
+#
+# July 2020: BCC was fun and I feel like rip van winkle after 5 years.
+# Decided to
+# 1. Fix the toolfactory so it works - done for simplest case
+# 2. Fix planemo so the toolfactory function works
+# 3. Rewrite bits using galaxyxml functions where that makes sense - done
+#
+# removed all the old complications including making the new tool use this same script
+# galaxyxml now generates the tool xml https://github.com/hexylena/galaxyxml
+# No support for automatic HTML file creation from arbitrary outputs
+# TODO: add option to run that code as a post execution hook
+# TODO: add additional history input parameters - currently only one
+
+
+import argparse
+import logging
+import os
+import re
+import shutil
+import subprocess
+import sys
+import tarfile
+import tempfile
+import time
+
+import galaxyxml.tool as gxt
+import galaxyxml.tool.parameters as gxtp
+
+import lxml
+
+myversion = "V2.1 July 2020"
+verbose = True
+debug = True
+toolFactoryURL = "https://github.com/fubar2/toolfactory"
+ourdelim = "~~~"
+
+# --input_files="$input_files~~~$CL~~~$input_formats~~~$input_label
+# ~~~$input_help"
+IPATHPOS = 0
+ICLPOS = 1
+IFMTPOS = 2
+ILABPOS = 3
+IHELPOS = 4
+IOCLPOS = 5
+
+# --output_files "$otab.history_name~~~$otab.history_format~~~$otab.CL
+ONAMEPOS = 0
+OFMTPOS = 1
+OCLPOS = 2
+OOCLPOS = 3
+
+# --additional_parameters="$i.param_name~~~$i.param_value~~~
+# $i.param_label~~~$i.param_help~~~$i.param_type~~~$i.CL~~~i$.param_CLoverride"
+ANAMEPOS = 0
+AVALPOS = 1
+ALABPOS = 2
+AHELPPOS = 3
+ATYPEPOS = 4
+ACLPOS = 5
+AOVERPOS = 6
+AOCLPOS = 7
+
+
+foo = len(lxml.__version__)
+# fug you, flake8. Say my name!
+
+def timenow():
+ """return current time as a string
+ """
+ return time.strftime("%d/%m/%Y %H:%M:%S", time.localtime(time.time()))
+
+
+def quote_non_numeric(s):
+ """return a prequoted string for non-numerics
+ useful for perl and Rscript parameter passing?
+ """
+ try:
+ _ = float(s)
+ return s
+ except ValueError:
+ return '"%s"' % s
+
+
+html_escape_table = {"&": "&", ">": ">", "<": "<", "$": r"\$"}
+
+
+def html_escape(text):
+ """Produce entities within text."""
+ return "".join(html_escape_table.get(c, c) for c in text)
+
+
+def html_unescape(text):
+ """Revert entities within text. Multiple character targets so use replace"""
+ t = text.replace("&", "&")
+ t = t.replace(">", ">")
+ t = t.replace("<", "<")
+ t = t.replace("\\$", "$")
+ return t
+
+
+def parse_citations(citations_text):
+ """
+ """
+ citations = [c for c in citations_text.split("**ENTRY**") if c.strip()]
+ citation_tuples = []
+ for citation in citations:
+ if citation.startswith("doi"):
+ citation_tuples.append(("doi", citation[len("doi") :].strip()))
+ else:
+ citation_tuples.append(
+ ("bibtex", citation[len("bibtex") :].strip())
+ )
+ return citation_tuples
+
+
+class ScriptRunner:
+ """Wrapper for an arbitrary script
+ uses galaxyxml
+
+ """
+
+ def __init__(self, args=None):
+ """
+ prepare command line cl for running the tool here
+ and prepare elements needed for galaxyxml tool generation
+ """
+
+ self.infiles = [x.split(ourdelim) for x in args.input_files]
+ self.outfiles = [x.split(ourdelim) for x in args.output_files]
+ self.addpar = [x.split(ourdelim) for x in args.additional_parameters]
+ self.args = args
+ self.cleanuppar()
+ self.lastclredirect = None
+ self.lastxclredirect = None
+ self.cl = []
+ self.xmlcl = []
+ self.is_positional = self.args.parampass == "positional"
+ aCL = self.cl.append
+ assert args.parampass in [
+ "0",
+ "argparse",
+ "positional",
+ ], 'Parameter passing in args.parampass must be "0","positional" or "argparse"'
+ self.tool_name = re.sub("[^a-zA-Z0-9_]+", "", args.tool_name)
+ self.tool_id = self.tool_name
+ if self.args.interpreter_name:
+ exe = "$runMe"
+ else:
+ exe = self.args.exe_package
+ assert (
+ exe is not None
+ ), "No interpeter or executable passed in - nothing to run so cannot build"
+ self.tool = gxt.Tool(
+ self.args.tool_name,
+ self.tool_id,
+ self.args.tool_version,
+ self.args.tool_desc,
+ exe,
+ )
+ self.tinputs = gxtp.Inputs()
+ self.toutputs = gxtp.Outputs()
+ self.testparam = []
+ if (
+ self.args.runmode == "Executable" or self.args.runmode == "system"
+ ): # binary - no need
+ aCL(self.args.exe_package) # this little CL will just run
+ else:
+ self.prepScript()
+ self.elog = "%s_error_log.txt" % self.tool_name
+ self.tlog = "%s_runner_log.txt" % self.tool_name
+
+ if self.args.parampass == "0":
+ self.clsimple()
+ else:
+ clsuffix = []
+ xclsuffix = []
+ for i, p in enumerate(self.infiles):
+ if p[IOCLPOS] == "STDIN":
+ appendme = [
+ p[IOCLPOS],
+ p[ICLPOS],
+ p[IPATHPOS],
+ "< %s" % p[IPATHPOS],
+ ]
+ xappendme = [
+ p[IOCLPOS],
+ p[ICLPOS],
+ p[IPATHPOS],
+ "< $%s" % p[ICLPOS],
+ ]
+ else:
+ appendme = [p[IOCLPOS], p[ICLPOS], p[IPATHPOS], ""]
+ xappendme = [p[IOCLPOS], p[ICLPOS], "$%s" % p[ICLPOS], ""]
+ clsuffix.append(appendme)
+ xclsuffix.append(xappendme)
+ # print('##infile i=%d, appendme=%s' % (i,appendme))
+ for i, p in enumerate(self.outfiles):
+ if p[OOCLPOS] == "STDOUT":
+ self.lastclredirect = [">", p[ONAMEPOS]]
+ self.lastxclredirect = [">", "$%s" % p[OCLPOS]]
+ else:
+ clsuffix.append([p[OOCLPOS], p[OCLPOS], p[ONAMEPOS], ""])
+ xclsuffix.append(
+ [p[OOCLPOS], p[OCLPOS], "$%s" % p[ONAMEPOS], ""]
+ )
+ for p in self.addpar:
+ clsuffix.append(
+ [p[AOCLPOS], p[ACLPOS], p[AVALPOS], p[AOVERPOS]]
+ )
+ xclsuffix.append(
+ [p[AOCLPOS], p[ACLPOS], '"$%s"' % p[ANAMEPOS], p[AOVERPOS]]
+ )
+ clsuffix.sort()
+ xclsuffix.sort()
+ self.xclsuffix = xclsuffix
+ self.clsuffix = clsuffix
+ if self.args.parampass == "positional":
+ self.clpositional()
+ else:
+ self.clargparse()
+
+ def prepScript(self):
+ aCL = self.cl.append
+ rx = open(self.args.script_path, "r").readlines()
+ rx = [x.rstrip() for x in rx]
+ rxcheck = [x.strip() for x in rx if x.strip() > ""]
+ assert len(rxcheck) > 0, "Supplied script is empty. Cannot run"
+ self.script = "\n".join(rx)
+ fhandle, self.sfile = tempfile.mkstemp(
+ prefix=self.tool_name, suffix="_%s" % (self.args.interpreter_name)
+ )
+ tscript = open(self.sfile, "w")
+ tscript.write(self.script)
+ tscript.close()
+ self.indentedScript = " %s" % "\n".join(
+ [" %s" % html_escape(x) for x in rx]
+ )
+ self.escapedScript = "%s" % "\n".join(
+ [" %s" % html_escape(x) for x in rx]
+ )
+ art = "%s.%s" % (self.tool_name, self.args.interpreter_name)
+ artifact = open(art, "wb")
+ artifact.write(bytes(self.script, "utf8"))
+ artifact.close()
+ aCL(self.args.interpreter_name)
+ aCL(self.sfile)
+
+ def cleanuppar(self):
+ """ positional parameters are complicated by their numeric ordinal"""
+ for i, p in enumerate(self.infiles):
+ if self.args.parampass == "positional":
+ assert p[ICLPOS].isdigit(), (
+ "Positional parameters must be ordinal integers - got %s for %s"
+ % (p[ICLPOS], p[ILABPOS])
+ )
+ p.append(p[ICLPOS])
+ if p[ICLPOS].isdigit() or self.args.parampass == "0":
+ scl = "input%d" % (i + 1)
+ p[ICLPOS] = scl
+ self.infiles[i] = p
+ for i, p in enumerate(
+ self.outfiles
+ ): # trying to automagically gather using extensions
+ if self.args.parampass == "positional" and p[OCLPOS] != "STDOUT":
+ assert p[OCLPOS].isdigit(), (
+ "Positional parameters must be ordinal integers - got %s for %s"
+ % (p[OCLPOS], p[ONAMEPOS])
+ )
+ p.append(p[OCLPOS])
+ if p[OCLPOS].isdigit() or p[OCLPOS] == "STDOUT":
+ scl = p[ONAMEPOS]
+ p[OCLPOS] = scl
+ self.outfiles[i] = p
+ for i, p in enumerate(self.addpar):
+ if self.args.parampass == "positional":
+ assert p[ACLPOS].isdigit(), (
+ "Positional parameters must be ordinal integers - got %s for %s"
+ % (p[ACLPOS], p[ANAMEPOS])
+ )
+ p.append(p[ACLPOS])
+ if p[ACLPOS].isdigit():
+ scl = "input%s" % p[ACLPOS]
+ p[ACLPOS] = scl
+ self.addpar[i] = p
+
+ def clsimple(self):
+ """ no parameters - uses < and > for i/o
+ """
+ aCL = self.cl.append
+ aCL("<")
+ aCL(self.infiles[0][IPATHPOS])
+ aCL(">")
+ aCL(self.outfiles[0][OCLPOS])
+ aXCL = self.xmlcl.append
+ aXCL("<")
+ aXCL("$%s" % self.infiles[0][ICLPOS])
+ aXCL(">")
+ aXCL("$%s" % self.outfiles[0][ONAMEPOS])
+
+ def clpositional(self):
+ # inputs in order then params
+ aCL = self.cl.append
+ for (o_v, k, v, koverride) in self.clsuffix:
+ if " " in v:
+ aCL("%s" % v)
+ else:
+ aCL(v)
+ aXCL = self.xmlcl.append
+ for (o_v, k, v, koverride) in self.xclsuffix:
+ aXCL(v)
+ if self.lastxclredirect:
+ aXCL(self.lastxclredirect[0])
+ aXCL(self.lastxclredirect[1])
+
+ def clargparse(self):
+ """ argparse style
+ """
+ aCL = self.cl.append
+ aXCL = self.xmlcl.append
+ # inputs then params in argparse named form
+ for (o_v, k, v, koverride) in self.xclsuffix:
+ if koverride > "":
+ k = koverride
+ elif len(k.strip()) == 1:
+ k = "-%s" % k
+ else:
+ k = "--%s" % k
+ aXCL(k)
+ aXCL(v)
+ for (o_v, k, v, koverride) in self.clsuffix:
+ if koverride > "":
+ k = koverride
+ elif len(k.strip()) == 1:
+ k = "-%s" % k
+ else:
+ k = "--%s" % k
+ aCL(k)
+ aCL(v)
+
+ def getNdash(self, newname):
+ if self.is_positional:
+ ndash = 0
+ else:
+ ndash = 2
+ if len(newname) < 2:
+ ndash = 1
+ return ndash
+
+ def doXMLparam(self):
+ """flake8 made me do this..."""
+ for p in self.outfiles:
+ newname, newfmt, newcl, oldcl = p
+ ndash = self.getNdash(newcl)
+ aparm = gxtp.OutputData(newcl, format=newfmt, num_dashes=ndash)
+ aparm.positional = self.is_positional
+ if self.is_positional:
+ if oldcl == "STDOUT":
+ aparm.positional = 9999999
+ aparm.command_line_override = "> $%s" % newcl
+ else:
+ aparm.positional = int(oldcl)
+ aparm.command_line_override = "$%s" % newcl
+ self.toutputs.append(aparm)
+ tp = gxtp.TestOutput(
+ name=newcl, value="%s_sample" % newcl, format=newfmt
+ )
+ self.testparam.append(tp)
+ for p in self.infiles:
+ newname = p[ICLPOS]
+ newfmt = p[IFMTPOS]
+ ndash = self.getNdash(newname)
+ if not len(p[ILABPOS]) > 0:
+ alab = p[ICLPOS]
+ else:
+ alab = p[ILABPOS]
+ aninput = gxtp.DataParam(
+ newname,
+ optional=False,
+ label=alab,
+ help=p[IHELPOS],
+ format=newfmt,
+ multiple=False,
+ num_dashes=ndash,
+ )
+ aninput.positional = self.is_positional
+ self.tinputs.append(aninput)
+ tparm = gxtp.TestParam(name=newname, value="%s_sample" % newname)
+ self.testparam.append(tparm)
+ for p in self.addpar:
+ newname, newval, newlabel, newhelp, newtype, newcl, override, oldcl = p
+ if not len(newlabel) > 0:
+ newlabel = newname
+ ndash = self.getNdash(newname)
+ if newtype == "text":
+ aparm = gxtp.TextParam(
+ newname,
+ label=newlabel,
+ help=newhelp,
+ value=newval,
+ num_dashes=ndash,
+ )
+ elif newtype == "integer":
+ aparm = gxtp.IntegerParam(
+ newname,
+ label=newname,
+ help=newhelp,
+ value=newval,
+ num_dashes=ndash,
+ )
+ elif newtype == "float":
+ aparm = gxtp.FloatParam(
+ newname,
+ label=newname,
+ help=newhelp,
+ value=newval,
+ num_dashes=ndash,
+ )
+ else:
+ raise ValueError(
+ 'Unrecognised parameter type "%s" for\
+ additional parameter %s in makeXML'
+ % (newtype, newname)
+ )
+ aparm.positional = self.is_positional
+ if self.is_positional:
+ aninput.positional = int(oldcl)
+ self.tinputs.append(aparm)
+ self.tparm = gxtp.TestParam(newname, value=newval)
+ self.testparam.append(tparm)
+
+ def doNoXMLparam(self):
+ alab = self.infiles[0][ILABPOS]
+ if len(alab) == 0:
+ alab = self.infiles[0][ICLPOS]
+ max1s = (
+ "Maximum one input if parampass is 0 - more than one input files supplied - %s"
+ % str(self.infiles)
+ )
+ assert len(self.infiles) == 1, max1s
+ newname = self.infiles[0][ICLPOS]
+ aninput = gxtp.DataParam(
+ newname,
+ optional=False,
+ label=alab,
+ help=self.infiles[0][IHELPOS],
+ format=self.infiles[0][IFMTPOS],
+ multiple=False,
+ num_dashes=0,
+ )
+ aninput.command_line_override = "< $%s" % newname
+ aninput.positional = self.is_positional
+ self.tinputs.append(aninput)
+ tp = gxtp.TestParam(name=newname, value="%s_sample" % newname)
+ self.testparam.append(tp)
+ newname = self.outfiles[0][OCLPOS]
+ newfmt = self.outfiles[0][OFMTPOS]
+ anout = gxtp.OutputData(newname, format=newfmt, num_dashes=0)
+ anout.command_line_override = "> $%s" % newname
+ anout.positional = self.is_positional
+ self.toutputs.append(anout)
+ tp = gxtp.TestOutput(
+ name=newname, value="%s_sample" % newname, format=newfmt
+ )
+ self.testparam.append(tp)
+
+ def makeXML(self):
+ """
+ Create a Galaxy xml tool wrapper for the new script
+ Uses galaxyhtml
+ Hmmm. How to get the command line into correct order...
+ """
+ self.tool.command_line_override = self.xmlcl
+ if self.args.interpreter_name:
+ self.tool.interpreter = self.args.interpreter_name
+ if self.args.help_text:
+ helptext = open(self.args.help_text, "r").readlines()
+ helptext = [html_escape(x) for x in helptext]
+ self.tool.help = "".join([x for x in helptext])
+ else:
+ self.tool.help = (
+ "Please ask the tool author (%s) for help \
+ as none was supplied at tool generation\n"
+ % (self.args.user_email)
+ )
+ self.tool.version_command = None # do not want
+ requirements = gxtp.Requirements()
+
+ if self.args.interpreter_name:
+ if self.args.interpreter_name == "python":
+ requirements.append(
+ gxtp.Requirement(
+ "package", "python", self.args.interpreter_version
+ )
+ )
+ elif self.args.interpreter_name not in ["bash", "sh"]:
+ requirements.append(
+ gxtp.Requirement(
+ "package",
+ self.args.interpreter_name,
+ self.args.interpreter_version,
+ )
+ )
+ else:
+ if self.args.exe_package and self.args.parampass != "system":
+ requirements.append(
+ gxtp.Requirement(
+ "package",
+ self.args.exe_package,
+ self.args.exe_package_version,
+ )
+ )
+ self.tool.requirements = requirements
+ if self.args.parampass == "0":
+ self.doNoXMLparam()
+ else:
+ self.doXMLparam()
+ self.tool.outputs = self.toutputs
+ self.tool.inputs = self.tinputs
+ if self.args.runmode not in ["Executable", "system"]:
+ configfiles = gxtp.Configfiles()
+ configfiles.append(gxtp.Configfile(name="runMe", text=self.script))
+ self.tool.configfiles = configfiles
+ tests = gxtp.Tests()
+ test_a = gxtp.Test()
+ for tp in self.testparam:
+ test_a.append(tp)
+ tests.append(test_a)
+ self.tool.tests = tests
+ self.tool.add_comment(
+ "Created by %s at %s using the Galaxy Tool Factory."
+ % (self.args.user_email, timenow())
+ )
+ self.tool.add_comment("Source in git at: %s" % (toolFactoryURL))
+ self.tool.add_comment(
+ "Cite: Creating re-usable tools from scripts doi: 10.1093/bioinformatics/bts573"
+ )
+ exml = self.tool.export()
+ xf = open('%s.xml' % self.tool_name, "w")
+ xf.write(exml)
+ xf.write("\n")
+ xf.close()
+ # ready for the tarball
+
+ def makeTooltar(self):
+ """
+ a tool is a gz tarball with eg
+ /toolname/tool.xml /toolname/tool.py /toolname/test-data/test1_in.foo ...
+ NOTE names for test inputs and outputs are munged here so must
+ correspond to actual input and output names used on the generated cl
+ """
+ retval = self.run()
+ if retval:
+ sys.stderr.write(
+ "## Run failed. Cannot build yet. Please fix and retry"
+ )
+ sys.exit(1)
+ tdir = "tfout"
+ if not os.path.exists(tdir):
+ os.mkdir(tdir)
+ self.makeXML()
+ testdir = os.path.join(tdir, "test-data")
+ if not os.path.exists(testdir):
+ os.mkdir(testdir) # make tests directory
+ for p in self.infiles:
+ pth = p[IPATHPOS]
+ dest = os.path.join(testdir, "%s_sample" % p[ICLPOS])
+ shutil.copyfile(pth, dest)
+ for p in self.outfiles:
+ pth = p[OCLPOS]
+ if p[OOCLPOS] == "STDOUT" or self.args.parampass == "0":
+ pth = p[ONAMEPOS]
+ dest = os.path.join(testdir, "%s_sample" % p[ONAMEPOS])
+ shutil.copyfile(pth, dest)
+ dest = os.path.join(tdir, p[ONAMEPOS])
+ shutil.copyfile(pth, dest)
+ else:
+ pth = p[OCLPOS]
+ dest = os.path.join(testdir, "%s_sample" % p[OCLPOS])
+ shutil.copyfile(pth, dest)
+ dest = os.path.join(tdir, p[OCLPOS])
+ shutil.copyfile(pth, dest)
+
+ if os.path.exists(self.tlog) and os.stat(self.tlog).st_size > 0:
+ shutil.copyfile(self.tlog, os.path.join(testdir, "test1_log_outfiletxt"))
+ if self.args.runmode not in ["Executable", "system"]:
+ stname = os.path.join(tdir, "%s" % (self.sfile))
+ if not os.path.exists(stname):
+ shutil.copyfile(self.sfile, stname)
+ xreal = '%s.xml' % self.tool_name
+ xout = os.path.join(tdir,xreal)
+ shutil.copyfile(xreal, xout)
+ tarpath = "toolfactory_%s.tgz" % self.tool_name
+ tf = tarfile.open(tarpath, "w:gz")
+ tf.add(name=tdir, arcname=self.tool_name)
+ tf.close()
+ shutil.copyfile(tarpath, self.args.new_tool)
+ shutil.copyfile(xreal,"tool_xml.txt")
+ repdir = "TF_run_report_tempdir"
+ if not os.path.exists(repdir):
+ os.mkdir(repdir)
+ repoutnames = [x[OCLPOS] for x in self.outfiles]
+ with os.scandir('.') as outs:
+ for entry in outs:
+ if entry.name.endswith('.tgz') or not entry.is_file():
+ continue
+ if entry.name in repoutnames:
+ shutil.copyfile(entry.name,os.path.join(repdir,entry.name))
+ elif entry.name == "%s.xml" % self.tool_name:
+ shutil.copyfile(entry.name,os.path.join(repdir,"new_tool_xml"))
+ return retval
+
+ def run(self):
+ """
+ Some devteam tools have this defensive stderr read so I'm keeping with the faith
+ Feel free to update.
+ """
+ s = "run cl=%s" % str(self.cl)
+
+ logging.debug(s)
+ scl = " ".join(self.cl)
+ err = None
+ if self.args.parampass != "0":
+ ste = open(self.elog, "wb")
+ if self.lastclredirect:
+ sto = open(
+ self.lastclredirect[1], "wb"
+ ) # is name of an output file
+ else:
+ sto = open(self.tlog, "wb")
+ sto.write(
+ bytes(
+ "## Executing Toolfactory generated command line = %s\n"
+ % scl,
+ "utf8",
+ )
+ )
+ sto.flush()
+ p = subprocess.run(self.cl, shell=False, stdout=sto, stderr=ste)
+ sto.close()
+ ste.close()
+ tmp_stderr = open(self.elog, "rb")
+ err = ""
+ buffsize = 1048576
+ try:
+ while True:
+ err += str(tmp_stderr.read(buffsize))
+ if not err or len(err) % buffsize != 0:
+ break
+ except OverflowError:
+ pass
+ tmp_stderr.close()
+ retval = p.returncode
+ else: # work around special case of simple scripts that take stdin and write to stdout
+ sti = open(self.infiles[0][IPATHPOS], "rb")
+ sto = open(self.outfiles[0][ONAMEPOS], "wb")
+ # must use shell to redirect
+ p = subprocess.run(self.cl, shell=False, stdout=sto, stdin=sti)
+ retval = p.returncode
+ sto.close()
+ sti.close()
+ if os.path.isfile(self.tlog) and os.stat(self.tlog).st_size == 0:
+ os.unlink(self.tlog)
+ if os.path.isfile(self.elog) and os.stat(self.elog).st_size == 0:
+ os.unlink(self.elog)
+ if p.returncode != 0 and err: # problem
+ sys.stderr.write(err)
+ logging.debug("run done")
+ return retval
+
+
+def main():
+ """
+ This is a Galaxy wrapper. It expects to be called by a special purpose tool.xml as:
+ rgBaseScriptWrapper.py --script_path "$scriptPath" --tool_name "foo" --interpreter "Rscript"
+
+ """
+ parser = argparse.ArgumentParser()
+ a = parser.add_argument
+ a("--script_path", default="")
+ a("--tool_name", default=None)
+ a("--interpreter_name", default=None)
+ a("--interpreter_version", default=None)
+ a("--exe_package", default=None)
+ a("--exe_package_version", default=None)
+ a("--input_files", default=[], action="append")
+ a("--output_files", default=[], action="append")
+ a("--user_email", default="Unknown")
+ a("--bad_user", default=None)
+ a("--make_Tool", default=None)
+ a("--help_text", default=None)
+ a("--tool_desc", default=None)
+ a("--tool_version", default=None)
+ a("--citations", default=None)
+ a("--additional_parameters", action="append", default=[])
+ a("--edit_additional_parameters", action="store_true", default=False)
+ a("--parampass", default="positional")
+ a("--tfout", default="./tfout")
+ a("--new_tool", default="new_tool")
+ a("--runmode", default=None)
+ args = parser.parse_args()
+ assert not args.bad_user, (
+ 'UNAUTHORISED: %s is NOT authorized to use this tool until Galaxy admin adds %s to "admin_users" in the Galaxy configuration file'
+ % (args.bad_user, args.bad_user)
+ )
+ assert (
+ args.tool_name
+ ), "## Tool Factory expects a tool name - eg --tool_name=DESeq"
+ assert (
+ args.interpreter_name or args.exe_package
+ ), "## Tool Factory wrapper expects an interpreter or an executable package"
+ assert args.exe_package or (
+ len(args.script_path) > 0 and os.path.isfile(args.script_path)
+ ), "## Tool Factory wrapper expects a script path - eg --script_path=foo.R if no executable"
+ args.input_files = [
+ x.replace('"', "").replace("'", "") for x in args.input_files
+ ]
+ # remove quotes we need to deal with spaces in CL params
+ for i, x in enumerate(args.additional_parameters):
+ args.additional_parameters[i] = args.additional_parameters[i].replace(
+ '"', ""
+ )
+ r = ScriptRunner(args)
+ if args.make_Tool:
+ retcode = r.makeTooltar()
+ else:
+ retcode = r.run()
+ if retcode:
+ sys.exit(retcode) # indicate failure to job runner
+
+
+if __name__ == "__main__":
+ main()
diff -r 2beaae16651e -r 0183cad9d13b toolfactory/test-data/output2_sample
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/toolfactory/test-data/output2_sample Thu Feb 22 10:48:01 2024 +0000
@@ -0,0 +1,165 @@
+*trats uoy erofeb GNINRAW*
+
+YLNO yxalaG etavirp a no loot siht llatsnI
+ecnatsni noitcudorp ro cilbup a no REVEN esaelP
+
+troppus noitatic gnidda notlihC nhoJ yb 4102 tsugua detadpU
+
+keeB ned nav suiraM yb detroper sgub xif ot 4102 8 tsugua detadpU
+
+ta ecruoser eht etic esaelP
+fer=epytyek&JWYdwMrWs1hQzcl=yekji?375stb/tnirper/igc/gro.slanruojdrofxo.scitamrofnioib//:ptth
+.krow dehsilbup ruoy ni loot siht esu uoy fi
+
+**yrotS trohS**
+
+.sloot yxalaG wen gnitareneg fo elbapac loot yxalaG lausunu na si sihT
+gnitpircs suoregnad ylemertxe erofereht dna *detcirtsernu* gnisopxe yb skrow tI
+ot meht gniwolla ,revres yxalaG tsoh eht fo srotartsinimda detangised lla ot
+,stes atad tupni detceles elpitlum revo lrep dna hs ,nohtyp ,R ni stpircs nur
+.tuptuo sa tes atad wen elgnis a gnitirw
+
+*sretemarap elyts esrapgra ro lanoitisop htiw elbatucexe yna ro tpircs hsab/lrep/nohtyp/r gnikrow a evah uoY*
+
+.loot yxalaG a gnisu ,setunim ni loot yxalaG yranidro na otni denrut eb nac tI
+
+
+**yxalaG yna otni noitallatsni rof sloot yxalaG wen fo noitareneg detamotuA**
+
+.ylppus uoy sgnittes retemarap dna stupni atad tset elpmas llams gnisu detareneg si tset A
+a dliub ot desu eb nac yeht ,decudorp neeb evah stuptuo esac tset eht ecnO
+tnemeriuqer a sa dekab si elbatucexe ro tpircs deilppus ehT .loot yxalaG wen
+.xob eht fo tuo elbitapmoc wolfkrow ylluf ,loot yxalaG yranidro ,wen a otni
+rotartsinimda na yb dehs loot a aiv dellatsni era sloot detareneG
+.sresu ruoy rof sloot yxalaG rehto lla ekil yltcaxe krow dna
+
+**liateD eroM**
+
+a otni etsap ot tpircs a deraperp evah dluohs uoy ,yrotcaFlooT eht esu oT
+yrotsih ruoy morf tceles ot ydaer elpmaxe tupni tset llams a dna dnim ni egakcap a evah ro ,xob txet
+.tpircs wen ruoy tset ot
+
+em rof skrow ```atad-tset/yrotcafloot/srekam_loot/sloot/yxalag/~ atad_tset-- yxalag/~ toor_yxalag-- lmx.2yrotcaFlooTgr tset omenalp```
+
+uoY .mrof yrotcaF looT eht no egaugnal gnitpircs hcae ni elpmaxe na si erehT
+thgir eht tceles ot rebmemer - tuo ti yrt ot eseht etsap dna tuc tsuj nac
+gnisu tes atad tset llams a etaerc ot deen osla ll'uoY .esaelp reterpretni
+.loot atad wen dda yrotsih yxalaG eht
+
+ni tuptuo loot eht no nottub "oder" eht esu ,wohemos sliaf tpircs eht fI
+gub eht xiF .tpircs nekorb htiw etelpmoc mrof eht etaercer ot yrotsih ruoy
+.taeper ,hsaw ,esniR .niaga etucexe dna
+
+tpircs ruoy snur taht loot yxalaG wen a ,yllufssecus snur tpircs eht ecnO
+dna txet pleh emos ylppus dna noitpo "etareneg" eht tceleS .detareneg eb nac
+epytatad yxalaG wen a fo mrof eht ni detareneg eb lliw loot wen ehT .seman
+a ot daolpu ot ydaer evihcra na s'ti ,stseggus eman eht sa - *zg.dehsloot*
+.yrotisoper loot wen a sa dehSlooT yxalaG
+
+revres yxalaG lacol yna otni dellatsni eb nac ti ,dehSlooT a ni s'ti ecnO
+.ecafretni evitartsinimda revres eht morf
+
+tpircs eht ,emit hcae - ti nur nac sresu lacol ,dellatsni si loot wen eht ecnO
+nesohc tupni eht htiw detucexe eb lliw tliub saw ti nehw deilppus saw taht
+eht htiw etareneg uoy sloot eht ,sdrow rehto nI .yrotsih s'resu eht morf
+.emit yreve tpircs ruoy nur tub,loot yxalaG rehto yna ekil tsuj nur yrotcaFlooT
+
+,tuptuo eno ,tupni enO .stnenopmoc wolfkrow rof tcefrep era sloot yrotcaf looT
+.selbairav on
+
+,loot siht fo *rewop emosewa eht tiolpxe ylefas dna ylluf oT*
+siht gnillatsni repoleved a eb dluohs uoy ,dehSlooT eht dna yxalaG
+na era uoy erehw ecnatsni lacol hctarcs/lanosrep/etavirp a no loot
+ees seceip eht lla peek ot teg uoy ,ti kaerb uoy fi ,nehT .resu_nimda
+emoH/ikiw/yrotcaflootyxalag/rabuf/gro.tekcubtib//:sptth
+
+**noitallatsnI**
+eht gnisu yltneinevnoc tsom ti llatsni nac uoY .loot yxalaG a si sihT
+niaM yxalaG eht dniF .knil "sdehs loot esworb dna hcraeS" evitartsinimda
+yrotcafloot eht rof hcraes dna /ude.usp.xb.2g.dehsloot//:sptth ta dehsloot
+.ti llatsni ot noitpo eht tceles dna edoc eht weiver dna ti nepO .yrotisoper
+
+eb ot deen ereh selif yp dna lmx eht ,yaw taht loot eht teg t'nac uoy fI
+sloot wen a otni deipoc
+yrtne wen a sdeen lmx.fnoc_loot ruoY yrotcafloot/sloot sa hcus yrotceridbus
+lmx eht ot gnitniop
+::ekil gnihtemos - elif
+
+>"sredliubloot"=di "sloot gnidliub looT"=eman noitces<
+>/"lmx.yrotcaFlooTgr/yrotcafloot"=elif loot<
+>noitces/<
+
+,ereht ydaerla ton fI
+:dda esaelp
+"yraniB:yranib.sepytatad.yxalag"=epyt "zg.dehsloot"=noisnetxe epytatad<
+>/ "eurT"=ssalcbus "pizg-x/trapitlum"=epytemim
+.lmx.fnoc_sepyt_atad lacol ruoy ot
+
+
+**noitucexe detcirtseR**
+
+- sresu nimda yb YLNO elbasu eb neht lliw flesti loot yrotcaf loot ehT
+YLNO .thgir s'taht ,seY** ini.igsw_esrevinu ni sresu_nimda ni sDI htiw elpoep
+ot dewolla fI .tnemom a rof ti tuoba knihT **loot siht nur nac sresu_nimda
+dluow taht gniht ylno eht ,revres yxalaG ruoy no tpircs yrartibra yna nur
+ylbaborp dluow atad yxalaG ruoy lla gniyortsed no tneb tnaercsim a edepmi
+.slliks lacinhcet etairporppa fo kcal eb
+
+**seod ti tahW**
+
+dna R ,nohtyp ni stpircs elpmis rof yrotcaf loot a si sihT
+.taht si looc woH .detareneg yllacitamotua era stset lanoitcnuF .yltnerruc lrep
+
+nac yllanoitpO .yrotsih eht morf tupni eno daer taht stpircs elpmis ot DETIMIL
+stuptuo fo rebmun yna tcelloc yllanoitpo dna ,tesatad yrotsih wen eno etirw
+- etagivan ot resu eht rof egap xedni LMTH detarenegotua na no sknil otni
+nwohs era stuptuo fdp - selif tuptuo dna segami setirw tpircs eht fi lufesu
+dna taht os tpircstsohg htiw knurhs era s'fdp detaolb s'R dna slianbmuht sa
+.elbaliava eb ot deen kigamegami
+
+trats os ,loot yxalaG yna ekil decnahne dna detide eb nac sloot detareneG
+a ot pu gel suoires a uoy steg tpircs detareneg a ecnis pu dliub dna llams
+.eno xelpmoc erom
+
+**od uoy tahW**
+
+dna srorre xatnys eht xif uoy ,tpircs ruoy nur dna etsap uoY
+erofeb tpircs eht tide dna nottub oder eht esu nac uoY .snur ti yllautneve
+.llew ytterp skrow ti - gubed uoy sa ti nurer ot gniyrt
+
+elbitapmoc dehsloot a etareneg nac uoy ,atad tset emos no skrow tpircs eht ecnO
+ni loot yxalaG yranidro na sa nur ot ydaer tpircs ruoy gniniatnoc elif pizg
+detamotua ylegral dna efas snaem tahT .dehsloot lacol ruoy no yrotisoper a
+.dehsloot ruoy esu ot derugifnoc yxalaG noitcudorp yna ni noitallatsni
+
+**ytiruceS loot detareneG**
+
+tsuj s'ti ,loot detareneg a llatsni uoy ecnO
+rieht dna yllamron nur tsuj yehT .efas si tpircs eht gnimussa - loot rehtona
+.dehsloot efas ecitcarp ,esaelp tub erucesni yllausunu gnihtyna od tonnac resu
+.yracs yllaer si ti - eno siht yllaicepsE .loot yna llatsni uoy erofeb edoc eht daeR
+
+**edoC dneS**
+
+?esaelp seussi tekcubtib sa emoclew snoitseggus dna sehctaP
+
+**noitubirttA**
+
+yrotcaF looT yxalaG ehT :stpircs morf sloot elbasu-er gnitaerC
+maeT yxalaG ehT ;nnameiZ kraM ;ipsaK ynotnA ;surazaL ssoR
+375stb/scitamrofnioib/3901.01 :iod ;2102 scitamrofnioiB
+
+fer=epytyek&JWYdwMrWs1hQzcl=yekji?375stb/tnirper/igc/gro.slanruojdrofxo.scitamrofnioib//:ptth
+
+**gnisneciL**
+
+0102 surazaL ssoR thgirypoC
+moc doirep liam g ta surazal ssor
+
+.devreser sthgir llA
+
+LPGL eht rednu desneciL
+
+**tohsneercs yrotagilbO**
+
+gnp.looTtpircScimanyd/segami/989ef2308adf/crs/rekamlootyxalag/rabuf/gro.tekcubtib//:ptth
diff -r 2beaae16651e -r 0183cad9d13b toolfactory/test-data/pyrevpos.python
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/toolfactory/test-data/pyrevpos.python Thu Feb 22 10:48:01 2024 +0000
@@ -0,0 +1,13 @@
+# reverse order of text by row
+import sys
+inp = sys.argv[1]
+outp = sys.argv[2]
+i = open(inp,'r').readlines()
+o = open(outp,'w')
+for row in i:
+ rs = row.rstrip()
+ rs = list(rs)
+ rs.reverse()
+ o.write(''.join(rs))
+o.close()
+
diff -r 2beaae16651e -r 0183cad9d13b toolfactory/test-data/pyrevpos_not_tested.toolshed_sample
Binary file toolfactory/test-data/pyrevpos_not_tested.toolshed_sample has changed
diff -r 2beaae16651e -r 0183cad9d13b toolfactory/test-data/test1_log.txt
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/toolfactory/test-data/test1_log.txt Thu Feb 22 10:48:01 2024 +0000
@@ -0,0 +1,1 @@
+## Executing Toolfactory generated command line = python /tmp/pyrevposq5dmcdy1.python /tmp/tmpqrksf8sd/files/5/b/9/dataset_5b952a86-87df-44ad-a415-ea549f3f0cee.dat output2
diff -r 2beaae16651e -r 0183cad9d13b toolfactory/test-data/toolfactory_pyrevpos_tgz_sample
Binary file toolfactory/test-data/toolfactory_pyrevpos_tgz_sample has changed
diff -r 2beaae16651e -r 0183cad9d13b toolfactory/toolfactory.py
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/toolfactory/toolfactory.py Thu Feb 22 10:48:01 2024 +0000
@@ -0,0 +1,1393 @@
+# see https://github.com/fubar2/toolfactory
+#
+# copyright ross lazarus (ross stop lazarus at gmail stop com) May 2012
+#
+# all rights reserved
+# Licensed under the LGPL
+# suggestions for improvement and bug fixes welcome at
+# https://github.com/fubar2/toolfactory
+#
+# February 2023: Refactored to use galaxy-tool-test script in galaxyutil
+# planemo not needed if tool is already installed.
+# sqlite does not seem to work - switch to postgresql in the installation script
+#
+# march 2022: Refactored into two tools - generate and test/install
+# as part of GTN tutorial development and biocontainer adoption
+# The tester runs planemo on a non-tested archive, creates the test outputs
+# and returns a new proper tool with test.
+
+
+import argparse
+import copy
+import json
+import logging
+import os
+import re
+import shlex
+import shutil
+import subprocess
+import sys
+import tarfile
+import tempfile
+import time
+
+from bioblend import galaxy
+from bioblend import ConnectionError
+
+import galaxyxml.tool as gxt
+import galaxyxml.tool.parameters as gxtp
+
+import lxml.etree as ET
+
+import yaml
+
+
+logger = logging.getLogger(__name__)
+
+
+class Tool_Factory:
+ """Wrapper for an arbitrary script
+ uses galaxyxml
+ """
+
+ def __init__(self, args=None): # noqa
+ """
+ prepare command line cl for running the tool here
+ and prepare elements needed for galaxyxml tool generation
+ """
+ assert args.parampass in [
+ "0",
+ "embed",
+ "argparse",
+ "positional",
+ "embednfmod",
+ ], (
+ "args.parampass %s not 0,positional, embed, embednfmod or argparse"
+ % args.parampass
+ )
+ # sed will update these settings during tfsetup.py first run
+ self.GALAXY_ADMIN_KEY = "1718977735397126400"
+ self.GALAXY_URL = "http://localhost:8080"
+ self.profile = "22.05"
+ self.not_iuc = True
+ self.args = args
+ self.tool_version = self.args.tool_version
+ self.myversion = "V3.0 February 2023"
+ self.verbose = True
+ self.debug = True
+ self.toolFactoryURL = "https://github.com/fubar2/galaxy_tf_overlay"
+ self.logger = logging.getLogger(__name__)
+ self.nfcoremod = False
+ if args.parampass == "embednfmod":
+ self.nfcoremod = True
+ self.script_in_help = False # IUC recommendation
+ self.tool_name = re.sub("[^a-zA-Z0-9_]+", "", args.tool_name)
+ self.tool_id = self.tool_name
+ self.local_tools = os.path.realpath(
+ os.path.join(args.galaxy_root, "local_tools")
+ )
+ self.repdir = os.path.realpath(args.tfcollection)
+ self.testdir = os.path.join(self.repdir, self.tool_name)
+ self.toold = os.path.join(self.local_tools, self.tool_name)
+ self.tooltestd = os.path.join(self.toold, "test-data")
+ if self.nfcoremod:
+ self.local_tools = os.path.join(args.tfcollection, "tools")
+ self.repdir = os.path.join(args.tfcollection, "TFouts", self.tool_name)
+ self.toold = os.path.join(self.local_tools, self.tool_name)
+ self.tooltestd = os.path.join(self.toold, "test-data")
+ os.makedirs(self.repdir, exist_ok=True)
+ os.makedirs(self.toold, exist_ok=True)
+ os.makedirs(self.tooltestd, exist_ok=True)
+ os.makedirs(self.local_tools, exist_ok=True)
+ self.local_tool_conf = os.path.join(self.local_tools, "local_tool_conf.xml")
+ self.ourcwd = os.getcwd()
+ self.collections = []
+ if len(args.collection) > 0:
+ try:
+ self.collections = [
+ json.loads(x) for x in args.collection if len(x.strip()) > 1
+ ]
+ except Exception:
+ self.logger.error(
+ f"--collections parameter {str(args.collection)} is malformed - should be a dictionary"
+ )
+ self.infiles = []
+ try:
+ self.infiles = [
+ json.loads(x) for x in args.input_files if len(x.strip()) > 1
+ ]
+ except Exception:
+ self.logger.error(
+ f"--input_files parameter {str(args.input_files)} is malformed - should be a dictionary"
+ )
+ self.extra_files = []
+ if len(args.xtra_files) > 0:
+ try:
+ self.extra_files = [
+ json.loads(x) for x in args.xtra_files if len(x.strip()) > 1
+ ]
+ except Exception:
+ self.logger.error(
+ f"--xtra_files parameter {str(args.xtra_files)} is malformed - should be a dictionary"
+ )
+ self.outfiles = []
+ try:
+ self.outfiles = [
+ json.loads(x) for x in args.output_files if len(x.strip()) > 1
+ ]
+ except Exception:
+ self.logger.error(
+ f"--output_files parameter {args.output_files} is malformed - should be a dictionary"
+ )
+ assert (
+ len(self.outfiles) + len(self.collections)
+ ) > 0, "No outfiles or output collections specified. The Galaxy job runner will fail without an output of some sort"
+ self.addpar = []
+ try:
+ self.addpar = [
+ json.loads(x) for x in args.additional_parameters if len(x.strip()) > 1
+ ]
+ except Exception:
+ self.logger.error(
+ f"--additional_parameters {args.additional_parameters} is malformed - should be a dictionary"
+ )
+ self.selpar = []
+ try:
+ self.selpar = [
+ json.loads(x) for x in args.selecttext_parameters if len(x.strip()) > 1
+ ]
+ except Exception:
+ self.logger.error(
+ f"--selecttext_parameters {args.selecttext_parameters} is malformed - should be a dictionary"
+ )
+ self.selfagpar = []
+ try:
+ self.selflagpar = [
+ json.loads(x) for x in args.selectflag_parameters if len(x.strip()) > 1
+ ]
+ except Exception:
+ self.logger.error(
+ f"--selectflag_parameters {args.selecttext_parameters} is malformed - should be a dictionary"
+ )
+ self.cleanuppar()
+ self.lastxclredirect = None
+ self.xmlcl = []
+ self.is_positional = self.args.parampass == "positional"
+ self.is_embedded = self.args.parampass == "embedded"
+ if self.args.sysexe:
+ if " " in self.args.sysexe:
+ self.executeme = shlex.split(self.args.sysexe)
+ else:
+ self.executeme = [
+ self.args.sysexe,
+ ]
+ else:
+ if self.args.packages:
+ self.executeme = [
+ self.args.packages.split(",")[0].split(":")[0].strip(),
+ ]
+ else:
+ self.executeme = []
+ aXCL = self.xmlcl.append
+ self.newtarpath = args.tested_tool_out
+ self.tinputs = gxtp.Inputs()
+ self.toutputs = gxtp.Outputs()
+ self.testparam = []
+ if self.args.script_path:
+ self.prepScript()
+ else:
+ self.script = None
+ if self.args.cl_override != None:
+ scos = open(self.args.cl_override, "r").readlines()
+ self.cl_override = [x.rstrip() for x in scos]
+ else:
+ self.cl_override = None
+ if self.args.test_override != None:
+ stos = open(self.args.test_override, "r").readlines()
+ self.test_override = [x.rstrip() for x in stos]
+ else:
+ self.test_override = None
+ if self.args.cl_prefix != None:
+ scos = open(self.args.cl_prefix, "r").readlines()
+ self.cl_prefix = [x.rstrip() for x in scos]
+ else:
+ self.cl_prefix = None
+ if self.args.cl_suffix != None:
+ stos = open(self.args.cl_suffix, "r").readlines()
+ self.cl_suffix = [x.rstrip() for x in stos]
+ else:
+ self.cl_suffix = None
+ if self.args.script_path:
+ for ex in self.executeme:
+ if ex:
+ aXCL(ex)
+ aXCL("'$runme'")
+ else:
+ for ex in self.executeme:
+ aXCL(ex)
+ if self.args.parampass == "0":
+ self.clsimple()
+ elif self.args.parampass == "positional":
+ self.prepclpos()
+ self.clpositional()
+ elif self.args.parampass == "argparse":
+ self.prepargp()
+ self.clargparse()
+ elif self.args.parampass.startswith("embed"):
+ self.prepembed()
+ else:
+ logging.error(
+ "Parampass value %s not in 0, positional, argparse, embed or embednfmod"
+ % self.args.parampass
+ )
+ logging.shutdown()
+ sys.exit(6)
+
+ def clsimple(self):
+ """no parameters or repeats - uses < and > for i/o"""
+ aXCL = self.xmlcl.append
+ if len(self.infiles) > 0:
+ aXCL("<")
+ aXCL("'$%s'" % self.infiles[0]["infilename"])
+ if len(self.outfiles) > 0:
+ aXCL(">")
+ aXCL("'$%s'" % self.outfiles[0]["name"])
+
+ def prepembed(self):
+ """fix self.script"""
+ scrip = self.script
+ if self.nfcoremod:
+ self.script = (
+ '#set prefix = "%s"\n#set task_process = "%s"\n'
+ % (self.tool_name, self.tool_name)
+ + scrip
+ )
+ self.xmlcl = [] # wipe anything there
+ aX = self.xmlcl.append
+ aX("")
+ if self.nfcoremod:
+ aX('#set prefix = "%s"' % self.tool_name)
+ aX('#set task_process = "%s"' % self.tool_name)
+ for p in self.collections:
+ aX("mkdir -p %s &&" % p["name"])
+ aX("%s '$runme'" % self.args.sysexe)
+
+ def prepargp(self):
+ xclsuffix = []
+ for i, p in enumerate(self.infiles):
+ rep = p["required"] in ["optional1", "required1"]
+ req = p["required"] in ["required", "required1"]
+ nam = p["infilename"]
+ flag = p["CL"]
+ if p["origCL"].strip().upper() == "STDIN":
+ xappendme = [
+ nam,
+ nam,
+ "< '$%s'" % nam,
+ ]
+ else:
+ xappendme = [p["CL"], "'$%s'" % p["CL"], ""]
+ xclsuffix.append(xappendme)
+ for i, p in enumerate(self.outfiles):
+ if p["origCL"].strip().upper() == "STDOUT":
+ self.lastxclredirect = [">", "'$%s'" % p["name"]]
+ else:
+ xclsuffix.append([p["name"], "'$%s'" % p["name"], ""])
+ for p in self.addpar:
+ nam = p["name"]
+ val = p["value"]
+ flag = p["CL"]
+ rep = p.get("repeat", 0) == "1"
+ if rep:
+ over = f'#for $rep in $R_{nam}:\n--{nam} "$rep.{nam}"\n#end for'
+ else:
+ over = p.get("override", "")
+ if p["type"] == "clflag":
+ over = f'#if ${nam} == "set"\n --{flag}\n#end if'
+ xclsuffix.append([p["CL"], "'$%s'" % nam, over])
+ for p in self.selpar:
+ xclsuffix.append([p["CL"], "'$%s'" % p["name"], p.get("override", "")])
+ for p in self.selflagpar:
+ xclsuffix.append(["", "'$%s'" % p["name"], ""])
+ for p in self.collections:
+ newname = p["name"]
+ xclsuffix.append([newname, "'%s'" % newname, ""])
+ self.xclsuffix = xclsuffix
+
+ def prepclpos(self):
+ xclsuffix = []
+ for i, p in enumerate(self.infiles):
+ if p["origCL"].strip().upper() == "STDIN":
+ xappendme = [
+ "999",
+ p["infilename"],
+ "< '$%s'" % p["infilename"],
+ ]
+ else:
+ xappendme = [p["CL"], "'$%s'" % p["infilename"], ""]
+ xclsuffix.append(xappendme)
+ for i, p in enumerate(self.outfiles):
+ if p["origCL"].strip().upper() == "STDOUT":
+ self.lastxclredirect = [">", "'$%s'" % p["name"]]
+ else:
+ xclsuffix.append([p["CL"], "'$%s'" % p["name"], ""])
+ for p in self.addpar:
+ nam = p["name"]
+ rep = p.get("repeat", "0") == "1" # repeats make NO sense
+ if rep:
+ logger.warning(
+ f"### warning. Repeats for {nam} ignored - not permitted in positional parameter command lines!"
+ )
+ over = p.get("override", "")
+ xclsuffix.append([p["CL"], "'$%s'" % nam, over])
+ for p in self.selpar:
+ xclsuffix.append([p["CL"], "'$%s'" % p["name"], p.get("override", "")])
+ for p in self.selflagpar:
+ xclsuffix.append(["", "'$%s'" % p["name"], ""])
+ for p in self.collections:
+ newname = p["name"]
+ xclsuffix.append([newname, "'$%s'" % newname, ""])
+ xclsuffix.sort()
+ self.xclsuffix = xclsuffix
+
+ def prepScript(self):
+ s = open(self.args.script_path, "r").read()
+ ss = s.split("\n")
+ rxcheck = [x for x in ss if x.strip() > ""]
+ assert len(rxcheck) > 0, "Supplied script is empty. Cannot run"
+ if self.args.sysexe and self.args.parampass != "embed":
+ rxcheck.insert(0, "#raw")
+ rxcheck.append("#end raw")
+ self.script = "\n".join(rxcheck)
+ if len(self.executeme) > 0:
+ self.sfile = os.path.join(
+ self.repdir, "%s.%s.txt" % (self.tool_name, self.executeme[0])
+ )
+ else:
+ self.sfile = os.path.join(
+ self.repdir, "%s.script.txt" % (self.tool_name)
+ )
+ tscript = open(self.sfile, "w")
+ tscript.write(self.script)
+ tscript.write("\n")
+ tscript.close()
+ self.spacedScript = [
+ f" {x.replace('${','$ {')}" for x in ss if x.strip() > ""
+ ]
+ self.escapedScript = rxcheck
+
+ def cleanuppar(self):
+ """positional parameters are complicated by their numeric ordinal"""
+ if self.args.parampass == "positional":
+ for i, p in enumerate(self.infiles):
+ assert (
+ p["CL"].isdigit() or p["CL"].strip().upper() == "STDIN"
+ ), "Positional parameters must be ordinal integers - got %s for %s" % (
+ p["CL"],
+ p["label"],
+ )
+ for i, p in enumerate(self.outfiles):
+ assert (
+ p["CL"].isdigit() or p["CL"].strip().upper() == "STDOUT"
+ ), "Positional parameters must be ordinal integers - got %s for %s" % (
+ p["CL"],
+ p["name"],
+ )
+ for i, p in enumerate(self.addpar):
+ assert p[
+ "CL"
+ ].isdigit(), "Positional parameters must be ordinal integers - got %s for %s" % (
+ p["CL"],
+ p["name"],
+ )
+ for i, p in enumerate(self.infiles):
+ infp = copy.copy(p)
+ infp["origCL"] = infp["CL"]
+ if self.args.parampass in ["positional", "0"]:
+ infp["infilename"] = infp["label"].replace(" ", "_")
+ else:
+ infp["infilename"] = infp["CL"]
+ self.infiles[i] = infp
+ for i, p in enumerate(self.outfiles):
+ outfp = copy.copy(p)
+ outfp["origCL"] = outfp["CL"] # keep copy
+ if outfp.get("label", None) == None:
+ outfp["label"] = ""
+ self.outfiles[i] = outfp
+ for i, p in enumerate(self.addpar):
+ addp = copy.copy(p)
+ addp["origCL"] = addp["CL"]
+ self.addpar[i] = addp
+ for i, p in enumerate(self.collections):
+ addp = copy.copy(p)
+ addp["CL"] = addp["name"]
+ self.collections[i] = addp
+
+ def clpositional(self):
+ # inputs in order then params
+ aXCL = self.xmlcl.append
+ for (k, v, koverride) in self.xclsuffix:
+ aXCL(v)
+ if self.lastxclredirect:
+ for cl in self.lastxclredirect:
+ aXCL(cl)
+
+ def clargparse(self):
+ """argparse style"""
+ aXCL = self.xmlcl.append
+ # inputs then params in argparse named form
+ for (k, v, koverride) in self.xclsuffix:
+ if koverride > "":
+ k = koverride
+ aXCL(k)
+ else:
+ kl = len(k.strip())
+ if kl == 0:
+ k = " "
+ elif kl == 1:
+ k = "-%s" % k
+ else:
+ k = "--%s" % k
+ aXCL(k)
+ aXCL(v)
+ if self.lastxclredirect:
+ for cl in self.lastxclredirect:
+ aXCL(cl)
+
+ def getNdash(self, newname):
+ if self.is_positional:
+ ndash = 0
+ else:
+ ndash = 2
+ if len(newname) < 2:
+ ndash = 1
+ return ndash
+
+ def doXMLparam(self): # noqa
+ """Add all needed elements to tool"""
+ for p in self.outfiles:
+ newname = p["name"]
+ newfmt = p["format"]
+ newcl = p["CL"]
+ test = p["test"]
+ oldcl = p["origCL"]
+ test = test.strip()
+ filta = p.get("when", [])
+ lab = p.get("label", "")
+ if len(lab.strip()) == 0:
+ lab = newname
+ ndash = self.getNdash(newcl)
+ aparm = gxtp.OutputData(
+ name=newname, format=newfmt, num_dashes=ndash, label=lab
+ )
+ if len(filta) > 0:
+ ofilta = gxtp.ChangeFormat()
+ for (
+ whens
+ ) in filta: # when input=|image_type| value=|large_png| format=|png|
+ whenss = whens.replace("|", '"').replace("when ", "")
+ clauses = whenss.split()
+ for c in clauses:
+ if c.startswith("value"):
+ v = c.split("=")[1]
+ elif c.startswith("format"):
+ f = c.split("=")[1]
+ elif c.startswith("input"):
+ i = c.split("=")[1]
+ else:
+ print(
+ "bad when - need value=, format= and input=, got", whens
+ )
+ owhen = gxtp.ChangeFormatWhen(format=f, input=i, value=v)
+ ofilta.append(owhen)
+ aparm.append(ofilta)
+ aparm.positional = self.is_positional
+ if self.is_positional:
+ if oldcl.upper() == "STDOUT":
+ aparm.positional = 9999999
+ aparm.command_line_override = "> '$%s'" % newname
+ else:
+ aparm.positional = int(oldcl)
+ aparm.command_line_override = "'$%s'" % newname
+ self.toutputs.append(aparm)
+ ld = None
+ if test.strip() > "":
+ if test.strip().startswith("diff"):
+ c = "diff"
+ ld = 0
+ if test.split(":")[1].isdigit:
+ ld = int(test.split(":")[1])
+ tp = gxtp.TestOutput(
+ name=newname,
+ value="%s_sample" % newname,
+ compare=c,
+ lines_diff=ld,
+ )
+ elif test.startswith("sim_size"):
+ c = "sim_size"
+ tn = test.split(":")[1].strip()
+ if tn > "":
+ if "." in tn:
+ delta = None
+ delta_frac = min(1.0, float(tn))
+ else:
+ delta = int(tn)
+ delta_frac = None
+ tp = gxtp.TestOutput(
+ name=newname,
+ value="%s_sample" % newname,
+ compare=c,
+ delta=delta,
+ delta_frac=delta_frac,
+ )
+ else:
+ c = test
+ tp = gxtp.TestOutput(
+ name=newname,
+ value="%s_sample" % newname,
+ compare=c,
+ )
+ self.testparam.append(tp)
+ for p in self.infiles:
+ newname = p["infilename"]
+ newfmt = p["format"]
+ ndash = self.getNdash(newname)
+ reps = p.get("required", "") in ["optional1", "required1"]
+ isoptional = p.get("required", "") in ["optional", "optional1"]
+ if not len(p["label"]) > 0:
+ alab = p["CL"]
+ else:
+ alab = p["label"]
+ aninput = gxtp.DataParam(
+ newname,
+ optional=isoptional,
+ label=alab,
+ help=p["help"],
+ format=newfmt,
+ multiple=reps,
+ num_dashes=ndash,
+ )
+ aninput.positional = self.is_positional
+ if self.is_positional:
+ if p["origCL"].upper() == "STDIN":
+ aninput.positional = 9999998
+ aninput.command_line_override = "< '$%s'" % newname
+ else:
+ aninput.positional = int(p["origCL"])
+ aninput.command_line_override = "'$%s'" % newname
+ self.tinputs.append(aninput)
+ tparm = gxtp.TestParam(newname, value="%s_sample" % newname)
+ self.testparam.append(tparm)
+ for p in self.addpar:
+ newname = p["name"]
+ newval = p.get("value", "")
+ newlabel = p["label"]
+ newhelp = p.get("help", "")
+ newtype = p.get("type", "?")
+ newcl = p["CL"]
+ oldcl = p["origCL"]
+ reps = p.get("repeat", "0") == "1"
+ if not len(newlabel) > 0:
+ newlabel = newname
+ ndash = self.getNdash(newname)
+ if newtype == "text":
+ aparm = gxtp.TextParam(
+ newname,
+ label=newlabel,
+ help=newhelp,
+ value=newval,
+ num_dashes=ndash,
+ )
+ elif newtype == "integer":
+ aparm = gxtp.IntegerParam(
+ newname,
+ label=newlabel,
+ help=newhelp,
+ value=int(newval.replace("'", "").replace('"', "")),
+ num_dashes=ndash,
+ )
+ elif newtype == "float":
+ aparm = gxtp.FloatParam(
+ newname,
+ label=newlabel,
+ help=newhelp,
+ value=float(newval.replace("'", "").replace('"', "")),
+ num_dashes=ndash,
+ )
+ elif newtype == "boolean":
+ aparm = gxtp.BooleanParam(
+ newname,
+ label=newlabel,
+ help=newhelp,
+ value=newval,
+ num_dashes=ndash,
+ )
+ elif newtype == "clflag":
+ initval = newval
+ aparm = gxtp.SelectParam(
+ newname,
+ label=newlabel,
+ help=newhelp,
+ num_dashes=ndash,
+ display="radio",
+ )
+ anoptt = gxtp.SelectOption(
+ value="set",
+ text="Set this flag",
+ )
+ anoptf = gxtp.SelectOption(
+ value="notset",
+ text="Do not set this flag",
+ )
+ if p["value"] == "set": # make default same as form
+ aparm.append(anoptt)
+ aparm.append(anoptf)
+ else:
+ aparm.append(anoptf)
+ aparm.append(anoptt)
+ elif newtype == "datacolumn":
+ aparm = gxtp.TextParam(
+ newname,
+ type="data_column",
+ data_ref=p["dataref"],
+ multiple=(p["multiple"] == "1"),
+ label=newlabel,
+ help=newhelp,
+ value=newval,
+ num_dashes=ndash,
+ )
+ else:
+ raise ValueError(
+ 'Unrecognised parameter type "%s" for \
+ additional parameter %s in makeXML'
+ % (newtype, newname)
+ )
+ aparm.positional = self.is_positional
+ if self.is_positional:
+ aparm.positional = int(oldcl)
+ if reps:
+ repe = gxtp.Repeat(
+ name=f"R_{newname}",
+ title=f"Any number of {newlabel} repeats are allowed",
+ )
+ repe.append(aparm)
+ self.tinputs.append(repe)
+ tparm = gxtp.TestRepeat(name=f"R_{newname}")
+ tparm2 = gxtp.TestParam(newname, value=newval)
+ tparm.append(tparm2)
+ self.testparam.append(tparm)
+ else:
+ self.tinputs.append(aparm)
+ tparm = gxtp.TestParam(newname, value=newval)
+ self.testparam.append(tparm)
+ for p in self.selpar:
+ newname = p["name"]
+ newval = p.get("value", "")
+ newlabel = p["label"]
+ newhelp = p["help"]
+ newtype = p["type"]
+ newcl = p["CL"]
+ if not len(newlabel) > 0:
+ newlabel = newname
+ ndash = self.getNdash(newname)
+ if newtype == "selecttext":
+ newtext = p["texts"]
+ aparm = gxtp.SelectParam(
+ newname,
+ label=newlabel,
+ help=newhelp,
+ num_dashes=ndash,
+ )
+ for i in range(len(newval)):
+ anopt = gxtp.SelectOption(
+ value=newval[i],
+ text=newtext[i],
+ )
+ aparm.append(anopt)
+ aparm.positional = self.is_positional
+ if self.is_positional:
+ aparm.positional = int(newcl)
+ self.tinputs.append(aparm)
+ tparm = gxtp.TestParam(newname, value=newval[0])
+ self.testparam.append(tparm)
+ else:
+ raise ValueError(
+ 'Unrecognised parameter type "%s" for\
+ selecttext parameter %s in makeXML'
+ % (newtype, newname)
+ )
+ for p in self.selflagpar:
+ newname = p["name"]
+ newval = p["value"]
+ newlabel = p["label"]
+ newhelp = p["help"]
+ newtype = p["type"]
+ newtext = p["texts"]
+ newcl = p["CL"]
+ if not len(newlabel) > 0:
+ newlabel = newname
+ aparm = gxtp.SelectParam(
+ newname,
+ label=newlabel,
+ help=newhelp,
+ num_dashes=0,
+ )
+ for i in range(len(newval)):
+ anopt = gxtp.SelectOption(
+ value=newval[i],
+ text=newtext[i],
+ )
+ aparm.append(anopt)
+ aparm.positional = self.is_positional
+ if self.is_positional:
+ aparm.positional = int(newcl)
+ self.tinputs.append(aparm)
+ tparm = gxtp.TestParam(newname, value=newval[0])
+ self.testparam.append(tparm)
+
+ def doNoXMLparam(self):
+ """filter style package - stdin to stdout"""
+ if len(self.infiles) > 0:
+ alab = self.infiles[0]["label"]
+ if len(alab) == 0:
+ alab = self.infiles[0]["infilename"]
+ max1s = (
+ "Maximum one input if parampass is 0 but multiple input files supplied - %s"
+ % str(self.infiles)
+ )
+ assert len(self.infiles) == 1, max1s
+ newname = self.infiles[0]["infilename"]
+ aninput = gxtp.DataParam(
+ newname,
+ optional=False,
+ label=alab,
+ help=self.infiles[0]["help"],
+ format=self.infiles[0]["format"],
+ multiple=False,
+ num_dashes=0,
+ )
+ aninput.command_line_override = "< $%s" % newname
+ aninput.positional = True
+ self.tinputs.append(aninput)
+ tp = gxtp.TestParam(name=newname, value="%s_sample" % newname)
+ self.testparam.append(tp)
+ if len(self.outfiles) > 0:
+ newname = self.outfiles[0]["name"]
+ newfmt = self.outfiles[0]["format"]
+ anout = gxtp.OutputData(newname, format=newfmt, num_dashes=0)
+ anout.command_line_override = "> $%s" % newname
+ anout.positional = self.is_positional
+ self.toutputs.append(anout)
+ tp = gxtp.TestOutput(name=newname, value="%s_sample" % newname)
+ self.testparam.append(tp)
+
+ def makeXML(self): # noqa
+ """
+ Create a Galaxy xml tool wrapper for the new script
+ Uses galaxyhtml
+ Hmmm. How to get the command line into correct order...
+ """
+ requirements = gxtp.Requirements()
+ self.condaenv = []
+ if self.args.packages:
+ try:
+ for d in self.args.packages.split(","):
+ ver = None
+ packg = None
+ d = d.replace("==", ":")
+ d = d.replace("=", ":")
+ if ":" in d:
+ packg, ver = d.split(":")[:2]
+ ver = ver.strip()
+ packg = packg.strip()
+ self.tool_version = ver
+ else:
+ packg = d.strip()
+ ver = None
+ if ver == "":
+ ver = None
+ if packg:
+ requirements.append(
+ gxtp.Requirement("package", packg.strip(), ver)
+ )
+ self.condaenv.append(d)
+ except Exception:
+ self.logger.error(
+ "### malformed packages string supplied - cannot parse = %s"
+ % self.args.packages
+ )
+ sys.exit(2)
+ elif self.args.container:
+ requirements.append(gxtp.Requirement("container", self.args.container))
+ self.newtool = gxt.Tool(
+ self.tool_name,
+ self.tool_id,
+ self.tool_version,
+ self.args.tool_desc,
+ "",
+ profile=self.profile,
+ )
+ self.newtool.requirements = requirements
+ iXCL = self.xmlcl.insert
+ aXCL = self.xmlcl.append
+ if self.args.cl_prefix: # DIY CL start
+ self.xmlcl = self.cl_prefix + self.xmlcl
+ if self.args.cl_suffix: # DIY CL end
+ self.xmlcl += self.cl_suffix
+ if self.cl_override:
+ self.newtool.command_override = self.cl_override # config file
+ else:
+ self.newtool.command_override = self.xmlcl
+ self.cites = self.parse_citations()
+ cite = gxtp.Citations()
+ if self.cites and len(self.cites) > 0:
+ for c in self.cites:
+ acite = gxtp.Citation(type=c[0], value=c[1])
+ cite.append(acite)
+ acite = gxtp.Citation(type="doi", value="10.1093/bioinformatics/bts573")
+ cite.append(acite)
+ self.newtool.citations = cite
+ safertext = ""
+ if self.args.help_text:
+ self.helptext = open(self.args.help_text, "r").readlines()
+ safertext = "\n".join([self.cheetah_escape(x) for x in self.helptext])
+ if len(safertext.strip()) == 0:
+ safertext = (
+ "Ask the tool author (%s) to rebuild with help text please\n"
+ % (self.args.user_email)
+ )
+ if self.script_in_help and self.args.script_path:
+ if len(safertext) > 0:
+ safertext = safertext + "\n\n------\n" # transition allowed!
+ scr = [x for x in self.spacedScript if x.strip() > ""]
+ scr.insert(0, "\n\nScript::\n")
+ if len(scr) > 300:
+ scr = (
+ scr[:100]
+ + [" >300 lines - stuff deleted", " ......"]
+ + scr[-100:]
+ )
+ scr.append("\n")
+ safertext = safertext + "\n".join(scr)
+ self.newtool.help = " ".join(self.helptext)
+ for p in self.collections:
+ newkind = p["kind"]
+ newname = p["name"]
+ newlabel = p["label"]
+ newdisc = p["discover"]
+ collect = gxtp.OutputCollection(newname, label=newlabel, type=newkind)
+ disc = gxtp.DiscoverDatasets(
+ pattern=newdisc, directory=f"{newname}", visible="false"
+ )
+ collect.append(disc)
+ self.toutputs.append(collect)
+ try:
+ tparm = gxtp.TestOutputCollection(newname) # broken until PR merged.
+ self.testparam.append(tparm)
+ except Exception:
+ logging.error(
+ "WARNING: Galaxyxml version does not have the PR merged yet - tests for collections must be over-ridden until then!"
+ )
+ self.newtool.version_command = f'echo "{self.tool_version}"'
+ if self.args.parampass == "0":
+ self.doNoXMLparam()
+ else:
+ self.doXMLparam()
+ self.newtool.outputs = self.toutputs
+ self.newtool.inputs = self.tinputs
+ if self.args.script_path:
+ configfiles = gxtp.Configfiles()
+ configfiles.append(gxtp.Configfile(name="runme", text=self.script))
+ self.newtool.configfiles = configfiles
+ tests = gxtp.Tests()
+ test_a = gxtp.Test()
+ for tp in self.testparam:
+ test_a.append(tp)
+ tests.append(test_a)
+ self.newtool.tests = tests
+ self.newtool.add_comment(
+ "Created by %s at %s using the Galaxy Tool Factory."
+ % (self.args.user_email, self.timenow())
+ )
+ self.newtool.add_comment("Source in git at: %s" % (self.toolFactoryURL))
+ exml = self.newtool.export()
+ if (
+ self.test_override
+ ): # cannot do this inside galaxyxml as it expects lxml objects for tests
+ part1 = exml.split("")[0]
+ part2 = exml.split("")[1]
+ fixed = "%s\n%s\n%s" % (part1, "\n".join(self.test_override), part2)
+ exml = fixed
+ with open(os.path.join(self.toold, "%s.xml" % self.tool_name), "w") as xf:
+ xf.write(exml)
+ xf.write("\n")
+ with open(os.path.join(self.repdir, "%s_xml.xml" % self.tool_name), "w") as xf:
+ xf.write(exml)
+ xf.write("\n")
+
+ def writeShedyml(self):
+ """for planemo"""
+ yuser = self.args.user_email.split("@")[0]
+ yfname = os.path.join(self.toold, ".shed.yml")
+ yamlf = open(yfname, "w")
+ odict = {
+ "name": self.tool_name,
+ "owner": "fubar2",
+ "type": "unrestricted",
+ "description": "ToolFactory autogenerated tool",
+ "synopsis": self.args.tool_desc,
+ "category": "ToolFactory generated Tools",
+ }
+ yaml.dump(odict, yamlf, allow_unicode=True)
+ yamlf.close()
+
+ def writeTFyml(self):
+ """for posterity"""
+ adict = {}
+ rargs = [
+ "input_files",
+ "output_files",
+ "additional_parameters",
+ "selecttext_parameters",
+ "selectflag_parameters",
+ "xtra_files",
+ ]
+ args = vars(self.args)
+ for k in args.keys():
+ if k not in rargs:
+ adict[k] = args.get(k, None)
+ else:
+ if adict.get(k, None):
+ adict[k].append(adict[k])
+ else:
+ adict[k] = [args.get(k, None)]
+ adict["script"] = self.script
+ adict["help"] = self.helptext
+ yfname = os.path.join(self.repdir, "%s_ToolFactory.yml" % self.tool_name)
+ yf = open(yfname, "w")
+ yaml.dump(adict, yf)
+ yf.close()
+
+ def saveTestdata(self, pname, testDataURL):
+ """
+ may need to be ungzipped and in test folder
+ """
+ res = 0
+ localpath = os.path.join(self.tooltestd, "%s_sample" % pname)
+ print("#### save", testDataURL, "for", pname, "to", localpath)
+ if not os.path.exists(localpath):
+ cl = [
+ "wget",
+ "--timeout",
+ "5",
+ "--tries",
+ "2",
+ "-O",
+ localpath,
+ testDataURL,
+ ]
+ if testDataURL.endswith(".gz"): # major kludge as usual...
+ gzlocalpath = "%s.gz" % localpath
+ cl = [
+ "wget",
+ "-q",
+ "--timeout",
+ "5",
+ "--tries",
+ "2",
+ "-O",
+ gzlocalpath,
+ testDataURL,
+ "&&",
+ "rm",
+ "-f",
+ localpath,
+ "&&",
+ "gunzip",
+ gzlocalpath,
+ ]
+ p = subprocess.run(" ".join(cl), shell=True)
+ if p.returncode:
+ print("Got", p.returncode, "from executing", " ".join(cl))
+ else:
+ print("Not re-downloading", localpath)
+ return res
+
+ def makeTool(self):
+ """write xmls and input samples into place"""
+ if self.args.parampass == 0:
+ self.doNoXMLparam()
+ else:
+ self.makeXML()
+ if self.args.script_path and self.not_iuc:
+ stname = os.path.join(self.toold, os.path.split(self.sfile)[1])
+ if not os.path.exists(stname):
+ shutil.copyfile(self.sfile, stname)
+ logger.info("Copied %s to %s" % (self.sfile, stname))
+ for p in self.infiles:
+ paths = p["name"]
+ pname = p["CL"]
+ pathss = paths.split(",")
+ np = len(pathss)
+ if p.get("URL", None):
+ res = self.saveTestdata(pname, p["URL"])
+ for i, pth in enumerate(pathss):
+ if os.path.exists(pth):
+ if np > 1:
+ dest = os.path.join(
+ self.tooltestd, "%s_%d_sample" % (p["infilename"], i + 1)
+ )
+ else:
+ dest = os.path.join(
+ self.tooltestd, "%s_sample" % p["infilename"]
+ )
+ shutil.copyfile(pth, dest)
+ logger.info("Copied %s to %s" % (pth, dest))
+ else:
+ logger.info(
+ "Optional input path %s does not exist - not copied" % pth
+ )
+ if self.extra_files and len(self.extra_files) > 0:
+ for xtra in self.extra_files:
+ fpath = xtra["fpath"]
+ dest = os.path.join(self.toold, xtra["fname"])
+ shutil.copyfile(fpath, dest)
+ logger.info("Copied xtra file %s to %s" % (fpath, dest))
+ shutil.copytree(self.toold, self.testdir, dirs_exist_ok=True)
+
+ def makeToolTar(self, test_retcode=0):
+ """move outputs into test-data and prepare the tarball"""
+ excludeme = "tool_test_output"
+
+ def exclude_function(tarinfo):
+ filename = tarinfo.name
+ return None if filename.startswith(excludeme) else tarinfo
+
+ logger.info("makeToolTar starting with tool test retcode=%d\n" % test_retcode)
+ td = os.listdir(self.toold)
+ for f in td:
+ if f.startswith("tool_test_output"):
+ os.unlink(os.path.join(self.toold, f))
+ if self.newtarpath:
+ tf = tarfile.open(self.newtarpath, "w:gz")
+ tf.add(
+ name=self.toold,
+ arcname=self.tool_name,
+ # filter=exclude_function,
+ )
+
+ def planemo_local_test(self):
+ """
+ weird legacyversion error popping up again from package version upgrade in conda_util.py in the venv.
+ Seems ok if run as a shell script using the Galaxy installed planemo august 1st 2023
+ """
+ shutil.copytree(self.toold, self.testdir, dirs_exist_ok=True)
+ x = "%s.xml" % self.tool_name
+ xout = os.path.abspath(os.path.join(self.testdir, x))
+ cl = [
+ "planemo",
+ "test",
+ "--galaxy_admin_key",
+ self.GALAXY_ADMIN_KEY,
+ "--engine",
+ "external_galaxy",
+ "--update_test_data",
+ "--galaxy_url",
+ self.GALAXY_URL,
+ xout,
+ ]
+ clx = [
+ "planemo",
+ "test",
+ "--galaxy_admin_key",
+ "[GALAXY_ADMIN_KEY]",
+ "--engine",
+ "external_galaxy",
+ "--update_test_data",
+ "--galaxy_url",
+ self.GALAXY_URL,
+ xout,
+ ]
+ logger.info("planemo_local_test executing: %s" % " ".join(clx))
+ p = subprocess.run(
+ " ".join(cl),
+ timeout=90,
+ shell=True,
+ cwd=self.testdir,
+ capture_output=True,
+ check=True,
+ text=True,
+ )
+ for errline in p.stderr.splitlines():
+ logger.info("planemo: %s" % errline)
+ for errline in p.stdout.splitlines():
+ logger.info("planemo: %s" % errline)
+ shutil.copytree(self.testdir, self.toold)
+ dest = self.repdir
+ src = self.tooltestd
+ logger.info("copying to %s to %s test_outs" % (src, dest))
+ shutil.copytree(src, dest, dirs_exist_ok=True)
+ return p.returncode
+
+ def fast_local_test(self):
+ """
+ galaxy-tool-test -u http://localhost:8080 -a 1613612977827175424 -t tacrev -o local --publish-history
+ Seems to have a race condition when multiple jobs running. Works well - 15 secs or so if only onejob at a time! so job_conf fixed.
+ Failure will eventually get stuck. Might need a timeout in the script
+ """
+ scrpt = os.path.join(self.args.toolfactory_dir, "toolfactory_fast_test.sh")
+ extrapaths = self.tooltestd
+ cl = ["/usr/bin/bash", scrpt, self.tool_name, extrapaths, extrapaths]
+ logger.info("fast_local_test executing %s \n" % (" ".join(cl)))
+ p = subprocess.run(
+ " ".join(cl),
+ shell=True,
+ cwd=self.testdir,
+ capture_output=True,
+ check=True,
+ text=True,
+ )
+ for errline in p.stderr.splitlines():
+ logger.info("ephemeris: %s" % errline)
+ for errline in p.stdout.splitlines():
+ logger.info("ephemeris: %s" % errline)
+ shutil.copytree(self.testdir, self.toold, dirs_exist_ok=True)
+ dest = self.repdir
+ src = self.tooltestd
+ shutil.copytree(src, dest, dirs_exist_ok=True)
+ return p.returncode
+
+ def update_toolconf(self, remove=False):
+ """tempting to recreate it from the local_tools directory each time
+ currently adds new tools if not there.
+ """
+
+ def sortchildrenby(parent, attr):
+ parent[:] = sorted(parent, key=lambda child: child.get(attr))
+
+ logger.info("Updating tool conf files for %s\n" % (self.tool_name))
+ tcpath = self.local_tool_conf
+ xmlfile = os.path.join(self.tool_name, "%s.xml" % self.tool_name)
+ try:
+ parser = ET.XMLParser(remove_blank_text=True)
+ tree = ET.parse(tcpath, parser)
+ except ET.XMLSyntaxError:
+ logger.error(
+ "### Tool configuration update access error - %s cannot be parsed as xml by element tree\n"
+ % tcpath
+ )
+ sys.exit(4)
+ root = tree.getroot()
+ hasTF = False
+ e = root.findall("section")
+ if len(e) > 0:
+ hasTF = True
+ TFsection = e[0]
+ if not hasTF:
+ TFsection = ET.Element(
+ "section", {"id": "localtools", "name": "Local Tools"}
+ )
+ root.insert(0, TFsection) # at the top!
+ our_tools = TFsection.findall("tool")
+ conf_tools = [x.attrib["file"] for x in our_tools]
+ if not remove:
+ if xmlfile not in conf_tools: # new
+ ET.SubElement(TFsection, "tool", {"file": xmlfile})
+ sortchildrenby(TFsection, "file")
+ tree.write(tcpath, pretty_print=True)
+ gi = galaxy.GalaxyInstance(url=self.GALAXY_URL, key=self.GALAXY_ADMIN_KEY)
+ toolready = False
+ now = time.time()
+ nloop = 5
+ while nloop >= 0 and not toolready:
+ try:
+ res = gi.tools.show_tool(tool_id=self.tool_name)
+ toolready = True
+ logger.info(
+ "Tool %s ready after %f seconds - %s\n"
+ % (self.tool_name, time.time() - now, res)
+ )
+ except ConnectionError:
+ nloop -= 1
+ time.sleep(2)
+ logger.info("Connection error - waiting 2 seconds.\n")
+ if nloop < 1:
+ logger.error(
+ "Tool %s still not ready after %f seconds - please check the form and the generated xml for errors? \n"
+ % (self.tool_name, time.time() - now)
+ )
+ return 2
+ else:
+ return 0
+ else:
+ if xmlfile in conf_tools: # remove
+ for rem in our_tools:
+ if rem.attrib["file"] == xmlfile:
+ rem.getparent().remove(rem)
+ self.logger.info(
+ "###=============== removed tool %s from %s"
+ % (xmlfile, tcpath)
+ )
+ sortchildrenby(TFsection, "file")
+ tree.write(tcpath, pretty_print=True)
+
+ def install_deps(self):
+ """
+ use script to install new tool dependencies
+ """
+ cll = [
+ "sh",
+ "%s/install_tf_deps.sh" % self.args.toolfactory_dir,
+ self.tool_name,
+ ]
+ self.logger.info("Running %s\n" % " ".join(cll))
+ try:
+ p = subprocess.run(
+ " ".join(cll), shell=True, capture_output=True, check=True, text=True
+ )
+ for errline in p.stderr.splitlines():
+ self.logger.info(errline)
+ return p.returncode
+ except:
+ return 1
+
+ def timenow(self):
+ """return current time as a string"""
+ return time.strftime("%d/%m/%Y %H:%M:%S", time.localtime(time.time()))
+
+ def cheetah_escape(self, text):
+ """Produce entities within text."""
+ cheetah_escape_table = {"$": "\\$", "#": "\\#"}
+ return "".join([cheetah_escape_table.get(c, c) for c in text])
+
+ def parse_citations(self):
+ """"""
+ if self.args.citations:
+ ct = open(self.args.citations, "r").read()
+ citations = [c.strip() for c in ct.split("**ENTRY**") if c.strip()]
+ citation_tuples = []
+ for citation in citations:
+ if citation.startswith("doi"):
+ citation_tuples.append(("doi", citation[len("doi") :].strip()))
+ else:
+ citation_tuples.append(
+ ("bibtex", citation[len("bibtex") :].strip())
+ )
+ return citation_tuples
+ else:
+ return None
+
+
+def main():
+ """
+ This is a Galaxy wrapper.
+ It expects to be called by a special purpose tool.xml
+
+ """
+ parser = argparse.ArgumentParser()
+ a = parser.add_argument
+ a("--nftest", action="store_true", default=False)
+ a("--script_path", default=None)
+ a("--sysexe", default=None)
+ a("--packages", default=None)
+ a("--tool_name", default="newtool")
+ a("--input_files", default=[], action="append")
+ a("--output_files", default=[], action="append")
+ a("--user_email", default="Unknown")
+ a("--bad_user", default=None)
+ a("--help_text", default=None)
+ a("--tool_desc", default=None)
+ a("--toolfactory_dir", default=None)
+ a("--tool_version", default="0.01")
+ a("--citations", default=None)
+ a("--cl_suffix", default=None)
+ a("--cl_prefix", default=None)
+ a("--cl_override", default=None)
+ a("--test_override", default=None)
+ a("--additional_parameters", action="append", default=[])
+ a("--selecttext_parameters", action="append", default=[])
+ a("--selectflag_parameters", action="append", default=[])
+ a("--edit_additional_parameters", action="store_true", default=False)
+ a("--parampass", default="positional")
+ a("--tfcollection", default="toolgen")
+ a("--galaxy_root", default="/galaxy-central")
+ a("--collection", action="append", default=[])
+ a("--include_tests", default=False, action="store_true")
+ a("--install_flag", action="store_true", default=False)
+ a("--admin_only", default=True, action="store_true")
+ a("--tested_tool_out", default=None)
+ a("--container", default=None, required=False)
+ a("--tool_conf_path", default="config/tool_conf.xml") # relative to $__root_dir__
+ a(
+ "--xtra_files",
+ default=[],
+ action="append",
+ ) # history data items to add to the tool base directory
+ tfcl = sys.argv[1:]
+ args = parser.parse_args()
+ if args.admin_only:
+ assert not args.bad_user, (
+ 'UNAUTHORISED: %s is NOT authorized to use this tool until Galaxy admin adds %s to "admin_users" in the galaxy.yml Galaxy configuration file'
+ % (args.bad_user, args.bad_user)
+ )
+ assert (
+ args.tool_name
+ ), "## This ToolFactory cannot build a tool without a tool name. Please supply one."
+ os.makedirs(args.tfcollection, exist_ok=True)
+ logfilename = os.path.join(
+ args.tfcollection, "ToolFactory_make_%s_log.txt" % args.tool_name
+ )
+ logger.setLevel(logging.INFO)
+ fh = logging.FileHandler(logfilename, mode="w")
+ fformatter = logging.Formatter("%(asctime)s - %(levelname)s - %(message)s")
+ fh.setFormatter(fformatter)
+ logger.addHandler(fh)
+ tf = Tool_Factory(args)
+ tf.makeTool()
+ tf.writeShedyml()
+ # tf.writeTFyml()tf.writeTFyml()
+ tf.update_toolconf()
+ time.sleep(5)
+ if tf.condaenv and len(tf.condaenv) > 0:
+ res = tf.install_deps()
+ if res > 0:
+ logger.debug("Toolfactory installed deps failed")
+ logging.shutdown()
+ sys.exit(6)
+ time.sleep(2)
+ testret = tf.fast_local_test() # planemo_local_test()
+ if False and int(testret) > 0:
+ logger.error("ToolFactory tool build and test failed. :(")
+ logger.info(
+ "This is usually because the supplied script or dependency did not run correctly with the test inputs and parameter settings"
+ )
+ logger.info("when tested with galaxy_tool_test. Error code:%d" % int(testret))
+ logger.info(
+ "The 'i' (information) option shows how the ToolFactory was called, stderr and stdout, and what the command line was."
+ )
+ logger.info(
+ "Expand (click on) any of the broken (red) history output titles to see that 'i' button and click it"
+ )
+ logger.info(
+ "Make sure it is the same as your working test command line and double check that data files are coming from and going to where they should"
+ )
+ logger.info(
+ "In the output collection, the tool xml element must be the equivalent of your working command line for the test to work"
+ )
+ logging.shutdown()
+ sys.exit(5)
+ else:
+ tf.makeToolTar(testret)
+ jcl = sys.argv[1:]
+ with open(
+ os.path.join(
+ args.tfcollection, "ToolFactory_%s_commandline.json" % args.tool_name
+ ),
+ "w",
+ ) as fout:
+ fout.write(" ".join(jcl))
+ logging.shutdown()
+
+
+if __name__ == "__main__":
+ main()
diff -r 2beaae16651e -r 0183cad9d13b toolfactory/toolfactory.xml
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/toolfactory/toolfactory.xml Thu Feb 22 10:48:01 2024 +0000
@@ -0,0 +1,655 @@
+
+ Scripts into tools v3.0
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ python
+ galaxyxml
+ bioblend
+ planemo
+ ephemeris
+
+
+ 0
+--cl_suffix "$clsuffix"
+ #end if
+ #if len(str($cl_options.cl_prefix)) > 0
+--cl_prefix "$clprefix"
+ #end if
+ #if len(str($cl_options.cl_override)) > 0
+--cl_override "$commandoverride"
+ #end if
+ #if len(str($cl_options.test_override)) > 0
+--test_override "$testoverride"
+ #end if
+ #if $deps.packages > "":
+ --packages "$deps.packages"
+ #end if
+ #if $deps.usescript.choosescript == "yes"
+--script_path "$runscript"
+--sysexe "$deps.usescript.scriptrunner"
+ #end if
+--tool_name "$tool_name" --user_email "$useremail" --citations "$citeme" --parampass "$io_param.ppass.parampass"
+--tool_desc "$tool_desc"
+--tool_version "$tool_version"
+--help_text "$helpme"
+ #if $io_param.ppass.parampass != '0'
+ #if str($io_param.ppass.addparam.edit_params) == "yes"
+--edit_additional_parameters
+ #end if
+ #for $apar in $io_param.ppass.addparam.additional_parameters
+ #if $apar.ap_type.param_type=="selecttext"
+--selecttext_parameters '{"name":"$apar.param_name", "label":"$apar.param_label", "help":"$apar.param_help",
+"type":"$apar.ap_type.param_type","CL":"$apar.param_CL","override":"$apar.param_CLprefixed","value": [
+ #for $i,$st in enumerate($apar.ap_type.selectTexts):
+ "$st.select_value"
+ #if ($i < (len($apar.ap_type.selectTexts)-1)):
+ ,
+ #end if
+ #end for
+ ], "texts": [
+ #for $i,$st in enumerate($apar.ap_type.selectTexts):
+ "$st.select_text"
+ #if ($i < (len($apar.ap_type.selectTexts)-1)):
+ ,
+ #end if
+
+ #end for
+ ]
+ }'
+ #else if $apar.ap_type.param_type=="selectflag"
+--selectflag_parameters '{"name":"$apar.param_name", "label":"$apar.param_label", "help":"$apar.param_help",
+"type":"$apar.ap_type.param_type","CL":"$apar.param_CL","override":"$apar.param_CLprefixed","value": [
+ #for $i,$st in enumerate($apar.ap_type.selectFlags):
+ "$st.select_value"
+ #if ($i < (len($apar.ap_type.selectFlags)-1)):
+ ,
+ #end if
+ #end for
+ ], "texts": [
+ #for $i,$st in enumerate($apar.ap_type.selectFlags):
+ "$st.select_text"
+ #if ($i < (len($apar.ap_type.selectFlags)-1)):
+ ,
+ #end if
+
+ #end for
+ ]
+ }'
+ #else if $apar.ap_type.param_type=="datacolumn"
+--additional_parameters '{"name": "$apar.param_name", "value": "$apar.ap_type.param_value", "label": "$apar.param_label", "help": "$apar.param_help",
+"type": "$apar.ap_type.param_type","CL": "$apar.param_CL","override": "$apar.param_CLprefixed", "repeat": "$apar.param_repeat", "multiple": "$apar.ap_type.param_multiple",
+ "dataref": "$apar.ap_type.param_dataref"}'
+ #else:
+--additional_parameters '{"name": "$apar.param_name", "value": "$apar.ap_type.param_value", "label": "$apar.param_label", "help": "$apar.param_help",
+"type": "$apar.ap_type.param_type","CL": "$apar.param_CL","override": "$apar.param_CLprefixed", "repeat": "$apar.param_repeat"}'
+ #end if
+ #end for
+ #end if
+ #for $intab in $io_param.ppass.io.history_inputs
+--input_files '{"name": "$intab.input_files", "CL": "$intab.input_CL", "format": "$intab.input_formats", "label": "$intab.input_label",
+"help": "$intab.input_help", "required": "$intab.input_required"}'
+ #end for
+ #for $otab in $io_param.ppass.io.history_outputs
+ #if str($otab.history_label) > ""
+ --output_files '{"name": "$otab.history_name", "format": "$otab.history_format", "CL": "$otab.history_CL", "test": "$otab.history_test", "label": "$otab.history_label"
+ #else
+ --output_files '{"name": "$otab.history_name", "format": "$otab.history_format", "CL": "$otab.history_CL", "test": "$otab.history_test"
+ #end if
+ #if $otab.history_whens
+ , "when": [
+ #for $i, $hw in enumerate($otab.history_whens)
+ "$hw.history_when"
+ #if ($i < (len($otab.history_whens)-1))
+ ,
+ #end if
+ #end for
+ ]
+ #end if
+ }'
+ #end for
+ #for $collect in $io_param.ppass.io.collection_outputs
+--collection '{"name": "$collect.name", "kind": "$collect.kind", "discover": "$collect.discover", "label": "$collect.label"}'
+ #end for
+--tfcollection 'toolgen'
+--tested_tool_out "$untested_tool"
+--nftest
+--galaxy_root "$__root_dir__"
+--toolfactory_dir "$__tool_directory__"
+ #if $cl_options.xtracond.needxtra == "yes"
+ #for $x in $cl_options.xtracond.xtra_files
+--xtra_file '{"fpath":"$x", "fname":"$x.element_identifier"}'
+ #end for
+ #end if
+#end if
+]]>
+
+
+
+${deps.usescript.dynScript}
+
+
+#if len(str($cl_options.cl_override).strip()) > 1:
+${cl_options.cl_override}
+#end if
+
+
+#if len(str($cl_options.test_override).strip()) > 1:
+${cl_options.test_override}
+#end if
+
+
+#if len(str($cl_options.cl_prefix).strip()) > 1:
+${cl_options.cl_prefix}
+#end if
+
+
+#if len(str($cl_options.cl_suffix).strip()) > 1:
+${cl_options.cl_suffix}
+#end if
+
+
+${help_text}
+
+
+
+#for $citation in $citations:
+ #if $citation.citation_type.type == "bibtex":
+ **ENTRY**bibtex
+ ${citation.citation_type.bibtex}
+ #else
+ **ENTRY**doi
+ ${citation.citation_type.doi}
+ #end if
+#end for
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+**Details and attribution**
+(see GTF_)
+
+**Local Admins ONLY**
+Only users with emails in the local admin_user configuration setting in config/galaxy.yml can run this tool.
+
+**If you find a bug**
+Please raise an issue, or even better, submit a pull request fixing it, on the github repository GTF_
+
+**What it does**
+This tool contains an automated code generator, and creates normal, workflow compatible Galaxy tools as Toolshed ready archives. The
+new tool is immediately installed and available for use - a page refresh will be needed to see the new tool in the "Local" tool section.
+
+Generated tools can use existing Conda packages. These become requirements for optional scripts pasted into this tool form.
+Pasted scripts *cannot be adjusted* by the downstream user.
+
+Any number of parameters can be built into the new tool form for passing in to the script or executable at runtime.
+These can be editable by the downstream user or baked in.
+
+A new tarball compatible with any Galaxy toolshed is created in your history, including a test based on the supplied default parameter
+values and input history datasets.
+
+.. class:: warningmark
+
+**Note to system administrators**
+This tool offers *NO* built in protection against malicious scripts. It should only be installed on private/personnal Galaxy instances.
+Admin_users will have the power to do anything they want as the Galaxy user if you install this tool.
+
+.. class:: warningmark
+
+**Use on public servers** is STRONGLY discouraged for obvious reasons
+
+The tools generated by this tool will run just as securely as any other normal installed Galaxy tool but like any other new tools,
+should always be checked carefully before installation. We recommend that you follow the good code hygiene practices associated with safe toolshed practices.
+
+
+Paper_
+
+*Licensing*
+
+Copyright Ross Lazarus May 2012
+Licensed under the MIT_ licence.
+
+.. _MIT: https://mit-license.org/
+.. _GTF: https://github.com/fubar2/galaxy_tf_overlay
+.. _Paper: https://academic.oup.com/bioinformatics/article/28/23/3139/192853
+
+
+
+
+ 10.1093/bioinformatics/bts573
+
+
+
+
diff -r 2beaae16651e -r 0183cad9d13b toolfactory/toolfactory_fast_test.sh
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/toolfactory/toolfactory_fast_test.sh Thu Feb 22 10:48:01 2024 +0000
@@ -0,0 +1,11 @@
+GALAXY_URL=http://localhost:8080
+GALAXY_VENV=/home/ross/rossgit/galaxytf231/.venv
+API_KEY=1718977735397126400
+API_KEY_USER=995248011247121408
+# for test@bx.psu.edu user
+# for sed to edit at installation
+# must pass toolname outdir as cl params in that order...
+# shows api keys do uncomment for debugging if you must
+# echo "toolfactory_fast_test.sh: galaxy-tool-test -u $GALAXY_URL -a $API_KEY -k $API_KEY_USER -t $1 -o $2 --test-data $3"
+galaxy-tool-test -u $GALAXY_URL -a $API_KEY -k $API_KEY_USER -t $1 -o $2 --test-data $3 --publish-history
+