]> SALOME platform Git repositories - modules/kernel.git/blob - bin/appli_gen.py
Salome HOME
dd1233d2d9ab591775759db394c7347472b546af
[modules/kernel.git] / bin / appli_gen.py
1 #! /usr/bin/env python3
2 # Copyright (C) 2007-2023  CEA/DEN, EDF R&D, OPEN CASCADE
3 #
4 # Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
5 # CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
6 #
7 # This library is free software; you can redistribute it and/or
8 # modify it under the terms of the GNU Lesser General Public
9 # License as published by the Free Software Foundation; either
10 # version 2.1 of the License, or (at your option) any later version.
11 #
12 # This library is distributed in the hope that it will be useful,
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15 # Lesser General Public License for more details.
16 #
17 # You should have received a copy of the GNU Lesser General Public
18 # License along with this library; if not, write to the Free Software
19 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
20 #
21 # See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
22 #
23
24 ## \file appli_gen.py
25 #  Create a %SALOME application (virtual Salome installation)
26 #
27 usage = """%(prog)s [options]
28 Typical use is:
29   python %(prog)s
30 Typical use with options is:
31   python %(prog)s --verbose --prefix=<install directory> --config=<configuration file>
32 """
33
34 import os
35 import sys
36 import shutil
37 import virtual_salome
38 import xml.sax
39 import optparse
40 import subprocess
41
42 # --- names of tags in XML configuration file
43 appli_tag   = "application"
44 prereq_tag  = "prerequisites"
45 context_tag = "context"
46 venv_directory_tag = "venv_directory"
47 sha1_collect_tag = "sha1_collections"
48 system_conf_tag  = "system_conf"
49 modules_tag = "modules"
50 module_tag  = "module"
51 samples_tag = "samples"
52 extra_tests_tag = "extra_tests"
53 extra_test_tag = "extra_test"
54 resources_tag = "resources"
55 env_modules_tag = "env_modules"
56 env_module_tag = "env_module"
57 python_tag = "python"
58
59 # --- names of attributes in XML configuration file
60 nam_att  = "name"
61 path_att = "path"
62 gui_att  = "gui"
63 version_att = "version"
64
65 # -----------------------------------------------------------------------------
66
67 # --- xml reader for SALOME application configuration file
68
69 class xml_parser:
70     def __init__(self, fileName ):
71         print("Configure parser: processing %s ..." % fileName)
72         self.space = []
73         self.config = {}
74         self.config["modules"] = []
75         self.config["guimodules"] = []
76         self.config["extra_tests"] = []
77         self.config["env_modules"] = []
78         parser = xml.sax.make_parser()
79         parser.setContentHandler(self)
80         parser.parse(fileName)
81         pass
82
83     def boolValue( self, text):
84         if text in ("yes", "y", "1"):
85             return 1
86         elif text in ("no", "n", "0"):
87             return 0
88         else:
89             return text
90         pass
91
92     def startElement(self, name, attrs):
93         self.space.append(name)
94         self.current = None
95         # --- if we are analyzing "prerequisites" element then store its "path" attribute
96         if self.space == [appli_tag, prereq_tag] and path_att in attrs.getNames():
97             self.config["prereq_path"] = attrs.getValue( path_att )
98             pass
99         # --- if we are analyzing "context" element then store its "path" attribute
100         if self.space == [appli_tag, context_tag] and path_att in attrs.getNames():
101             self.config["context_path"] = attrs.getValue( path_att )
102             pass
103         # --- if we are analyzing "venv_directory" element then store its "path" attribute
104         if self.space == [appli_tag, venv_directory_tag] and path_att in attrs.getNames():
105             self.config["venv_directory_path"] = attrs.getValue( path_att )
106             pass
107         # --- if we are analyzing "sha1_collection" element then store its "path" attribute
108         if self.space == [appli_tag, sha1_collect_tag] and path_att in attrs.getNames():
109             self.config["sha1_collect_path"] = attrs.getValue( path_att )
110             pass
111         # --- if we are analyzing "python" element then store its "version" attribute
112         if self.space == [appli_tag, python_tag] and version_att in attrs.getNames():
113             self.config["python_version"] = attrs.getValue( version_att )
114             pass
115         # --- if we are analyzing "system_conf" element then store its "path" attribute
116         if self.space == [appli_tag, system_conf_tag] and path_att in attrs.getNames():
117             self.config["system_conf_path"] = attrs.getValue( path_att )
118             pass
119         # --- if we are analyzing "resources" element then store its "path" attribute
120         if self.space == [appli_tag, resources_tag] and path_att in attrs.getNames():
121             self.config["resources_path"] = attrs.getValue( path_att )
122             pass
123         # --- if we are analyzing "samples" element then store its "path" attribute
124         if self.space == [appli_tag, samples_tag] and path_att in attrs.getNames():
125             self.config["samples_path"] = attrs.getValue( path_att )
126             pass
127         # --- if we are analyzing "module" element then store its "name" and "path" attributes
128         elif self.space == [appli_tag,modules_tag,module_tag] and \
129             nam_att in attrs.getNames() and \
130             path_att in attrs.getNames():
131             nam = attrs.getValue( nam_att )
132             path = attrs.getValue( path_att )
133             gui = 1
134             if gui_att in attrs.getNames():
135                 gui = self.boolValue(attrs.getValue( gui_att ))
136                 pass
137             self.config["modules"].append(nam)
138             self.config[nam]=path
139             if gui:
140                 self.config["guimodules"].append(nam)
141                 pass
142             pass
143         # --- if we are analyzing "env_module" element then store its "name" attribute
144         elif self.space == [appli_tag, env_modules_tag, env_module_tag] and \
145                 nam_att in attrs.getNames():
146             nam = attrs.getValue( nam_att )
147             self.config["env_modules"].append(nam)
148             pass
149         # --- if we are analyzing "extra_test" element then store its "name" and "path" attributes
150         elif self.space == [appli_tag,extra_tests_tag,extra_test_tag] and \
151             nam_att in attrs.getNames() and \
152             path_att in attrs.getNames():
153             nam = attrs.getValue( nam_att )
154             path = attrs.getValue( path_att )
155             self.config["extra_tests"].append(nam)
156             self.config[nam]=path
157             pass
158         pass
159
160     def endElement(self, name):
161         self.space.pop()
162         self.current = None
163         pass
164
165     def characters(self, content):
166         pass
167
168     def processingInstruction(self, target, data):
169         pass
170
171     def setDocumentLocator(self, locator):
172         pass
173
174     def startDocument(self):
175         self.read = None
176         pass
177
178     def endDocument(self):
179         self.read = None
180         pass
181
182 # -----------------------------------------------------------------------------
183
184 class params:
185     pass
186
187 # -----------------------------------------------------------------------------
188
189 def makedirs(namedir):
190   if os.path.exists(namedir):
191     dirbak = namedir+".bak"
192     if os.path.exists(dirbak):
193       shutil.rmtree(dirbak)
194     os.rename(namedir, dirbak)
195     os.listdir(dirbak) #sert seulement a mettre a jour le systeme de fichier sur certaines machines
196   os.makedirs(namedir)
197
198 def install(prefix, config_file, verbose=0):
199     home_dir = os.path.abspath(os.path.expanduser(prefix))
200     filename = os.path.abspath(os.path.expanduser(config_file))
201     _config = {}
202     try:
203         parser = xml_parser(filename)
204         _config = parser.config
205     except xml.sax.SAXParseException as inst:
206         print(inst.getMessage())
207         print("Configure parser: parse error in configuration file %s" % filename)
208         pass
209     except xml.sax.SAXException as inst:
210         print(inst.args)
211         print("Configure parser: error in configuration file %s" % filename)
212         pass
213     except Exception:
214         print("Configure parser: Error : can not read configuration file %s, check existence and rights" % filename)
215         pass
216
217     if verbose:
218         for cle,val in _config.items():
219             print(cle, val)
220             pass
221
222     # Remove CTestTestfile.cmake; this file will be filled by successive calls to link_module and link_extra_test
223     try:
224       ctest_file = os.path.join(home_dir, 'bin', 'salome', 'test', "CTestTestfile.cmake")
225       os.remove(ctest_file)
226     except Exception:
227       pass
228
229     for module in _config.get("modules", []):
230         if module in _config:
231             print("--- add module ", module, _config[module])
232             options = params()
233             options.verbose = verbose
234             options.clear = 0
235             options.prefix = home_dir
236             options.module_name = module
237             options.module_path = _config[module]
238             virtual_salome.link_module(options)
239             # To fix GEOM_TestXAO issue https://codev-tuleap.cea.fr/plugins/tracker/?aid=16599
240             if module == "GEOM":
241                 # link <appli_path>/bin/salome/test/<module> to <module_path>/bin/salome/test
242                 test_dir=os.path.join(home_dir,'bin','salome', 'test')
243                 module_dir=os.path.abspath(options.module_path)
244                 xao_link=os.path.join(module_dir,'bin','salome', 'test', "xao")
245                 print("link %s --> %s"%(os.path.join(test_dir, "xao"), xao_link))
246                 virtual_salome.symlink(xao_link, os.path.join(test_dir, "xao"))
247             pass
248         pass
249
250     for extra_test in _config.get("extra_tests", []):
251         if extra_test in _config:
252             print("--- add extra test ", extra_test, _config[extra_test])
253             options = params()
254             options.verbose = verbose
255             options.clear = 0
256             options.prefix = home_dir
257             options.extra_test_name = extra_test
258             options.extra_test_path = _config[extra_test]
259             virtual_salome.link_extra_test(options)
260             pass
261         pass
262
263     # Sort test labels by name in generated CTestTestfile.cmake
264     with open(ctest_file) as f:
265         lines = f.readlines()
266     lines.sort()
267     with open(ctest_file, "w") as f:
268         f.write("".join(lines))
269
270     # Generate CTestCustom.cmake to handle long output
271     ctest_custom = os.path.join(home_dir, 'bin', 'salome', 'test', "CTestCustom.cmake")
272     with open(ctest_custom, 'w') as f:
273       f.write("SET(CTEST_CUSTOM_MAXIMUM_PASSED_TEST_OUTPUT_SIZE 1048576) # 1MB\n")
274       f.write("SET(CTEST_CUSTOM_MAXIMUM_FAILED_TEST_OUTPUT_SIZE 1048576) # 1MB\n")
275
276     appliskel_dir = os.path.join(prefix, 'bin', 'salome', 'appliskel')
277
278     for fn in ('envd',
279                'getAppliPath.py',
280                'kill_remote_containers.py',
281                'runRemote.sh',
282                'runRemoteSSL.sh',
283                '.salome_run',
284                'update_catalogs.py',
285                '.bashrc',
286                ):
287         virtual_salome.symlink( os.path.join( appliskel_dir, fn ), os.path.join( home_dir, fn) )
288         pass
289
290     if filename != os.path.join(home_dir,"config_appli.xml"):
291         shutil.copyfile(filename, os.path.join(home_dir,"config_appli.xml"))
292         pass
293
294     # Creation of env.d directory
295     virtual_salome.mkdir(os.path.join(home_dir,'env.d'))
296
297     venv_directory_path = _config.get('venv_directory_path')
298     if venv_directory_path and os.path.isdir(venv_directory_path):
299         virtual_salome.symlink(venv_directory_path, os.path.join(home_dir, "venv"))
300
301     # Get the env modules which will be loaded
302     # In the same way as: module load [MODULE_LIST]
303     env_modules = _config.get('env_modules', [])
304     if env_modules:
305         with open(os.path.join(home_dir, 'env.d', 'envModules.sh'), 'w') as fd:
306             fd.write('#!/bin/bash\n')
307             fd.write('module load %s\n' % (' '.join(env_modules)))
308
309     # Copy salome / salome_mesa scripts:
310
311     for scripts in ('salome', 'salome_mesa', 'salome_common.py'):
312         salome_script = open(os.path.join(appliskel_dir, scripts)).read()
313         salome_file = os.path.join(home_dir, scripts)
314         try:
315             os.remove(salome_file)
316         except Exception:
317             pass
318         with open(salome_file, 'w') as fd:
319             fd.write(salome_script.replace('MODULES = []', 'MODULES = {}'.format(env_modules)))
320             os.chmod(salome_file, 0o755)
321
322     # Add .salome-completion.sh file
323     shutil.copyfile(os.path.join(appliskel_dir, ".salome-completion.sh"),
324                     os.path.join(home_dir, ".salome-completion.sh"))
325
326     if "prereq_path" in _config and os.path.isfile(_config["prereq_path"]):
327         shutil.copyfile(_config["prereq_path"],
328                         os.path.join(home_dir, 'env.d', 'envProducts.sh'))
329         pass
330     else:
331         print("WARNING: prerequisite file does not exist")
332         pass
333
334     if "context_path" in _config and os.path.isfile(_config["context_path"]):
335         shutil.copyfile(_config["context_path"],
336                         os.path.join(home_dir, 'env.d', 'envProducts.cfg'))
337         pass
338     else:
339         print("WARNING: context file does not exist")
340         pass
341
342     if "sha1_collect_path" in _config and os.path.isfile(_config["sha1_collect_path"]):
343         shutil.copyfile(_config["sha1_collect_path"],
344                         os.path.join(home_dir, 'sha1_collections.txt'))
345         pass
346     else:
347         print("WARNING: sha1 collections file does not exist")
348         pass
349
350     if "system_conf_path" in _config and os.path.isfile(_config["system_conf_path"]):
351         shutil.copyfile(_config["system_conf_path"],
352                         os.path.join(home_dir, 'env.d', 'envConfSystem.sh'))
353         pass
354
355     # Create environment file: configSalome.sh
356
357     if "python_version" in _config:
358        versionPython_split = _config["python_version"].split('.')
359        versionPython = versionPython_split[0] + "." + versionPython_split[1]
360     else:
361        cmd='source %s && python3 -c "import sys ; sys.stdout.write(\\"{}.{}\\".format(sys.version_info.major,sys.version_info.minor))"' %(_config["prereq_path"])
362        versionPython=subprocess.check_output(['/bin/bash', '-l' ,'-c',cmd]).decode("utf-8")
363
364     venv_directory_path = None
365     if "venv_directory_path" in _config:
366         venv_directory_path = _config["venv_directory_path"]
367         venv_bin_directory_path = os.path.join(venv_directory_path, 'bin')
368         venv_pip_executable = os.path.join(venv_bin_directory_path, 'pip')
369         venv_python_executable = os.path.join(venv_bin_directory_path, 'python')
370         if os.path.isdir(venv_directory_path) and os.path.isfile(venv_pip_executable):
371             requirement_file = os.path.join(home_dir, 'requirements.txt')
372             with open(requirement_file, 'w') as fd:
373                 subprocess.call([venv_python_executable, '-m', 'pip', 'freeze'], stdout=fd)
374         else:
375             venv_directory_path = None
376
377     with open(os.path.join(home_dir, 'env.d', 'configSalome.sh'),'w') as f:
378         for module in _config.get("modules", []):
379             command = 'export '+ module + '_ROOT_DIR=${HOME}/${APPLI}\n'
380             f.write(command)
381             pass
382         if "samples_path" in _config:
383             command = 'export DATA_DIR=' + _config["samples_path"] +'\n'
384             f.write(command)
385             pass
386         if "resources_path" in _config and os.path.isfile(_config["resources_path"]):
387             command = 'export USER_CATALOG_RESOURCES_FILE=' + os.path.abspath(_config["resources_path"]) +'\n'
388             f.write(command)
389         # Note: below, PYTHONPATH should not be extended to bin/salome! Python modules must be installed in lib/pythonX.Y, to be fixed (e.g. Kernel SALOME_Container.py)
390         command ="""export PATH=${HOME}/${APPLI}/bin/salome:$PATH
391 export PYTHONPATH=${HOME}/${APPLI}/lib/python%s/site-packages/salome:$PYTHONPATH
392 export PYTHONPATH=${HOME}/${APPLI}/lib/salome:$PYTHONPATH
393 export PYTHONPATH=${HOME}/${APPLI}/bin/salome:$PYTHONPATH
394 export LD_LIBRARY_PATH=${HOME}/${APPLI}/lib/salome:$LD_LIBRARY_PATH
395 """ %versionPython
396         f.write(command)
397         # Create environment variable for the salome test
398         for module in _config.get("modules", []):
399             command = "export LD_LIBRARY_PATH=${HOME}/${APPLI}/bin/salome/test/" + module + "/lib:$LD_LIBRARY_PATH\n"
400             f.write(command)
401             pass
402         # Create environment for plugins GEOM
403         command = "export GEOM_PluginsList=BREPPlugin:STEPPlugin:IGESPlugin:STLPlugin:XAOPlugin:VTKPlugin:AdvancedGEOM\n"
404         f.write(command)
405         # Create environment for Healing
406         command = "export CSF_ShHealingDefaults=${HOME}/${APPLI}/share/salome/resources/geom\n"
407         f.write(command)
408         # Create environment for Meshers
409         command = "export SMESH_MeshersList=StdMeshers:HYBRIDPlugin:HexoticPLUGIN:GMSHPlugin:GHS3DPlugin:NETGENPlugin:HEXABLOCKPlugin:BLSURFPlugin:GHS3DPRLPlugin\nexport SALOME_StdMeshersResources=${HOME}/${APPLI}/share/salome/resources/smesh\n"
410         f.write(command)
411         # Create environment for virtual env
412         if venv_directory_path:
413             command = """# SALOME venv Configuration
414 export SALOME_VENV_DIRECTORY=${HOME}/${APPLI}/venv
415 export PATH=${HOME}/${APPLI}/venv/bin:$PATH
416 export LD_LIBRARY_PATH=${HOME}/${APPLI}/venv/lib:$LD_LIBRARY_PATH
417 export PYTHONPATH=${HOME}/${APPLI}/venv/lib/python%s/site-packages
418 """ % (versionPython)
419             f.write(command)
420             pass
421
422     # Create configuration file: configSalome.cfg
423     with open(os.path.join(home_dir, 'env.d', 'configSalome.cfg'),'w') as f:
424         command = "[SALOME ROOT_DIR (modules) Configuration]\n"
425         f.write(command)
426         for module in _config.get("modules", []):
427             command = module + '_ROOT_DIR=${HOME}/${APPLI}\n'
428             f.write(command)
429             pass
430         if "samples_path" in _config:
431             command = 'DATA_DIR=' + _config["samples_path"] +'\n'
432             f.write(command)
433             pass
434         if "resources_path" in _config and os.path.isfile(_config["resources_path"]):
435             command = 'USER_CATALOG_RESOURCES_FILE=' + os.path.abspath(_config["resources_path"]) +'\n'
436             f.write(command)
437         command ="""ADD_TO_PATH: ${HOME}/${APPLI}/bin/salome
438 ADD_TO_PYTHONPATH: ${HOME}/${APPLI}/lib/python%s/site-packages/salome
439 ADD_TO_PYTHONPATH: ${HOME}/${APPLI}/lib/salome
440 ADD_TO_LD_LIBRARY_PATH: ${HOME}/${APPLI}/lib/salome
441 """%versionPython
442         f.write(command)
443         for module in _config.get("modules", []):
444             command = "ADD_TO_LD_LIBRARY_PATH: ${HOME}/${APPLI}/bin/salome/test/" + module + "/lib\n"
445             f.write(command)
446             pass
447         # Create environment for plugins GEOM
448         command = "GEOM_PluginsList=BREPPlugin:STEPPlugin:IGESPlugin:STLPlugin:XAOPlugin:VTKPlugin:AdvancedGEOM\n"
449         f.write(command)
450         # Create environment for Healing
451         command = "CSF_ShHealingDefaults=${HOME}/${APPLI}/share/salome/resources/geom\n"
452         f.write(command)
453         # Create environment for Meshers
454         command = "SMESH_MeshersList=StdMeshers:HYBRIDPlugin:HexoticPLUGIN:GMSHPlugin:GHS3DPlugin:NETGENPlugin:HEXABLOCKPlugin:BLSURFPlugin:GHS3DPRLPlugin\nSALOME_StdMeshersResources=${HOME}/${APPLI}/share/salome/resources/smesh\n"
455         f.write(command)
456         # Create environment for virtual env
457         if venv_directory_path:
458             command = """[SALOME venv Configuration]
459 SALOME_VENV_DIRECTORY: ${HOME}/${APPLI}/venv
460 ADD_TO_PATH: ${HOME}/${APPLI}/venv/bin
461 ADD_TO_LD_LIBRARY_PATH: ${HOME}/${APPLI}/venv/lib
462 ADD_TO_PYTHONPATH: ${HOME}/${APPLI}/venv/lib/python%s/site-packages
463 """ % (versionPython)
464             f.write(command)
465             pass
466
467     # Create environment file: configGUI.sh
468     dirs_ress_icon = []
469     salomeappname  = "SalomeApp"
470     with open(os.path.join(home_dir, 'env.d', 'configGUI.sh'),'w') as f:
471         for module in _config.get("modules", []):
472             if module not in ["KERNEL", "GUI", ""]:
473                 d = os.path.join(_config[module],"share","salome","resources",module.lower())
474                 d_appli = os.path.join("${HOME}","${APPLI}","share","salome","resources",module.lower())
475                 if os.path.exists( os.path.join(d,"{0}.xml".format(salomeappname)) ):
476                    dirs_ress_icon.append( d_appli )
477         AppConfig="export SalomeAppConfig=${HOME}/${APPLI}:${HOME}/${APPLI}/share/salome/resources/gui/"
478         for dir_module in dirs_ress_icon:
479              AppConfig=AppConfig+":"+dir_module
480         f.write(AppConfig+"\n")
481         command = """export SUITRoot=${HOME}/${APPLI}/share/salome
482 export DISABLE_FPE=1
483 export MMGT_REENTRANT=1
484 """
485         f.write(command)
486
487     # Create configuration file: configGUI.cfg
488     dirs_ress_icon = []
489     with open(os.path.join(home_dir, 'env.d', 'configGUI.cfg'),'w') as f:
490         command = """[SALOME GUI Configuration]\n"""
491         f.write(command)
492         for module in _config.get("modules", []):
493             if module not in ["KERNEL", "GUI", ""]:
494                 d = os.path.join(_config[module],"share","salome","resources",module.lower())
495                 d_appli = os.path.join("${HOME}","${APPLI}","share","salome","resources",module.lower())
496                 if os.path.exists( os.path.join(d,"{0}.xml".format(salomeappname)) ):
497                    dirs_ress_icon.append( d_appli )
498         AppConfig="SalomeAppConfig=${HOME}/${APPLI}:${HOME}/${APPLI}/share/salome/resources/gui/"
499         for dir_module in dirs_ress_icon:
500              AppConfig=AppConfig+":"+dir_module
501         f.write(AppConfig+"\n")
502         command = """SUITRoot=${HOME}/${APPLI}/share/salome
503 DISABLE_FPE=1
504 MMGT_REENTRANT=1
505 """
506         f.write(command)
507
508     #SalomeApp.xml file
509     with open(os.path.join(home_dir,'SalomeApp.xml'),'w') as f:
510         command = """<document>
511   <section name="launch">
512     <!-- SALOME launching parameters -->
513     <parameter name="gui"        value="yes"/>
514     <parameter name="splash"     value="yes"/>
515     <parameter name="file"       value="no"/>
516     <parameter name="key"        value="no"/>
517     <parameter name="interp"     value="no"/>
518     <parameter name="logger"     value="no"/>
519     <parameter name="xterm"      value="no"/>
520     <parameter name="portkill"   value="no"/>
521     <parameter name="killall"    value="no"/>
522     <parameter name="noexcepthandler"  value="no"/>
523     <parameter name="modules"    value="%s"/>
524     <parameter name="pyModules"  value=""/>
525     <parameter name="embedded"   value="SalomeAppEngine,study,cppContainer,registry,moduleCatalog"/>
526     <parameter name="standalone" value=""/>
527   </section>
528 </document>
529 """
530         mods = []
531         #Keep all modules except KERNEL and GUI
532         for module in _config.get("modules", []):
533             if module in ("KERNEL","GUI"):
534                 continue
535             mods.append(module)
536         f.write(command % ",".join(mods))
537
538     #Add USERS directory with 777 permission to store users configuration files
539     users_dir = os.path.join(home_dir,'USERS')
540     makedirs(users_dir)
541     os.chmod(users_dir, 0o777)
542
543 def main():
544     parser = optparse.OptionParser(usage=usage)
545
546     parser.add_option('--prefix', dest="prefix", default='.',
547                       help="Installation directory (default .)")
548
549     parser.add_option('--config', dest="config", default='config_appli.xml',
550                       help="XML configuration file (default config_appli.xml)")
551
552     parser.add_option('-v', '--verbose', action='count', dest='verbose',
553                       default=0, help="Increase verbosity")
554
555     options, args = parser.parse_args()
556     if not os.path.exists(options.config):
557         print("ERROR: config file %s does not exist. It is mandatory." % options.config)
558         sys.exit(1)
559
560     install(prefix=options.prefix, config_file=options.config, verbose=options.verbose)
561     pass
562
563 # -----------------------------------------------------------------------------
564
565 if __name__ == '__main__':
566     main()
567     pass