Salome HOME
sat #32302 pip option --build obsolète : integration du patch fourni par Nabil
[tools/sat.git] / commands / config.py
index 3df71fec024b518f2ea0ac060baca3d86fd475df..a5997bb7814fcc265dbeef9d3df3413f44d0eb58 100644 (file)
@@ -53,8 +53,14 @@ parser.add_option('l', 'list', 'boolean', 'list',
     _("Optional: list all available applications."))
 parser.add_option('', 'show_patchs', 'boolean', 'show_patchs',
     _("Optional: synthetic list of all patches used in the application"))
+parser.add_option('', 'show_dependencies', 'boolean', 'show_dependencies',
+    _("Optional: list of product dependencies in the application"))
+parser.add_option('', 'show_install', 'boolean', 'show_install',
+    _("Optional: synthetic list of all install directories in the application"))
 parser.add_option('', 'show_properties', 'boolean', 'show_properties',
     _("Optional: synthetic list of all properties used in the application"))
+parser.add_option('', 'check_system', 'boolean', 'check_system',
+    _("Optional: check if system products are installed"))
 parser.add_option('c', 'copy', 'boolean', 'copy',
     _("""Optional: copy a config file to the personal config files directory.
 WARNING: the included files are not copied.
@@ -133,6 +139,10 @@ class ConfigManager:
         var['srcDir'] =  osJoin(var['salometoolsway'], 'src')
         var['internal_dir'] =  osJoin(var['srcDir'], 'internal_config')
         var['sep']= os.path.sep
+        if src.architecture.is_windows():
+          var['scriptExtension'] = '.bat'
+        else:
+          var['scriptExtension'] = '.sh'
         
         # datadir has a default location
         var['datadir'] =  osJoin(var['salometoolsway'], 'data')
@@ -255,8 +265,12 @@ class ConfigManager:
         src.pyconf.streamOpener = ConfigOpener([
                              osJoin(cfg.VARS.srcDir, 'internal_config')])
         try:
-            internal_cfg = src.pyconf.Config(open( osJoin(cfg.VARS.srcDir,
-                                    'internal_config', 'salomeTools.pyconf')))
+            if src.architecture.is_windows(): # special internal config for windows
+                internal_cfg = src.pyconf.Config(open( osJoin(cfg.VARS.srcDir,
+                                        'internal_config', 'salomeTools_win.pyconf')))
+            else:
+                internal_cfg = src.pyconf.Config(open( osJoin(cfg.VARS.srcDir,
+                                        'internal_config', 'salomeTools.pyconf')))
         except src.pyconf.ConfigError as e:
             raise src.SatException(_("Error in configuration file:"
                                      " salomeTools.pyconf\n  %(error)s") % \
@@ -297,7 +311,7 @@ class ConfigManager:
             cfg.LOCAL.archive_dir = os.path.abspath( osJoin(cfg.VARS.salometoolsway, "..", "ARCHIVES"))
 
         # if the sat tag was not set permanently by user
-        if cfg.LOCAL.tag == None:
+        if cfg.LOCAL.tag == "unknown":
             # get the tag with git, and store it
             sat_version=src.system.git_describe(cfg.VARS.salometoolsway) 
             if sat_version == False:
@@ -395,7 +409,9 @@ class ConfigManager:
                          "LICENCEPATH"]:
                 if PATH not in cfg.PROJECTS.projects[project]:
                     continue
-                cfg.PATHS[PATH].append(cfg.PROJECTS.projects[project][PATH], "")
+                pathlist=cfg.PROJECTS.projects[project][PATH].split(":")
+                for path in pathlist:
+                    cfg.PATHS[PATH].append(path, "")
         
         # apply overwrite from command line if needed
         for rule in self.get_command_line_overrides(options, ["PATHS"]):
@@ -451,7 +467,6 @@ class ConfigManager:
         
             else:
                 cfg['open_application'] = 'yes'
-
         # =====================================================================
         # Load product config files in PRODUCTS section
         products_cfg = src.pyconf.Config()
@@ -514,6 +529,12 @@ class ConfigManager:
         for rule in self.get_command_line_overrides(options, ["USER"]):
             exec('cfg.' + rule) # this cannot be factorize because of the exec
         
+        # remove application products "blacklisted" in rm_products field
+        if "APPLICATION" in cfg and "rm_products" in cfg.APPLICATION:
+            for prod_to_remove in cfg.APPLICATION.rm_products:
+                cfg.APPLICATION.products.__delitem__(prod_to_remove)
+            # remove rm_products section after usage
+            cfg.APPLICATION.__delitem__("rm_products")
         return cfg
 
     def set_user_config_file(self, config):
@@ -570,15 +591,6 @@ class ConfigManager:
                                  'evince', 
                                  "This is the pdf_viewer used "
                                  "to read pdf documentation\n")
-# CNC 25/10/17 : plus nécessaire a priori
-#        user_cfg.USER.addMapping("base",
-#                                 src.pyconf.Reference(
-#                                            user_cfg,
-#                                            src.pyconf.DOLLAR,
-#                                            'workdir  + $VARS.sep + "BASE"'),
-#                                 "The products installation base (could be "
-#                                 "ignored if this key exists in the local.pyconf"
-#                                 " file of salomTools).\n")
 
         src.ensure_path_exists(config.VARS.personalDir)
         src.ensure_path_exists( osJoin(config.VARS.personalDir,
@@ -641,6 +653,10 @@ def show_product_info(config, name, logger):
     if "opt_depend" in pinfo:
         src.printcolors.print_value(logger, "optional", sorted(pinfo.opt_depend), 2)
 
+    if "build_depend" in pinfo:
+        src.printcolors.print_value(logger, "build depend on", sorted(pinfo.build_depend), 2)
+
+
     # information on pyconf
     logger.write("\n", 2)
     logger.write(src.printcolors.printcLabel("configuration:") + "\n", 2)
@@ -731,6 +747,12 @@ def show_product_info(config, name, logger):
             logger.write("  " + 
                          src.printcolors.printcWarning(_("no install dir")) + 
                          "\n", 2)
+
+        src.printcolors.print_value(logger, "debug ", pinfo.debug, 2)
+        src.printcolors.print_value(logger, "verbose ", pinfo.verbose, 2)
+        src.printcolors.print_value(logger, "hpc ", pinfo.hpc, 2)
+        src.printcolors.print_value(logger, "dev ", pinfo.dev, 2)
+
     else:
         logger.write("\n", 2)
         msg = _("This product does not compile")
@@ -778,6 +800,150 @@ def show_patchs(config, logger):
   else:
     logger.write("No patchs found\n", 1)
 
+def check_install_system(config, logger):
+  '''Check the installation of all (declared) system products
+
+  :param config Config: the global configuration.
+  :param logger Logger: The logger instance to use for the display
+  '''
+  # get the command to use for checking the system dependencies
+  # (either rmp or apt)
+  check_cmd=src.system.get_pkg_check_cmd(config.VARS.dist_name)
+  logger.write("\nCheck the system dependencies declared in the application\n",1)
+  pkgmgr=check_cmd[0]
+  run_dep_ko=[] # list of missing run time dependencies
+  build_dep_ko=[] # list of missing compile time dependencies
+  for product in sorted(config.APPLICATION.products):
+    try:
+      product_info = src.product.get_product_config(config, product)
+      if src.product.product_is_native(product_info):
+        # if the product is native, get (in two dictionnaries the runtime and compile time 
+        # system dependencies with the status (OK/KO)
+        run_pkg,build_pkg=src.product.check_system_dep(config.VARS.dist, check_cmd, product_info)
+        #logger.write("\n*** %s ***\n" % product, 1)
+        for pkg in run_pkg:
+            logger.write("\n   - "+pkg + " : " + run_pkg[pkg], 1)
+            if "KO" in run_pkg[pkg]:
+                run_dep_ko.append(pkg)
+        for pkg in build_pkg:
+            logger.write("\n   - "+pkg + " : " + build_pkg[pkg], 1)
+            if "KO" in build_pkg[pkg]:
+                build_dep_ko.append(pkg)
+        #  logger.write(src.printcolors.printcInfo("    %s\n" % i), 1)
+
+    except Exception as e:
+      msg = "\nproblem with the check of system prerequisite %s\n%s\n" % (product, str(e))
+      logger.error(msg)
+      raise Exception(msg)
+
+  logger.write("\n\n",1)
+  if run_dep_ko:
+      msg="Some run time system dependencies are missing!\n"+\
+          "Please install them with %s before running salome" % pkgmgr
+      logger.warning(msg)
+      logger.write("missing run time dependencies : ",1)
+      for md in run_dep_ko: 
+        logger.write(md+" ",1)
+      logger.write("\n\n")
+        
+  if build_dep_ko:
+      msg="Some compile time system dependencies are missing!\n"+\
+          "Please install them with %s before compiling salome" % pkgmgr
+      logger.warning(msg)
+      logger.write("missing compile time dependencies : ",1)
+      for md in build_dep_ko: 
+        logger.write(md+" ",1)
+      logger.write("\n\n")
+    
+
+def show_dependencies(config, products, logger):
+    '''Prints dependencies of products in the application.
+
+    :param config Config: the global configuration.
+    :param logger Logger: The logger instance to use for the display
+    '''
+
+    from compile import get_dependencies_graph,depth_search_graph,find_path_graph
+    # Get the list of all application products, and create its dependency graph
+    all_products_infos = src.product.get_products_infos(config.APPLICATION.products,config)
+    all_products_graph=get_dependencies_graph(all_products_infos, compile_time=False)
+
+    products_list=[]
+    product_liste_name=""
+    if products is None:
+        products_list=config.APPLICATION.products
+        products_graph = all_products_graph
+    else:
+        # 1. Extend the list with all products that depends upon the given list of products
+        products_list=products
+        product_liste_name="_".join(products)
+        visited=[]
+        for p_name in products_list:
+            visited=depth_search_graph(all_products_graph, p_name, visited)
+        products_infos = src.product.get_products_infos(visited, config)
+        products_graph = get_dependencies_graph(products_infos, compile_time=False)
+
+        # 2. Extend the list with all the dependencies of the given list of products
+        children=[]
+        for n in all_products_graph:
+            # for all products (that are not in products_list):
+            # if we we find a path from the product to the product list,
+            # then we product is a child and we add it to the children list 
+            if (n not in children) and (n not in products_list):
+                if find_path_graph(all_products_graph, n, products_list):
+                    children = children + [n]
+        products_infos_rev = src.product.get_products_infos(children, config)
+        products_graph_rev = get_dependencies_graph(products_infos_rev, compile_time=False)
+
+    logger.write("Dependency graph (python format)\n%s\n" % products_graph, 3)
+
+    gv_file_name='%s_%s_dep.gv' % (config.VARS.application,product_liste_name)
+    logger.write("\nDependency graph (graphviz format) written in file %s\n" % 
+                 src.printcolors.printcLabel(gv_file_name), 3)
+    with open(gv_file_name,"w") as f:
+        f.write("digraph G {\n")
+        for p in products_graph:
+            for dep in products_graph[p]:
+                f.write ("\t%s -> %s\n" % (p,dep))
+        f.write("}\n")
+        
+
+    if products is not None:
+        # if a list of products was given, produce also the reverse dependencies
+        gv_revfile_name='%s_%s_rev_dep.gv' % (config.VARS.application,product_liste_name)
+        logger.write("\nReverse dependency graph (graphviz format) written in file %s\n" % 
+                 src.printcolors.printcLabel(gv_revfile_name), 3)
+        with open(gv_revfile_name,"w") as rf:
+            rf.write("digraph G {\n")
+            for p in products_graph_rev:
+                for dep in products_graph_rev[p]:
+                    rf.write ("\t%s -> %s\n" % (p,dep))
+            rf.write("}\n")
+    
+    graph_cmd = "dot -Tpdf %s -o %s.pdf" % (gv_file_name,gv_file_name)
+    logger.write("\nTo generate a graph use dot tool : \n  %s" % 
+                 src.printcolors.printcLabel(graph_cmd), 3)
+def show_install_dir(config, logger):
+  '''Prints all the used installed directories in the application.
+
+  :param config Config: the global configuration.
+  :param logger Logger: The logger instance to use for the display
+  '''
+  for product in sorted(config.APPLICATION.products):
+    try:
+      product_info = src.product.get_product_config(config, product)
+      install_path=src.Path(product_info.install_dir)
+      if (src.product.product_is_native(product_info)):
+          install_path="Native"
+      elif (src.product.product_is_fixed(product_info)):
+          install_path+=" (Fixed)"
+      logger.write("%s : %s\n" % (product, install_path) , 1)
+    except Exception as e:
+      msg = "problem on product %s\n%s\n" % (product, str(e))
+      logger.error(msg)
+  logger.write("\n", 1)
+
 
 def show_properties(config, logger):
   '''Prints all the used properties in the application.
@@ -785,18 +951,23 @@ def show_properties(config, logger):
   :param config Config: the global configuration.
   :param logger Logger: The logger instance to use for the display
   '''
+  if "properties" in config.APPLICATION:
+      # some properties are defined at application level, we display them
+      logger.write("Application properties:\n", 1)
+      for prop in config.APPLICATION.properties:
+          logger.write(src.printcolors.printcInfo("    %s : %s\n" % (prop, config.APPLICATION.properties[prop])), 1)
   oneOrMore = False
   for product in sorted(config.APPLICATION.products):
     try:
       product_info = src.product.get_product_config(config, product)
       done = False
       try:
-        for i in product_info.properties:
+        for prop in product_info.properties:
           if not done:
             logger.write("%s:\n" % product, 1)
             done = True
           oneOrMore = True
-          logger.write(src.printcolors.printcInfo("    %s\n" % i), 1)
+          logger.write(src.printcolors.printcInfo("    %s : %s\n" % (prop, product_info.properties[prop])), 1)
       except Exception as e:
         pass
     except Exception as e:
@@ -1094,12 +1265,35 @@ def run(args, runner, logger):
         logger.write("\n", 2, False)
         show_patchs(runner.cfg, logger)
 
+    # case : give a synthetic view of all install directories used in the application
+    if options.show_install:
+        src.check_config_has_application(runner.cfg)
+        # Print some informations
+        logger.write(_('Installation directories of application %s\n') %
+                    src.printcolors.printcLabel(runner.cfg.VARS.application), 3)
+        logger.write("\n", 2, False)
+        show_install_dir(runner.cfg, logger)
+
+    # case : give a synthetic view of all dependencies between products of the application
+    if options.show_dependencies:
+        src.check_config_has_application(runner.cfg)
+        # Print some informations
+        logger.write(_('List of run-time dependencies of the application %s, product by product\n') %
+                    src.printcolors.printcLabel(runner.cfg.VARS.application), 3)
+        logger.write("\n", 2, False)
+        show_dependencies(runner.cfg, options.products, logger)
+
     # case : give a synthetic view of all patches used in the application
     if options.show_properties:
         src.check_config_has_application(runner.cfg)
+
         # Print some informations
         logger.write(_('Properties of application %s\n') %
                     src.printcolors.printcLabel(runner.cfg.VARS.application), 3)
         logger.write("\n", 2, False)
         show_properties(runner.cfg, logger)
 
+    # check system prerequisites
+    if options.check_system:
+       check_install_system(runner.cfg, logger)
+       pass