Salome HOME
sat #18867 : pour les url des bases git : substitution des references par leur valeur...
[tools/sat.git] / commands / compile.py
index 15a84250dd2e5202611e9b1b2fec4dd6e966acdb..984363c0db1e9c51683e2a84a866b15b83807cb7 100644 (file)
@@ -34,6 +34,10 @@ except NameError:
 parser = src.options.Options()
 parser.add_option('p', 'products', 'list2', 'products',
     _('Optional: products to compile. This option accepts a comma separated list.'))
+parser.add_option('f', 'force', 'boolean', 'force',
+    'Optional: force the compilation of product, even if it is already installed. The BUILD directory is cleaned before compilation.')
+parser.add_option('u', 'update', 'boolean', 'update',
+    'Optional: update mode, compile only products which sources has changed, including the dependencies.')
 parser.add_option('', 'with_fathers', 'boolean', 'fathers',
     _("Optional: build all necessary products to the given product (KERNEL is "
       "build before building GUI)."), False)
@@ -62,10 +66,16 @@ parser.add_option('', 'clean_build_after', 'boolean', 'clean_build_after',
 
 # from sat product infos, represent the product dependencies in a simple python graph
 # keys are nodes, the list of dependencies are values
-def get_dependencies_graph(p_infos):
+def get_dependencies_graph(p_infos, compile_time=True):
     graph={}
     for (p_name,p_info) in p_infos:
-        graph[p_name]=p_info.depend
+        depprod=[]
+        for d in p_info.depend:
+            depprod.append(d)
+        if compile_time and "build_depend" in p_info:
+            for d in p_info.build_depend:
+                depprod.append(d)
+        graph[p_name]=depprod
     return graph
 
 # this recursive function calculates all the dependencies of node start
@@ -129,7 +139,7 @@ def log_res_step(logger, res):
         logger.write("%s \n" % src.printcolors.printcError("KO"), 4)
         logger.flush()
 
-def compile_all_products(sat, config, options, products_infos, all_products_dict, logger):
+def compile_all_products(sat, config, options, products_infos, all_products_dict, all_products_graph, logger):
     '''Execute the proper configuration commands 
        in each product build directory.
 
@@ -137,10 +147,112 @@ def compile_all_products(sat, config, options, products_infos, all_products_dict
     :param products_info list: List of 
                                  (str, Config) => (product_name, product_info)
     :param all_products_dict: Dict of all products 
+    :param all_products_graph: graph of all products 
     :param logger Logger: The logger instance to use for the display and logging
     :return: the number of failing commands.
     :rtype: int
     '''
+    # first loop for the cleaning 
+    check_salome_configuration=False
+    updated_products=[]
+    for p_name_info in products_infos:
+        
+        p_name, p_info = p_name_info
+        if src.product.product_is_salome(p_info):
+            check_salome_configuration=True
+        
+        # nothing to clean for native or fixed products
+        if (not src.product.product_compiles(p_info)) or\
+           src.product.product_is_native(p_info) or\
+           src.product.product_is_fixed(p_info):
+            continue
+
+        # Clean the build and the install directories 
+        # if the corresponding options was called
+        if options.clean_all:
+            sat.clean(config.VARS.application + 
+                      " --products " + p_name + 
+                      " --build --install",
+                      batch=True,
+                      verbose=0,
+                      logger_add_link = logger)
+
+        else:
+            # Clean the the install directory 
+            # if the corresponding option was called
+            if options.clean_install:
+                sat.clean(config.VARS.application + 
+                          " --products " + p_name + 
+                          " --install",
+                          batch=True,
+                          verbose=0,
+                          logger_add_link = logger)
+            
+            # Clean the the install directory 
+            # if the corresponding option was called
+            if options.force:
+                sat.clean(config.VARS.application + 
+                          " --products " + p_name + 
+                          " --build",
+                          batch=True,
+                          verbose=0,
+                          logger_add_link = logger)
+
+            if options.update and src.product.product_is_vcs(p_info):
+            # only VCS products are concerned by update option
+                try: 
+                    do_update=False
+                    if len(updated_products)>0:
+                        # if other products where updated, check that the current product is a child 
+                        # in this case it will be also updated
+                        if find_path_graph(all_products_graph, p_name, updated_products):
+                            logger.write("\nUpdate product %s (child)" % p_name, 5)
+                            do_update=True
+                    if (not do_update) and os.path.isdir(p_info.source_dir) \
+                                       and os.path.isdir(p_info.install_dir):
+                        source_time=os.path.getmtime(p_info.source_dir)
+                        install_time=os.path.getmtime(p_info.install_dir)
+                        if install_time<source_time:
+                            logger.write("\nupdate product %s" % p_name, 5)
+                            do_update=True
+                    if do_update:
+                        updated_products.append(p_name) 
+                        sat.clean(config.VARS.application + 
+                                  " --products " + p_name + 
+                                  " --build --install",
+                                  batch=True,
+                                  verbose=0,
+                                  logger_add_link = logger)
+                except:
+                    pass
+
+    if check_salome_configuration:
+        # For salome applications, we check if the sources of configuration modules are present
+        # configuration modules have the property "configure_dependency"
+        # they are implicit prerequisites of the compilation.
+        res=0
+
+        # get the list of all modules in application 
+        all_products_infos = src.product.get_products_infos(config.APPLICATION.products,
+                                                            config)
+        check_source = True
+        # for configuration modules, check if sources are present
+        for prod in all_products_dict:
+            product_name, product_info = all_products_dict[prod]
+            if ("properties" in product_info and
+                "configure_dependency" in product_info.properties and
+                product_info.properties.configure_dependency == "yes"):
+                check_source = check_source and src.product.check_source(product_info)
+                if not check_source:
+                    logger.write(_("\nERROR : SOURCES of %s not found! It is required for" 
+                                   " the configuration\n" % product_name))
+                    logger.write(_("        Get it with the command : sat prepare %s -p %s \n" % 
+                                  (config.APPLICATION.name, product_name)))
+                    res += 1
+        if res>0:
+            return res  # error configure dependency : we stop the compilation
+
+    # second loop to compile
     res = 0
     for p_name_info in products_infos:
         
@@ -171,29 +283,7 @@ def compile_all_products(sat, config, options, products_infos, all_products_dict
             logger.write("\n", 3, False)
             continue
 
-        # Clean the build and the install directories 
-        # if the corresponding options was called
-        if options.clean_all:
-            log_step(logger, header, "CLEAN BUILD AND INSTALL ")
-            sat.clean(config.VARS.application + 
-                      " --products " + p_name + 
-                      " --build --install",
-                      batch=True,
-                      verbose=0,
-                      logger_add_link = logger)
-
 
-        # Clean the the install directory 
-        # if the corresponding option was called
-        if options.clean_install and not options.clean_all:
-            log_step(logger, header, "CLEAN INSTALL ")
-            sat.clean(config.VARS.application + 
-                      " --products " + p_name + 
-                      " --install",
-                      batch=True,
-                      verbose=0,
-                      logger_add_link = logger)
-        
         # Recompute the product information to get the right install_dir
         # (it could change if there is a clean of the install directory)
         p_info = src.product.get_product_config(config, p_name)
@@ -209,33 +299,9 @@ def compile_all_products(sat, config, options, products_infos, all_products_dict
                 res += 1 # one more error
                 continue
         
-        if src.product.product_is_salome(p_info):
-            # For salome modules, we check if the sources of configuration modules are present
-            # configuration modules have the property "configure_dependency"
-
-            # get the list of all modules in application 
-            all_products_infos = src.product.get_products_infos(config.APPLICATION.products,
-                                                                config)
-            check_source = True
-            # for configuration modules, check if sources are present
-            for prod in all_products_dict:
-                product_name, product_info = all_products_dict[prod]
-                if ("properties" in product_info and
-                    "configure_dependency" in product_info.properties and
-                    product_info.properties.configure_dependency == "yes"):
-                    check_source = check_source and src.product.check_source(product_info)
-                    if not check_source:
-                        logger.write(_("\nERROR : SOURCES of %s not found! It is required for" 
-                                       " the configuration\n" % product_name))
-                        logger.write(_("        Get it with the command : sat prepare %s -p %s \n" % 
-                                      (config.APPLICATION.name, product_name)))
-            if not check_source:
-                # if at least one configuration module is not present, we stop compilation
-                res += 1
-                continue
-        
-        # Check if it was already successfully installed
-        if src.product.check_installation(config, p_info):
+        # if we don't force compilation, check if the was already successfully installed.
+        # we don't compile in this case.
+        if (not options.force) and src.product.check_installation(config, p_info):
             logger.write(_("Already installed"))
             logger.write(_(" in %s" % p_info.install_dir), 4)
             logger.write(_("\n"))
@@ -267,9 +333,15 @@ def compile_all_products(sat, config, options, products_infos, all_products_dict
             #  - the error step is "check", or
             #  - the product is managed by pip and installed in python dir
             do_not_clean_install=False
-            if (error_step == "CHECK") or (is_pip and \
-                src.appli_test_property(config,"pip_install_dir", "python")) :
-                do_not_clean_install=True
+            is_single_dir=(src.appli_test_property(config,"single_install_dir", "yes") and \
+                           src.product.product_test_property(p_info,"single_install_dir", "yes"))
+              
+            if (error_step == "CHECK") or (is_pip and src.appli_test_property(config,"pip_install_dir", "python")) or is_single_dir  :
+                # cases for which we do not want to remove install dir
+                #   for is_single_dir and is_pip, the test to determine if the product is already 
+                #   compiled is based on configuration file, not the directory
+                do_not_clean_install=True 
+
             if not do_not_clean_install:
                 # Clean the install directory if there is any
                 logger.write(_(
@@ -438,6 +510,7 @@ def compile_product_pip(sat,
                              src.environment.Environ(dict(os.environ)),
                              True)
     environ_info = src.product.get_product_dependencies(config,
+                                                        p_name,
                                                         p_info)
     build_environ.silent = (config.USER.output_verbose_level < 5)
     build_environ.set_full_environ(logger, environ_info)
@@ -633,6 +706,9 @@ def run(args, runner, logger):
         if rep.upper() != _("YES").upper():
             return 0
         
+    if options.update and (options.clean_all or options.force or options.clean_install):
+        options.update=False  # update is useless in this case
+
     # check that the command has been called with an application
     src.check_config_has_application( runner.cfg )
 
@@ -693,26 +769,29 @@ def run(args, runner, logger):
             visited_nodes,sorted_nodes=depth_first_topo_graph(all_products_graph, n, visited_nodes,sorted_nodes)
     logger.write("Complete dependency graph topological search (sorting): %s\n" % sorted_nodes, 6)
 
-#   use the sorted list of all products to sort the list of products we have to compile
+    #  Create a dict of all products to facilitate products_infos sorting
+    all_products_dict={}
+    for (pname,pinfo) in all_products_infos:
+        all_products_dict[pname]=(pname,pinfo)
+
+    # Use the sorted list of all products to sort the list of products we have to compile
     sorted_product_list=[]
+    product_list_runtime=[]
+    product_list_compiletime=[]
+
+    # store at beginning compile time products, we need to compile them before!
     for n in sorted_nodes:
         if n in products_list:
             sorted_product_list.append(n)
     logger.write("Sorted list of products to compile : %s\n" % sorted_product_list, 5)
-
     
     # from the sorted list of products to compile, build a sorted list of products infos
-    #  a- create a dict to facilitate products_infos sorting
-    all_products_dict={}
-    for (pname,pinfo) in all_products_infos:
-        all_products_dict[pname]=(pname,pinfo)
-    #  b- build a sorted list of products infos in products_infos
     products_infos=[]
     for product in sorted_product_list:
         products_infos.append(all_products_dict[product])
 
     # for all products to compile, store in "depend_all" field the complete dependencies (recursive) 
-    # (will be used by check_dependencies funvtion)
+    # (will be used by check_dependencies function)
     for pi in products_infos:
         dep_prod=[]
         dep_prod=depth_search_graph(all_products_graph,pi[0], dep_prod)
@@ -721,7 +800,7 @@ def run(args, runner, logger):
 
     # Call the function that will loop over all the products and execute
     # the right command(s)
-    res = compile_all_products(runner, runner.cfg, options, products_infos, all_products_dict, logger)
+    res = compile_all_products(runner, runner.cfg, options, products_infos, all_products_dict, all_products_graph, logger)
     
     # Print the final state
     nb_products = len(products_infos)