Salome HOME
CMake: doing proper string comparison in IF clause
[modules/kernel.git] / bin / salomeRunner.py
index 9b9343a63bbcfdc4b898a9b4feb48f39db8f1e26..c80c4f3164b2ece36bd755f268562ff7c2da4a37 100644 (file)
@@ -1,6 +1,7 @@
 import os
 import sys
 import logging
+import ConfigParser
 
 from parseConfigFile import parseConfigFile
 from parseConfigFile import convertEnvFileToConfigFile
@@ -10,6 +11,31 @@ import pickle
 import subprocess
 import platform
 
+from salomeLauncherUtils import SalomeRunnerException
+from salomeLauncherUtils import getScriptsAndArgs, formatScriptsAndArgs
+
+def usage():
+  #exeName = os.path.splitext(os.path.basename(__file__))[0]
+
+  msg = '''\
+Usage: salome [command] [options] [--config=file1,...,filen]
+
+Commands:
+    start         Launches SALOME virtual application [DEFAULT]
+    shell         Executes a script under SALOME application environment
+    connect       Connects a Python console to the active SALOME session
+    killall       Kill all SALOME running sessions
+    info          Display some information about SALOME
+    help          Show this message
+    coffee        Yes! SALOME can also make coffee!!"
+
+Use salome start --help or salome shell --help
+to show help on start and shell commands.
+'''
+
+  print msg
+#
+
 """
 The SalomeRunner class in an API to configure SALOME environment then
 start SALOME using a single python command.
@@ -25,84 +51,98 @@ class SalomeRunner:
   to .cfg format before setting the environment.
   """
   def __init__(self, configFileNames=[]):
+    #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")
+
+    reserved=['PATH', 'LD_LIBRARY_PATH', 'PYTHONPATH', 'MANPATH', 'PV_PLUGIN_PATH']
     for filename in configFileNames:
       basename, extension = os.path.splitext(filename)
       if extension == ".cfg":
-        self.__setEnvironmentFromConfigFile(filename)
+        self.__setEnvironmentFromConfigFile(filename, reserved)
       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')
         try:
-          convertEnvFileToConfigFile(filename, temp.name)
-          self.__setEnvironmentFromConfigFile(temp.name)
+          convertEnvFileToConfigFile(filename, temp.name, reserved)
+          self.__setEnvironmentFromConfigFile(temp.name, reserved)
+        except ConfigParser.ParsingError, e:
+          self.getLogger().warning("Invalid token found when parsing file: %s\n"%(filename))
+          print e
+          print '\n'
         finally:
           # Automatically cleans up the file
           temp.close()
       else:
-        self._getLogger().warning("Unrecognized extension for configuration file: %s", filename)
+        self.getLogger().warning("Unrecognized extension for configuration file: %s", filename)
   #
 
   def go(self, args):
     # Run this module as a script, in order to use appropriate Python interpreter
     # according to current path (initialized from environment files).
-    absoluteAppliPath = os.environ['ABSOLUTE_APPLI_PATH']
+    absoluteAppliPath = os.getenv('ABSOLUTE_APPLI_PATH','')
     proc = subprocess.Popen(['python', absoluteAppliPath+'/bin/salome/salomeRunner.py', pickle.dumps(self),  pickle.dumps(args)], shell=False, close_fds=True)
     proc.wait()
   #
 
   """Append value to PATH environment variable"""
   def addToPath(self, value):
-    self.__addToReserved( 'PATH', value)
+    self.addToEnviron('PATH', value)
   #
 
   """Append value to LD_LIBRARY_PATH environment variable"""
   def addToLdLibraryPath(self, value):
-    self.__addToReserved('LD_LIBRARY_PATH', value)
+    self.addToEnviron('LD_LIBRARY_PATH', value)
   #
 
   """Append value to PYTHONPATH environment variable"""
   def addToPythonPath(self, value):
-    self.__addToReserved('PYTHONPATH', value)
+    self.addToEnviron('PYTHONPATH', value)
   #
 
   """Set environment variable to value"""
   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", name)
+      self.getLogger().warning("Environment variable already existing (and not overwritten): %s=%s", name, value)
       return
 
     if env:
-      self._getLogger().info("Overwriting environment variable: %s", name)
+      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)
+    self.getLogger().debug("Set environment variable: %s=%s", name, value)
     os.environ[name] = value
   #
 
-  ###################################
-  # This begins the private section #
-  ###################################
-
-  def _usage(self, unused=[]):
-    exeName = os.path.splitext(os.path.basename(__file__))[0]
-
-    msg = '''\
-Usage: %s [command] [options] [--config=file1,...,filen]
-
-Commands:
-    start         Launches SALOME virtual application [DEFAULT]
-    shell         Executes a script under SALOME application environment
-    connect       Connects a Python console to the active SALOME session
-    killall       Kill all SALOME running sessions
-    info          Display some information about SALOME
-    help          Show this message
-    coffee        Yes! SALOME can also make coffee!!"\
+  """Unset environment variable"""
+  def unsetEnviron(self, name):
+    if os.environ.has_key(name):
+      del os.environ[name]
+  #
 
-'''%exeName
+  """Append value to environment variable"""
+  def addToEnviron(self, name, value, separator=os.pathsep):
+    if value == '':
+      return
 
-    print msg
+    value = os.path.expandvars(value) # expand environment variables
+    self.getLogger().debug("Add to %s: %s", name, value)
+    env = os.getenv(name, None)
+    if env is None:
+      os.environ[name] = value
+    else:
+      os.environ[name] = value + separator + env
   #
 
+  ###################################
+  # This begins the private section #
+  ###################################
+
   def __parseArguments(self, args):
     if len(args) == 0 or args[0].startswith("-"):
       return None, args
@@ -121,9 +161,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
   #
@@ -139,46 +178,49 @@ Commands:
 
     if command is None:
       if args and args[0] in ["-h","--help","help"]:
-        self._usage()
+        usage()
         sys.exit(0)
       # try to default to "start" command
       command = "_runAppli"
 
     try:
-      getattr(self, command)(options) # run appropriate method
-    except AttributeError:
-      self._getLogger().error("Method %s is not implemented.", command)
+      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 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):
-    configVars, reservedDict = parseConfigFile(filename, reserved=['PATH', 'LD_LIBRARY_PATH', 'PYTHONPATH'])
+  def __setEnvironmentFromConfigFile(self, filename, reserved=[]):
+    unsetVars, configVars, reservedDict = parseConfigFile(filename, reserved)
+
+    # unset variables
+    for var in unsetVars:
+      self.unsetEnviron(var)
 
     # set environment
     for reserved in reservedDict:
       a = filter(None, reservedDict[reserved]) # remove empty elements
       reformattedVals = ':'.join(a)
-      self.__addToReserved(reserved, reformattedVals)
+      self.addToEnviron(reserved, reformattedVals)
       pass
 
     for key,val in configVars:
       self.setEnviron(key, val, overwrite=True)
       pass
 
-    sys.path[:0] = os.environ['PYTHONPATH'].split(':')
-  #
-
-  def __addToReserved(self, name, value):
-    if value == '':
-      return
-
-    value = os.path.expandvars(value) # expand environment variables
-    self._getLogger().debug("Add to %s: %s", name, value)
-    env = os.getenv(name, None)
-    if env is None:
-      os.environ[name] = value
-    else:
-      os.environ[name] = value + os.pathsep + env
+    sys.path[:0] = os.getenv('PYTHONPATH','').split(':')
   #
 
   def _runAppli(self, args=[]):
@@ -199,19 +241,13 @@ 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.environ['ABSOLUTE_APPLI_PATH']
+      absoluteAppliPath = os.getenv('ABSOLUTE_APPLI_PATH','')
       cmd = ["/bin/bash",  "--rcfile", absoluteAppliPath + "/.bashrc" ]
       proc = subprocess.Popen(cmd, shell=False, close_fds=True)
       proc.wait()
@@ -228,7 +264,6 @@ Commands:
   #
 
   def _killAll(self, args=[]):
-    #self._runAppli(['-k'] + args)
     from killSalome import killAllPorts
     killAllPorts()
   #
@@ -238,6 +273,10 @@ Commands:
     self._runAppli(["--version"])
   #
 
+  def _usage(self, unused=[]):
+    usage()
+  #
+
   def _makeCoffee(self, args=[]):
     print "                        ("
     print "                          )     ("
@@ -268,17 +307,19 @@ Commands:
   # Ref: http://stackoverflow.com/questions/2999638/how-to-stop-attributes-from-being-pickled-in-python
   def __getstate__(self):
     d = dict(self.__dict__)
-    del d['_logger']
+    if hasattr(self, '_logger'):
+      del d['_logger']
     return d
   #
   def __setstate__(self, d):
     self.__dict__.update(d) # I *think* this is a safe way to do it
   #
   # Excluding self._logger from pickle operation imply using the following method to access logger
-  def _getLogger(self):
+  def getLogger(self):
     if not hasattr(self, '_logger'):
       self._logger = logging.getLogger(__name__)
       #self._logger.setLevel(logging.DEBUG)
+      self._logger.setLevel(logging.ERROR)
     return self._logger;
   #
 
@@ -288,7 +329,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()
+    usage()
 #