X-Git-Url: http://git.salome-platform.org/gitweb/?a=blobdiff_plain;f=bin%2FparseConfigFile.py;h=58ff8af7ef440aa8b37719df2efbebf8a5a801b0;hb=f2d7bee74f47cd695b4c4b9b0921424837140d0c;hp=cd224019933adfc2a072bd6a268f75b2c3dee478;hpb=309d4eee23b39959d125501a57691a0d8d235dec;p=modules%2Fkernel.git diff --git a/bin/parseConfigFile.py b/bin/parseConfigFile.py index cd2240199..58ff8af7e 100644 --- a/bin/parseConfigFile.py +++ b/bin/parseConfigFile.py @@ -1,15 +1,48 @@ +# 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__) -RESERVED_PREFIX = 'ADD_TO_' +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): @@ -65,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) @@ -82,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 = '' @@ -93,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 @@ -123,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 @@ -136,16 +178,23 @@ 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 - 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 +205,13 @@ 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) + expandedVal = _expandSystemVariables(key, val) 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 +223,14 @@ def _processConfigFile(config, reserved = []): pass # end for key,val pass # end for section - return 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): @@ -196,16 +249,21 @@ 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', '#' ] + 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 +283,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 +299,40 @@ 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 "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 +340,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 +377,10 @@ 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=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' @@ -295,6 +392,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)