Salome HOME
Improve configuration read
authorSerge Rehbinder <serge.rehbinder@cea.fr>
Wed, 27 Jan 2016 13:01:15 +0000 (14:01 +0100)
committerSerge Rehbinder <serge.rehbinder@cea.fr>
Wed, 27 Jan 2016 13:01:15 +0000 (14:01 +0100)
src/common/__init__.py
src/common/config_pyconf.py
src/common/internal_config/salomeTools.pyconf [new file with mode: 0644]
src/config.py
src/salomeTools.py

index e6ddc372ce5a00fe776b9b7f180a102aabdc0a4e..3eeca22030a11ec6bb3661d3ac41f5a414225e50 100644 (file)
 #  License along with this library; if not, write to the Free Software
 #  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
 
+import os
 
 from . import config_pyconf
 from . import architecture
 from . import printcolors
-from . import options
\ No newline at end of file
+from . import options
+
+class SatException(Exception):
+    pass
+
+def ensure_path_exists(p):
+    if not os.path.exists(p):
+        os.mkdir(p)
\ No newline at end of file
index 89b66bd99a71089ddfbfd69e91cecd0db6d1d027..53bd184574094ea8d02b87915c0f621430cbf3b7 100644 (file)
@@ -642,7 +642,7 @@ class Config(Mapping):
         object.__setattr__(self, 'reader', ConfigReader(self))
         object.__setattr__(self, 'namespaces', [Config.Namespace()])
         if streamOrFile is not None:
-            if isinstance(streamOrFile, str) or isinstance(streamOrFile, unicode):
+            if isinstance(streamOrFile, str) or isinstance(streamOrFile, bytes):
                 global streamOpener
                 if streamOpener is None:
                     streamOpener = defaultStreamOpener
@@ -747,6 +747,14 @@ class Sequence(Container):
             rv = self.seq[self.index]
             self.index += 1
             return rv
+        
+        # This method is for python3 compatibility
+        def __next__(self): 
+            if self.index >= self.limit:
+                raise StopIteration
+            rv = self.seq[self.index]
+            self.index += 1
+            return rv
 
     def __init__(self, parent=None):
         """
@@ -1058,7 +1066,10 @@ class ConfigReader(object):
         else:
             c = self.stream.read(1)
             if isinstance(c,bytes):
-                c = c.decode()
+                try:
+                    c = c.decode()
+                except:
+                    import pdb;pdb.set_trace()
             self.colno += 1
             if c == '\n':
                 self.lineno += 1
diff --git a/src/common/internal_config/salomeTools.pyconf b/src/common/internal_config/salomeTools.pyconf
new file mode 100644 (file)
index 0000000..9aa08bf
--- /dev/null
@@ -0,0 +1,8 @@
+#!/usr/bin/env python
+#-*- coding:utf-8 -*-
+
+INTERNAL :
+{   
+    sat_version : "5.0.0dev"
+}
+
index 0e887a2d6fa710fe4a8f7dae0424e272781be19d..b82e4af38a67778464e71569005a4d442c17e0b9 100644 (file)
@@ -21,6 +21,9 @@ import sys
 import common
 import platform
 import datetime
+import glob
+import re
+import shutil
 
 # Define all possible option for config command :  sat config <options>
 parser = common.options.Options()
@@ -38,6 +41,23 @@ class MergeHandler:
             return common.config_pyconf.overwriteMergeResolve(map1, map2, key)
 '''
 
+class ConfigOpener:
+    def __init__(self, pathList):
+        self.pathList = pathList
+
+    def __call__(self, name):
+        if os.path.isabs(name):
+            return common.config_pyconf.ConfigInputStream(open(name, 'rb'))
+        else:
+            return common.config_pyconf.ConfigInputStream( open(os.path.join( self.getPath(name), name ), 'rb') )
+        raise IOError(_("Configuration file '%s' not found") % name)
+
+    def getPath( self, name ):
+        for path in self.pathList:
+            if os.path.exists(os.path.join(path, name)):
+                return path
+        raise IOError(_("Configuration file '%s' not found") % name)
+
 class ConfigManager:
     '''Class that manages the read of all the configuration files of salomeTools
     '''
@@ -155,8 +175,159 @@ class ConfigManager:
         for rule in self.get_command_line_overrides(options, ["VARS"]):
             exec('cfg.' + rule) # this cannot be factorized because of the exec
         
+        # =======================================================================================
+        # Load INTERNAL config
+        # read src/common/internal_config/salomeTools.pyconf
+        common.config_pyconf.streamOpener = ConfigOpener([os.path.join(cfg.VARS.srcDir, 'common', 'internal_config')])
+        try:
+            internal_cfg = common.config_pyconf.Config(open(os.path.join(cfg.VARS.srcDir, 'common', 'internal_config', 'salomeTools.pyconf')))
+        except common.config_pyconf.ConfigError as e:
+            raise common.SatException(_("Error in configuration file: salomeTools.pyconf\n  %(error)s") % \
+                {'error': str(e) })
+
+        merger.merge(cfg, internal_cfg)
+
+        for rule in self.get_command_line_overrides(options, ["INTERNAL"]):
+            exec('cfg.' + rule) # this cannot be factorized because of the exec        
+        
+        # =======================================================================================
+        # Load SITE config file
+        # search only in the data directory
+        common.config_pyconf.streamOpener = ConfigOpener([cfg.VARS.dataDir])
+        try:
+            site_cfg = common.config_pyconf.Config(open(os.path.join(cfg.VARS.dataDir, 'site.pyconf')))
+        except common.config_pyconf.ConfigError as e:
+            raise common.SatException(_("Error in configuration file: site.pyconf\n  %(error)s") % \
+                {'error': str(e) })
+        except IOError as error:
+            e = str(error)
+            if "site.pyconf" in e :
+                e += "\nYou can copy data" + cfg.VARS.sep + "site.template.pyconf to data" + cfg.VARS.sep + "site.pyconf and edit the file"
+            raise common.SatException( e );
+
+        merger.merge(cfg, site_cfg)
+
+        for rule in self.get_command_line_overrides(options, ["SITE"]):
+            exec('cfg.' + rule) # this cannot be factorized because of the exec
+        
+        # =======================================================================================
+        # Load APPLICATION config file
+        if application is not None:
+            # search APPLICATION file in all directories in configPath
+            cp = cfg.SITE.config.configPath
+            common.config_pyconf.streamOpener = ConfigOpener(cp)
+            try:
+                application_cfg = common.config_pyconf.Config(application + '.pyconf')
+            except IOError as e:
+                raise common.SatException(_("%s, use 'config --list' to get the list of available applications.") %e)
+            except common.config_pyconf.ConfigError as e:
+                raise common.SatException(_("Error in configuration file: %(application)s.pyconf\n  %(error)s") % \
+                    { 'application': application, 'error': str(e) } )
+
+            merger.merge(cfg, application_cfg)
+
+            for rule in self.get_command_line_overrides(options, ["APPLICATION"]):
+                exec('cfg.' + rule) # this cannot be factorized because of the exec
+        
+        # =======================================================================================
+        # load USER config
+        self.setUserConfigFile(cfg)
+        user_cfg_file = self.getUserConfigFile()
+        user_cfg = common.config_pyconf.Config(open(user_cfg_file))
+        merger.merge(cfg, user_cfg)
+
+        for rule in self.get_command_line_overrides(options, ["USER"]):
+            exec('cfg.' + rule) # this cannot be factorize because of the exec
+
         return cfg
+
+    def setUserConfigFile(self, config):
+        '''Set the user config file name and path.
+        If necessary, build it from another one or create it from scratch.
+        '''
+        if not config:
+            raise common.SatException(_("Error in setUserConfigFile: config is None"))
+        sat_version = config.INTERNAL.sat_version
+        self.config_file_name = 'salomeTools-%s.pyconf'%sat_version
+        self.user_config_file_path = os.path.join(config.VARS.personalDir, self.config_file_name)
+        if not os.path.isfile(self.user_config_file_path):
+            # if pyconf does not exist, 
+            # Make a copy of an existing  salomeTools-<sat_version>.pyconf
+            # or at least a copy of salomeTools.pyconf
+            # If there is no pyconf file at all, create it from scratch 
+            already_exisiting_pyconf_file = self.getAlreadyExistingUserPyconf( config.VARS.personalDir, sat_version )
+            if already_exisiting_pyconf_file:  
+                # copy
+                shutil.copyfile( already_exisiting_pyconf_file, self.user_config_file_path )
+                cfg = common.config_pyconf.Config(open(self.user_config_file_path))
+            else: # create from scratch
+                self.createConfigFile(config)
+    
+    def getAlreadyExistingUserPyconf(self, dir, sat_version ):
+        '''Get a pyconf file younger than the given sat version in the given directory
+        The file basename can be one of salometools-<younger version>.pyconf or salomeTools.pyconf
+        Returns the file path or None if no file has been found.
+        '''
+        file_path = None  
+        # Get a younger pyconf version   
+        pyconfFiles = glob.glob( os.path.join(dir, 'salomeTools-*.pyconf') )
+        sExpr = "^salomeTools-(.*)\.pyconf$"
+        oExpr = re.compile(sExpr)
+        younger_version = None
+        for s in pyconfFiles:
+            oSreMatch = oExpr.search( os.path.basename(s) )
+            if oSreMatch:
+                pyconf_version = oSreMatch.group(1)
+                if pyconf_version < sat_version: 
+                    younger_version = pyconf_version 
+
+        # Build the pyconf filepath
+        if younger_version :   
+            file_path = os.path.join( dir, 'salomeTools-%s.pyconf'%younger_version )
+        elif os.path.isfile( os.path.join(dir, 'salomeTools.pyconf') ):
+            file_path = os.path.join( dir, 'salomeTools.pyconf' )
+        
+        return file_path 
     
+    def createConfigFile(self, config):
+        
+        cfg_name = self.getUserConfigFile()
+
+        user_cfg = common.config_pyconf.Config()
+        #
+        user_cfg.addMapping('USER', common.config_pyconf.Mapping(user_cfg), "")
+
+        #
+        user_cfg.USER.addMapping('workDir', os.path.expanduser('~'),
+            "This is where salomeTools will work. You may (and probably do) change it.\n")
+        user_cfg.USER.addMapping('cvs_user', config.VARS.user,
+            "This is the user name used to access salome cvs base.\n")
+        user_cfg.USER.addMapping('svn_user', config.VARS.user,
+            "This is the user name used to access salome svn base.\n")
+        user_cfg.USER.addMapping('output_level', 3,
+            "This is the default output_level you want. 0=>no output, 5=>debug.\n")
+        user_cfg.USER.addMapping('publish_dir', os.path.join(os.path.expanduser('~'), 'websupport', 'satreport'), "")
+        user_cfg.USER.addMapping('editor', 'vi', "This is the editor used to modify configuration files\n")
+        user_cfg.USER.addMapping('browser', 'firefox', "This is the browser used to read html documentation\n")
+        user_cfg.USER.addMapping('pdf_viewer', 'evince', "This is the pdf_viewer used to read pdf documentation\n")
+        # 
+        common.ensure_path_exists(config.VARS.personalDir)
+        common.ensure_path_exists(os.path.join(config.VARS.personalDir, 'Applications'))
+
+        f = open(cfg_name, 'w')
+        user_cfg.__save__(f)
+        f.close()
+        print(_("You can edit it to configure salomeTools (use: sat config --edit).\n"))
+
+        return user_cfg   
+
+    def getUserConfigFile(self):
+        '''Get the user config file
+        '''
+        if not self.user_config_file_path:
+            raise common.SatException(_("Error in getUserConfigFile: missing user config file path"))
+        return self.user_config_file_path     
+        
     
 def print_value(config, path, show_label, level=0, show_full_path=False):
     '''Prints a value from the configuration. Prints recursively the values under the initial path.
index 3eaab74571f456081a174130d99f3537e10ce98d..57f235a3b992ec4245d9dfd82dbad630aa346974 100755 (executable)
@@ -53,9 +53,23 @@ parser = common.options.Options()
 parser.add_option('h', 'help', 'boolean', 'help', _(u"shows global help or help on a specific command."))
 
 class salomeTools(object):
-    def __init__(self, options, dataDir=None):
+    def __init__(self, opt, dataDir=None):
         '''Initialization
         '''
+        # Read the salomeTools options (the list of possible options is at the beginning of this file)
+        try:
+            (options, args) = parser.parse_args(opt)
+        except Exception as exc:
+            write_exception(exc)
+            sys.exit(-1)
+            
+        if options.help:
+            try:
+                sat.print_help(args)
+            except Exception as exc:
+                code = 1
+                write_exception(exc)
+                
         self.__dict__ = dict()
         self.options = options
         self.dataDir = dataDir
@@ -134,19 +148,14 @@ if __name__ == "__main__":
     # Initialize the code that will be returned by the terminal command 
     code = 0
     
-    # Read the salomeTools options (the list of possible options is at the beginning of this file)
-    try:
-        (options, args) = parser.parse_args(sys.argv[1:])
-    except Exception as exc:
-        write_exception(exc)
-        sys.exit(-1)
+    (options, args) = parser.parse_args(sys.argv[1:])
     
     if len(args) == 0:
         # no options => show help
         print_help(options)
-    
-    sat = salomeTools('')
-    sat.config('-v VARS.python')
+    else:
+        sat = salomeTools(sys.argv[1:])
+