Salome HOME
Fix for the bug 0023165: [CEA 1590] Salome 7.6.0 on Windows does not liberate the...
[modules/kernel.git] / bin / salome_utils.py
1 #  -*- coding: iso-8859-1 -*-
2 # Copyright (C) 2007-2015  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     import os
152     try:
153         import socket
154         host = socket.gethostname()
155     except:
156         host = None
157         pass
158     if not host: host = os.getenv("HOSTNAME")
159     if not host: host = os.getenv("HOST")
160     if not host: host = "unknown"           # 'unknown' is default host name
161     return host
162
163 # ---
164
165 def getShortHostName():
166     """
167     Get short host name:
168     1. try socket python module gethostname() function
169     2. if fails, try HOSTNAME environment variable
170     3. if fails, try HOST environment variable
171     4. if fails, return 'unknown' as default host name
172     """
173     try:
174         return getHostName().split('.')[0]
175     except:
176         pass
177     return "unknown"           # 'unknown' is default host name
178
179 # ---
180
181 def getAppName():
182     """
183     Get application name:
184     1. try APPNAME environment variable
185     2. if fails, return 'SALOME' as default application name
186     """
187     import os
188     return os.getenv( "APPNAME", "SALOME" ) # 'SALOME' is default user name
189
190 # ---
191
192 def getPortNumber(use_default=True):
193     """
194     Get current naming server port number:
195     1. try NSPORT environment variable
196     1. if fails, try to parse config file defined by OMNIORB_CONFIG environment variable
197     2. if fails, return 2809 as default port number (if use_default is True) or None (id use_default is False)
198     """
199     import os
200     try:
201         return int( os.getenv( "NSPORT" ) )
202     except:
203         pass
204     try:
205         port = int( getPortFromORBcfg() )
206         if port is not None: return port
207     except:
208         pass
209     if use_default: return 2809 # '2809' is default port number
210     return None
211
212 # ---
213
214 def getHomeDir():
215     """
216     Get home directory.
217     """
218     import os
219     return os.path.realpath(os.path.expanduser('~'))
220 # ---
221
222 def getLogDir():
223     """
224     Get directory to be used for the log files.
225     """
226     import os
227     return os.path.join(getTmpDir(), "logs", getUserName())
228 # ---
229
230 def getTmpDir():
231     """
232     Get directory to be used for the temporary files.
233     """
234     import os, tempfile
235     f = tempfile.NamedTemporaryFile()
236     tmpdir = os.path.dirname(f.name)
237     f.close()
238     return tmpdir
239 # ---
240
241 def generateFileName( dir, prefix = None, suffix = None, extension = None,
242                       unique = False, separator = "_", hidden = False, **kwargs ):
243     """
244     Generate file name by sepecified parameters. If necessary, file name
245     can be generated to be unique.
246
247     Parameters:
248     - dir       : directory path
249     - prefix    : file prefix (not added by default)
250     - suffix    : file suffix (not added by default)
251     - extension : file extension (not added by default)
252     - unique    : if this parameter is True, the unique file name is generated:
253     in this case, if the file with the generated name already exists
254     in the <dir> directory, an integer suffix is added to the end of the
255     file name. This parameter is False by default.
256     - separator : separator of the words ('_' by default)
257     - hidden    : if this parameter is True, the file name is prepended by . (dot)
258     symbol. This parameter is False by default.
259
260     Other keyword parameters are:
261     - with_username : 'add user name' flag/option:
262       * boolean value can be passed to determine user name automatically
263       * string value to be used as user name
264     - with_hostname : 'add host name' flag/option:
265       * boolean value can be passed to determine host name automatically
266       * string value to be used as host name
267     - with_port     : 'add port number' flag/option:
268       * boolean value can be passed to determine port number automatically
269       * string value to be used as port number
270     - with_app      : 'add application name' flag/option:
271       * boolean value can be passed to determine application name automatically
272       * string value to be used as application name
273     All <with_...> parameters are optional.
274     """
275     supported = [ 'with_username', 'with_hostname', 'with_port', 'with_app' ]
276     from launchConfigureParser import verbose
277     filename = []
278     # separator
279     if separator is None:
280         separator = ""
281         pass
282     else:
283         separator = str( separator )
284         pass
285     # prefix (if specified)
286     if prefix is not None:
287         filename.append( str( prefix ) )
288         pass
289     # additional keywords
290     ### check unsupported parameters
291     for kw in kwargs:
292         if kw not in supported and verbose():
293             print 'Warning! salome_utilitie.py: generateFileName(): parameter %s is not supported' % kw
294             pass
295         pass
296     ### process supported keywords
297     for kw in supported:
298         if kw not in kwargs: continue
299         ### user name
300         if kw == 'with_username':
301             try:
302                 # auto user name ?
303                 if _try_bool( kwargs[kw] ): filename.append( getUserName() )
304                 pass
305             except:
306                 # user name given as parameter
307                 filename.append( kwargs[kw] )
308                 pass
309             pass
310         ### host name
311         elif kw == 'with_hostname':
312             try:
313                 # auto host name ?
314                 if _try_bool( kwargs[kw] ): filename.append( getShortHostName() )
315                 pass
316             except:
317                 # host name given as parameter
318                 filename.append( kwargs[kw] )
319                 pass
320             pass
321         ### port number
322         elif kw == 'with_port':
323             try:
324                 # auto port number ?
325                 if _try_bool( kwargs[kw] ): filename.append( str( getPortNumber() ) )
326                 pass
327             except:
328                 # port number given as parameter
329                 filename.append( str( kwargs[kw] ) )
330                 pass
331             pass
332         ### application name
333         elif kw == 'with_app':
334             try:
335                 # auto application name ?
336                 if _try_bool( kwargs[kw] ): filename.append( getAppName() )
337                 pass
338             except:
339                 # application name given as parameter
340                 filename.append( kwargs[kw] )
341                 pass
342             pass
343         pass
344     # suffix (if specified)
345     if suffix is not None:
346         filename.append( str( suffix ) )
347         pass
348     # raise an exception if file name is empty
349     if not filename:
350         raise Exception("Empty file name")
351     #
352     if extension is not None and extension.startswith("."): extension = extension[1:]
353     #
354     import os
355     name = separator.join( filename )
356     if hidden: name = "." + name                       # add dot for hidden files
357     if extension: name = name + "." + str( extension ) # add extension if defined
358     name = os.path.join( dir, name )
359     if unique:
360         # create unique file name
361         index = 0
362         while os.path.exists( name ):
363             index = index + 1
364             name = separator.join( filename ) + separator + str( index )
365             if hidden: name = "." + name                       # add dot for hidden files
366             if extension: name = name + "." + str( extension ) # add extension if defined
367             name = os.path.join( dir, name )
368             pass
369         pass
370     return os.path.normpath(name)
371
372 # ---
373
374 def makeTmpDir( path, mode=0777 ):
375     """
376     Make temporary directory with the specified path.
377     If the directory exists then clear its contents.
378
379     Parameters:
380     - path : absolute path to the directory to be created.
381     - mode : access mode
382     """
383     import os
384     if os.path.exists( path ):
385         import sys
386         if sys.platform == "win32":
387             os.system( "rmdir /S /Q " + '"' + path + '"' )
388             os.system( "mkdir " + '"' + path + '"' )
389         else:
390             os.system( "rm -rf " + path + "/*" )
391     else:
392         dirs = path.split("/")
393         shift1 = shift2 = 0
394         if not dirs[0]: shift1 = 1
395         if dirs[-1]: shift2 = 1
396         for i in range(1+shift1,len(dirs)+shift2):
397             p = "/".join(dirs[:i])
398             try:
399                 os.mkdir(p, mode)
400                 os.chmod(p, mode)
401             except:
402                 pass
403
404 # ---
405
406 def uniteFiles( src_file, dest_file ):
407     """
408     Unite contents of the source file with contents of the destination file
409     and put result of the uniting to the destination file.
410     If the destination file does not exist then the source file is simply
411     copied to its path.
412
413     Parameters:
414     - src_file  : absolute path to the source file
415     - dest_file : absolute path to the destination file
416     """
417     import os
418
419     if not os.path.exists( src_file ):
420         return
421         pass
422
423     if os.path.exists( dest_file ):
424         # add a symbol of new line to contents of the destination file (just in case)
425         dest = open( dest_file, 'r' )
426         dest_lines = dest.readlines()
427         dest.close()
428
429         dest_lines.append( "\n" )
430
431         dest = open( dest_file, 'w' )
432         dest.writelines( dest_lines )
433         dest.close()
434
435         import sys
436         if sys.platform == "win32":
437             command = "type " + '"' + src_file + '"' + " >> " + '"' + dest_file + '"'
438         else:
439             command = "cat " + src_file + " >> " + dest_file
440             pass
441         pass
442     else:
443         import sys
444         if sys.platform == "win32":
445             command = "copy " + '"' + src_file + '"' + " " + '"' + dest_file + '"' + " > nul"
446         else:
447             command = "cp " + src_file + " " + dest_file
448             pass
449         pass
450
451     os.system( command )
452
453 # --
454
455 _verbose = None
456
457 def verbose():
458     """
459     Get verbosity level. Default verbosity level is specified via the environment variable
460     SALOME_VERBOSE, e.g.:
461     [bash %] export SALOME_VERBOSE=1
462     The function setVerbose() can be used to change verbosity level explicitly.
463     """
464     global _verbose
465     # verbose has already been called
466     if _verbose is not None:
467         return _verbose
468     # first time
469     try:
470         from os import getenv
471         _verbose = int(getenv('SALOME_VERBOSE'))
472     except:
473         _verbose = 0
474         pass
475     #
476     return _verbose
477 # --
478
479 def setVerbose(level):
480     """
481     Change verbosity level. The function verbose() can be used to get current verbosity level.
482     """
483     global _verbose
484     _verbose = level
485     return
486 # --
487
488 def killpid(pid):
489     """
490     Kill process by pid.
491     """
492     if not pid: return
493     import os,sys,signal
494     if verbose(): print "######## killpid pid = ", pid
495     if sys.platform == "win32":
496         import ctypes
497         handle = ctypes.windll.kernel32.OpenProcess(1, False, int(pid))
498         ctypes.windll.kernel32.TerminateProcess(handle, -1)
499         ctypes.windll.kernel32.CloseHandle(handle)
500     else:
501         os.kill(int(pid),signal.SIGKILL)
502         pass
503 # --
504
505 def getOmniNamesPid(port):
506     """
507     Return OmniNames pid by port number.
508     """
509     import sys,subprocess,re
510     if sys.platform == "win32":
511         # Get process list by WMI Command Line Utility(WMIC)
512         # Output is formatted with each value listed on a separate line and with the name of the property:
513         #   ...
514         #   Caption=<caption0>
515         #   CommandLine=<commandline0>
516         #   ProcessId=<processid0>
517         #
518         #
519         #
520         #   Caption=<caption1>
521         #   CommandLine=<commandline1>
522         #   ProcessId=<processid1>
523         #   ...
524         cmd = 'WMIC PROCESS get Caption,Commandline,Processid /VALUE'
525         proc = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE)
526         # Get stdout
527         allProc = proc.communicate()[0]
528         # find Pid of omniNames
529         pid = re.findall(r'Caption=.*omniNames.*\n?CommandLine=.*omniNames.*\D%s\D.*\n?ProcessId=(\d*)'%(port),allProc)[0]
530     else:        
531         cmd = "ps -eo pid,command | grep -v grep | grep -E \"omniNames.*%s\" | awk '{print $1}'"%(port)
532         proc = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE)
533         pid = proc.communicate()[0]
534         pass
535
536     return pid
537 # --
538
539 def killOmniNames(port):
540     """
541     Kill OmniNames process by port number.
542     """
543     try:
544         pid = getOmniNamesPid(port)
545         if pid: killpid(pid)
546     except:
547         pass
548     pass
549 # --