Salome HOME
fix(commands/sources): missing newline in logger
[tools/sat.git] / commands / source.py
index 70d756435ececd679ef9381683e62b7a295ccf12..832e484f0f032653e3522caa83bbfe2e58b87ef7 100644 (file)
 
 import os
 import shutil
+import re
+import subprocess
 
 import src
 import prepare
+import src.debug as DBG
 
-# Define all possible option for log command :  sat log <options>
+# Define all possible option for patch command :  sat patch <options>
 parser = src.options.Options()
-parser.add_option('p', 'product', 'list2', 'products',
-    _('products from which to get the sources. This option can be'
-    ' passed several time to get the sources of several products.'))
-parser.add_option('', 'no_sample', 'boolean', 'no_sample', 
-    _("do not get sources from sample products."))
-parser.add_option('f', 'force', 'boolean', 'force', 
-    _("force to get the sources of the products in development mode."))
-
-def get_source_for_dev(config, product_info, source_dir, force, logger, pad):
+parser.add_option('p', 'products', 'list2', 'products',
+    _('Optional: products from which to get the sources. This option accepts a comma separated list.'))
+
+def get_source_for_dev(config, product_info, source_dir, logger, pad):
     '''The method called if the product is in development mode
     
     :param config Config: The global configuration
@@ -40,34 +38,23 @@ def get_source_for_dev(config, product_info, source_dir, force, logger, pad):
                                the product to be prepared
     :param source_dir Path: The Path instance corresponding to the 
                             directory where to put the sources
-    :param force boolean: True if the --force option was invoked
     :param logger Logger: The logger instance to use for the display and logging
     :param pad int: The gap to apply for the terminal display
     :return: True if it succeed, else False
     :rtype: boolean
     '''
-    retcode = 'N\A'
-    # if the product source directory does not exist,
-    # get it in checkout mode, else, do not do anything
-    # unless the force option is invoked
-    if not os.path.exists(product_info.source_dir) or force:
-        # If the source path exists (it means that force option is invoked)
-        # remove the source path
-        if source_dir.exists():
-            source_dir.rm()
-            
-        # Call the function corresponding to get the sources with True checkout
-        retcode = get_product_sources(config, 
-                                     product_info, 
-                                     True, 
-                                     source_dir,
-                                     force, 
-                                     logger, 
-                                     pad, 
-                                     checkout=True)
-        logger.write("\n", 3, False)
-        # +2 because product name is followed by ': '
-        logger.write(" " * (pad+2), 3, False) 
+       
+    # Call the function corresponding to get the sources with True checkout
+    retcode = get_product_sources(config, 
+                                 product_info, 
+                                 True, 
+                                 source_dir,
+                                 logger, 
+                                 pad, 
+                                 checkout=True)
+    logger.write("\n", 3, False)
+    # +2 because product name is followed by ': '
+    logger.write(" " * (pad+2), 3, False) 
     
     logger.write('dev: %s ... ' % 
                  src.printcolors.printcInfo(product_info.source_dir), 3, False)
@@ -75,7 +62,13 @@ def get_source_for_dev(config, product_info, source_dir, force, logger, pad):
     
     return retcode
 
-def get_source_from_git(product_info, source_dir, logger, pad, is_dev=False):
+def get_source_from_git(config,
+                        product_info,
+                        source_dir,
+                        logger,
+                        pad,
+                        is_dev=False,
+                        environ = None):
     '''The method called if the product is to be get in git mode
     
     :param product_info Config: The configuration specific to 
@@ -85,20 +78,32 @@ def get_source_from_git(product_info, source_dir, logger, pad, is_dev=False):
     :param logger Logger: The logger instance to use for the display and logging
     :param pad int: The gap to apply for the terminal display
     :param is_dev boolean: True if the product is in development mode
+    :param environ src.environment.Environ: The environment to source when
+                                                extracting.
     :return: True if it succeed, else False
     :rtype: boolean
     '''
     # The str to display
     coflag = 'git'
 
-    # Get the repository address. (from repo_dev key if the product is 
-    # in dev mode.
-    if is_dev and 'repo_dev' in product_info.git_info:
+    use_repo_dev=False
+    if ("APPLICATION" in config  and
+            "properties"  in config.APPLICATION  and
+            "repo_dev"    in config.APPLICATION.properties  and
+            config.APPLICATION.properties.repo_dev == "yes") :
+                use_repo_dev=True
+
+    # Get the repository address.
+    # If the application has the repo_dev property
+    # Or if the product is in dev mode
+    # Then we use repo_dev if the key exists
+    if (is_dev or use_repo_dev) and 'repo_dev' in product_info.git_info:
         coflag = src.printcolors.printcHighlight(coflag.upper())
         repo_git = product_info.git_info.repo_dev    
     else:
         repo_git = product_info.git_info.repo    
-        
+
+
     # Display informations
     logger.write('%s:%s' % (coflag, src.printcolors.printcInfo(repo_git)), 3, 
                  False)
@@ -111,15 +116,39 @@ def get_source_from_git(product_info, source_dir, logger, pad, is_dev=False):
                  False)
     logger.flush()
     logger.write('\n', 5, False)
-    # Call the system function that do the extraction in git mode
-    retcode = src.system.git_extract(repo_git,
-                                 product_info.git_info.tag,
-                                 source_dir, logger)
+
+    git_options= ''
+    if "git_options" in product_info.git_info:
+        git_options = product_info.git_info.git_options
+
+    sub_dir = None
+    # what do we do with git tree structure and history
+    if is_dev and "sub_dir" in product_info.git_info:
+        logger.error("dev mode for product is incompatible with 'sub_dir' option")
+        return False
+
+    if not is_dev and "sub_dir" in product_info.git_info:
+        sub_dir = product_info.git_info.sub_dir
+
+    if sub_dir is None:
+      # Call the system function that do the extraction in git mode
+      retcode = src.system.git_extract(repo_git,
+                                   product_info.git_info.tag, git_options,
+                                   source_dir, logger, environ)
+    else:
+      # Call the system function that do the extraction of a sub_dir in git mode
+      logger.write("sub_dir:%s " % sub_dir, 3)
+      retcode = src.system.git_extract_sub_dir(repo_git,
+                                   product_info.git_info.tag,git_options,
+                                   source_dir, sub_dir, logger, environ)
+
+
     return retcode
 
-def get_source_from_archive(product_info, source_dir, logger):
+def get_source_from_archive(config, product_info, source_dir, logger):
     '''The method called if the product is to be get in archive mode
     
+    :param config Config: The global configuration
     :param product_info Config: The configuration specific to 
                                the product to be prepared
     :param source_dir Path: The Path instance corresponding to the 
@@ -128,10 +157,27 @@ def get_source_from_archive(product_info, source_dir, logger):
     :return: True if it succeed, else False
     :rtype: boolean
     '''
+
+    # check if pip should be used : pip mode id activated if the application and product have pip property
+    if (src.appli_test_property(config,"pip", "yes") and 
+       src.product.product_test_property(product_info,"pip", "yes")):
+        pip_msg = "PIP : do nothing, product will be downloaded later at compile time "
+        logger.write(pip_msg, 3) 
+        return True
+
     # check archive exists
     if not os.path.exists(product_info.archive_info.archive_name):
-        raise src.SatException(_("Archive not found: '%s'") % 
-                               product_info.archive_info.archive_name)
+        # The archive is not found on local file system (ARCHIVEPATH)
+        # We try ftp!
+        logger.write("\n   The archive is not found on local file system, we try ftp\n", 3)
+        ret=src.find_file_in_ftppath(product_info.archive_info.archive_name, 
+                                     config.PATHS.ARCHIVEFTP, config.LOCAL.archive_dir, logger)
+        if ret:
+            # archive was found on ftp and stored in ret
+            product_info.archive_info.archive_name=ret
+        else:
+            raise src.SatException(_("Archive not found in ARCHIVEPATH, nor on ARCHIVEFTP: '%s'") % 
+                                   product_info.archive_info.archive_name)
 
     logger.write('arc:%s ... ' % 
                  src.printcolors.printcInfo(product_info.archive_info.archive_name),
@@ -153,7 +199,43 @@ def get_source_from_archive(product_info, source_dir, logger):
     
     return retcode
 
-def get_source_from_cvs(user, product_info, source_dir, checkout, logger, pad):
+def get_source_from_dir(product_info, source_dir, logger):
+    
+    if "dir_info" not in product_info:
+        msg = _("Error: you must put a dir_info section"
+                " in the file %s.pyconf" % product_info.name)
+        logger.write("\n%s\n" % src.printcolors.printcError(msg), 1)
+        return False
+
+    if "dir" not in product_info.dir_info:
+        msg = _("Error: you must put a dir in the dir_info section"
+                " in the file %s.pyconf" % product_info.name)
+        logger.write("\n%s\n" % src.printcolors.printcError(msg), 1)
+        return False
+
+    # check that source exists
+    if not os.path.exists(product_info.dir_info.dir):
+        msg = _("Error: the dir %s defined in the file"
+                " %s.pyconf does not exists" % (product_info.dir_info.dir,
+                                                product_info.name))
+        logger.write("\n%s\n" % src.printcolors.printcError(msg), 1)
+        return False
+    
+    logger.write('DIR: %s ... ' % src.printcolors.printcInfo(
+                                           product_info.dir_info.dir), 3)
+    logger.flush()
+
+    retcode = src.Path(product_info.dir_info.dir).copy(source_dir)
+    
+    return retcode
+    
+def get_source_from_cvs(user,
+                        product_info,
+                        source_dir,
+                        checkout,
+                        logger,
+                        pad,
+                        environ = None):
     '''The method called if the product is to be get in cvs mode
     
     :param user str: The user to use in for the cvs command
@@ -164,6 +246,8 @@ def get_source_from_cvs(user, product_info, source_dir, checkout, logger, pad):
     :param checkout boolean: If True, get the source in checkout mode
     :param logger Logger: The logger instance to use for the display and logging
     :param pad int: The gap to apply for the terminal display
+    :param environ src.environment.Environ: The environment to source when
+                                                extracting.
     :return: True if it succeed, else False
     :rtype: boolean
     '''
@@ -211,10 +295,15 @@ def get_source_from_cvs(user, product_info, source_dir, checkout, logger, pad):
                                  product_info.cvs_info.product_base,
                                  product_info.cvs_info.tag,
                                  product_info.cvs_info.source,
-                                 source_dir, logger, checkout)
+                                 source_dir, logger, checkout, environ)
     return retcode
 
-def get_source_from_svn(user, product_info, source_dir, checkout, logger):
+def get_source_from_svn(user,
+                        product_info,
+                        source_dir,
+                        checkout,
+                        logger,
+                        environ = None):
     '''The method called if the product is to be get in svn mode
     
     :param user str: The user to use in for the svn command
@@ -224,6 +313,8 @@ def get_source_from_svn(user, product_info, source_dir, checkout, logger):
                             directory where to put the sources
     :param checkout boolean: If True, get the source in checkout mode
     :param logger Logger: The logger instance to use for the display and logging
+    :param environ src.environment.Environ: The environment to source when
+                                                extracting.
     :return: True if it succeed, else False
     :rtype: boolean
     '''
@@ -243,14 +334,14 @@ def get_source_from_svn(user, product_info, source_dir, checkout, logger):
                                      product_info.svn_info.tag,
                                      source_dir, 
                                      logger, 
-                                     checkout)
+                                     checkout,
+                                     environ)
     return retcode
 
 def get_product_sources(config, 
                        product_info, 
                        is_dev, 
                        source_dir,
-                       force,
                        logger, 
                        pad, 
                        checkout=False):
@@ -262,51 +353,77 @@ def get_product_sources(config,
     :param is_dev boolean: True if the product is in development mode
     :param source_dir Path: The Path instance corresponding to the 
                             directory where to put the sources
-    :param force boolean: True if the --force option was invoked
     :param logger Logger: The logger instance to use for the display and logging
     :param pad int: The gap to apply for the terminal display
     :param checkout boolean: If True, get the source in checkout mode
     :return: True if it succeed, else False
     :rtype: boolean
     '''
+    
+    # Get the application environment
+    logger.write(_("Set the application environment\n"), 5)
+    env_appli = src.environment.SalomeEnviron(config,
+                                      src.environment.Environ(dict(os.environ)))
+    env_appli.set_application_env(logger)
+    
+    # Call the right function to get sources regarding the product settings
     if not checkout and is_dev:
         return get_source_for_dev(config, 
                                    product_info, 
                                    source_dir, 
-                                   force, 
                                    logger, 
                                    pad)
 
     if product_info.get_source == "git":
-        return get_source_from_git(product_info, source_dir, logger, pad, 
-                                    is_dev)
+        return get_source_from_git(config, product_info, source_dir, logger, pad, 
+                                    is_dev, env_appli)
 
     if product_info.get_source == "archive":
-        return get_source_from_archive(product_info, source_dir, logger)
+        return get_source_from_archive(config, product_info, source_dir, logger)
+
+    if product_info.get_source == "dir":
+        return get_source_from_dir(product_info, source_dir, logger)
     
     if product_info.get_source == "cvs":
         cvs_user = config.USER.cvs_user
-        return get_source_from_cvs(cvs_user, 
-                                    product_info, 
-                                    source_dir, 
-                                    checkout, 
-                                    logger,
-                                    pad)
+        return get_source_from_cvs(cvs_user, product_info, source_dir, 
+                                    checkout, logger, pad, env_appli)
 
     if product_info.get_source == "svn":
         svn_user = config.USER.svn_user
         return get_source_from_svn(svn_user, product_info, source_dir, 
-                                    checkout,
-                                    logger)
+                                    checkout, logger, env_appli)
 
     if product_info.get_source == "native":
-        # skip
-        logger.write('%s ...' % _("native (ignored)"), 3, False)
-        return True        
+        # for native products we check the corresponding system packages are installed
+        logger.write("Native : Checking system packages are installed\n" , 3)
+        check_cmd=src.system.get_pkg_check_cmd(config.VARS.dist_name) # (either rmp or apt)
+        run_pkg,build_pkg=src.product.check_system_dep(config.VARS.dist, check_cmd, product_info)
+        result=True
+        for pkg in run_pkg:
+            logger.write(" - " + pkg + " : " + run_pkg[pkg] + '\n', 1)
+            if "KO" in run_pkg[pkg]:
+                result=False
+        for pkg in build_pkg:
+            logger.write(" - " + pkg + " : " + build_pkg[pkg] + '\n', 1)
+            if "KO" in build_pkg[pkg]:
+                result=False
+        if result==False:
+            logger.error("some system dependencies are missing, please install them with "+\
+                         check_cmd[0])
+        return result        
 
     if product_info.get_source == "fixed":
         # skip
-        logger.write('%s ...' % _("fixed (ignored)"), 3, False)
+        logger.write('%s  ' % src.printcolors.printc(src.OK_STATUS),
+                     3,
+                     False)
+        msg = "FIXED : %s\n" % product_info.install_dir
+
+        if not os.path.isdir(product_info.install_dir):
+            logger.warning("The fixed path do not exixts!! Please check it : %s\n" % product_info.install_dir)
+        else:
+            logger.write(msg, 3)
         return True  
 
     # if the get_source is not in [git, archive, cvs, svn, fixed, native]
@@ -316,12 +433,11 @@ def get_product_sources(config,
     logger.flush()
     return False
 
-def get_all_product_sources(config, products, force, logger):
+def get_all_product_sources(config, products, logger):
     '''Get all the product sources.
     
     :param config Config: The global configuration
     :param products List: The list of tuples (product name, product informations)
-    :param force boolean: True if the --force option was invoked
     :param logger Logger: The logger instance to be used for the logging
     :return: the tuple (number of success, dictionary product_name/success_fail)
     :rtype: (int,dict)
@@ -337,6 +453,7 @@ def get_all_product_sources(config, products, force, logger):
         max_product_name_len = max(map(lambda l: len(l), products[0])) + 4
     
     # The loop on all the products from which to get the sources
+    # DBG.write("source.get_all_product_sources config id", id(config), True)
     for product_name, product_info in products:
         # get product name, product informations and the directory where to put
         # the sources
@@ -354,19 +471,17 @@ def get_all_product_sources(config, products, force, logger):
         # Remove the existing source directory if 
         # the product is not in development mode
         is_dev = src.product.product_is_dev(product_info)
-        if source_dir.exists() and not is_dev:
-            logger.write("  " + _('remove %s') % source_dir, 4)
-            logger.write("\n  ", 4, False)
-            source_dir.rm()
+        if source_dir.exists():
+            logger.write('%s  ' % src.printcolors.printc(src.OK_STATUS), 3, False)
+            msg = _("INFO : Not doing anything because the source directory already exists:\n    %s\n") % source_dir
+            logger.write(msg, 3)
+            good_result = good_result + 1
+            # Do not get the sources and go to next product
+            continue
 
         # Call to the function that get the sources for one product
-        retcode = get_product_sources(config, 
-                                     product_info, 
-                                     is_dev, 
-                                     source_dir,
-                                     force, 
-                                     logger, 
-                                     max_product_name_len, 
+        retcode = get_product_sources(config, product_info, is_dev, 
+                                     source_dir, logger, max_product_name_len, 
                                      checkout=False)
         
         '''
@@ -374,17 +489,20 @@ def get_all_product_sources(config, products, force, logger):
             if product_info.no_rpath:
                 hack_no_rpath(config, product_info, logger)
         '''
+        
+        # Check that the sources are correctly get using the files to be tested
+        # in product information
+        if retcode:
+            check_OK, wrong_path = check_sources(product_info, logger)
+            if not check_OK:
+                # Print the missing file path
+                msg = _("The required file %s does not exists. " % wrong_path)
+                logger.write(src.printcolors.printcError("\nERROR: ") + msg, 3)
+                retcode = False
 
         # show results
         results[product_name] = retcode
-        if retcode == 'N\A':
-            # The case where the product was not prepared because it is 
-            # in development mode
-            res =(src.printcolors.printc(src.OK_STATUS) + 
-                    src.printcolors.printcWarning(_(
-                                    ' source directory already exists')))
-            good_result = good_result + 1
-        elif retcode:
+        if retcode:
             # The case where it succeed
             res = src.OK_STATUS
             good_result = good_result + 1
@@ -393,10 +511,36 @@ def get_all_product_sources(config, products, force, logger):
             res = src.KO_STATUS
         
         # print the result
-        logger.write('%s\n' % src.printcolors.printc(res), 3, False)
+        if not(src.product.product_is_fixed(product_info) or 
+               src.product.product_is_native(product_info)):
+            logger.write('%s\n' % src.printcolors.printc(res), 3, False)
 
     return good_result, results
 
+def check_sources(product_info, logger):
+    '''Check that the sources are correctly get, using the files to be tested
+       in product information
+    
+    :param product_info Config: The configuration specific to 
+                                the product to be prepared
+    :return: True if the files exists (or no files to test is provided).
+    :rtype: boolean
+    '''
+    # Get the files to test if there is any
+    if ("present_files" in product_info and 
+        "source" in product_info.present_files):
+        l_files_to_be_tested = product_info.present_files.source
+        for file_path in l_files_to_be_tested:
+            # The path to test is the source directory 
+            # of the product joined the file path provided
+            path_to_test = os.path.join(product_info.source_dir, file_path)
+            logger.write(_("\nTesting existence of file: \n"), 5)
+            logger.write(path_to_test, 5)
+            if not os.path.exists(path_to_test):
+                return False, path_to_test
+            logger.write(src.printcolors.printcSuccess(" OK\n"), 5)
+    return True, ""
+
 def description():
     '''method that is called when salomeTools is called with --help option.
     
@@ -404,11 +548,13 @@ def description():
     :rtype: str
     '''
     return _("The source command gets the sources of the application products "
-             "from cvs, git, an archive or a directory..")
+             "from cvs, git or an archive.\n\nexample:"
+             "\nsat source SALOME-master --products KERNEL,GUI")
   
 def run(args, runner, logger):
     '''method that is called when salomeTools is called with source parameter.
     '''
+    DBG.write("source.run()", args)
     # Parse the options
     (options, args) = parser.parse_args(args)
     
@@ -418,25 +564,15 @@ def run(args, runner, logger):
     # Print some informations
     logger.write(_('Getting sources of the application %s\n') % 
                 src.printcolors.printcLabel(runner.cfg.VARS.application), 1)
-    src.printcolors.print_value(logger, 'out_dir', 
-                                runner.cfg.APPLICATION.out_dir, 2)
+    src.printcolors.print_value(logger, 'workdir', 
+                                runner.cfg.APPLICATION.workdir, 2)
     logger.write("\n", 2, False)
-    
-    # Get the force option if it was passed
-    force = options.force
-    if force:
-        msg = _("Warning: the --force option has effect only "
-                "on products in development mode\n\n")
-        logger.write(src.printcolors.printcWarning(msg))
-    
+       
     # Get the products list with products informations regarding the options
-    products_infos = prepare.get_products_list(options, runner.cfg, logger)
+    products_infos = src.product.get_products_list(options, runner.cfg, logger)
     
     # Call to the function that gets all the sources
-    good_result, results = get_all_product_sources(runner.cfg, 
-                                                  products_infos,
-                                                  force,
-                                                  logger)
+    good_result, results = get_all_product_sources(runner.cfg, products_infos, logger)
 
     # Display the results (how much passed, how much failed, etc...)
     status = src.OK_STATUS