Salome HOME
Management of scripts+args in SALOME shell and TUI (not yet in GUI)
authoraguerre <aguerre>
Mon, 26 Aug 2013 16:11:13 +0000 (16:11 +0000)
committeraguerre <aguerre>
Mon, 26 Aug 2013 16:11:13 +0000 (16:11 +0000)
18 files changed:
bin/CMakeLists.txt
bin/appliskel/CMakeLists.txt
bin/appliskel/salome
bin/appliskel/tests/CMakeLists.txt [new file with mode: 0644]
bin/appliskel/tests/launcher/CMakeLists.txt [new file with mode: 0644]
bin/appliskel/tests/launcher/TestLauncherSessionArgs.py [new file with mode: 0644]
bin/appliskel/tests/launcher/add.py [new file with mode: 0755]
bin/appliskel/tests/launcher/getLogger.py [new file with mode: 0644]
bin/appliskel/tests/launcher/hello.py [new file with mode: 0755]
bin/appliskel/tests/launcher/lines.py [new file with mode: 0755]
bin/launchConfigureParser.py
bin/parseConfigFile.py
bin/runConsole.py
bin/runSalome.py
bin/runSession.py
bin/salomeConsole.py
bin/salomeLauncherUtils.py [new file with mode: 0644]
bin/salomeRunner.py

index 3be32fdeeb027f6bde4a7bc91f88a957af152f2c..a562f96f8fe3032c9568e09478c6ea9af8d00f58 100755 (executable)
@@ -48,6 +48,7 @@ SET(SCRIPTS
   runSession.py
   runConsole.py
   salomeConsole.py
+  salomeLauncherUtils.py
   salomeRunner.py
   salome_session.py
   salome_utils.py
index 9feeb7934700e736b017afb383130cbe27c1c11a..1e563744ff76c2ab647c6a3e1a5944855172bcf0 100755 (executable)
@@ -17,6 +17,8 @@
 # See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
 #
 
+ADD_SUBDIRECTORY(tests)
+
 # ===============================================================
 # Files to be installed
 # ===============================================================
index d31f6c1f1470e86615bb8a2f196fa128f079fe1d..dd2342985d9d12095bcbf04a42c19e2d340195cb 100755 (executable)
@@ -2,7 +2,6 @@
 
 import os
 import sys
-import glob
 
 # Preliminary work to initialize path to SALOME Python modules
 def __initialize():
@@ -28,70 +27,26 @@ def __initialize():
   sys.path[:0] = [absoluteAppliPath+'/bin/salome']
 # End of preliminary work
 
-def __listDirectory(path):
-  allFiles = []
-  for root, dirs, files in os.walk(path):
-    configFileNames = glob.glob(os.path.join(root,'*.cfg')) + glob.glob(os.path.join(root,'*.sh'))
-    allFiles += configFileNames
-  return allFiles
-#
-
-def __getConfigFileNamesDefault():
-  absoluteAppliPath = os.getenv('ABSOLUTE_APPLI_PATH','')
-  envdDir = absoluteAppliPath + '/env.d'
-  if os.path.isdir(envdDir):
-    configFileNames = __listDirectory(envdDir)
-  else:
-    configFileNames = []
-
-  return configFileNames
-#
-
-def __getConfigFileNames(args):
-  # special case: configuration files are provided by user
-  # Search for command-line argument(s) --config=file1,file2,..., filen
-  # Search for command-line argument(s) --config=dir1,dir2,..., dirn
-  configOptionPrefix = "--config="
-  configArgs = [ str(x) for x in args if str(x).startswith(configOptionPrefix) ]
-
-  if len(configArgs) == 0:
-    return __getConfigFileNamesDefault(), args
-
-  args = [ x for x in args if not x.startswith(configOptionPrefix) ]
-  allLists = [ x.replace(configOptionPrefix, '') for x in configArgs ]
-
-  configFileNames = []
-  for currentList in allLists:
-    elements = currentList.split(',')
-    for elt in elements:
-      elt = os.path.realpath(os.path.expanduser(elt))
-      if os.path.isdir(elt):
-        configFileNames += __listDirectory(elt)
-      else:
-        configFileNames += [elt]
-
-  return configFileNames, args
-#
-
-
-if __name__ == "__main__":
-  args = sys.argv[1:]
-
+def main(args):
   # Identify application path then locate configuration files
   __initialize()
-  configFileNames, args = __getConfigFileNames(args)
-  
+  from salomeLauncherUtils import getConfigFileNames
+  configFileNames, args = getConfigFileNames(args)
+
+  # WHY? Incorrect/Inexisting files are supposed to be ignored by SalomeRunner.
+  # Might simply need bug fix; please provide test case.
   error=False
   for aFile in configFileNames:
     if not os.path.isfile(aFile):
       print "ERROR: inexisting file: "+aFile
       error=True
-  if error: 
+  if error:
     sys.exit(1)
-     
+
+
   # Create a SalomeRunner which parses configFileNames to initialize environment
-  from salomeRunner import SalomeRunner, SalomeRunnerException
   try:
+    from salomeRunner import SalomeRunner, SalomeRunnerException
     runner = SalomeRunner(configFileNames)
 
     # Here set specific variables, if needed
@@ -100,6 +55,18 @@ if __name__ == "__main__":
     # runner.addToPythonPath('mypythonpath')
     # runner.setEnviron('myvarname', 'value')
 
+    kernel_root_dir = os.getenv("KERNEL_ROOT_DIR")
+    if kernel_root_dir:
+      runner.addToLdLibraryPath(os.path.join(kernel_root_dir, "lib/salome"))
+
+    gui_root_dir = os.getenv("GUI_ROOT_DIR")
+    if gui_root_dir:
+      runner.addToLdLibraryPath(os.path.join(gui_root_dir, "lib/salome"))
+
+    paravis_root_dir = os.getenv("PARAVIS_ROOT_DIR")
+    if paravis_root_dir:
+      runner.addToLdLibraryPath(os.path.join(paravis_root_dir, "lib/salome"))
+
 
     # Start SALOME, parsing command line arguments
     runner.go(args)
@@ -110,3 +77,8 @@ if __name__ == "__main__":
     logging.getLogger("salome").error(e)
     sys.exit(1)
 #
+
+if __name__ == "__main__":
+  args = sys.argv[1:]
+  main(args)
+#
diff --git a/bin/appliskel/tests/CMakeLists.txt b/bin/appliskel/tests/CMakeLists.txt
new file mode 100644 (file)
index 0000000..e051906
--- /dev/null
@@ -0,0 +1,20 @@
+# Copyright (C) 2013  CEA/DEN, EDF R&D, OPEN CASCADE
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+#
+# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+#
+
+ADD_SUBDIRECTORY(launcher)
diff --git a/bin/appliskel/tests/launcher/CMakeLists.txt b/bin/appliskel/tests/launcher/CMakeLists.txt
new file mode 100644 (file)
index 0000000..8158f4f
--- /dev/null
@@ -0,0 +1,28 @@
+# Copyright (C) 2013  CEA/DEN, EDF R&D, OPEN CASCADE
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+#
+# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+#
+
+SET(SCRIPTS
+  add.py
+  getLogger.py
+  hello.py
+  lines.py
+  TestLauncherSessionArgs.py
+)
+
+SALOME_INSTALL_SCRIPTS("${SCRIPTS}" ${SALOME_INSTALL_SCRIPT_SCRIPTS}/appliskel/tests/launcher)
diff --git a/bin/appliskel/tests/launcher/TestLauncherSessionArgs.py b/bin/appliskel/tests/launcher/TestLauncherSessionArgs.py
new file mode 100644 (file)
index 0000000..d100086
--- /dev/null
@@ -0,0 +1,138 @@
+import unittest
+
+import os
+import sys
+import imp
+from cStringIO import StringIO
+import logging
+
+logger = logging.getLogger("TestLauncherLogger")
+logger.level = logging.DEBUG
+logger.addHandler(logging.StreamHandler())
+
+class TestSessionArgs(unittest.TestCase):
+  @classmethod
+  def setUpClass(cls):
+    # Initialize path to SALOME application
+    path_to_launcher = os.getenv("SALOME_LAUNCHER")
+    if not path_to_launcher:
+      msg = "Error: please set SALOME_LAUNCHER variable to the salome command of your application folder."
+      self.fail(msg)
+    #
+    appli_dir = os.path.dirname(path_to_launcher)
+    envd_dir = os.path.join(appli_dir, "env.d")
+
+    # Configure session startup
+    cls.SALOME = imp.load_source("SALOME", os.path.join(appli_dir,"salome"))
+    cls.SALOME_args = ["shell", "--config="+envd_dir]
+
+    cls.logFile = "log.txt"
+    sys.stdout = StringIO()
+
+    # Set some predefined command args and corresponding output messages
+    cls.hello0 = ["hello.py", "args:outfile="+cls.logFile]
+    cls.hello0Msg = "Hello!"
+    cls.hello1 = ["hello.py", "args:you,outfile="+cls.logFile]
+    cls.hello1Msg = "Hello to: you"
+    cls.helloToAdd = ["hello.py", "args:add.py,1,2,3,outfile="+cls.logFile]
+    cls.helloToAddMsg = "Hello to: add.py, 1, 2, 3"
+    cls.add0 = ["add.py", "args:outfile="+cls.logFile]
+    cls.add0Msg = "No args!"
+    cls.add3 = ["add.py", "args:1,2,3,outfile="+cls.logFile]
+    cls.add3Msg = "1+2+3 = 6"
+    cls.lines0 = ["lines.py", "args:outfile="+cls.logFile]
+    cls.lines0Msg = "No files given"
+    cls.lines2 = ["lines.py", "args:hello.py,add.py,outfile="+cls.logFile]
+    cls.lines2Msg = "hello.py is 16 lines longadd.py is 18 lines long"
+    cls.linesUnreadable = ["lines.py", "args:hello.py,add.py,1,2,outfile="+cls.logFile]
+    cls.linesUnreadableMsg = "hello.py is 16 lines longadd.py is 18 lines longFile '1' cannot be readFile '2' cannot be read"
+
+  #
+  @classmethod
+  def tearDownClass(cls):
+    pass
+  #
+  def setUp(self):
+    self.removeLogFile()
+  #
+  def tearDown(self):
+    self.removeLogFile()
+  #
+  def session(self, args=[]):
+    self.SALOME.main(self.SALOME_args + args)
+  #
+  def removeLogFile(self):
+    try:
+      os.remove(self.logFile)
+    except OSError:
+      pass
+  #
+  def assertLogFileContentsEqual(self, message):
+    with open(self.logFile, "r") as f:
+      contents = f.read().replace('\n', '')
+
+    #sys.stderr.write("Generated contents :%s\n"%contents)
+    #sys.stderr.write("Expected contents :%s\n"%message)
+    self.assertTrue(contents==message)
+  #
+  def testHello0(self):
+    self.session(self.hello0)
+    self.assertLogFileContentsEqual(self.hello0Msg)
+  #
+  def testPythonHello0(self):
+    self.session(["python"]+self.hello0)
+    self.assertLogFileContentsEqual(self.hello0Msg)
+  #
+  def testHello1(self):
+    self.session(self.hello1)
+    self.assertLogFileContentsEqual(self.hello1Msg)
+  #
+  def testAdd0(self):
+    self.session(self.add0)
+    self.assertLogFileContentsEqual(self.add0Msg)
+  #
+  def testAdd3(self):
+    self.session(self.add3)
+    self.assertLogFileContentsEqual(self.add3Msg)
+  #
+  def testHello0Add3(self):
+    self.session(self.hello0+self.add3)
+    self.assertLogFileContentsEqual(self.hello0Msg+self.add3Msg)
+  #
+  def testHello1Add3(self):
+    self.session(self.hello1+self.add3)
+    self.assertLogFileContentsEqual(self.hello1Msg+self.add3Msg)
+  #
+  def testHelloToAdd(self):
+    self.session(self.helloToAdd)
+    self.assertLogFileContentsEqual(self.helloToAddMsg)
+  #
+  def testLines0(self):
+    self.session(self.lines0)
+    self.assertLogFileContentsEqual(self.lines0Msg)
+  #
+  def testLines2(self):
+    self.session(self.lines2)
+    self.assertLogFileContentsEqual(self.lines2Msg)
+  #
+  def testLines2Add3(self):
+    self.session(self.lines2+self.add3)
+    self.assertLogFileContentsEqual(self.lines2Msg+self.add3Msg)
+  #
+  def testLinesUnreadable(self):
+    self.session(self.linesUnreadable)
+    self.assertLogFileContentsEqual(self.linesUnreadableMsg)
+  #
+  def testAddAddHello(self):
+    self.session(self.add3+self.add3+self.hello1)
+    self.assertLogFileContentsEqual(self.add3Msg+self.add3Msg+self.hello1Msg)
+  #
+  def testHello0Add3Hello0Add3Hello0(self):
+    self.session(self.hello1+self.add3+self.hello0+self.add3+self.hello0)
+    self.assertLogFileContentsEqual(self.hello1Msg+self.add3Msg+self.hello0Msg+self.add3Msg+self.hello0Msg)
+  #
+#
+
+
+if __name__ == "__main__":
+  unittest.main()
diff --git a/bin/appliskel/tests/launcher/add.py b/bin/appliskel/tests/launcher/add.py
new file mode 100755 (executable)
index 0000000..0f55d92
--- /dev/null
@@ -0,0 +1,18 @@
+#! /usr/bin/env python
+
+import sys
+import logging
+
+from getLogger import getLogger
+
+if __name__ == "__main__":
+  args = sys.argv[1:]
+  logger, args = getLogger(args)
+
+  if len(args)==0:
+    logger.info("No args!")
+  else:
+    msg = "+".join(args)
+    res = sum(map(int, args))
+    logger.info("%s = %s"%(msg, res))
+#
diff --git a/bin/appliskel/tests/launcher/getLogger.py b/bin/appliskel/tests/launcher/getLogger.py
new file mode 100644 (file)
index 0000000..ade7601
--- /dev/null
@@ -0,0 +1,24 @@
+import os
+import sys
+import logging
+
+def getLogger(args=[]):
+  outfileOptionPrefix = "outfile="
+  outfileArgs = [ str(x) for x in args if str(x).startswith(outfileOptionPrefix) ]
+  allFiles = [ x.replace(outfileOptionPrefix, '') for x in outfileArgs ]
+  args = [ x for x in args if not str(x).startswith(outfileOptionPrefix) ]
+
+  logger = logging.getLogger(__name__)
+  if len(allFiles) == 0:
+    logger.addHandler(logging.StreamHandler())
+  else:
+    for currentFile in allFiles:
+      elements = currentFile.split(',')
+      for elt in elements:
+        elt = os.path.realpath(os.path.expanduser(elt))
+        hdlr = logging.FileHandler(elt)
+        logger.addHandler(hdlr)
+  #
+  logger.level = logging.DEBUG
+  return logger, args
+#
diff --git a/bin/appliskel/tests/launcher/hello.py b/bin/appliskel/tests/launcher/hello.py
new file mode 100755 (executable)
index 0000000..cda6042
--- /dev/null
@@ -0,0 +1,16 @@
+#! /usr/bin/env python
+
+import sys
+import logging
+
+from getLogger import getLogger
+
+if __name__ == "__main__":
+  args = sys.argv[1:]
+  logger, args = getLogger(args)
+
+  if len(args)==0:
+    logger.info("Hello!")
+  else:
+    logger.info("Hello to: %s"%(", ".join(args)))
+#
diff --git a/bin/appliskel/tests/launcher/lines.py b/bin/appliskel/tests/launcher/lines.py
new file mode 100755 (executable)
index 0000000..38b7cda
--- /dev/null
@@ -0,0 +1,29 @@
+#! /usr/bin/env python
+
+import sys
+import logging
+
+from getLogger import getLogger
+
+
+def file_len(fname):
+  with open(fname) as f:
+    for i, l in enumerate(f):
+      pass
+    return i + 1
+#
+
+if __name__ == "__main__":
+  args = sys.argv[1:]
+  logger, args = getLogger(args)
+
+  if len(args)==0:
+    logger.info("No files given")
+  else:
+    for filename in args:
+      try:
+        nb = file_len(filename)
+        logger.info("%s is %s lines long"%(filename, nb))
+      except IOError:
+        logger.info("File '%s' cannot be read"%(filename))
+#
index 43c334e4127e18a9c4b2f98acf8f3e557881d83e..4bbc9d60d0947a2aa5cd6158ca4ce9b484fa4486 100755 (executable)
@@ -28,6 +28,8 @@ import types
 
 from salome_utils import verbose, setVerbose, getPortNumber, getHomeDir
 
+from salomeLauncherUtils import getScriptsAndArgs
+
 # names of tags in XML configuration file
 doc_tag = "document"
 sec_tag = "section"
@@ -537,21 +539,6 @@ def CreateOptionParser (theAdditionalOptions=[]):
                           dest="log_file",
                           help=help_str)
 
-    # Execute python scripts. Default: None.
-    help_str  = "Python script(s) to be imported. Python scripts are imported "
-    help_str += "in the order of their appearance. In GUI mode python scripts "
-    help_str += "are imported in the embedded python interpreter of current study, "
-    help_str += "otherwise in an external python interpreter. "
-    help_str += "Note: this option is obsolete. Instead you can pass Python script(s) "
-    help_str += "directly as positional parameter."
-    o_u = optparse.Option("-u",
-                          "--execute",
-                          metavar="<script1,script2,...>",
-                          type="string",
-                          action="append",
-                          dest="py_scripts",
-                          help=help_str)
-
     # Configuration XML file. Default: see defaultUserFile() function
     help_str  = "Parse application settings from the <file> "
     help_str += "instead of default %s" % defaultUserFile()
@@ -791,7 +778,6 @@ def CreateOptionParser (theAdditionalOptions=[]):
                 o_d,o_o, # Desktop
                 o_b,     # Batch
                 o_l,o_f, # Use logger or log-file
-                o_u,     # Execute python scripts
                 o_r,     # Configuration XML file
                 o_x,     # xterm
                 o_m,     # Modules
@@ -818,14 +804,16 @@ def CreateOptionParser (theAdditionalOptions=[]):
                 o_port,  # Use port
                 ]
 
-    #std_options = ["gui", "desktop", "log_file", "py_scripts", "resources",
+    #std_options = ["gui", "desktop", "log_file", "resources",
     #               "xterm", "modules", "embedded", "standalone",
     #               "portkill", "killall", "interp", "splash",
     #               "catch_exceptions", "print_port", "save_config", "ns_port_log_file"]
 
     opt_list += theAdditionalOptions
 
-    a_usage = "%prog [options] [STUDY_FILE] [PYTHON_FILE [PYTHON_FILE ...]]"
+    a_usage = """%prog [options] [STUDY_FILE] [PYTHON_FILE [args] [PYTHON_FILE [args]...]]
+Python file arguments, if any, must be comma-separated (without blank characters) and prefixed by "args:" (without quotes), e.g. myscript.py args:arg1,arg2=val,...
+"""
     version_str = "Salome %s" % version()
     pars = optparse.OptionParser(usage=a_usage, version=version_str, option_list=opt_list)
 
@@ -984,7 +972,7 @@ def get_env(theAdditionalOptions=[], appname=salomeappname, cfgname=salomecfgnam
     # apply command-line options to the arguments
     # each option given in command line overrides the option from xml config file
     #
-    # Options: gui, desktop, log_file, py_scripts, resources,
+    # Options: gui, desktop, log_file, resources,
     #          xterm, modules, embedded, standalone,
     #          portkill, killall, interp, splash,
     #          catch_exceptions, pinter
@@ -1024,22 +1012,14 @@ def get_env(theAdditionalOptions=[], appname=salomeappname, cfgname=salomecfgnam
     if cmd_opts.ns_port_log_file is not None:
       args["ns_port_log_file"] = cmd_opts.ns_port_log_file
 
-    # Python scripts
-    args[script_nam] = []
-    if cmd_opts.py_scripts is not None:
-        listlist = cmd_opts.py_scripts
-        for listi in listlist:
-            if os.sys.platform == 'win32':
-                args[script_nam] += re.split( "[;,]", listi)
-            else:
-                args[script_nam] += re.split( "[:;,]", listi)
-    for arg in cmd_args:
-        if arg[-3:] == ".py":
-            args[script_nam].append(arg)
-        elif not args["study_hdf"]:
+    # Study files
+    if len(cmd_args) > 0 and not args["study_hdf"]:
+        arg = cmd_args[0] # :NOTE: only look at first element
+        if arg[-4:] == ".hdf":
             args["study_hdf"] = arg
-            pass
-        pass
+
+    # Python scripts
+    args[script_nam] = getScriptsAndArgs(cmd_args)
 
     # xterm
     if cmd_opts.xterm is not None: args[xterm_nam] = cmd_opts.xterm
index 65219d3734569942dc18138a30b1cb01df364bac..76c014c8f70bcabf4e2851d45a64d38f240e7551 100644 (file)
@@ -208,7 +208,7 @@ class EnvFileConverter(object):
     self.outputFile = outputFile
     self.allParsedVariableNames=[]
     # exclude line that begin with:
-    self.exclude = [ 'if', 'then', 'fi', '#', 'echo' ]
+    self.exclude = [ 'if', 'then', 'else', 'fi', '#', 'echo' ]
     # discard the following keywords if at the beginning of line:
     self.discard = [ 'export' ]
     # the following keywords imply a special processing if at the beginning of line:
@@ -305,7 +305,7 @@ class EnvFileConverter(object):
 # Convert .sh environment file to configuration file format
 def convertEnvFileToConfigFile(envFilename, configFilename):
   #reserved=['PATH', 'LD_LIBRARY_PATH', 'PYTHONPATH']
-  print "convert envFilename",envFilename,"to",configFilename
+  logConfigParser.debug('convert env file %s to %s'%(envFilename, configFilename))
   reserved=['PATH', 'LD_LIBRARY_PATH', 'PYTHONPATH', 'MANPATH', 'R_LIBS', 'PV_PLUGIN_PATH', 'TCLLIBPATH', 'TKLIBPATH']
   fileContents = open(envFilename, 'r').read()
 
index 72d73c77b4b0eb6a7875a7e89284f1af15a0fb4c..a6e4001429c63be1566721df4d93940ebd619944 100644 (file)
@@ -1,5 +1,5 @@
 #  -*- coding: iso-8859-1 -*-
-# Copyright (C) 2007-2012  CEA/DEN, EDF R&D, OPEN CASCADE
+# Copyright (C) 2007-2013  CEA/DEN, EDF R&D, OPEN CASCADE
 #
 # Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
 # CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
 # See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
 #
 
-def __prompt(vars = None, commands=[], message = "Connecting to SALOME"):
-  if vars is None:
-    vars = globals()
+def __prompt(environment = None, commands=[], message = "Connecting to SALOME"):
+  if environment is None:
+    environment = globals().copy()
+    environment.update(locals())
+
   import code
   import rlcompleter
   import readline
   readline.parse_and_bind("tab: complete")
   # calling this with globals ensures we can see the environment
   print message
-  shell = code.InteractiveConsole(vars)
+  shell = code.InteractiveConsole(environment)
   for cmd in commands:
     shell.push(cmd)
   return shell.interact
index 7e3d62634a53fb7c66440ea4c89949153d9185ab..1c6791c823550c8b4bcb759eb5fc954135f367b0 100755 (executable)
@@ -31,6 +31,9 @@ import orbmodule
 import setenv
 from launchConfigureParser import verbose
 from server import process_id, Server
+import json
+from salomeLauncherUtils import formatScriptsAndArgs
+import subprocess
 
 # -----------------------------------------------------------------------------
 
@@ -261,7 +264,8 @@ class SessionServer(Server):
                     pass
                 pass
                 if self.args.has_key('pyscript') and len(self.args['pyscript']) > 0:
-                    self.SCMD2+=['--pyscript=%s'%(",".join(self.args['pyscript']))]
+                    msg = json.dumps(self.args['pyscript'])
+                    self.SCMD2+=['--pyscript=%s'%(msg)]
                     pass
                 pass
             pass
@@ -724,39 +728,11 @@ def useSalome(args, modules_list, modules_root_dir):
                 if not args['gui'] or not args['session_gui']:
                     toimport = args['pyscript']
 
-        for srcname in toimport :
-            if srcname == 'killall':
-                clt.showNS()
-                killAllPorts()
-                sys.exit(0)
-            else:
-                if os.path.isabs(srcname):
-                    if os.path.exists(srcname):
-                        execScript(srcname)
-                    elif os.path.exists(srcname+".py"):
-                        execScript(srcname+".py")
-                    else:
-                        print "Can't execute file %s" % srcname
-                    pass
-                else:
-                    found = False
-                    for path in [os.getcwd()] + sys.path:
-                        if os.path.exists(os.path.join(path,srcname)):
-                            execScript(os.path.join(path,srcname))
-                            found = True
-                            break
-                        elif os.path.exists(os.path.join(path,srcname+".py")):
-                            execScript(os.path.join(path,srcname+".py"))
-                            found = True
-                            break
-                        pass
-                    if not found:
-                        print "Can't execute file %s" % srcname
-                        pass
-                    pass
-                pass
-            pass
-        pass
+        command = formatScriptsAndArgs(toimport)
+        if command:
+            proc = subprocess.Popen(command, shell=True)
+            proc.wait()
+
     return clt
 
 def execScript(script_path):
index 07665fdd5310217b8b3b4eeac99f34c22c686892..e3b5f0857269b73356ce963d4dd7a5c58b0ae95a 100644 (file)
@@ -33,8 +33,12 @@ class MyParser(OptionParser):
 #
 
 def configureSession(args=[]):
-  usage = "Usage: %prog [options]"
-  epilog  = """\nIf the command is not given a shell is opened.
+  usage = "Usage: %prog [options] [command]"
+  epilog  = """\n
+If the command is not given a shell is opened; else execute the given command.
+Command may be a series of Python scripts with arguments: [PYTHON_FILE [args] [PYTHON_FILE [args]...]]
+Python file arguments, if any, must be comma-separated (without blank characters) and prefixed by "args:" (without quotes), e.g. myscript.py args:arg1,arg2=val,...
+\n
 If PORT and MACHINE are not given, try to connect to the last active session on the local machine.
 If PORT and MACHINE are given, try to connect to the remote session associated with PORT on MACHINE.
 If MACHINE is not given, try to connect to the session associated to PORT on the local machine.
index 0a80ae6625935d44b50ac590ae52339439ef7658..46036d3e712595e9365a79aceff6d97194cdd59e 100755 (executable)
@@ -24,6 +24,8 @@
 
 import os
 import sys
+import glob
+
 #-------------------------------
 # Python completion and others if you want
 # You should have set PYTHONSTARTUP env variable
@@ -36,56 +38,41 @@ import user
 #-------------------------------
 import CORBA
 import CosNaming
-# There are cyclic dependencies between Engines, SALOME and SALOMEDS.
-# import first Engines, then SALOME and then SALOMEDS
-# Or use reload(Engines) to be safe.
-import Engines
-import SALOME
-import SALOMEDS
-import SALOME_ModuleCatalog
-reload(Engines)
-reload(SALOME)
-reload(SALOMEDS)
 import salome_utils
 
-import LifeCycleCORBA
 import orbmodule
-from runSalome import *
 
-omniorbUserPath = os.getenv("OMNIORB_USER_PATH")
-files = glob.glob(os.path.join(omniorbUserPath,".omniORB_"+salome_utils.getUserName()+"_*.cfg"))
+def getRunningSession():
+  omniorbUserPath = os.getenv("OMNIORB_USER_PATH")
+  files = glob.glob(os.path.join(omniorbUserPath,".omniORB_"+salome_utils.getUserName()+"_*.cfg"))
 
-filename=""
-if len(files)==1:
-  filename=files[0]
-else:
-  print "You have %d sessions running" % len(files)
-  for f in files:
-     print "Session:",f
-     rep= raw_input("Do you want to connect to this session [y|n]")
-     if rep == "y":
+  filename=""
+  if len(files)==1:
+    filename=files[0]
+  else:
+    print "You have %d sessions running" % len(files)
+    for f in files:
+      print "Session:",f
+      rep= raw_input("Do you want to connect to this session [y|n]")
+      if rep == "y":
         filename=f
         break
 
-if filename != "":
-  os.environ['OMNIORB_CONFIG']=filename
-else:
-  rep= raw_input("Do you want to try a local session on port 2810 ? [y|n]")
-  if rep == "y":
-     # Try a local session running on port 2810
-     sys.argv=sys.argv+['-ORBInitRef','NameService=corbaname::localhost:2810']#+['-ORBgiopMaxMsgSize','2097152000']  # 2 GBytes
+  if filename != "":
+    os.environ['OMNIORB_CONFIG']=filename
   else:
-     sys.exit(1)
-
-#print sys.argv
-
-#direct adress from clt.orb.object_to_string(clt.rootContext)
-#sys.argv=sys.argv+['-ORBInitRef','NameService=IOR:010000000100000000000000010000000000000023000000010100000a0000006c6f63616c686f737400fa0a0b0000004e616d6553657276696365']
+    rep= raw_input("Do you want to try a local session on port 2810 ? [y|n]")
+    if rep == "y":
+      # Try a local session running on port 2810
+      sys.argv=sys.argv+['-ORBInitRef','NameService=corbaname::localhost:2810']
+    else:
+      sys.exit(1)
+#
 
 class client(orbmodule.client):
    def initNS(self,args):
       # Obtain a reference to the root naming context
-      obj         = self.orb.resolve_initial_references("NameService")
+      obj = self.orb.resolve_initial_references("NameService")
       try:
           self.rootContext = obj._narrow(CosNaming.NamingContext)
           return
@@ -93,15 +80,25 @@ class client(orbmodule.client):
           print "It's not a valid naming service"
           self.rootContext = None
           raise
+#
 
-clt=client()
-print "Naming Service address: ",clt.orb.object_to_string(clt.rootContext)
+def startClient():
+  try:
+    clt=client()
+  except Exception:
+    sys.exit(1)
+  #
+  print "Naming Service address: ",clt.orb.object_to_string(clt.rootContext)
 
-clt.showNS()
+  clt.showNS()
+
+  session=clt.waitNS("/Kernel/Session")
+  catalog=clt.waitNS("/Kernel/ModulCatalog")
+  studyMgr=clt.waitNS("/myStudyManager")
+  import salome
+  salome.salome_init()
+  from salome import lcc
+#
 
-session=clt.waitNS("/Kernel/Session")
-catalog=clt.waitNS("/Kernel/ModulCatalog")
-studyMgr=clt.waitNS("/myStudyManager")
-import salome
-salome.salome_init()
-from salome import lcc
+getRunningSession()
+startClient()
diff --git a/bin/salomeLauncherUtils.py b/bin/salomeLauncherUtils.py
new file mode 100644 (file)
index 0000000..6d26e9c
--- /dev/null
@@ -0,0 +1,112 @@
+#! /usr/bin/env python
+
+import os
+import sys
+import glob
+import subprocess
+
+"""
+Define a specific exception class to manage exceptions related to SalomeRunner
+"""
+class SalomeRunnerException(Exception):
+  """Report error messages to the user interface of SalomeRunner."""
+#
+
+def __listDirectory(path):
+  allFiles = []
+  for root, dirs, files in os.walk(path):
+    configFileNames = glob.glob(os.path.join(root,'*.cfg')) + glob.glob(os.path.join(root,'*.sh'))
+    allFiles += configFileNames
+  return allFiles
+#
+
+def __getConfigFileNamesDefault():
+  absoluteAppliPath = os.getenv('ABSOLUTE_APPLI_PATH','')
+  if not absoluteAppliPath:
+    return []
+
+  envdDir = absoluteAppliPath + '/env.d'
+  if not os.path.isdir(envdDir):
+    return []
+
+  return __listDirectory(envdDir)
+#
+
+def getConfigFileNames(args):
+  # special case: configuration files are provided by user
+  # Search for command-line argument(s) --config=file1,file2,..., filen
+  # Search for command-line argument(s) --config=dir1,dir2,..., dirn
+  configOptionPrefix = "--config="
+  configArgs = [ str(x) for x in args if str(x).startswith(configOptionPrefix) ]
+
+  if len(configArgs) == 0:
+    return __getConfigFileNamesDefault(), args
+
+  args = [ x for x in args if not x.startswith(configOptionPrefix) ]
+  allLists = [ x.replace(configOptionPrefix, '') for x in configArgs ]
+
+  configFileNames = []
+  for currentList in allLists:
+    elements = currentList.split(',')
+    for elt in elements:
+      elt = os.path.realpath(os.path.expanduser(elt))
+      if os.path.isdir(elt):
+        configFileNames += __listDirectory(elt)
+      else:
+        configFileNames += [elt]
+
+  return configFileNames, args
+#
+
+# Return an array of dictionaries {script_name: [list_of_its_args]}
+def getScriptsAndArgs(args=[]):
+  # Syntax of args: script.py [args:a1,a2=val,an] ... script.py [args:a1,a2=val,an]
+  scriptArgs = []
+  currentScript = None
+  argsPrefix = "args:"
+  callPython = False
+
+  for i in range(len(args)):
+    elt = args[i]
+
+    if elt.startswith(argsPrefix):
+      if not currentScript or callPython:
+        raise SalomeRunnerException("args list must follow corresponding script file in command line.")
+      elt = elt.replace(argsPrefix, '')
+      scriptArgs[len(scriptArgs)-1][currentScript] = elt.split(",")
+      currentScript = None
+      callPython = False
+    elif elt.startswith("python"):
+      callPython = True
+    elif os.path.isfile(elt) or os.path.isfile(elt+".py"):
+      if elt[-3:] == ".py":
+        currentScript = os.path.abspath(elt)
+      else:
+        currentScript = os.path.abspath(elt+".py")
+      if callPython:
+        scriptArgs.append({"python "+currentScript:[]})
+        callPython = False
+      else:
+        if not os.access(currentScript, os.X_OK):
+          raise SalomeRunnerException("Argument %s cannot be executed (please check file permissions)"%currentScript)
+        scriptArgs.append({currentScript:[]})
+    else:
+      raise SalomeRunnerException("Incorrect syntax in command line: %s:\n\t%s"%(elt," ".join(args)))
+  # end for loop
+  return scriptArgs
+#
+
+# Formatting scripts and args as a Bash-like command-line:
+# script1.py [args] ; script2.py [args] ; ...
+def formatScriptsAndArgs(scriptArgs=[]):
+    commands = []
+    for sc_dict in scriptArgs:
+      for script, sc_args in sc_dict.items(): # single entry
+        cmd = script
+        if sc_args:
+          cmd = cmd + " " + " ".join(sc_args)
+        commands.append(cmd)
+
+    command = "; ".join(["%s"%x for x in commands])
+    return command
+#
index ab60f5d4b36b8554b4b8e6d2d4daa34a74e4709a..875e914d8a36ff12ebb8d304e6303069980236b2 100644 (file)
@@ -11,14 +11,8 @@ import pickle
 import subprocess
 import platform
 
-
-"""
-Define a specific exception class to manage exceptions related to SalomeRunner
-"""
-class SalomeRunnerException(Exception):
-  """Report error messages to the user interface of SalomeRunner."""
-#
-
+from salomeLauncherUtils import SalomeRunnerException
+from salomeLauncherUtils import getScriptsAndArgs, formatScriptsAndArgs
 
 """
 The SalomeRunner class in an API to configure SALOME environment then
@@ -38,7 +32,7 @@ class SalomeRunner:
     #it could be None explicitely (if user use multiples setEnviron...for standalone)
     if configFileNames==None:
        return
-    
+
     if len(configFileNames) == 0:
       raise SalomeRunnerException("No configuration files given")
 
@@ -48,8 +42,8 @@ class SalomeRunner:
         self.__setEnvironmentFromConfigFile(filename)
       elif extension == ".sh":
         #new convert procedures, temporary could be use not to be automatically deleted
-        temp = tempfile.NamedTemporaryFile(suffix='.cfg', delete=False)
-        #temp = tempfile.NamedTemporaryFile(suffix='.cfg')
+        #temp = tempfile.NamedTemporaryFile(suffix='.cfg', delete=False)
+        temp = tempfile.NamedTemporaryFile(suffix='.cfg')
         try:
           convertEnvFileToConfigFile(filename, temp.name)
           self.__setEnvironmentFromConfigFile(temp.name)
@@ -98,14 +92,14 @@ class SalomeRunner:
   #
 
   """Set environment variable to value"""
-  def setEnviron(self, name, value, overwrite=True):
+  def setEnviron(self, name, value, overwrite=False):
     env = os.getenv(name, '')
     if env and not overwrite:
-      self.getLogger().warning("Environment variable already existing (and not overwritten): %s%s", name, value)
+      self.getLogger().warning("Environment variable already existing (and not overwritten): %s=%s", name, value)
       return
 
     if env:
-      self.getLogger().warning("Environment variable overwriting: %s, %s", name, value)
+      self.getLogger().warning("Overwriting environment variable: %s=%s", name, value)
 
     value = os.path.expandvars(value) # expand environment variables
     self.getLogger().debug("Set environment variable: %s=%s", name, value)
@@ -123,10 +117,10 @@ class SalomeRunner:
   ###################################
 
   def _usage(self, unused=[]):
-    exeName = os.path.splitext(os.path.basename(__file__))[0]
+    #exeName = os.path.splitext(os.path.basename(__file__))[0]
 
     msg = '''\
-Usage: %s [command] [options] [--config=file1,...,filen]
+Usage: salome [command] [options] [--config=file1,...,filen]
 
 Commands:
     start         Launches SALOME virtual application [DEFAULT]
@@ -137,7 +131,7 @@ Commands:
     help          Show this message
     coffee        Yes! SALOME can also make coffee!!"\
 
-'''%exeName
+'''
 
     print msg
   #
@@ -160,9 +154,8 @@ Commands:
       }
 
     if not command in availableCommands.keys():
-      self.getLogger().error("Unrecognized command: %s.", command)
-      self._usage()
-      sys.exit(1)
+      command = "start"
+      options = args
 
     return availableCommands[command], options
   #
@@ -184,21 +177,22 @@ Commands:
       command = "_runAppli"
 
     try:
-      getattr(self, command)(options) # run appropriate method
-    except AttributeError:
-      self.getLogger().error("Method %s is not implemented.", command)
-      sys.exit(1)
+      res = getattr(self, command)(options) # run appropriate method
+      return res or (None, None)
     except SystemExit, exc:
       if exc==0:
         sys.exit(0) #catch sys.exit(0) happy end no warning
       if exc==1:
         self.getLogger().warning("SystemExit 1 in method %s.", command)
       sys.exit(1)
-    except:
+    except StandardError:
       self.getLogger().error("Unexpected error:")
       import traceback
       traceback.print_exc()
       sys.exit(1)
+    except SalomeRunnerException, e:
+      self.getLogger().error(e)
+      sys.exit(1)
   #
 
   def __setEnvironmentFromConfigFile(self, filename):
@@ -268,17 +262,11 @@ Commands:
     import setenv
     setenv.main(True)
 
-    if args:
-      exe = args[0]
-      # if exe does not contain any slashes (/), search in PATH
-      # if exe contains slashes:
-      #    if exe begins with a slash, use this absolute path
-      #    else build absolute path relative to current working directory
-      if (os.sep in exe) and (exe[0] is not os.sep):
-        args[0] = os.getcwd() + os.sep + exe
-
-      proc = subprocess.Popen(args, shell=False, close_fds=True)
-      proc.wait()
+    scriptArgs = getScriptsAndArgs(args)
+    command = formatScriptsAndArgs(scriptArgs)
+    if command:
+      proc = subprocess.Popen(command, shell=True, close_fds=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+      return proc.communicate()
     else:
       absoluteAppliPath = os.getenv('ABSOLUTE_APPLI_PATH','')
       cmd = ["/bin/bash",  "--rcfile", absoluteAppliPath + "/.bashrc" ]
@@ -297,7 +285,6 @@ Commands:
   #
 
   def _killAll(self, args=[]):
-    #self._runAppli(['-k'] + args)
     from killSalome import killAllPorts
     killAllPorts()
   #
@@ -349,6 +336,7 @@ Commands:
     if not hasattr(self, '_logger'):
       self._logger = logging.getLogger(__name__)
       #self._logger.setLevel(logging.DEBUG)
+      self._logger.setLevel(logging.ERROR)
     return self._logger;
   #
 
@@ -358,7 +346,11 @@ if __name__ == "__main__":
   if len(sys.argv) == 3:
     runner = pickle.loads(sys.argv[1])
     args = pickle.loads(sys.argv[2])
-    runner._getStarted(args)
+    (out, err) = runner._getStarted(args)
+    if out:
+      sys.stdout.write(out)
+    if err:
+      sys.stderr.write(err)
   else:
     SalomeRunner()._usage()
 #