Salome HOME
Fix for the "23289: [CEA 1872] Problem in the CMakelists.txt of the template profile...
[modules/kernel.git] / bin / parseConfigFile.py
index db33a4fe0f5237ae30f937ddd2195639bf1f5ef4..58ff8af7ef440aa8b37719df2efbebf8a5a801b0 100644 (file)
@@ -1,9 +1,29 @@
+# Copyright (C) 2013-2016  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, or (at your option) any later version.
+#
+# 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
+#
+
 import ConfigParser
 import os
 import logging
 import re
 from io import StringIO
 import subprocess
+from salomeContextUtils import SalomeContextException #@UnresolvedImport
 
 logging.basicConfig()
 logConfigParser = logging.getLogger(__name__)
@@ -12,6 +32,17 @@ ADD_TO_PREFIX = 'ADD_TO_'
 UNSET_KEYWORD = 'UNSET'
 
 
+def _expandSystemVariables(key, val):
+  expandedVal = os.path.expandvars(val) # expand environment variables
+  # Search for not expanded variables (i.e. non-existing environment variables)
+  pattern = re.compile('\${ ( [^}]* ) }', re.VERBOSE) # string enclosed in ${ and }
+  expandedVal = pattern.sub(r'', expandedVal) # remove matching patterns
+
+  if not "DLIM8VAR" in key: # special case: DISTENE licence key can contain double clons (::)
+    expandedVal = _trimColons(expandedVal)
+  return expandedVal
+#
+
 # :TRICKY: So ugly solution...
 class MultiOptSafeConfigParser(ConfigParser.SafeConfigParser):
   def __init__(self):
@@ -67,7 +98,7 @@ class MultiOptSafeConfigParser(ConfigParser.SafeConfigParser):
           optname = None
         # no section header in the file?
         elif cursect is None:
-          raise MissingSectionHeaderError(fpname, lineno, line)
+          raise ConfigParser.MissingSectionHeaderError(fpname, lineno, line)
         # an option line?
         else:
           mo = self.OPTCRE.match(line)
@@ -84,6 +115,13 @@ class MultiOptSafeConfigParser(ConfigParser.SafeConfigParser):
                 if pos != -1 and optval[pos-1].isspace():
                   optval = optval[:pos]
               optval = optval.strip()
+              # ADD THESE LINES
+              splittedComments = optval.split('#')
+              s = _expandSystemVariables(optname, splittedComments[0])
+              optval = s.strip().strip("'").strip('"')
+              #if len(splittedComments) > 1:
+              #  optval += " #" + " ".join(splittedComments[1:])
+              # END OF ADD
               # allow empty values
               if optval == '""':
                 optval = ''
@@ -95,7 +133,7 @@ class MultiOptSafeConfigParser(ConfigParser.SafeConfigParser):
                 cursect[optname][0] += ','+optval
               else:
                 cursect[optname] = [optval]
-              # END OF SUBSITUTION
+              # END OF SUBSTITUTION
             else:
               # valueless option handling
               cursect[optname] = optval
@@ -125,7 +163,9 @@ class MultiOptSafeConfigParser(ConfigParser.SafeConfigParser):
 # Input: filename, and a list of reserved keywords (environment variables)
 # Output: a list of pairs (variable, value), and a dictionary associating a list of user-defined values to each reserved keywords
 # Note: Does not support duplicate keys in a same section
-def parseConfigFile(filename, reserved = []):
+def parseConfigFile(filename, reserved = None):
+  if reserved is None:
+    reserved = []
   config = MultiOptSafeConfigParser()
   config.optionxform = str # case sensitive
 
@@ -138,13 +178,19 @@ def parseConfigFile(filename, reserved = []):
     logConfigParser.error("No section found in file: %s"%(filename))
     return []
 
-  return _processConfigFile(config, reserved)
+  try:
+    return __processConfigFile(config, reserved, filename)
+  except ConfigParser.InterpolationMissingOptionError, e:
+    msg = "A variable may be undefined in SALOME context file: %s\nParser error is: %s\n"%(filename, e)
+    raise SalomeContextException(msg)
 #
 
-def _processConfigFile(config, reserved = []):
+def __processConfigFile(config, reserved = None, filename="UNKNOWN FILENAME"):
   # :TODO: may detect duplicated variables in the same section (raise a warning)
   #        or even duplicate sections
 
+  if reserved is None:
+    reserved = []
   unsetVariables = []
   outputVariables = []
   # Get raw items for each section, and make some processing for environment variables management
@@ -162,12 +208,7 @@ def _processConfigFile(config, reserved = []):
       elif key == UNSET_KEYWORD:
         unsetVariables += val.replace(',', ' ').split()
       else:
-        expandedVal = os.path.expandvars(val) # expand environment variables
-        # Search for not expanded variables (i.e. non-existing environment variables)
-        pattern = re.compile('\${ ( [^}]* ) }', re.VERBOSE) # string enclosed in ${ and }
-        expandedVal = pattern.sub(r'', expandedVal) # remove matching patterns
-        # Trim colons
-        expandedVal = _trimColons(expandedVal)
+        expandedVal = _expandSystemVariables(key, val)
 
         if key in reservedKeys:
           shortKey = key[len(ADD_TO_PREFIX):]
@@ -182,7 +223,14 @@ def _processConfigFile(config, reserved = []):
       pass # end for key,val
     pass # end for section
 
-  return unsetVariables, outputVariables, reservedValues
+  # remove duplicate values
+  outVars = []
+  for (var, values) in outputVariables:
+    vals = values.split(',')
+    vals = list(set(vals))
+    outVars.append((var, ','.join(vals)))
+
+  return unsetVariables, outVars, reservedValues
 #
 
 def _trimColons(var):
@@ -201,14 +249,17 @@ def _trimColons(var):
 #    - virtually add a section to configuration file
 #    - process shell keywords (if, then...)
 class EnvFileConverter(object):
-  def __init__(self, fp, section_name, reserved = [], outputFile=None):
+  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=[]
+    self.allParsedVariableNames = []
     # exclude line that begin with:
-    self.exclude = [ 'if', 'then', 'fi', '#', 'echo' ]
+    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:
@@ -250,6 +301,7 @@ class EnvFileConverter(object):
           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:
@@ -257,12 +309,30 @@ class EnvFileConverter(object):
           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:
-        variable, value = line.split('=')
+        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)
-      # Self-extending variables that are not in reserved keywords
-      # Example: FOO=something:${FOO}
-      # :TODO:
+      # 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)
@@ -270,10 +340,16 @@ class EnvFileConverter(object):
         key = r'\$\{?'+k+'\}?'
         pattern = re.compile(key, re.VERBOSE)
         line = pattern.sub(r'%('+k+')s', line)
-      # Remove quotes
-        pattern = re.compile(r'\"', re.VERBOSE)
-        line = pattern.sub(r'', 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
@@ -301,10 +377,10 @@ 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
-  reserved=['PATH', 'LD_LIBRARY_PATH', 'PYTHONPATH', 'MANPATH', 'R_LIBS', 'PV_PLUGIN_PATH', 'TCLLIBPATH', 'TKLIBPATH']
+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'