Salome HOME
Merge branch 'gdd_env_modules_in_config_appli'
[modules/yacs.git] / bin / salome_utils.py
1 #  -*- coding: iso-8859-1 -*-
2 # Copyright (C) 2007-2016  CEA/DEN, EDF R&D, OPEN CASCADE
3 #
4 # This library is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU Lesser General Public
6 # License as published by the Free Software Foundation; either
7 # version 2.1 of the License, or (at your option) any later version.
8 #
9 # This library is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12 # Lesser General Public License for more details.
13 #
14 # You should have received a copy of the GNU Lesser General Public
15 # License along with this library; if not, write to the Free Software
16 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
17 #
18 # See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
19 #
20
21 # ---
22 # File   : salome_utils.py
23 # Author : Vadim SANDLER, Open CASCADE S.A.S. (vadim.sandler@opencascade.com)
24 # ---
25
26 ## @package salome_utils
27 # \brief Set of utility functions used by SALOME python scripts.
28
29 #
30 # Exported functions
31 #
32
33 __all__ = [
34     'getORBcfgInfo',
35     'getHostFromORBcfg',
36     'getPortFromORBcfg',
37     'getUserName',
38     'getHostName',
39     'getShortHostName',
40     'getAppName',
41     'getPortNumber',
42     'getLogDir',
43     'getTmpDir',
44     'getHomeDir',
45     'generateFileName',
46     'makeTmpDir',
47     'uniteFiles',
48     ]
49
50 # ---
51
52 def _try_bool( arg ):
53     """
54     Check if specified parameter represents boolean value and returns its value.
55     String values like 'True', 'TRUE', 'YES', 'Yes', 'y', 'NO', 'false', 'n', etc
56     are supported.
57     If <arg> does not represent a boolean, an exception is raised.
58     """
59     import types
60     if type( arg ) == types.BooleanType  :
61         return arg
62     elif type( arg ) == types.StringType  :
63         v = str( arg ).lower()
64         if   v in [ "yes", "y", "true"  ]: return True
65         elif v in [ "no",  "n", "false" ]: return False
66         pass
67     raise Exception("Not boolean value")
68
69 # ---
70
71 def getORBcfgInfo():
72     """
73     Get omniORB current configuration.
74     Returns a list of three values: [ orb_version, host_name, port_number ].
75
76     The information is retrieved from the omniORB configuration file defined
77     by the OMNIORB_CONFIG environment variable.
78     If omniORB configuration file can not be accessed, a list of three empty
79     strings is returned.
80     """
81     import os, re
82     ret = [ "", "", "" ]
83     try:
84         f = open( os.getenv( "OMNIORB_CONFIG" ) )
85         lines = f.readlines()
86         f.close()
87         regvar = re.compile( "(ORB)?InitRef.*corbaname::(.*):(\d+)\s*$" )
88         for l in lines:
89             try:
90                 m = regvar.match( l )
91                 if m:
92                     if m.group(1) is None:
93                         ret[0] = "4"
94                     else:
95                         ret[0] = "3"
96                         pass
97                     ret[1] = m.group(2)
98                     ret[2] = m.group(3)
99                     break
100                 pass
101             except:
102                 pass
103             pass
104         pass
105     except:
106         pass
107     return ret
108
109 # ---
110
111 def getHostFromORBcfg():
112     """
113     Get current omniORB host.
114     """
115     return getORBcfgInfo()[1]
116 # ---
117
118 def getPortFromORBcfg():
119     """
120     Get current omniORB port.
121     """
122     return getORBcfgInfo()[2]
123
124 # ---
125
126 def getUserName():
127     """
128     Get user name:
129     1. try USER environment variable (USERNAME on windows)
130     2. if fails, try LOGNAME (un*x)
131     3. if fails return 'unknown' as default user name
132     """
133     import os, sys
134     if sys.platform == "win32":
135         return os.getenv("USERNAME", "unknown")
136     else:
137         user = os.getenv("USER")
138         if user:
139             return user
140         return os.getenv("LOGNAME", "unknown")
141 # ---
142
143 def getHostName():
144     """
145     Get host name:
146     1. try socket python module gethostname() function
147     2. if fails, try HOSTNAME environment variable
148     3. if fails, try HOST environment variable
149     4. if fails, return 'unknown' as default host name
150     """
151     try:
152         import socket
153         host = socket.gethostname()
154     except:
155         host = None
156         pass
157     if not host: host = os.getenv("HOSTNAME")
158     if not host: host = os.getenv("HOST")
159     if not host: host = "unknown"           # 'unknown' is default host name
160     try:
161         socket.gethostbyname(host)
162     except:
163         host = "localhost"
164     pass
165     return host
166
167 # ---
168
169 def getShortHostName():
170     """
171     Get short host name:
172     1. try socket python module gethostname() function
173     2. if fails, try HOSTNAME environment variable
174     3. if fails, try HOST environment variable
175     4. if fails, return 'unknown' as default host name
176     """
177     try:
178         return getHostName().split('.')[0]
179     except:
180         pass
181     return "unknown"           # 'unknown' is default host name
182
183 # ---
184
185 def getAppName():
186     """
187     Get application name:
188     1. try APPNAME environment variable
189     2. if fails, return 'SALOME' as default application name
190     """
191     import os
192     return os.getenv( "APPNAME", "SALOME" ) # 'SALOME' is default user name
193
194 # ---
195
196 def getPortNumber(use_default=True):
197     """
198     Get current naming server port number:
199     1. try NSPORT environment variable
200     1. if fails, try to parse config file defined by OMNIORB_CONFIG environment variable
201     2. if fails, return 2809 as default port number (if use_default is True) or None (id use_default is False)
202     """
203     import os
204     try:
205         return int( os.getenv( "NSPORT" ) )
206     except:
207         pass
208     try:
209         port = int( getPortFromORBcfg() )
210         if port is not None: return port
211     except:
212         pass
213     if use_default: return 2809 # '2809' is default port number
214     return None
215
216 # ---
217
218 def getHomeDir():
219     """
220     Get home directory.
221     """
222     import os
223     return os.path.realpath(os.path.expanduser('~'))
224 # ---
225
226 def getLogDir():
227     """
228     Get directory to be used for the log files.
229     """
230     import os
231     return os.path.join(getTmpDir(), "logs", getUserName())
232 # ---
233
234 def getTmpDir():
235     """
236     Get directory to be used for the temporary files.
237     """
238     import os, tempfile
239     f = tempfile.NamedTemporaryFile()
240     tmpdir = os.path.dirname(f.name)
241     f.close()
242     return tmpdir
243 # ---
244
245 def generateFileName( dir, prefix = None, suffix = None, extension = None,
246                       unique = False, separator = "_", hidden = False, **kwargs ):
247     """
248     Generate file name by sepecified parameters. If necessary, file name
249     can be generated to be unique.
250
251     Parameters:
252     - dir       : directory path
253     - prefix    : file prefix (not added by default)
254     - suffix    : file suffix (not added by default)
255     - extension : file extension (not added by default)
256     - unique    : if this parameter is True, the unique file name is generated:
257     in this case, if the file with the generated name already exists
258     in the <dir> directory, an integer suffix is added to the end of the
259     file name. This parameter is False by default.
260     - separator : separator of the words ('_' by default)
261     - hidden    : if this parameter is True, the file name is prepended by . (dot)
262     symbol. This parameter is False by default.
263
264     Other keyword parameters are:
265     - with_username : 'add user name' flag/option:
266       * boolean value can be passed to determine user name automatically
267       * string value to be used as user name
268     - with_hostname : 'add host name' flag/option:
269       * boolean value can be passed to determine host name automatically
270       * string value to be used as host name
271     - with_port     : 'add port number' flag/option:
272       * boolean value can be passed to determine port number automatically
273       * string value to be used as port number
274     - with_app      : 'add application name' flag/option:
275       * boolean value can be passed to determine application name automatically
276       * string value to be used as application name
277     All <with_...> parameters are optional.
278     """
279     supported = [ 'with_username', 'with_hostname', 'with_port', 'with_app' ]
280     from launchConfigureParser import verbose
281     filename = []
282     # separator
283     if separator is None:
284         separator = ""
285         pass
286     else:
287         separator = str( separator )
288         pass
289     # prefix (if specified)
290     if prefix is not None:
291         filename.append( str( prefix ) )
292         pass
293     # additional keywords
294     ### check unsupported parameters
295     for kw in kwargs:
296         if kw not in supported and verbose():
297             print 'Warning! salome_utilitie.py: generateFileName(): parameter %s is not supported' % kw
298             pass
299         pass
300     ### process supported keywords
301     for kw in supported:
302         if kw not in kwargs: continue
303         ### user name
304         if kw == 'with_username':
305             try:
306                 # auto user name ?
307                 if _try_bool( kwargs[kw] ): filename.append( getUserName() )
308                 pass
309             except:
310                 # user name given as parameter
311                 filename.append( kwargs[kw] )
312                 pass
313             pass
314         ### host name
315         elif kw == 'with_hostname':
316             try:
317                 # auto host name ?
318                 if _try_bool( kwargs[kw] ): filename.append( getShortHostName() )
319                 pass
320             except:
321                 # host name given as parameter
322                 filename.append( kwargs[kw] )
323                 pass
324             pass
325         ### port number
326         elif kw == 'with_port':
327             try:
328                 # auto port number ?
329                 if _try_bool( kwargs[kw] ): filename.append( str( getPortNumber() ) )
330                 pass
331             except:
332                 # port number given as parameter
333                 filename.append( str( kwargs[kw] ) )
334                 pass
335             pass
336         ### application name
337         elif kw == 'with_app':
338             try:
339                 # auto application name ?
340                 if _try_bool( kwargs[kw] ): filename.append( getAppName() )
341                 pass
342             except:
343                 # application name given as parameter
344                 filename.append( kwargs[kw] )
345                 pass
346             pass
347         pass
348     # suffix (if specified)
349     if suffix is not None:
350         filename.append( str( suffix ) )
351         pass
352     # raise an exception if file name is empty
353     if not filename:
354         raise Exception("Empty file name")
355     #
356     if extension is not None and extension.startswith("."): extension = extension[1:]
357     #
358     import os
359     name = separator.join( filename )
360     if hidden: name = "." + name                       # add dot for hidden files
361     if extension: name = name + "." + str( extension ) # add extension if defined
362     name = os.path.join( dir, name )
363     if unique:
364         # create unique file name
365         index = 0
366         while os.path.exists( name ):
367             index = index + 1
368             name = separator.join( filename ) + separator + str( index )
369             if hidden: name = "." + name                       # add dot for hidden files
370             if extension: name = name + "." + str( extension ) # add extension if defined
371             name = os.path.join( dir, name )
372             pass
373         pass
374     return os.path.normpath(name)
375
376 # ---
377
378 def makeTmpDir( path, mode=0777 ):
379     """
380     Make temporary directory with the specified path.
381     If the directory exists then clear its contents.
382
383     Parameters:
384     - path : absolute path to the directory to be created.
385     - mode : access mode
386     """
387     import os
388     if os.path.exists( path ):
389         import sys
390         if sys.platform == "win32":
391             os.system( "rmdir /S /Q " + '"' + path + '"' )
392             os.system( "mkdir " + '"' + path + '"' )
393         else:
394             os.system( "rm -rf " + path + "/*" )
395     else:
396         dirs = path.split("/")
397         shift1 = shift2 = 0
398         if not dirs[0]: shift1 = 1
399         if dirs[-1]: shift2 = 1
400         for i in range(1+shift1,len(dirs)+shift2):
401             p = "/".join(dirs[:i])
402             try:
403                 os.mkdir(p, mode)
404                 os.chmod(p, mode)
405             except:
406                 pass
407
408 # ---
409
410 def uniteFiles( src_file, dest_file ):
411     """
412     Unite contents of the source file with contents of the destination file
413     and put result of the uniting to the destination file.
414     If the destination file does not exist then the source file is simply
415     copied to its path.
416
417     Parameters:
418     - src_file  : absolute path to the source file
419     - dest_file : absolute path to the destination file
420     """
421     import os
422
423     if not os.path.exists( src_file ):
424         return
425         pass
426
427     if os.path.exists( dest_file ):
428         # add a symbol of new line to contents of the destination file (just in case)
429         dest = open( dest_file, 'r' )
430         dest_lines = dest.readlines()
431         dest.close()
432
433         dest_lines.append( "\n" )
434
435         dest = open( dest_file, 'w' )
436         dest.writelines( dest_lines )
437         dest.close()
438
439         import sys
440         if sys.platform == "win32":
441             command = "type " + '"' + src_file + '"' + " >> " + '"' + dest_file + '"'
442         else:
443             command = "cat " + src_file + " >> " + dest_file
444             pass
445         pass
446     else:
447         import sys
448         if sys.platform == "win32":
449             command = "copy " + '"' + src_file + '"' + " " + '"' + dest_file + '"' + " > nul"
450         else:
451             command = "cp " + src_file + " " + dest_file
452             pass
453         pass
454
455     os.system( command )
456
457 # --
458
459 _verbose = None
460
461 def verbose():
462     """
463     Get verbosity level. Default verbosity level is specified via the environment variable
464     SALOME_VERBOSE, e.g.:
465     [bash %] export SALOME_VERBOSE=1
466     The function setVerbose() can be used to change verbosity level explicitly.
467     """
468     global _verbose
469     # verbose has already been called
470     if _verbose is not None:
471         return _verbose
472     # first time
473     try:
474         from os import getenv
475         _verbose = int(getenv('SALOME_VERBOSE'))
476     except:
477         _verbose = 0
478         pass
479     #
480     return _verbose
481 # --
482
483 def setVerbose(level):
484     """
485     Change verbosity level. The function verbose() can be used to get current verbosity level.
486     """
487     global _verbose
488     _verbose = level
489     return
490 # --
491
492 import signal
493 def killpid(pid, sig = 9):
494     """
495     Send signal sig to the process by pid.
496
497     Parameters:
498     - pid : PID of process
499     - sig : signal for sending
500             Possible values of signals: 
501             9 means kill the process
502             0 only check existing of the process
503             NOTE: Other values are not processed on Windows
504     Returns:
505      1 Success
506      0 Fail, no such process
507     -1 Fail, another reason
508
509     """
510     if not pid: return
511     import os, sys
512     if sig != 0:
513         if verbose(): print "######## killpid pid = ", pid
514     try:
515         if sys.platform == "win32":
516             import ctypes
517             if sig == 0:
518                 # PROCESS_QUERY_INFORMATION (0x0400)    Required to retrieve certain information about a process
519                 handle = ctypes.windll.kernel32.OpenProcess(0x0400, False, int(pid))
520                 if handle: 
521                     ret = 1
522                     ctypes.windll.kernel32.CloseHandle(handle)
523                 else:
524                     ret = 0
525             if sig == 9:
526                 # PROCESS_TERMINATE (0x0001)    Required to terminate a process using TerminateProcess.
527                 handle = ctypes.windll.kernel32.OpenProcess(0x0001, False, int(pid))
528                 ret = ctypes.windll.kernel32.TerminateProcess(handle, -1)
529                 ctypes.windll.kernel32.CloseHandle(handle)
530                 pass
531             pass
532         else:
533             # Default: signal.SIGKILL = 9
534             os.kill(int(pid),sig)
535             ret = 1
536             pass
537         pass
538     except OSError, e:
539         # errno.ESRCH == 3 is 'No such process'
540         if e.errno == 3:
541             ret = 0
542         else:
543             ret = -1
544             pass
545         pass
546     return ret
547 # --
548
549 def getOmniNamesPid(port):
550     """
551     Return OmniNames pid by port number.
552     """
553     import sys,subprocess,re
554     if sys.platform == "win32":
555         # Get process list by WMI Command Line Utility(WMIC)
556         # Output is formatted with each value listed on a separate line and with the name of the property:
557         #   ...
558         #   Caption=<caption0>
559         #   CommandLine=<commandline0>
560         #   ProcessId=<processid0>
561         #
562         #
563         #
564         #   Caption=<caption1>
565         #   CommandLine=<commandline1>
566         #   ProcessId=<processid1>
567         #   ...
568         cmd = 'WMIC PROCESS get Caption,Commandline,Processid /VALUE'
569         proc = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE)
570         # Get stdout
571         allProc = proc.communicate()[0]
572         # find Pid of omniNames
573         pid = re.findall(r'Caption=.*omniNames.*\n?CommandLine=.*omniNames.*\D%s\D.*\n?ProcessId=(\d*)'%(port),allProc)[0]
574     else:        
575         cmd = "ps -eo pid,command | grep -v grep | grep -E \"omniNames.*%s\" | awk '{print $1}'"%(port)
576         proc = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE)
577         pid = proc.communicate()[0]
578         pass
579
580     return pid
581 # --
582
583 def killOmniNames(port):
584     """
585     Kill OmniNames process by port number.
586     """
587     try:
588         pid = getOmniNamesPid(port)
589         if pid: killpid(pid)
590     except:
591         pass
592     pass
593 # --