X-Git-Url: http://git.salome-platform.org/gitweb/?a=blobdiff_plain;f=bin%2FparseConfigFile.py;h=63d0c92cc1160b88074288c97cf14f4cf2cf7e62;hb=a7e425483b5eb6a0491cbad5ef63cc67ccf64f7c;hp=991dadd036f68ef54dfa6fa3c394b59d4a9ca473;hpb=f122464b264fb99fc7a7098bfdfeeb6fdef644f0;p=modules%2Fkernel.git diff --git a/bin/parseConfigFile.py b/bin/parseConfigFile.py index 991dadd03..63d0c92cc 100644 --- a/bin/parseConfigFile.py +++ b/bin/parseConfigFile.py @@ -1,9 +1,29 @@ -import ConfigParser +# 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,10 +32,21 @@ 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): +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 @@ -57,7 +88,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() @@ -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 @@ -105,7 +143,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: @@ -113,9 +151,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) # @@ -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 @@ -134,17 +174,23 @@ def parseConfigFile(filename, reserved = []): # Read config file try: config.read(filename) - except ConfigParser.MissingSectionHeaderError: + except configparser.MissingSectionHeaderError: logConfigParser.error("No section found in file: %s"%(filename)) return [] - return _processConfigFile(config, reserved, filename) + try: + return __processConfigFile(config, reserved, filename) + 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) # -def _processConfigFile(config, reserved = [], filename="UNKNOWN FILENAME"): +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 = [], filename="UNKNOWN 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(ADD_TO_PREFIX):] @@ -182,7 +223,14 @@ def _processConfigFile(config, reserved = [], filename="UNKNOWN FILENAME"): 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): @@ -195,135 +243,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 = [], outputFile=None): - 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' ] - # 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 - 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() - if "=" in line: - try: - variable, value = line.split('=') - except: #avoid error for complicated sh line xx=`...=...`, but warning - print "WARNING: EnvFileConverter: line with multiples '=' character are hazardous: '"+line+"'" - variable, value = line.split('=',1) - self.allParsedVariableNames.append(variable) - # Self-extending variables that are not in reserved keywords - # Example: FOO=something:${FOO} - # :TODO: - # - # 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 - 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=['PATH', 'LD_LIBRARY_PATH', 'PYTHONPATH'] - logConfigParser.debug('convert env file %s to %s'%(envFilename, configFilename)) - reserved=['PATH', 'LD_LIBRARY_PATH', 'PYTHONPATH', 'MANPATH', 'R_LIBS', 'PV_PLUGIN_PATH', 'TCLLIBPATH', 'TKLIBPATH'] - 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) -#