Salome HOME
[EDF29852] : first successful launch of out of process sever. my_log_4_this_session...
[modules/kernel.git] / bin / parseConfigFile.py
index 58ff8af7ef440aa8b37719df2efbebf8a5a801b0..20d782c8cba342b2895a23a615e983beae410bfc 100644 (file)
@@ -1,4 +1,4 @@
-# Copyright (C) 2013-2016  CEA/DEN, EDF R&D, OPEN CASCADE
+# Copyright (C) 2013-2024  CEA, EDF, OPEN CASCADE
 #
 # This library is free software; you can redistribute it and/or
 # modify it under the terms of the GNU Lesser General Public
 # See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
 #
 
-import ConfigParser
+import configparser
 import os
 import logging
 import re
 from io import StringIO
 import subprocess
+import collections
 from salomeContextUtils import SalomeContextException #@UnresolvedImport
 
 logging.basicConfig()
@@ -30,7 +31,8 @@ logConfigParser = logging.getLogger(__name__)
 
 ADD_TO_PREFIX = 'ADD_TO_'
 UNSET_KEYWORD = 'UNSET'
-
+# variables defined in this section are set only if not already defined
+DEFAULT_VARS_SECTION_NAME = 'SALOME DEFAULT VALUES'
 
 def _expandSystemVariables(key, val):
   expandedVal = os.path.expandvars(val) # expand environment variables
@@ -44,9 +46,9 @@ def _expandSystemVariables(key, val):
 #
 
 # :TRICKY: So ugly solution...
-class MultiOptSafeConfigParser(ConfigParser.SafeConfigParser):
+class MultiOptSafeConfigParser(configparser.SafeConfigParser):
   def __init__(self):
-    ConfigParser.SafeConfigParser.__init__(self)
+    configparser.SafeConfigParser.__init__(self)
 
   # copied from python 2.6.8 Lib.ConfigParser.py
   # modified (see code comments) to handle duplicate keys
@@ -88,7 +90,7 @@ class MultiOptSafeConfigParser(ConfigParser.SafeConfigParser):
           sectname = mo.group('header')
           if sectname in self._sections:
             cursect = self._sections[sectname]
-          elif sectname == ConfigParser.DEFAULTSECT:
+          elif sectname == configparser.DEFAULTSECT:
             cursect = self._defaults
           else:
             cursect = self._dict()
@@ -98,7 +100,7 @@ class MultiOptSafeConfigParser(ConfigParser.SafeConfigParser):
           optname = None
         # no section header in the file?
         elif cursect is None:
-          raise ConfigParser.MissingSectionHeaderError(fpname, lineno, line)
+          raise configparser.MissingSectionHeaderError(fpname, lineno, line)
         # an option line?
         else:
           mo = self.OPTCRE.match(line)
@@ -143,7 +145,7 @@ class MultiOptSafeConfigParser(ConfigParser.SafeConfigParser):
             # raised at the end of the file and will contain a
             # list of all bogus lines
             if not e:
-              e = ConfigParser.ParsingError(fpname)
+              e = configparser.ParsingError(fpname)
             e.append(lineno, repr(line))
     # if any parsing errors occurred, raise an exception
     if e:
@@ -151,9 +153,9 @@ class MultiOptSafeConfigParser(ConfigParser.SafeConfigParser):
 
     # join the multi-line values collected while reading
     all_sections = [self._defaults]
-    all_sections.extend(self._sections.values())
+    all_sections.extend(list(self._sections.values()))
     for options in all_sections:
-      for name, val in options.items():
+      for name, val in list(options.items()):
         if isinstance(val, list):
           options[name] = '\n'.join(val)
   #
@@ -174,13 +176,13 @@ def parseConfigFile(filename, reserved = None):
   # Read config file
   try:
     config.read(filename)
-  except ConfigParser.MissingSectionHeaderError:
+  except configparser.MissingSectionHeaderError:
     logConfigParser.error("No section found in file: %s"%(filename))
     return []
 
   try:
     return __processConfigFile(config, reserved, filename)
-  except ConfigParser.InterpolationMissingOptionError, e:
+  except configparser.InterpolationMissingOptionError as e:
     msg = "A variable may be undefined in SALOME context file: %s\nParser error is: %s\n"%(filename, e)
     raise SalomeContextException(msg)
 #
@@ -193,6 +195,7 @@ def __processConfigFile(config, reserved = None, filename="UNKNOWN FILENAME"):
     reserved = []
   unsetVariables = []
   outputVariables = []
+  defaultValues = []
   # Get raw items for each section, and make some processing for environment variables management
   reservedKeys = [ADD_TO_PREFIX+str(x) for x in reserved] # produce [ 'ADD_TO_reserved_1', 'ADD_TO_reserved_2', ..., ADD_TO_reserved_n ]
   reservedValues = dict([str(i),[]] for i in reserved) # create a dictionary in which keys are the 'ADD_TO_reserved_i' and associated values are empty lists: { 'reserved_1':[], 'reserved_2':[], ..., reserved_n:[] }
@@ -217,7 +220,10 @@ def __processConfigFile(config, reserved = None, filename="UNKNOWN FILENAME"):
           # remove left&right spaces on each element
           vals = [v.strip(' \t\n\r') for v in vals]
         else:
-          outputVariables.append((key, expandedVal))
+          if DEFAULT_VARS_SECTION_NAME == section.upper():
+            defaultValues.append((key, expandedVal))
+          else:
+            outputVariables.append((key, expandedVal))
           pass
         pass # end if key
       pass # end for key,val
@@ -230,7 +236,12 @@ def __processConfigFile(config, reserved = None, filename="UNKNOWN FILENAME"):
     vals = list(set(vals))
     outVars.append((var, ','.join(vals)))
 
-  return unsetVariables, outVars, reservedValues
+  ConfigInfo = collections.namedtuple("ConfigInfo",
+                                      ["unsetVariables",
+                                       "outputVariables",
+                                       "reservedValues",
+                                       "defaultValues"])
+  return ConfigInfo(unsetVariables, outVars, reservedValues, defaultValues)
 #
 
 def _trimColons(var):
@@ -243,157 +254,3 @@ def _trimColons(var):
   v = pattern.sub(r':', v) # remove matching patterns
   return v
 #
-
-# This class is used to parse .sh environment file
-# It deals with specific treatments:
-#    - virtually add a section to configuration file
-#    - process shell keywords (if, then...)
-class EnvFileConverter(object):
-  def __init__(self, fp, section_name, reserved = None, outputFile=None):
-    if reserved is None:
-      reserved = []
-    self.fp = fp
-    self.sechead = '[' + section_name + ']\n'
-    self.reserved = reserved
-    self.outputFile = outputFile
-    self.allParsedVariableNames = []
-    # exclude line that begin with:
-    self.exclude = [ 'if', 'then', 'else', 'fi', '#', 'echo', 'exit' ]
-    self.exclude.append('$gconfTool') # QUICK FIX :TODO: provide method to extend this variable
-    # 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:
-    self.special = [ 'unset' ]
-
-  def readline(self):
-    if self.sechead:
-      try:
-        if self.outputFile is not None:
-          self.outputFile.write(self.sechead)
-        return self.sechead
-      finally:
-        self.sechead = None
-    else:
-      line = self.fp.readline()
-      # trim  whitespaces
-      line = line.strip(' \t\n\r')
-      # line of interest? (not beginning by a keyword of self.exclude)
-      for k in self.exclude:
-        if line.startswith(k):
-          return '\n'
-      # look for substrinsg beginning with sharp charcter ('#')
-      line = re.sub(r'#.*$', r'', line)
-      # line to be pre-processed? (beginning by a keyword of self.special)
-      for k in self.special:
-        if k == "unset" and line.startswith(k):
-          line = line[len(k):]
-          line = line.strip(' \t\n\r')
-          line = UNSET_KEYWORD + ": " + line
-      # line to be pre-processed? (beginning by a keyword of self.discard)
-      for k in self.discard:
-        if line.startswith(k):
-          line = line[len(k):]
-          line = line.strip(' \t\n\r')
-      # process reserved keywords
-      for k in self.reserved:
-        if line.startswith(k) and "=" in line:
-          variable, value = line.split('=')
-          value = self._purgeValue(value, k)
-          line = ADD_TO_PREFIX + k + ": " + value
-      # Update list of variable names
-      # :TODO: define excludeBlock variable (similar to exclude) and provide method to extend it
-      if "cleandup()" in line:
-        print "WARNING: parseConfigFile.py: skip cleandup and look for '# PRODUCT environment'"
-        while True:
-          line = self.fp.readline()
-          if "# PRODUCT environment" in line:
-            print "WARNING: parseConfigFile.py: '# PRODUCT environment' found"
-            break
-      while "clean " in line[0:6]: #skip clean calls with ending ";" crash
-        line = self.fp.readline()
-      # Extract variable=value
-      if "=" in line:
-        try:
-          variable, value = line.split('=')
-        except: #avoid error for complicated sh line xx=`...=...`, but warning
-          print "WARNING: parseConfigFile.py: line with multiples '=' character are hazardous: '"+line+"'"
-          variable, value = line.split('=',1)
-          pass
-
-        # Self-extending variables that are not in reserved keywords
-        # Example: FOO=something:${FOO}
-        # In this case, remove the ${FOO} in value
-        if variable in value:
-          value = self._purgeValue(value, variable)
-          line = "%s=%s"%(variable,value)
-
-        self.allParsedVariableNames.append(variable)
-      # End of extraction
-
-      if not line:
-        return line
-
-      #
-      # replace "${FOO}" and "$FOO" and ${FOO} and $FOO by %(FOO)s if FOO is
-      # defined in current file (i.e. it is not an external environment variable)
-      for k in self.allParsedVariableNames:
-        key = r'\$\{?'+k+'\}?'
-        pattern = re.compile(key, re.VERBOSE)
-        line = pattern.sub(r'%('+k+')s', line)
-        # Remove quotes (if line does not contain whitespaces)
-        try:
-          variable, value = line.split('=', 1)
-        except ValueError:
-          variable, value = line.split(':', 1)
-        if not ' ' in value.strip():
-          pattern = re.compile(r'\"', re.VERBOSE)
-          line = pattern.sub(r'', line)
-      #
-
-      # Replace `shell_command` by its result
-      def myrep(obj):
-        obj = re.sub('`', r'', obj.group(0)) # remove quotes
-        obj = obj.split()
-        res = subprocess.Popen(obj, stdout=subprocess.PIPE).communicate()[0]
-        res = res.strip(' \t\n\r') # trim whitespaces
-        return res
-      #
-      line = re.sub('`[^`]+`', myrep, line)
-      #
-      if self.outputFile is not None:
-        self.outputFile.write(line+'\n')
-      return line
-
-  def _purgeValue(self, value, name):
-    # Replace foo:${PATTERN}:bar or foo:$PATTERN:bar by foo:bar
-    key = r'\$\{?'+name+'\}?'
-    pattern = re.compile(key, re.VERBOSE)
-    value = pattern.sub(r'', value)
-
-    # trim colons
-    value = _trimColons(value)
-
-    return value
-  #
-
-# Convert .sh environment file to configuration file format
-def convertEnvFileToConfigFile(envFilename, configFilename, reserved=None):
-  if reserved is None:
-    reserved = []
-  logConfigParser.debug('convert env file %s to %s'%(envFilename, configFilename))
-  fileContents = open(envFilename, 'r').read()
-
-  pattern = re.compile('\n[\n]+', re.VERBOSE) # multiple '\n'
-  fileContents = pattern.sub(r'\n', fileContents) # replace by a single '\n'
-
-  finput = StringIO(unicode(fileContents))
-  foutput = open(configFilename, 'w')
-
-  config = MultiOptSafeConfigParser()
-  config.optionxform = str # case sensitive
-  config.readfp(EnvFileConverter(finput, 'SALOME Configuration', reserved, outputFile=foutput))
-
-  foutput.close()
-
-  logConfigParser.info('Configuration file generated: %s'%configFilename)
-#