Salome HOME
Merge remote-tracking branch 'origin/vsr/fix_single_study_pb' into pre/fix_single_study
[modules/kernel.git] / bin / parseConfigFile.py
index 38f8f2dbf62b1713e6d62d88d53ef41942496e41..7d60b22095195aa1439ef8cc98385a3cd93fcbf4 100644 (file)
@@ -1,13 +1,34 @@
+# Copyright (C) 2013-2014  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
 
 logging.basicConfig()
 logConfigParser = logging.getLogger(__name__)
 
-RESERVED_PREFIX = 'ADD_TO_'
+ADD_TO_PREFIX = 'ADD_TO_'
+UNSET_KEYWORD = 'UNSET'
 
 
 # :TRICKY: So ugly solution...
@@ -17,7 +38,7 @@ class MultiOptSafeConfigParser(ConfigParser.SafeConfigParser):
 
   # copied from python 2.6.8 Lib.ConfigParser.py
   # modified (see code comments) to handle duplicate keys
-  def _read(self, fp, name):
+  def _read(self, fp, fpname):
     """Parse a sectioned setup file.
 
     The sections in setup file contains a title line at the top,
@@ -103,7 +124,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 = ParsingError(fpname)
+              e = ConfigParser.ParsingError(fpname)
             e.append(lineno, repr(line))
     # if any parsing errors occurred, raise an exception
     if e:
@@ -136,16 +157,17 @@ def parseConfigFile(filename, reserved = []):
     logConfigParser.error("No section found in file: %s"%(filename))
     return []
 
-  return _processConfigFile(config, reserved)
+  return __processConfigFile(config, reserved, filename)
 #
 
-def _processConfigFile(config, reserved = []):
+def __processConfigFile(config, reserved = [], filename="UNKNOWN FILENAME"):
   # :TODO: may detect duplicated variables in the same section (raise a warning)
   #        or even duplicate sections
 
+  unsetVariables = []
   outputVariables = []
   # Get raw items for each section, and make some processing for environment variables management
-  reservedKeys = [RESERVED_PREFIX+str(x) for x in reserved] # produce [ 'ADD_TO_reserved_1', 'ADD_TO_reserved_2', ..., ADD_TO_reserved_n ]
+  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:[] }
   sections = config.sections()
   for section in sections:
@@ -156,16 +178,19 @@ def _processConfigFile(config, reserved = []):
     for key,val in entries:
       if key in reserved:
         logConfigParser.error("Invalid use of reserved variable: %s in file: %s"%(key, filename))
+      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)
+        if not "DLIM8VAR" in key: # special case: DISTENE licence key can contain double clons (::)
+          expandedVal = _trimColons(expandedVal)
 
         if key in reservedKeys:
-          shortKey = key[len(RESERVED_PREFIX):]
+          shortKey = key[len(ADD_TO_PREFIX):]
           vals = expandedVal.split(',')
           reservedValues[shortKey] += vals
           # remove left&right spaces on each element
@@ -177,7 +202,7 @@ def _processConfigFile(config, reserved = []):
       pass # end for key,val
     pass # end for section
 
-  return outputVariables, reservedValues
+  return unsetVariables, outputVariables, reservedValues
 #
 
 def _trimColons(var):
@@ -203,9 +228,12 @@ class EnvFileConverter(object):
     self.outputFile = outputFile
     self.allParsedVariableNames=[]
     # exclude line that begin with:
-    self.exclude = [ 'if', 'then', 'fi', '#' ]
+    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:
@@ -225,6 +253,12 @@ class EnvFileConverter(object):
           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):
@@ -235,14 +269,42 @@ class EnvFileConverter(object):
         if line.startswith(k) and "=" in line:
           variable, value = line.split('=')
           value = self._purgeValue(value, k)
-          line = RESERVED_PREFIX + k + ": " + value
+          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 line.startswith("LOGNAME="):
+        return "\n"
+      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:
-        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)
@@ -250,15 +312,21 @@ 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
-        import subprocess
-        res = subprocess.Popen([obj], stdout=subprocess.PIPE).communicate()[0]
+        obj = obj.split()
+        res = subprocess.Popen(obj, stdout=subprocess.PIPE).communicate()[0]
         res = res.strip(' \t\n\r') # trim whitespaces
         return res
       #
@@ -281,9 +349,8 @@ class EnvFileConverter(object):
   #
 
 # Convert .sh environment file to configuration file format
-def convertEnvFileToConfigFile(envFilename, configFilename):
-  #reserved=['PATH', 'LD_LIBRARY_PATH', 'PYTHONPATH']
-  reserved=['PATH', 'LD_LIBRARY_PATH', 'PYTHONPATH', 'MANPATH', 'R_LIBS', 'PV_PLUGIN_PATH']
+def convertEnvFileToConfigFile(envFilename, configFilename, 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'
@@ -295,6 +362,7 @@ def convertEnvFileToConfigFile(envFilename, configFilename):
   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)