Salome HOME
Fix a bug: user preferences file is incorrectly detected on Windows
authorvsr <vsr@opencascade.com>
Wed, 23 Nov 2011 10:56:56 +0000 (10:56 +0000)
committervsr <vsr@opencascade.com>
Wed, 23 Nov 2011 10:56:56 +0000 (10:56 +0000)
bin/launchConfigureParser.py
bin/salome_utils.py

index eddc8f524115c264c011c103f71a85bc5b378175..caf138cd1e02e91dfdc8839616bc583d3f94d3c8 100755 (executable)
@@ -26,7 +26,7 @@ import xml.sax
 import optparse
 import types
 
-from salome_utils import verbose, setVerbose, getPortNumber
+from salome_utils import verbose, setVerbose, getPortNumber, getHomeDir
 
 # names of tags in XML configuration file
 doc_tag = "document"
@@ -74,6 +74,7 @@ plugins_nam    = "plugins"
 # values passed as arguments, NOT read from XML config file, but set from within this script
 appname_nam    = "appname"
 port_nam       = "port"
+salomecfgname  = "salome"
 salomeappname  = "SalomeApp"
 script_nam     = "pyscript"
 
@@ -115,20 +116,20 @@ def version():
 # Calculate and return configuration file unique ID
 # For example: for SALOME version 3.1.0a1 the id is 300999701
 ###
-def version_id( fname ):
+def version_id(fname):
+    major = minor = release = dev1 = dev2 = 0
     vers = fname.split(".")
-    major   = int(vers[0])
-    minor   = int(vers[1])
-    mr = re.search(r'^([0-9]+)([A-Za-z]?)([0-9]*)',vers[2])
-    release = dev = 0
-    if mr:
-        release = int(mr.group(1))
-        dev1 = dev2 = 0
-        if len(mr.group(2)): dev1 = ord(mr.group(2))
-        if len(mr.group(3)): dev2 = int(mr.group(3))
-        dev = dev1 * 100 + dev2
-    else:
-        return None
+    if len(vers) > 0: major = int(vers[0])
+    if len(vers) > 1: minor = int(vers[1])
+    if len(vers) > 2:
+        mr = re.search(r'^([0-9]+)([A-Za-z]?)([0-9]*)',vers[2])
+        if mr:
+            release = int(mr.group(1))
+            if mr.group(2).strip(): dev1 = ord(mr.group(2).strip())
+            if mr.group(3).strip(): dev2 = int(mr.group(3).strip())
+            pass
+        pass
+    dev = dev1 * 100 + dev2
     ver = major
     ver = ver * 100 + minor
     ver = ver * 100 + release
@@ -137,37 +138,75 @@ def version_id( fname ):
     return ver
 
 ###
-# Get user configuration file name
+# Get default user configuration file name
+# For SALOME, it is:
+# - on Linux:   ~/.config/salome/.SalomeApprc.[version]
+# - on Windows: ~/SalomeApp.xml.[version]
+# where [version] is a version number
 ###
-def userFile(appname):
+def defaultUserFile(appname=salomeappname, cfgname=salomecfgname):
     v = version()
-    if not v:
-        return ""        # not unknown version
+    if v: v = ".%s" % v
     if sys.platform == "win32":
-      filename = "%s\%s.xml.%s" % (os.environ['HOME'], appname, v)
+      filename = os.path.join(getHomeDir(), "%s.xml%s" % (appname, v))
     else:
-      filename = "%s/.%src.%s" % (os.environ['HOME'], appname, v)
-    if os.path.exists(filename):
-        return filename  # user preferences file for the current version exists
-    # initial id
-    id0 = version_id( v )
-    # get all existing user preferences files
+        if cfgname:
+            filename = os.path.join(getHomeDir(), ".config", cfgname, ".%src%s" % (appname, v))
+            pass
+        else:
+            filename = os.path.join(getHomeDir(), ".%src%s" % (appname, v))
+            pass
+        pass
+    return filename
+
+###
+# Get user configuration file name
+###
+def userFile(appname, cfgname):
+    # get app version
+    v = version()
+    if not v: return None                        # unknown version
+    
+    # get default user file name
+    filename = defaultUserFile(appname, cfgname)
+    if not filename: return None                 # default user file name is bad
+    
+    # check that default user file exists
+    if os.path.exists(filename): return filename # user file is found
+
+    # otherwise try to detect any appropriate user file
+
+    # ... calculate default version id
+    id0 = version_id(v)
+    if not id0: return None                      # bad version id -> can't detect appropriate file
+    
+    # ... get all existing user preferences files
     if sys.platform == "win32":
-      files = glob.glob( os.environ['HOME'] + "\." + appname + ".xml.*" )
+        files = glob.glob(os.path.join(getHomeDir(), "%s.xml.*" % appname))
     else:
-      files = glob.glob( os.environ['HOME'] + "/." + appname + "rc.*" )
-    f2v = {}
-    for file in files:
-        match = re.search( r'\.%src\.([a-zA-Z0-9.]+)$'%appname, file )
-        if match: f2v[file] = match.group(1)
-    last_file = ""
-    last_version = 0
-    for file in f2v:
-        ver = version_id( f2v[file] )
-        if ver and abs(last_version-id0) > abs(ver-id0):
-            last_version = ver
-            last_file = file
-    return last_file
+        files = []
+        if cfgname: files += glob.glob(os.path.join(getHomeDir(), ".config", cfgname, ".%src.*" % appname))
+        files             += glob.glob(os.path.join(getHomeDir(), ".%src.*" % appname))
+        pass
+
+    # ... loop through all files and find most appopriate file (with closest id)
+    appr_id   = -1
+    appr_file = ""
+    for f in files:
+        if sys.platform == "win32":
+            match = re.search( r'%s\.xml\.([a-zA-Z0-9.]+)$'%appname, f )
+        else:
+            match = re.search( r'\.%src\.([a-zA-Z0-9.]+)$'%appname, f )
+        if match:
+            ver = version_id(match.group(1))
+            if not ver: continue                 # bad version id -> skip file
+            if appr_id < 0 or abs(appr_id-id0) > abs(ver-id0):
+                appr_id   = ver
+                appr_file = f
+                pass
+            pass
+        pass
+    return appr_file
 
 # --
 
@@ -323,12 +362,12 @@ class xml_parser:
             if os.path.exists(absfname + ext) :
                 absfname += ext
                 if absfname in self.importHistory :
-                    if verbose(): print "Configure parser: file %s is already imported" % absfname
+                    if verbose(): print "Configure parser: Warning : file %s is already imported" % absfname
                     return # already imported
                 break
             pass
         else:
-            if verbose(): print "Configure parser: Error : file %s does NOT exists" % absfname
+            if verbose(): print "Configure parser: Error : file %s does not exist" % absfname
             return
          
         # importing file
@@ -494,9 +533,9 @@ def CreateOptionParser (theAdditionalOptions=[]):
                           dest="py_scripts",
                           help=help_str)
 
-    # Configuration XML file. Default: $(HOME)/.SalomeApprc.$(version).
+    # Configuration XML file. Default: see defaultUserFile() function
     help_str  = "Parse application settings from the <file> "
-    help_str += "instead of default $(HOME)/.SalomeApprc.$(version)"
+    help_str += "instead of default %s" % defaultUserFile()
     o_r = optparse.Option("-r",
                           "--resources",
                           metavar="<file>",
@@ -770,7 +809,7 @@ def CreateOptionParser (theAdditionalOptions=[]):
 args = {}
 #def get_env():
 #args = []
-def get_env(theAdditionalOptions=[], appname="SalomeApp"):
+def get_env(theAdditionalOptions=[], appname=salomeappname, cfgname=salomecfgname):
     ###
     # Collect launch configuration files:
     # - The environment variable "<appname>Config" (SalomeAppConfig) which can
@@ -786,8 +825,9 @@ def get_env(theAdditionalOptions=[], appname="SalomeApp"):
     #   has higher priority: it means that if some configuration options
     #   is found in the next analyzed cofiguration file - it will be replaced
     # - The last configuration file which is parsed is user configuration file
-    #   situated in the home directory: "~/.<appname>rc[.<version>]" (~/SalomeApprc.3.2.0)
-    #   (if it exists)
+    #   situated in the home directory (if it exists):
+    #   * ~/.config/salome/.<appname>rc[.<version>]" for Linux (e.g. ~/.config/salome/.SalomeApprc.6.4.0)
+    #   * ~/<appname>.xml[.<version>] for Windows (e.g. ~/SalomeApp.xml.6.4.0)
     # - Command line options have the highest priority and replace options
     #   specified in configuration file(s)
     ###
@@ -854,33 +894,33 @@ def get_env(theAdditionalOptions=[], appname="SalomeApp"):
 
     # parse SalomeApp.xml files in directories specified by SalomeAppConfig env variable
     for dir in dirs:
-        #filename = dir+'/'+appname+'.xml'
-        filename = dir+'/'+salomeappname+'.xml'
+        filename = os.path.join(dir, appname+'.xml')
         if not os.path.exists(filename):
-            print "Configure parser: Warning : could not find configuration file %s" % filename
+            if verbose(): print "Configure parser: Warning : can not find configuration file %s" % filename
         else:
             try:
                 p = xml_parser(filename, _opts)
                 _opts = p.opts
             except:
-                print "Configure parser: Error : can not read configuration file %s" % filename
+                if verbose(): print "Configure parser: Error : can not read configuration file %s" % filename
             pass
 
     # parse user configuration file
     # It can be set via --resources=<file> command line option
-    # or is given by default from ${HOME}/.<appname>rc.<version>
+    # or is given from default location (see defaultUserFile() function)
     # If user file for the current version is not found the nearest to it is used
     user_config = cmd_opts.resources
     if not user_config:
-        user_config = userFile(appname)
+        user_config = userFile(appname, cfgname)
+        if verbose(): print "Configure parser: user configuration file is", user_config
     if not user_config or not os.path.exists(user_config):
-        print "Configure parser: Warning : could not find user configuration file"
+        if verbose(): print "Configure parser: Warning : can not find user configuration file"
     else:
         try:
             p = xml_parser(user_config, _opts)
             _opts = p.opts
         except:
-            print 'Configure parser: Error : can not read user configuration file'
+            if verbose(): print 'Configure parser: Error : can not read user configuration file'
             user_config = ""
 
     args = _opts
index 4cd3bca8a66ae3c7c7acf0a2c2aa3ba993f71c93..4d2ae82e5e35038d98604b5ae031f475d655c493 100644 (file)
@@ -40,6 +40,7 @@ __all__ = [
     'getAppName',
     'getPortNumber',
     'getTmpDir',
+    'getHomeDir',
     'generateFileName',
     'makeTmpDir',
     'uniteFiles',
@@ -200,6 +201,30 @@ def getPortNumber(use_default=True):
 
 # ---
 
+def getHomeDir():
+    """
+    Get home directory.
+    """
+    import os, sys
+    if sys.platform == "win32":
+        # for Windows the home directory is detected in the following way:
+        # 1. try USERPROFILE env variable
+        # 2. try combination of HOMEDRIVE and HOMEPATH env variables
+        # 3. try HOME env variable
+        # TODO: on Windows, also GetUserProfileDirectoryW() system function might be used
+        dir = os.getenv("USERPROFILE")
+        if not dir and os.getenv("HOMEDRIVE") and os.getenv("HOMEPATH"):
+            dir = os.path.join(os.getenv("HOMEDRIVE"), os.getenv("HOMEPATH"))
+        if not dir:
+            dir = os.getenv("HOME")
+        pass
+    else:
+        # for Linux: use HOME variable
+        dir = os.getenv("HOME")
+        pass
+    return dir
+# ---
+
 def getTmpDir():
     """
     Get directory to be used for the temporary files.