Repository: HECBioSim/Longbow

Issue:
Longbow still breaks with generic executables
This is evident when trialling a link with chemshell and longbow. Initial goes at launching chemshell with Longbow using a hard path triggers a python traceback

```
Traceback (most recent call last):
  File "/home/jimboid/.local/lib/python2.7/site-packages/longbow/corelibs/entrypoints.py", line 227, in launcher
    longbow(parameters)
  File "/home/jimboid/.local/lib/python2.7/site-packages/longbow/corelibs/entrypoints.py", line 286, in longbow
    applications.processjobs(jobs)
  File "/home/jimboid/.local/lib/python2.7/site-packages/longbow/corelibs/applications.py", line 150, in processjobs
    app = appplugins[os.path.basename(jobs[job]["executable"])]
KeyError: 'chemsh.x'
```

This relates to code that is trying to determine which application plugin it should use to process the commandline information. Obviously in a generic case, Longbow should just simply scan the commandline for files to upload and that is it. Rather than trying to perform any fancy per application tests, if this is required then an app extension should be made.

Discussion:

Patch:
diff --git a/longbow/applications.py b/longbow/applications.py
index 0046592..c89cd77 100644
--- a/longbow/applications.py
+++ b/longbow/applications.py
@@ -146,8 +146,6 @@ def processjobs(jobs):
     for job in [a for a in jobs if "lbowconf" not in a]:
 
         filelist = []
-        appplugins = getattr(apps, "PLUGINEXECS")
-        app = appplugins[os.path.basename(jobs[job]["executable"])]
         foundflags = []
         substitution = {}
 
@@ -180,6 +178,37 @@ def processjobs(jobs):
                 "The local job directory '{0}' cannot be found for job '{1}'"
                 .format(jobs[job]["localworkdir"], job))
 
+        # Here we want to support generic executable launching. To do this
+        # we will switch off all checking and testing and simply upload all
+        # files in the job directory.
+        try:
+
+            appplugins = getattr(apps, "PLUGINEXECS")
+            app = appplugins[os.path.basename(jobs[job]["executable"])]
+
+        except KeyError:
+
+            LOG.info("The software you are using is unsupported by a plugin. "
+                     "Longbow will attempt to submit, but will assume you are"
+                     "supplying modules manually or have used a absolute path"
+                     "to your executable. If you think this is in error, "
+                     "please open a ticket on github.")
+
+            jobs[job]["upload-include"] = ""
+            jobs[job]["upload-exclude"] = "*.log"
+
+            # Replace the input command line with the execution command line.
+            jobs[job]["executableargs"] = (
+                jobs[job]["executable"] + " " +
+                " ".join(jobs[job]["executableargs"]))
+
+            LOG.info("For job '%s' - execution string: %s",
+                     job, jobs[job]["executableargs"])
+
+            LOG.info("Processing jobs - complete.")
+
+            return
+
         # Hook to determine command-line parameter substitutions.
         try:
 
diff --git a/longbow/apps/__init__.py b/longbow/apps/__init__.py
index 7ad59fb..662c5a6 100644
--- a/longbow/apps/__init__.py
+++ b/longbow/apps/__init__.py
@@ -45,7 +45,6 @@ MODULES = pkgutil.iter_modules(path=[PATH])
 
 EXECLIST = []
 PLUGINEXECS = {}
-MODNAMEOVERRIDES = {}
 
 # Loop through all the modules in the plugin.
 for loader, modulename, ispkg in MODULES:
@@ -62,12 +61,3 @@ for loader, modulename, ispkg in MODULES:
 
             # Compile a dictionary associating executable with plugins.
             PLUGINEXECS[executable] = modulename
-
-        # Is the module named differently on HPC than the software is called.
-        try:
-
-            MODNAMEOVERRIDES[modulename] = getattr(mod, "MODULENAME").items()
-
-        except AttributeError:
-
-            pass
diff --git a/longbow/configuration.py b/longbow/configuration.py
index 248d4c1..ac8672a 100644
--- a/longbow/configuration.py
+++ b/longbow/configuration.py
@@ -429,7 +429,6 @@ def _processconfigsfinalinit(jobs):
     """Perform some last bits of initialisation."""
     # Initialisation.
     modules = getattr(apps, "PLUGINEXECS")
-    modoverrides = getattr(apps, "MODNAMEOVERRIDES")
     modules[""] = ""
 
     for job in [a for a in jobs if "lbowconf" not in a]:
@@ -453,10 +452,6 @@ def _processconfigsfinalinit(jobs):
 
                 jobs[job]["modules"] = modules[jobs[job]["executable"]]
 
-                if jobs[job]["modules"] in modoverrides:
-
-                    jobs[job]["modules"] = modoverrides[jobs[job]["modules"]]
-
             except KeyError:
 
                 pass


Test patch:
diff --git a/tests/unit/applications/test_processjobs.py b/tests/unit/applications/test_processjobs.py
index 27b4152..94264ca 100644
--- a/tests/unit/applications/test_processjobs.py
+++ b/tests/unit/applications/test_processjobs.py
@@ -251,3 +251,52 @@ def test_processjobs_include(m_validator, m_proccommandline):
 
     assert jobs["jobone"]["upload-include"] == \
         "test.file, input, coords, topol"
+
+
+def test_processjobs_genericexec1():
+
+    """
+    Test that the generic executable case works with hard path
+    """
+
+    jobs = {
+        "jobone": {
+            "executableargs": ["-f", "input", "-c", "file", "-p", "test"],
+            "localworkdir": os.getcwd(),
+            "executable": "/opt/somesoftware/exec",
+            "upload-include": "",
+            "upload-exclude": ""
+        }
+    }
+
+    processjobs(jobs)
+
+    assert jobs["jobone"]["executableargs"] == \
+        "/opt/somesoftware/exec -f input -c file -p test"
+    assert jobs["jobone"]["upload-include"] == ""
+    assert jobs["jobone"]["upload-exclude"] == "*.log"
+
+
+def test_processjobs_genericexec2():
+
+    """
+    Test that the generic executable case works with module and exec only.
+    """
+
+    jobs = {
+        "jobone": {
+            "executableargs": ["-f", "input", "-c", "file", "-p", "test"],
+            "localworkdir": os.getcwd(),
+            "executable": "testexec",
+            "upload-include": "",
+            "upload-exclude": "",
+            "modules": "testsoftware"
+        }
+    }
+
+    processjobs(jobs)
+
+    assert jobs["jobone"]["executableargs"] == \
+        "testexec -f input -c file -p test"
+    assert jobs["jobone"]["upload-include"] == ""
+    assert jobs["jobone"]["upload-exclude"] == "*.log"
diff --git a/tests/unit/configuration/test_processconfigsfinalinit.py b/tests/unit/configuration/test_processconfigsfinalinit.py
index d86fdfb..691d085 100644
--- a/tests/unit/configuration/test_processconfigsfinalinit.py
+++ b/tests/unit/configuration/test_processconfigsfinalinit.py
@@ -33,33 +33,11 @@
 """
 This testing module contains the tests for the configuration module methods.
 """
-try:
-
-    from unittest import mock
-
-except ImportError:
-
-    import mock
 
 import os
 from longbow.configuration import _processconfigsfinalinit
 
 
-def pluginsdata(_, data):
-
-    """
-    mocked getattr call for external data.
-    """
-
-    if data == "PLUGINEXECS":
-
-        return {"testexec": "testmodule"}
-
-    elif data == "MODNAMEOVERRIDES":
-
-        return {"testmodule": "fictionmodule"}
-
-
 def test_processconfigsfinalinit1():
 
     """
@@ -124,32 +102,3 @@ def test_processconfigsfinalinit2():
     assert jobs["test"]["destdir"] != ""
     assert jobs["test"]["remoteworkdir"] == "/work/dir"
     assert jobs["test"]["modules"] == ""
-
-
-@mock.patch('longbow.configuration.getattr')
-def test_processconfigsfinalinit3(attr):
-
-    """
-    Test the modulename overrides
-    """
-
-    jobs = {
-        "jobone": {
-            "modules": "",
-            "localworkdir": "/somepath/to/dir",
-            "executableargs": "arg1 arg2 arg3",
-            "executable": "testexec",
-            "remoteworkdir": "/work/dir"
-        }
-    }
-
-    attr.side_effect = pluginsdata
-
-    _processconfigsfinalinit(jobs)
-
-    assert jobs["jobone"]["localworkdir"] == "/somepath/to/dir"
-    assert jobs["jobone"]["executableargs"] == ["arg1", "arg2", "arg3"]
-    assert jobs["jobone"]["executable"] == "testexec"
-    assert jobs["jobone"]["destdir"] != ""
-    assert jobs["jobone"]["remoteworkdir"] == "/work/dir"
-    assert jobs["jobone"]["modules"] == "fictionmodule"