Salome HOME
sat #32302 pip option --build obsolète : integration du patch fourni par Nabil
[tools/sat.git] / commands / config.py
1 #!/usr/bin/env python
2 #-*- coding:utf-8 -*-
3 #  Copyright (C) 2010-2012  CEA/DEN
4 #
5 #  This library is free software; you can redistribute it and/or
6 #  modify it under the terms of the GNU Lesser General Public
7 #  License as published by the Free Software Foundation; either
8 #  version 2.1 of the License.
9 #
10 #  This library is distributed in the hope that it will be useful,
11 #  but WITHOUT ANY WARRANTY; without even the implied warranty of
12 #  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13 #  Lesser General Public License for more details.
14 #
15 #  You should have received a copy of the GNU Lesser General Public
16 #  License along with this library; if not, write to the Free Software
17 #  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
18
19 import os
20 import sys
21 import platform
22 import datetime
23 import shutil
24 import gettext
25 import pprint as PP
26
27 import src
28 import src.logger as LOG
29 import src.debug as DBG
30 import src.callerName as CALN
31
32 logger = LOG.getDefaultLogger()
33
34 verbose = False # True for debug
35
36 # internationalization
37 satdir = os.path.dirname(os.path.dirname(os.path.realpath(__file__)))
38 gettext.install('salomeTools', os.path.join(satdir, 'src', 'i18n'))
39
40 # Define all possible option for config command :  sat config <options>
41 parser = src.options.Options()
42 parser.add_option('v', 'value', 'string', 'value',
43     _("Optional: print the value of CONFIG_VARIABLE."))
44 parser.add_option('g', 'debug', 'string', 'debug',
45     _("Optional: print the debugging mode value of CONFIG_VARIABLE."))
46 parser.add_option('e', 'edit', 'boolean', 'edit',
47     _("Optional: edit the product configuration file."))
48 parser.add_option('i', 'info', 'list2', 'info',
49     _("Optional: get information on product(s). This option accepts a comma separated list."))
50 parser.add_option('p', 'products', 'list2', 'products',
51     _("Optional: same as --info, for convenience."))
52 parser.add_option('l', 'list', 'boolean', 'list',
53     _("Optional: list all available applications."))
54 parser.add_option('', 'show_patchs', 'boolean', 'show_patchs',
55     _("Optional: synthetic list of all patches used in the application"))
56 parser.add_option('', 'show_dependencies', 'boolean', 'show_dependencies',
57     _("Optional: list of product dependencies in the application"))
58 parser.add_option('', 'show_install', 'boolean', 'show_install',
59     _("Optional: synthetic list of all install directories in the application"))
60 parser.add_option('', 'show_properties', 'boolean', 'show_properties',
61     _("Optional: synthetic list of all properties used in the application"))
62 parser.add_option('', 'check_system', 'boolean', 'check_system',
63     _("Optional: check if system products are installed"))
64 parser.add_option('c', 'copy', 'boolean', 'copy',
65     _("""Optional: copy a config file to the personal config files directory.
66 WARNING: the included files are not copied.
67 If a name is given the new config file takes the given name."""))
68 parser.add_option('n', 'no_label', 'boolean', 'no_label',
69     _("Internal use: do not print labels, Works only with --value and --list."))
70 parser.add_option('', 'completion', 'boolean', 'completion',
71     _("Internal use: print only keys, works only with --value."))
72 parser.add_option('s', 'schema', 'boolean', 'schema',
73     _("Internal use."))
74
75 def osJoin(*args):
76   """
77   shortcut wrapper to os.path.join
78   plus optionaly print for debug
79   """
80   res = os.path.realpath(os.path.join(*args))
81   if verbose:
82     if True: # ".pyconf" in res:
83       logger.info("osJoin %-80s in %s" % (res, CALN.caller_name(1)))
84   return res
85
86 class ConfigOpener:
87     '''Class that helps to find an application pyconf 
88        in all the possible directories (pathList)
89     '''
90     def __init__(self, pathList):
91         '''Initialization
92         
93         :param pathList list: The list of paths where to search a pyconf.
94         '''
95         self.pathList = pathList
96         if verbose:
97           for path in pathList:
98             if not os.path.isdir(path):
99               logger.warning("ConfigOpener inexisting directory: %s" % path)
100
101     def __call__(self, name):
102         if os.path.isabs(name):
103             return src.pyconf.ConfigInputStream(open(name, 'rb'))
104         else:
105             return src.pyconf.ConfigInputStream(open(osJoin(self.get_path(name), name), 'rb'))
106         raise IOError(_("Configuration file '%s' not found") % name)
107
108     def get_path( self, name ):
109         '''The method that returns the entire path of the pyconf searched
110         returns first found in self.pathList directories
111
112         :param name str: The name of the searched pyconf.
113         '''
114         for path in self.pathList:
115             if os.path.exists(osJoin(path, name)):
116                 return path
117         raise IOError(_("Configuration file '%s' not found") % name)
118
119 class ConfigManager:
120     '''Class that manages the read of all the configuration files of salomeTools
121     '''
122     def __init__(self, datadir=None):
123         pass
124
125     def _create_vars(self, application=None, command=None, datadir=None):
126         '''Create a dictionary that stores all information about machine,
127            user, date, repositories, etc...
128         
129         :param application str: The application for which salomeTools is called.
130         :param command str: The command that is called.
131         :param datadir str: The repository that contain external data 
132                             for salomeTools.
133         :return: The dictionary that stores all information.
134         :rtype: dict
135         '''
136         var = {}      
137         var['user'] = src.architecture.get_user()
138         var['salometoolsway'] = os.path.dirname( os.path.dirname(os.path.abspath(__file__)))
139         var['srcDir'] =  osJoin(var['salometoolsway'], 'src')
140         var['internal_dir'] =  osJoin(var['srcDir'], 'internal_config')
141         var['sep']= os.path.sep
142         if src.architecture.is_windows():
143           var['scriptExtension'] = '.bat'
144         else:
145           var['scriptExtension'] = '.sh'
146         
147         # datadir has a default location
148         var['datadir'] =  osJoin(var['salometoolsway'], 'data')
149         if datadir is not None:
150             var['datadir'] = datadir
151
152         var['personalDir'] =  osJoin(os.path.expanduser('~'), '.salomeTools')
153         src.ensure_path_exists(var['personalDir'])
154
155         var['personal_applications_dir'] =  osJoin(var['personalDir'], "Applications")
156         src.ensure_path_exists(var['personal_applications_dir'])
157         
158         var['personal_products_dir'] =  osJoin(var['personalDir'], "products")
159         src.ensure_path_exists(var['personal_products_dir'])
160         
161         var['personal_archives_dir'] =  osJoin(var['personalDir'], "Archives")
162         src.ensure_path_exists(var['personal_archives_dir'])
163
164         var['personal_jobs_dir'] =  osJoin(var['personalDir'], "Jobs")
165         src.ensure_path_exists(var['personal_jobs_dir'])
166
167         var['personal_machines_dir'] =  osJoin(var['personalDir'], "Machines")
168         src.ensure_path_exists(var['personal_machines_dir'])
169
170         # read linux distributions dictionary
171         distrib_cfg = src.pyconf.Config( osJoin(var['srcDir'], 'internal_config', 'distrib.pyconf'))
172         
173         # set platform parameters
174         dist_name = src.architecture.get_distribution(codes=distrib_cfg.DISTRIBUTIONS)
175         dist_version = src.architecture.get_distrib_version(dist_name)
176         dist_version_full = src.architecture.get_version_XY()
177         dist = dist_name + dist_version
178         
179         var['dist_name'] = dist_name
180         var['dist_version'] = dist_version
181         var['dist'] = dist
182         var['dist_ref'] = dist_name + dist_version_full
183         var['python'] = src.architecture.get_python_version()
184
185         var['nb_proc'] = src.architecture.get_nb_proc()
186         node_name = platform.node()
187         var['node'] = node_name
188         var['hostname'] = node_name
189
190         # set date parameters
191         dt = datetime.datetime.now()
192         var['date'] = dt.strftime('%Y%m%d')
193         var['datehour'] = dt.strftime('%Y%m%d_%H%M%S')
194         var['hour'] = dt.strftime('%H%M%S')
195
196         var['command'] = str(command)
197         var['application'] = str(application)
198
199         # Root dir for temporary files 
200         var['tmp_root'] = os.sep + 'tmp' + os.sep + var['user']
201         # particular win case 
202         if src.architecture.is_windows() : 
203             var['tmp_root'] =  os.path.expanduser('~') + os.sep + 'tmp'
204         
205         return var
206
207     def get_command_line_overrides(self, options, sections):
208         '''get all the overwrites that are in the command line
209         
210         :param options: the options from salomeTools class 
211                         initialization (like -l5 or --overwrite)
212         :param sections str: The config section to overwrite.
213         :return: The list of all the overwrites to apply.
214         :rtype: list
215         '''
216         # when there are no options or not the overwrite option, 
217         # return an empty list
218         if options is None or options.overwrite is None:
219             return []
220         
221         over = []
222         for section in sections:
223             # only overwrite the sections that correspond to the option 
224             over.extend(filter(lambda l: l.startswith(section + "."), 
225                                options.overwrite))
226         return over
227
228     def get_config(self, application=None, options=None, command=None,
229                     datadir=None):
230         '''get the config from all the configuration files.
231         
232         :param application str: The application for which salomeTools is called.
233         :param options class Options: The general salomeToos
234                                       options (--overwrite or -l5, for example)
235         :param command str: The command that is called.
236         :param datadir str: The repository that contain 
237                             external data for salomeTools.
238         :return: The final config.
239         :rtype: class 'src.pyconf.Config'
240         '''        
241         
242         # create a ConfigMerger to handle merge
243         merger = src.pyconf.ConfigMerger()#MergeHandler())
244         
245         # create the configuration instance
246         cfg = src.pyconf.Config()
247         
248         # =====================================================================
249         # create VARS section
250         var = self._create_vars(application=application, command=command, datadir=datadir)
251         # DBG.write("create_vars", var, DBG.isDeveloper())
252
253         # add VARS to config
254         cfg.VARS = src.pyconf.Mapping(cfg)
255         for variable in var:
256             cfg.VARS[variable] = var[variable]
257         
258         # apply overwrite from command line if needed
259         for rule in self.get_command_line_overrides(options, ["VARS"]):
260             exec('cfg.' + rule) # this cannot be factorized because of the exec
261         
262         # =====================================================================
263         # Load INTERNAL config
264         # read src/internal_config/salomeTools.pyconf
265         src.pyconf.streamOpener = ConfigOpener([
266                              osJoin(cfg.VARS.srcDir, 'internal_config')])
267         try:
268             if src.architecture.is_windows(): # special internal config for windows
269                 internal_cfg = src.pyconf.Config(open( osJoin(cfg.VARS.srcDir,
270                                         'internal_config', 'salomeTools_win.pyconf')))
271             else:
272                 internal_cfg = src.pyconf.Config(open( osJoin(cfg.VARS.srcDir,
273                                         'internal_config', 'salomeTools.pyconf')))
274         except src.pyconf.ConfigError as e:
275             raise src.SatException(_("Error in configuration file:"
276                                      " salomeTools.pyconf\n  %(error)s") % \
277                                    {'error': str(e) })
278         
279         merger.merge(cfg, internal_cfg)
280
281         # apply overwrite from command line if needed
282         for rule in self.get_command_line_overrides(options, ["INTERNAL"]):
283             exec('cfg.' + rule) # this cannot be factorized because of the exec        
284                
285         # =====================================================================
286         # Load LOCAL config file
287         # search only in the data directory
288         src.pyconf.streamOpener = ConfigOpener([cfg.VARS.datadir])
289         try:
290             local_cfg = src.pyconf.Config(open( osJoin(cfg.VARS.datadir,
291                                                            'local.pyconf')),
292                                          PWD = ('LOCAL', cfg.VARS.datadir) )
293         except src.pyconf.ConfigError as e:
294             raise src.SatException(_("Error in configuration file: "
295                                      "local.pyconf\n  %(error)s") % \
296                 {'error': str(e) })
297         except IOError as error:
298             e = str(error)
299             raise src.SatException( e );
300         merger.merge(cfg, local_cfg)
301
302         # When the key is "default", put the default value
303         if cfg.LOCAL.base == "default":
304             cfg.LOCAL.base = os.path.abspath(osJoin(cfg.VARS.salometoolsway, "..", "BASE"))
305         if cfg.LOCAL.workdir == "default":
306             cfg.LOCAL.workdir = os.path.abspath(osJoin(cfg.VARS.salometoolsway, ".."))
307         if cfg.LOCAL.log_dir == "default":
308             cfg.LOCAL.log_dir = os.path.abspath(osJoin(cfg.VARS.salometoolsway, "..", "LOGS"))
309
310         if cfg.LOCAL.archive_dir == "default":
311             cfg.LOCAL.archive_dir = os.path.abspath( osJoin(cfg.VARS.salometoolsway, "..", "ARCHIVES"))
312
313         # if the sat tag was not set permanently by user
314         if cfg.LOCAL.tag == "unknown":
315             # get the tag with git, and store it
316             sat_version=src.system.git_describe(cfg.VARS.salometoolsway) 
317             if sat_version == False:
318                 sat_version=cfg.INTERNAL.sat_version
319             cfg.LOCAL.tag=sat_version
320                 
321
322         # apply overwrite from command line if needed
323         for rule in self.get_command_line_overrides(options, ["LOCAL"]):
324             exec('cfg.' + rule) # this cannot be factorized because of the exec
325         
326         # =====================================================================
327         # Load the PROJECTS
328         projects_cfg = src.pyconf.Config()
329         projects_cfg.addMapping("PROJECTS",
330                                 src.pyconf.Mapping(projects_cfg),
331                                 "The projects\n")
332         projects_cfg.PROJECTS.addMapping("projects",
333                                 src.pyconf.Mapping(cfg.PROJECTS),
334                                 "The projects definition\n")
335         
336         for project_pyconf_path in cfg.PROJECTS.project_file_paths:
337             if not os.path.isabs(project_pyconf_path):
338                 # for a relative path (archive case) we complete with sat path
339                 project_pyconf_path = os.path.join(cfg.VARS.salometoolsway,
340                                                   project_pyconf_path)
341             if not os.path.exists(project_pyconf_path):
342                 msg = _("WARNING: The project file %s cannot be found. "
343                         "It will be ignored\n" % project_pyconf_path)
344                 sys.stdout.write(msg)
345                 continue
346             project_name = os.path.basename(
347                                     project_pyconf_path)[:-len(".pyconf")]
348             try:
349                 project_pyconf_dir = os.path.dirname(project_pyconf_path)
350                 project_cfg = src.pyconf.Config(open(project_pyconf_path),
351                                                 PWD=("", project_pyconf_dir))
352             except Exception as e:
353                 msg = _("ERROR: Error in configuration file: "
354                                  "%(file_path)s\n  %(error)s\n") % \
355                             {'file_path' : project_pyconf_path, 'error': str(e) }
356                 sys.stdout.write(msg)
357                 continue
358             projects_cfg.PROJECTS.projects.addMapping(project_name,
359                              src.pyconf.Mapping(projects_cfg.PROJECTS.projects),
360                              "The %s project\n" % project_name)
361             projects_cfg.PROJECTS.projects[project_name]=project_cfg
362             projects_cfg.PROJECTS.projects[project_name]["file_path"] = \
363                                                         project_pyconf_path
364             # store the project tag if any
365             product_project_git_tag = src.system.git_describe(os.path.dirname(project_pyconf_path))
366             if product_project_git_tag:
367                 projects_cfg.PROJECTS.projects[project_name]["git_tag"] = product_project_git_tag
368             else:
369                 projects_cfg.PROJECTS.projects[project_name]["git_tag"] = "unknown"
370                    
371         merger.merge(cfg, projects_cfg)
372
373         # apply overwrite from command line if needed
374         for rule in self.get_command_line_overrides(options, ["PROJECTS"]):
375             exec('cfg.' + rule) # this cannot be factorized because of the exec
376         
377         # =====================================================================
378         # Create the paths where to search the application configurations, 
379         # the product configurations, the products archives, 
380         # the jobs configurations and the machines configurations
381         cfg.addMapping("PATHS", src.pyconf.Mapping(cfg), "The paths\n")
382         cfg.PATHS["APPLICATIONPATH"] = src.pyconf.Sequence(cfg.PATHS)
383         cfg.PATHS.APPLICATIONPATH.append(cfg.VARS.personal_applications_dir, "")
384
385         
386         cfg.PATHS["PRODUCTPATH"] = src.pyconf.Sequence(cfg.PATHS)
387         cfg.PATHS.PRODUCTPATH.append(cfg.VARS.personal_products_dir, "")
388         cfg.PATHS["ARCHIVEPATH"] = src.pyconf.Sequence(cfg.PATHS)
389         cfg.PATHS.ARCHIVEPATH.append(cfg.VARS.personal_archives_dir, "")
390         cfg.PATHS["ARCHIVEFTP"] = src.pyconf.Sequence(cfg.PATHS)
391         cfg.PATHS["JOBPATH"] = src.pyconf.Sequence(cfg.PATHS)
392         cfg.PATHS.JOBPATH.append(cfg.VARS.personal_jobs_dir, "")
393         cfg.PATHS["MACHINEPATH"] = src.pyconf.Sequence(cfg.PATHS)
394         cfg.PATHS.MACHINEPATH.append(cfg.VARS.personal_machines_dir, "")
395         cfg.PATHS["LICENCEPATH"] = src.pyconf.Sequence(cfg.PATHS)
396
397         # initialise the path with local directory
398         cfg.PATHS["ARCHIVEPATH"].append(cfg.LOCAL.archive_dir, "")
399
400         # Loop over the projects in order to complete the PATHS variables
401         # as /data/tmpsalome/salome/prerequis/archives for example ARCHIVEPATH
402         for project in cfg.PROJECTS.projects:
403             for PATH in ["APPLICATIONPATH",
404                          "PRODUCTPATH",
405                          "ARCHIVEPATH", #comment this for default archive       #8646
406                          "ARCHIVEFTP",
407                          "JOBPATH",
408                          "MACHINEPATH",
409                          "LICENCEPATH"]:
410                 if PATH not in cfg.PROJECTS.projects[project]:
411                     continue
412                 pathlist=cfg.PROJECTS.projects[project][PATH].split(":")
413                 for path in pathlist:
414                     cfg.PATHS[PATH].append(path, "")
415         
416         # apply overwrite from command line if needed
417         for rule in self.get_command_line_overrides(options, ["PATHS"]):
418             exec('cfg.' + rule) # this cannot be factorized because of the exec
419
420         # AT END append APPLI_TEST directory in APPLICATIONPATH, for unittest
421         appli_test_dir =  osJoin(satdir, "test", "APPLI_TEST")
422         if appli_test_dir not in cfg.PATHS.APPLICATIONPATH:
423           cfg.PATHS.APPLICATIONPATH.append(appli_test_dir, "unittest APPLI_TEST path")
424
425         # =====================================================================
426         # Load APPLICATION config file
427         if application is not None:
428             # search APPLICATION file in all directories in configPath
429             cp = cfg.PATHS.APPLICATIONPATH
430             src.pyconf.streamOpener = ConfigOpener(cp)
431             do_merge = True
432             try:
433                 application_cfg = src.pyconf.Config(application + '.pyconf')
434             except IOError as e:
435                 raise src.SatException(
436                    _("%s, use 'config --list' to get the list of available applications.") % e)
437             except src.pyconf.ConfigError as e:
438                 if (not ('-e' in parser.parse_args()[1]) 
439                                          or ('--edit' in parser.parse_args()[1]) 
440                                          and command == 'config'):
441                     raise src.SatException(_("Error in configuration file: "
442                                              "%(application)s.pyconf\n "
443                                              " %(error)s") % \
444                         { 'application': application, 'error': str(e) } )
445                 else:
446                     sys.stdout.write(src.printcolors.printcWarning(
447                                         "There is an error in the file"
448                                         " %s.pyconf.\n" % cfg.VARS.application))
449                     do_merge = False
450             except Exception as e:
451                 if (not ('-e' in parser.parse_args()[1]) 
452                                         or ('--edit' in parser.parse_args()[1]) 
453                                         and command == 'config'):
454                     sys.stdout.write(src.printcolors.printcWarning("%s\n" % str(e)))
455                     raise src.SatException(_("Error in configuration file:"
456                                              " %(application)s.pyconf\n") % \
457                         { 'application': application} )
458                 else:
459                     sys.stdout.write(src.printcolors.printcWarning(
460                                 "There is an error in the file"
461                                 " %s.pyconf. Opening the file with the"
462                                 " default viewer\n" % cfg.VARS.application))
463                     sys.stdout.write("The error:"
464                                  " %s\n" % src.printcolors.printcWarning(
465                                                                       str(e)))
466                     do_merge = False
467         
468             else:
469                 cfg['open_application'] = 'yes'
470         # =====================================================================
471         # Load product config files in PRODUCTS section
472         products_cfg = src.pyconf.Config()
473         products_cfg.addMapping("PRODUCTS",
474                                 src.pyconf.Mapping(products_cfg),
475                                 "The products\n")
476         if application is not None:
477             src.pyconf.streamOpener = ConfigOpener(cfg.PATHS.PRODUCTPATH)
478             for product_name in application_cfg.APPLICATION.products.keys():
479                 # Loop on all files that are in softsDir directory
480                 # and read their config
481                 product_file_name = product_name + ".pyconf"
482                 product_file_path = src.find_file_in_lpath(product_file_name, cfg.PATHS.PRODUCTPATH)
483                 if product_file_path:
484                     products_dir = os.path.dirname(product_file_path)
485                     # for a relative path (archive case) we complete with sat path
486                     if not os.path.isabs(products_dir):
487                         products_dir = os.path.join(cfg.VARS.salometoolsway,
488                                                     products_dir)
489                     try:
490                         prod_cfg = src.pyconf.Config(open(product_file_path),
491                                                      PWD=("", products_dir))
492                         prod_cfg.from_file = product_file_path
493                         products_cfg.PRODUCTS[product_name] = prod_cfg
494                     except Exception as e:
495                         msg = _(
496                             "WARNING: Error in configuration file"
497                             ": %(prod)s\n  %(error)s" % \
498                             {'prod' :  product_name, 'error': str(e) })
499                         sys.stdout.write(msg)
500             
501             merger.merge(cfg, products_cfg)
502             
503             # apply overwrite from command line if needed
504             for rule in self.get_command_line_overrides(options, ["PRODUCTS"]):
505                 exec('cfg.' + rule) # this cannot be factorized because of the exec
506             
507             if do_merge:
508                 merger.merge(cfg, application_cfg)
509
510                 # default launcher name ('salome')
511                 if ('profile' in cfg.APPLICATION and 
512                     'launcher_name' not in cfg.APPLICATION.profile):
513                     cfg.APPLICATION.profile.launcher_name = 'salome'
514
515                 # apply overwrite from command line if needed
516                 for rule in self.get_command_line_overrides(options,
517                                                              ["APPLICATION"]):
518                     # this cannot be factorized because of the exec
519                     exec('cfg.' + rule)
520             
521         # =====================================================================
522         # load USER config
523         self.set_user_config_file(cfg)
524         user_cfg_file = self.get_user_config_file()
525         user_cfg = src.pyconf.Config(open(user_cfg_file))
526         merger.merge(cfg, user_cfg)
527
528         # apply overwrite from command line if needed
529         for rule in self.get_command_line_overrides(options, ["USER"]):
530             exec('cfg.' + rule) # this cannot be factorize because of the exec
531         
532         # remove application products "blacklisted" in rm_products field
533         if "APPLICATION" in cfg and "rm_products" in cfg.APPLICATION:
534             for prod_to_remove in cfg.APPLICATION.rm_products:
535                 cfg.APPLICATION.products.__delitem__(prod_to_remove)
536             # remove rm_products section after usage
537             cfg.APPLICATION.__delitem__("rm_products")
538         return cfg
539
540     def set_user_config_file(self, config):
541         '''Set the user config file name and path.
542         If necessary, build it from another one or create it from scratch.
543         
544         :param config class 'src.pyconf.Config': The global config 
545                                                  (containing all pyconf).
546         '''
547         # get the expected name and path of the file
548         self.config_file_name = 'SAT.pyconf'
549         self.user_config_file_path =  osJoin(config.VARS.personalDir, self.config_file_name)
550         
551         # if pyconf does not exist, create it from scratch
552         if not os.path.isfile(self.user_config_file_path): 
553             self.create_config_file(config)
554     
555     def create_config_file(self, config):
556         '''This method is called when there are no user config file. 
557            It build it from scratch.
558         
559         :param config class 'src.pyconf.Config': The global config.
560         :return: the config corresponding to the file created.
561         :rtype: config class 'src.pyconf.Config'
562         '''
563         
564         cfg_name = self.get_user_config_file()
565
566         user_cfg = src.pyconf.Config()
567         #
568         user_cfg.addMapping('USER', src.pyconf.Mapping(user_cfg), "")
569
570         user_cfg.USER.addMapping('cvs_user', config.VARS.user,
571             "This is the user name used to access salome cvs base.\n")
572         user_cfg.USER.addMapping('svn_user', config.VARS.user,
573             "This is the user name used to access salome svn base.\n")
574         user_cfg.USER.addMapping('output_verbose_level', 3,
575             "This is the default output_verbose_level you want."
576             " 0=>no output, 5=>debug.\n")
577         user_cfg.USER.addMapping('publish_dir', 
578                                   osJoin(os.path.expanduser('~'),
579                                  'websupport', 
580                                  'satreport'), 
581                                  "")
582         user_cfg.USER.addMapping('editor',
583                                  'vi', 
584                                  "This is the editor used to "
585                                  "modify configuration files\n")
586         user_cfg.USER.addMapping('browser', 
587                                  'firefox', 
588                                  "This is the browser used to "
589                                  "read html documentation\n")
590         user_cfg.USER.addMapping('pdf_viewer', 
591                                  'evince', 
592                                  "This is the pdf_viewer used "
593                                  "to read pdf documentation\n")
594
595         src.ensure_path_exists(config.VARS.personalDir)
596         src.ensure_path_exists( osJoin(config.VARS.personalDir,
597                                             'Applications'))
598
599         f = open(cfg_name, 'w')
600         user_cfg.__save__(f)
601         f.close()
602
603         return user_cfg   
604
605     def get_user_config_file(self):
606         '''Get the user config file
607         :return: path to the user config file.
608         :rtype: str
609         '''
610         if not self.user_config_file_path:
611             raise src.SatException(_("Error in get_user_config_file: "
612                                      "missing user config file path"))
613         return self.user_config_file_path     
614
615 def check_path(path, ext=[]):
616     '''Construct a text with the input path and "not found" if it does not
617        exist.
618     
619     :param path Str: the path to check.
620     :param ext List: An extension. Verify that the path extension 
621                      is in the list
622     :return: The string of the path with information
623     :rtype: Str
624     '''
625     # check if file exists
626     if not os.path.exists(path):
627         return "'%s'" % path + " " + src.printcolors.printcError(_(
628                                                             "** not found"))
629
630     # check extension
631     if len(ext) > 0:
632         fe = os.path.splitext(path)[1].lower()
633         if fe not in ext:
634             return "'%s'" % path + " " + src.printcolors.printcError(_(
635                                                         "** bad extension"))
636
637     return path
638
639 def show_product_info(config, name, logger):
640     '''Display on the terminal and logger information about a product.
641     
642     :param config Config: the global configuration.
643     :param name Str: The name of the product
644     :param logger Logger: The logger instance to use for the display
645     '''
646     
647     logger.write(_("%s is a product\n") % src.printcolors.printcLabel(name), 2)
648     pinfo = src.product.get_product_config(config, name)
649     
650     if "depend" in pinfo:
651         src.printcolors.print_value(logger, "depends on", sorted(pinfo.depend), 2)
652
653     if "opt_depend" in pinfo:
654         src.printcolors.print_value(logger, "optional", sorted(pinfo.opt_depend), 2)
655
656     if "build_depend" in pinfo:
657         src.printcolors.print_value(logger, "build depend on", sorted(pinfo.build_depend), 2)
658
659
660     # information on pyconf
661     logger.write("\n", 2)
662     logger.write(src.printcolors.printcLabel("configuration:") + "\n", 2)
663     if "from_file" in pinfo:
664         src.printcolors.print_value(logger,
665                                     "pyconf file path",
666                                     pinfo.from_file,
667                                     2)
668     if "section" in pinfo:
669         src.printcolors.print_value(logger,
670                                     "section",
671                                     pinfo.section,
672                                     2)
673
674     # information on prepare
675     logger.write("\n", 2)
676     logger.write(src.printcolors.printcLabel("prepare:") + "\n", 2)
677
678     is_dev = src.product.product_is_dev(pinfo)
679     method = pinfo.get_source
680     if is_dev:
681         method += " (dev)"
682     src.printcolors.print_value(logger, "get method", method, 2)
683
684     if method == 'cvs':
685         src.printcolors.print_value(logger, "server", pinfo.cvs_info.server, 2)
686         src.printcolors.print_value(logger, "base module",
687                                     pinfo.cvs_info.module_base, 2)
688         src.printcolors.print_value(logger, "source", pinfo.cvs_info.source, 2)
689         src.printcolors.print_value(logger, "tag", pinfo.cvs_info.tag, 2)
690
691     elif method == 'svn':
692         src.printcolors.print_value(logger, "repo", pinfo.svn_info.repo, 2)
693
694     elif method == 'git':
695         src.printcolors.print_value(logger, "repo", pinfo.git_info.repo, 2)
696         src.printcolors.print_value(logger, "tag", pinfo.git_info.tag, 2)
697
698     elif method == 'archive':
699         src.printcolors.print_value(logger,
700                                     "get from",
701                                     check_path(pinfo.archive_info.archive_name),
702                                     2)
703
704     if 'patches' in pinfo:
705         for patch in pinfo.patches:
706             src.printcolors.print_value(logger, "patch", check_path(patch), 2)
707
708     if src.product.product_is_fixed(pinfo):
709         src.printcolors.print_value(logger, "install_dir",
710                                     check_path(pinfo.install_dir), 2)
711
712     if src.product.product_is_native(pinfo) or src.product.product_is_fixed(pinfo):
713         return
714     
715     # information on compilation
716     if src.product.product_compiles(pinfo):
717         logger.write("\n", 2)
718         logger.write(src.printcolors.printcLabel("compile:") + "\n", 2)
719         src.printcolors.print_value(logger,
720                                     "compilation method",
721                                     pinfo.build_source,
722                                     2)
723         
724         if pinfo.build_source == "script" and "compil_script" in pinfo:
725             src.printcolors.print_value(logger, 
726                                         "Compilation script", 
727                                         pinfo.compil_script, 
728                                         2)
729         
730         if 'nb_proc' in pinfo:
731             src.printcolors.print_value(logger, "make -j", pinfo.nb_proc, 2)
732     
733         src.printcolors.print_value(logger, 
734                                     "source dir", 
735                                     check_path(pinfo.source_dir), 
736                                     2)
737         if 'install_dir' in pinfo:
738             src.printcolors.print_value(logger, 
739                                         "build dir", 
740                                         check_path(pinfo.build_dir), 
741                                         2)
742             src.printcolors.print_value(logger, 
743                                         "install dir", 
744                                         check_path(pinfo.install_dir), 
745                                         2)
746         else:
747             logger.write("  " + 
748                          src.printcolors.printcWarning(_("no install dir")) + 
749                          "\n", 2)
750
751         src.printcolors.print_value(logger, "debug ", pinfo.debug, 2)
752         src.printcolors.print_value(logger, "verbose ", pinfo.verbose, 2)
753         src.printcolors.print_value(logger, "hpc ", pinfo.hpc, 2)
754         src.printcolors.print_value(logger, "dev ", pinfo.dev, 2)
755
756     else:
757         logger.write("\n", 2)
758         msg = _("This product does not compile")
759         logger.write("%s\n" % msg, 2)
760
761     # information on environment
762     logger.write("\n", 2)
763     logger.write(src.printcolors.printcLabel("environ :") + "\n", 2)
764     if "environ" in pinfo and "env_script" in pinfo.environ:
765         src.printcolors.print_value(logger, 
766                                     "script", 
767                                     check_path(pinfo.environ.env_script), 
768                                     2)
769
770     # display run-time environment
771     zz = src.environment.SalomeEnviron(config,
772                                        src.fileEnviron.ScreenEnviron(logger), 
773                                        False)
774     zz.set_python_libdirs()
775     zz.set_a_product(name, logger)
776     logger.write("\n", 2)
777
778
779 def show_patchs(config, logger):
780   '''Prints all the used patchs in the application.
781
782   :param config Config: the global configuration.
783   :param logger Logger: The logger instance to use for the display
784   '''
785   oneOrMore = False
786   for product in sorted(config.APPLICATION.products):
787     try:
788       product_info = src.product.get_product_config(config, product)
789       if src.product.product_has_patches(product_info):
790         oneOrMore = True
791         logger.write("%s:\n" % product, 1)
792         for i in product_info.patches:
793           logger.write(src.printcolors.printcInfo("    %s\n" % i), 1)
794     except Exception as e:
795       msg = "problem on product %s\n%s\n" % (product, str(e))
796       logger.error(msg)
797
798   if oneOrMore:
799     logger.write("\n", 1)
800   else:
801     logger.write("No patchs found\n", 1)
802
803 def check_install_system(config, logger):
804   '''Check the installation of all (declared) system products
805
806   :param config Config: the global configuration.
807   :param logger Logger: The logger instance to use for the display
808   '''
809   # get the command to use for checking the system dependencies
810   # (either rmp or apt)
811   check_cmd=src.system.get_pkg_check_cmd(config.VARS.dist_name)
812   logger.write("\nCheck the system dependencies declared in the application\n",1)
813   pkgmgr=check_cmd[0]
814   run_dep_ko=[] # list of missing run time dependencies
815   build_dep_ko=[] # list of missing compile time dependencies
816   for product in sorted(config.APPLICATION.products):
817     try:
818       product_info = src.product.get_product_config(config, product)
819       if src.product.product_is_native(product_info):
820         # if the product is native, get (in two dictionnaries the runtime and compile time 
821         # system dependencies with the status (OK/KO)
822         run_pkg,build_pkg=src.product.check_system_dep(config.VARS.dist, check_cmd, product_info)
823         #logger.write("\n*** %s ***\n" % product, 1)
824         for pkg in run_pkg:
825             logger.write("\n   - "+pkg + " : " + run_pkg[pkg], 1)
826             if "KO" in run_pkg[pkg]:
827                 run_dep_ko.append(pkg)
828         for pkg in build_pkg:
829             logger.write("\n   - "+pkg + " : " + build_pkg[pkg], 1)
830             if "KO" in build_pkg[pkg]:
831                 build_dep_ko.append(pkg)
832         #  logger.write(src.printcolors.printcInfo("    %s\n" % i), 1)
833
834     except Exception as e:
835       msg = "\nproblem with the check of system prerequisite %s\n%s\n" % (product, str(e))
836       logger.error(msg)
837       raise Exception(msg)
838
839   logger.write("\n\n",1)
840   if run_dep_ko:
841       msg="Some run time system dependencies are missing!\n"+\
842           "Please install them with %s before running salome" % pkgmgr
843       logger.warning(msg)
844       logger.write("missing run time dependencies : ",1)
845       for md in run_dep_ko: 
846         logger.write(md+" ",1)
847       logger.write("\n\n")
848         
849   if build_dep_ko:
850       msg="Some compile time system dependencies are missing!\n"+\
851           "Please install them with %s before compiling salome" % pkgmgr
852       logger.warning(msg)
853       logger.write("missing compile time dependencies : ",1)
854       for md in build_dep_ko: 
855         logger.write(md+" ",1)
856       logger.write("\n\n")
857     
858
859 def show_dependencies(config, products, logger):
860     '''Prints dependencies of products in the application.
861
862     :param config Config: the global configuration.
863     :param logger Logger: The logger instance to use for the display
864     '''
865
866     from compile import get_dependencies_graph,depth_search_graph,find_path_graph
867     # Get the list of all application products, and create its dependency graph
868     all_products_infos = src.product.get_products_infos(config.APPLICATION.products,config)
869     all_products_graph=get_dependencies_graph(all_products_infos, compile_time=False)
870
871     products_list=[]
872     product_liste_name=""
873     if products is None:
874         products_list=config.APPLICATION.products
875         products_graph = all_products_graph
876     else:
877         # 1. Extend the list with all products that depends upon the given list of products
878         products_list=products
879         product_liste_name="_".join(products)
880         visited=[]
881         for p_name in products_list:
882             visited=depth_search_graph(all_products_graph, p_name, visited)
883         products_infos = src.product.get_products_infos(visited, config)
884         products_graph = get_dependencies_graph(products_infos, compile_time=False)
885
886         # 2. Extend the list with all the dependencies of the given list of products
887         children=[]
888         for n in all_products_graph:
889             # for all products (that are not in products_list):
890             # if we we find a path from the product to the product list,
891             # then we product is a child and we add it to the children list 
892             if (n not in children) and (n not in products_list):
893                 if find_path_graph(all_products_graph, n, products_list):
894                     children = children + [n]
895         products_infos_rev = src.product.get_products_infos(children, config)
896         products_graph_rev = get_dependencies_graph(products_infos_rev, compile_time=False)
897
898     logger.write("Dependency graph (python format)\n%s\n" % products_graph, 3)
899
900     gv_file_name='%s_%s_dep.gv' % (config.VARS.application,product_liste_name)
901     logger.write("\nDependency graph (graphviz format) written in file %s\n" % 
902                  src.printcolors.printcLabel(gv_file_name), 3)
903     with open(gv_file_name,"w") as f:
904         f.write("digraph G {\n")
905         for p in products_graph:
906             for dep in products_graph[p]:
907                 f.write ("\t%s -> %s\n" % (p,dep))
908         f.write("}\n")
909         
910
911     if products is not None:
912         # if a list of products was given, produce also the reverse dependencies
913         gv_revfile_name='%s_%s_rev_dep.gv' % (config.VARS.application,product_liste_name)
914         logger.write("\nReverse dependency graph (graphviz format) written in file %s\n" % 
915                  src.printcolors.printcLabel(gv_revfile_name), 3)
916         with open(gv_revfile_name,"w") as rf:
917             rf.write("digraph G {\n")
918             for p in products_graph_rev:
919                 for dep in products_graph_rev[p]:
920                     rf.write ("\t%s -> %s\n" % (p,dep))
921             rf.write("}\n")
922     
923     graph_cmd = "dot -Tpdf %s -o %s.pdf" % (gv_file_name,gv_file_name)
924     logger.write("\nTo generate a graph use dot tool : \n  %s" % 
925                  src.printcolors.printcLabel(graph_cmd), 3)
926  
927 def show_install_dir(config, logger):
928   '''Prints all the used installed directories in the application.
929
930   :param config Config: the global configuration.
931   :param logger Logger: The logger instance to use for the display
932   '''
933   for product in sorted(config.APPLICATION.products):
934     try:
935       product_info = src.product.get_product_config(config, product)
936       install_path=src.Path(product_info.install_dir)
937       if (src.product.product_is_native(product_info)):
938           install_path="Native"
939       elif (src.product.product_is_fixed(product_info)):
940           install_path+=" (Fixed)"
941       logger.write("%s : %s\n" % (product, install_path) , 1)
942     except Exception as e:
943       msg = "problem on product %s\n%s\n" % (product, str(e))
944       logger.error(msg)
945   logger.write("\n", 1)
946
947
948 def show_properties(config, logger):
949   '''Prints all the used properties in the application.
950
951   :param config Config: the global configuration.
952   :param logger Logger: The logger instance to use for the display
953   '''
954   if "properties" in config.APPLICATION:
955       # some properties are defined at application level, we display them
956       logger.write("Application properties:\n", 1)
957       for prop in config.APPLICATION.properties:
958           logger.write(src.printcolors.printcInfo("    %s : %s\n" % (prop, config.APPLICATION.properties[prop])), 1)
959   oneOrMore = False
960   for product in sorted(config.APPLICATION.products):
961     try:
962       product_info = src.product.get_product_config(config, product)
963       done = False
964       try:
965         for prop in product_info.properties:
966           if not done:
967             logger.write("%s:\n" % product, 1)
968             done = True
969           oneOrMore = True
970           logger.write(src.printcolors.printcInfo("    %s : %s\n" % (prop, product_info.properties[prop])), 1)
971       except Exception as e:
972         pass
973     except Exception as e:
974       # logger.write(src.printcolors.printcInfo("    %s\n" % "no properties"), 1)
975       msg = "problem on product %s\n%s\n" % (product, e)
976       logger.error(msg)
977
978   if oneOrMore:
979     logger.write("\n", 1)
980   else:
981     logger.write("No properties found\n", 1)
982
983 def print_value(config, path, show_label, logger, level=0, show_full_path=False):
984     '''Prints a value from the configuration. Prints recursively the values 
985        under the initial path.
986     
987     :param config class 'src.pyconf.Config': The configuration 
988                                              from which the value is displayed.
989     :param path str : the path in the configuration of the value to print.
990     :param show_label boolean: if True, do a basic display. 
991                                (useful for bash completion)
992     :param logger Logger: the logger instance
993     :param level int: The number of spaces to add before display.
994     :param show_full_path :
995     '''            
996     
997     # Make sure that the path does not ends with a point
998     if path.endswith('.'):
999         path = path[:-1]
1000     
1001     # display all the path or not
1002     if show_full_path:
1003         vname = path
1004     else:
1005         vname = path.split('.')[-1]
1006
1007     # number of spaces before the display
1008     tab_level = "  " * level
1009     
1010     # call to the function that gets the value of the path.
1011     try:
1012         val = config.getByPath(path)
1013     except Exception as e:
1014         logger.write(tab_level)
1015         logger.write("%s: ERROR %s\n" % (src.printcolors.printcLabel(vname), 
1016                                          src.printcolors.printcError(str(e))))
1017         return
1018
1019     # in this case, display only the value
1020     if show_label:
1021         logger.write(tab_level)
1022         logger.write("%s: " % src.printcolors.printcLabel(vname))
1023
1024     # The case where the value has under values, 
1025     # do a recursive call to the function
1026     if dir(val).__contains__('keys'):
1027         if show_label: logger.write("\n")
1028         for v in sorted(val.keys()):
1029             print_value(config, path + '.' + v, show_label, logger, level + 1)
1030     elif val.__class__ == src.pyconf.Sequence or isinstance(val, list): 
1031         # in this case, value is a list (or a Sequence)
1032         if show_label: logger.write("\n")
1033         index = 0
1034         for v in val:
1035             print_value(config, path + "[" + str(index) + "]", 
1036                         show_label, logger, level + 1)
1037             index = index + 1
1038     else: # case where val is just a str
1039         logger.write("%s\n" % val)
1040
1041 def get_config_children(config, args):
1042     '''Gets the names of the children of the given parameter.
1043        Useful only for completion mechanism
1044     
1045     :param config Config: The configuration where to read the values
1046     :param args: The path in the config from which get the keys
1047     '''
1048     vals = []
1049     rootkeys = config.keys()
1050     
1051     if len(args) == 0:
1052         # no parameter returns list of root keys
1053         vals = rootkeys
1054     else:
1055         parent = args[0]
1056         pos = parent.rfind('.')
1057         if pos < 0:
1058             # Case where there is only on key as parameter.
1059             # For example VARS
1060             vals = [m for m in rootkeys if m.startswith(parent)]
1061         else:
1062             # Case where there is a part from a key
1063             # for example VARS.us  (for VARS.user)
1064             head = parent[0:pos]
1065             tail = parent[pos+1:]
1066             try:
1067                 a = config.getByPath(head)
1068                 if dir(a).__contains__('keys'):
1069                     vals = map(lambda x: head + '.' + x,
1070                                [m for m in a.keys() if m.startswith(tail)])
1071             except:
1072                 pass
1073
1074     for v in sorted(vals):
1075         sys.stdout.write("%s\n" % v)
1076
1077 def description():
1078     '''method that is called when salomeTools is called with --help option.
1079     
1080     :return: The text to display for the config command description.
1081     :rtype: str
1082     '''
1083     return _("The config command allows manipulation "
1084              "and operation on config files.\n\nexample:\nsat config "
1085              "SALOME-master --info ParaView")
1086     
1087
1088 def run(args, runner, logger):
1089     '''method that is called when salomeTools is called with config parameter.
1090     '''
1091     # Parse the options
1092     (options, args) = parser.parse_args(args)
1093
1094     # Only useful for completion mechanism : print the keys of the config
1095     if options.schema:
1096         get_config_children(runner.cfg, args)
1097         return
1098
1099     # case : print a value of the config
1100     if options.value:
1101         if options.value == ".":
1102             # if argument is ".", print all the config
1103             for val in sorted(runner.cfg.keys()):
1104                 print_value(runner.cfg, val, not options.no_label, logger)
1105         else:
1106             print_value(runner.cfg, options.value, not options.no_label, logger, 
1107                         level=0, show_full_path=False)
1108     
1109     # case : print a debug value of the config
1110     if options.debug:
1111         if options.debug == ".":
1112             # if argument is ".", print all the config
1113             res = DBG.indent(DBG.getStrConfigDbg(runner.cfg))
1114             logger.write("\nConfig of application %s:\n\n%s\n" % (runner.cfg.VARS.application, res))
1115         else:
1116             if options.debug[0] == ".": # accept ".PRODUCT.etc" as "PRODUCT.etc"
1117               od = options.debug[1:]
1118             else:
1119               od = options.debug
1120             try:
1121               aCode = "a = runner.cfg.%s" % od
1122               # https://stackoverflow.com/questions/15086040/behavior-of-exec-function-in-python-2-and-python-3
1123               aDict = {"runner": runner}
1124               exec(aCode, globals(), aDict)
1125               # DBG.write("globals()", globals(), True)
1126               # DBG.write("aDict", aDict, True)
1127               res = DBG.indent(DBG.getStrConfigDbg(aDict["a"]))
1128               logger.write("\nConfig.%s of application %s:\n\n%s\n" % (od, runner.cfg.VARS.application, res))
1129             except Exception as e:
1130               msg = "\nConfig.%s of application %s: Unknown pyconf key\n" % (od, runner.cfg.VARS.application)
1131               logger.write(src.printcolors.printcError(msg), 1)
1132
1133     
1134     # case : edit user pyconf file or application file
1135     if options.edit:
1136         editor = runner.cfg.USER.editor
1137         if ('APPLICATION' not in runner.cfg and
1138                        'open_application' not in runner.cfg): # edit user pyconf
1139             usercfg =  osJoin(runner.cfg.VARS.personalDir,
1140                                    'SAT.pyconf')
1141             logger.write(_("Opening %s\n" % usercfg), 3)
1142             src.system.show_in_editor(editor, usercfg, logger)
1143         else:
1144             # search for file <application>.pyconf and open it
1145             for path in runner.cfg.PATHS.APPLICATIONPATH:
1146                 pyconf_path =  osJoin(path,
1147                                     runner.cfg.VARS.application + ".pyconf")
1148                 if os.path.exists(pyconf_path):
1149                     logger.write(_("Opening %s\n" % pyconf_path), 3)
1150                     src.system.show_in_editor(editor, pyconf_path, logger)
1151                     break
1152     
1153     # case : give information about the product(s) in parameter
1154     if options.products:
1155       if options.info is not None:
1156         logger.warning('options.products %s overrides options.info %s' % (options.products, options.info))
1157       options.info = options.products
1158
1159     if options.info:
1160       # DBG.write("products", sorted(runner.cfg.APPLICATION.products.keys()), True)
1161       src.check_config_has_application(runner.cfg)
1162       taggedProducts = src.getProductNames(runner.cfg, options.info, logger)
1163       DBG.write("tagged products", sorted(taggedProducts))
1164       for prod in sorted(taggedProducts):
1165         if prod in runner.cfg.APPLICATION.products:
1166           try:
1167             if len(taggedProducts) > 1:
1168               logger.write("#################### ", 2)
1169             show_product_info(runner.cfg, prod, logger)
1170           except Exception as e:
1171             msg = "problem on product %s\n%s\n" % (prod, str(e))
1172             logger.error(msg)
1173           # return
1174         else:
1175           msg = _("%s is not a product of %s.\n") % \
1176                 (prod, runner.cfg.VARS.application)
1177           logger.warning(msg)
1178           #raise Exception(msg)
1179     
1180     # case : copy an existing <application>.pyconf 
1181     # to ~/.salomeTools/Applications/LOCAL_<application>.pyconf
1182     if options.copy:
1183         # product is required
1184         src.check_config_has_application( runner.cfg )
1185
1186         # get application file path 
1187         source = runner.cfg.VARS.application + '.pyconf'
1188         source_full_path = ""
1189         for path in runner.cfg.PATHS.APPLICATIONPATH:
1190             # ignore personal directory
1191             if path == runner.cfg.VARS.personalDir:
1192                 continue
1193             # loop on all directories that can have pyconf applications
1194             zz =  osJoin(path, source)
1195             if os.path.exists(zz):
1196                 source_full_path = zz
1197                 break
1198
1199         if len(source_full_path) == 0:
1200             raise src.SatException(_(
1201                         "Config file for product %s not found\n") % source)
1202         else:
1203             if len(args) > 0:
1204                 # a name is given as parameter, use it
1205                 dest = args[0]
1206             elif 'copy_prefix' in runner.cfg.INTERNAL.config:
1207                 # use prefix
1208                 dest = (runner.cfg.INTERNAL.config.copy_prefix 
1209                         + runner.cfg.VARS.application)
1210             else:
1211                 # use same name as source
1212                 dest = runner.cfg.VARS.application
1213                 
1214             # the full path
1215             dest_file =  osJoin(runner.cfg.VARS.personalDir,
1216                                      'Applications', dest + '.pyconf')
1217             if os.path.exists(dest_file):
1218                 raise src.SatException(_("A personal application"
1219                                          " '%s' already exists") % dest)
1220             
1221             # perform the copy
1222             shutil.copyfile(source_full_path, dest_file)
1223             logger.write(_("%s has been created.\n") % dest_file)
1224     
1225     # case : display all the available pyconf applications
1226     if options.list:
1227         lproduct = list()
1228         # search in all directories that can have pyconf applications
1229         for path in runner.cfg.PATHS.APPLICATIONPATH:
1230             # print a header
1231             if not options.no_label:
1232                 logger.write("------ %s\n" % src.printcolors.printcHeader(path))
1233
1234             if not os.path.exists(path):
1235                 logger.write(src.printcolors.printcError(_(
1236                                             "Directory not found")) + "\n")
1237             else:
1238                 for f in sorted(os.listdir(path)):
1239                     # ignore file that does not ends with .pyconf
1240                     if not f.endswith('.pyconf'):
1241                         continue
1242
1243                     appliname = f[:-len('.pyconf')]
1244                     if appliname not in lproduct:
1245                         lproduct.append(appliname)
1246                         if path.startswith(runner.cfg.VARS.personalDir) \
1247                                     and not options.no_label:
1248                             logger.write("%s*\n" % appliname)
1249                         else:
1250                             logger.write("%s\n" % appliname)
1251                             
1252             logger.write("\n")
1253
1254     # case: print all the products name of the application (internal use for completion)
1255     if options.completion:
1256         for product_name in runner.cfg.APPLICATION.products.keys():
1257             logger.write("%s\n" % product_name)
1258         
1259     # case : give a synthetic view of all patches used in the application
1260     if options.show_patchs:
1261         src.check_config_has_application(runner.cfg)
1262         # Print some informations
1263         logger.write(_('Patchs of application %s\n') %
1264                     src.printcolors.printcLabel(runner.cfg.VARS.application), 3)
1265         logger.write("\n", 2, False)
1266         show_patchs(runner.cfg, logger)
1267
1268     # case : give a synthetic view of all install directories used in the application
1269     if options.show_install:
1270         src.check_config_has_application(runner.cfg)
1271         # Print some informations
1272         logger.write(_('Installation directories of application %s\n') %
1273                     src.printcolors.printcLabel(runner.cfg.VARS.application), 3)
1274         logger.write("\n", 2, False)
1275         show_install_dir(runner.cfg, logger)
1276
1277     # case : give a synthetic view of all dependencies between products of the application
1278     if options.show_dependencies:
1279         src.check_config_has_application(runner.cfg)
1280         # Print some informations
1281         logger.write(_('List of run-time dependencies of the application %s, product by product\n') %
1282                     src.printcolors.printcLabel(runner.cfg.VARS.application), 3)
1283         logger.write("\n", 2, False)
1284         show_dependencies(runner.cfg, options.products, logger)
1285
1286     # case : give a synthetic view of all patches used in the application
1287     if options.show_properties:
1288         src.check_config_has_application(runner.cfg)
1289
1290         # Print some informations
1291         logger.write(_('Properties of application %s\n') %
1292                     src.printcolors.printcLabel(runner.cfg.VARS.application), 3)
1293         logger.write("\n", 2, False)
1294         show_properties(runner.cfg, logger)
1295
1296     # check system prerequisites
1297     if options.check_system:
1298        check_install_system(runner.cfg, logger)
1299        pass