Salome HOME
Merge branch 'BR_8_3' of https://codev-tuleap.cea.fr/plugins/git/spns/SAT into BR_8_3
[tools/sat.git] / commands / package.py
index 69c079c97cae108fa4d74dfc25c795305c287a19..aa49bb5086df8766bd3cbbd97430c0ce4c6b4b62 100644 (file)
@@ -21,9 +21,13 @@ import stat
 import shutil
 import datetime
 import tarfile
+import codecs
+import string
 
 import src
 
+from application import get_SALOME_modules
+
 BINARY = "binary"
 SOURCE = "Source"
 PROJECT = "Project"
@@ -32,6 +36,9 @@ SAT = "Sat"
 ARCHIVE_DIR = "ARCHIVES"
 PROJECT_DIR = "PROJECT"
 
+IGNORED_DIRS = [".git", ".svn"]
+IGNORED_EXTENSIONS = []
+
 PROJECT_TEMPLATE = """#!/usr/bin/env python
 #-*- coding:utf-8 -*-
 
@@ -61,12 +68,6 @@ SITE :
     {
         log_dir : $USER.workdir + "/LOGS"
     }
-    test :{
-           tmp_dir_with_application : '/tmp' + $VARS.sep + $VARS.user + """
-"""$VARS.sep + $APPLICATION.name + $VARS.sep + 'test'
-           tmp_dir : '/tmp' + $VARS.sep + $VARS.user + $VARS.sep + 'test'
-           timeout : 150
-           }
 }
 
 PROJECTS :
@@ -97,8 +98,14 @@ parser.add_option('n', 'name', 'string', 'name',
     _('Optional: The name or full path of the archive.'), None)
 parser.add_option('', 'add_files', 'list2', 'add_files',
     _('Optional: The list of additional files to add to the archive.'), [])
+parser.add_option('', 'without_commercial', 'boolean', 'without_commercial',
+    _('Optional: do not add commercial licence.'), False)
+parser.add_option('', 'without_property', 'string', 'without_property',
+    _('Optional: Filter the products by their properties.\n\tSyntax: '
+      '--without_property <property>:<value>'))
+
 
-def add_files(tar, name_archive, d_content, logger):
+def add_files(tar, name_archive, d_content, logger, f_exclude=None):
     '''Create an archive containing all directories and files that are given in
        the d_content argument.
     
@@ -109,6 +116,7 @@ def add_files(tar, name_archive, d_content, logger):
                            d_content[label] = 
                                         (path_on_local_machine, path_in_archive)
     :param logger Logger: the logging instance
+    :param f_exclude Function: the function that filters
     :return: 0 if success, 1 if not.
     :rtype: int
     '''
@@ -127,7 +135,7 @@ def add_files(tar, name_archive, d_content, logger):
         in_archive = os.path.join(name_archive, archive_path)
         # Add it in the archive
         try:
-            tar.add(local_path, arcname=in_archive)
+            tar.add(local_path, arcname=in_archive, exclude=f_exclude)
             logger.write(src.printcolors.printcSuccess(_("OK")), 3)
         except Exception as e:
             logger.write(src.printcolors.printcError(_("KO ")), 3)
@@ -136,11 +144,28 @@ def add_files(tar, name_archive, d_content, logger):
         logger.write("\n", 3)
     return success
 
+def exclude_VCS_and_extensions(filename):
+    ''' The function that is used to exclude from package the link to the 
+        VCS repositories (like .git)
+
+    :param filename Str: The filname to exclude (or not).
+    :return: True if the file has to be exclude
+    :rtype: Boolean
+    '''
+    for dir_name in IGNORED_DIRS:
+        if dir_name in filename:
+            return True
+    for extension in IGNORED_EXTENSIONS:
+        if filename.endswith(extension):
+            return True
+    return False
+
 def produce_relative_launcher(config,
                               logger,
                               file_dir,
                               file_name,
-                              binaries_dir_name):
+                              binaries_dir_name,
+                              with_commercial=True):
     '''Create a specific SALOME launcher for the binary package. This launcher 
        uses relative paths.
     
@@ -179,7 +204,9 @@ def produce_relative_launcher(config,
     launch_file = open(filepath, "w")
     launch_file.write(before)
     # Write
-    writer.write_cfgForPy_file(launch_file, for_package = binaries_dir_name)
+    writer.write_cfgForPy_file(launch_file,
+                               for_package = binaries_dir_name,
+                               with_commercial=with_commercial)
     launch_file.write(after)
     launch_file.close()
     
@@ -195,7 +222,7 @@ def produce_relative_launcher(config,
              stat.S_IXUSR |
              stat.S_IXGRP |
              stat.S_IXOTH)
-    
+
     return filepath
 
 def produce_relative_env_files(config,
@@ -240,6 +267,124 @@ def produce_relative_env_files(config,
     
     return filepath
 
+def produce_install_bin_file(config,
+                             logger,
+                             file_dir,
+                             d_sub,
+                             file_name):
+    '''Create a bash shell script which do substitutions in BIRARIES dir 
+       in order to use it for extra compilations.
+    
+    :param config Config: The global configuration.
+    :param logger Logger: the logging instance
+    :param file_dir str: the directory where to put the files
+    :param d_sub, dict: the dictionnary that contains the substitutions to be done
+    :param file_name str: the name of the install script file
+    :return: the produced file
+    :rtype: str
+    '''  
+    # Write
+    filepath = os.path.join(file_dir, file_name)
+    # open the file and write into it
+    # use codec utf-8 as sat variables are in unicode
+    with codecs.open(filepath, "w", 'utf-8') as installbin_file:
+        installbin_template_path = os.path.join(config.VARS.internal_dir,
+                                        "INSTALL_BIN.template")
+        
+        # build the name of the directory that will contain the binaries
+        binaries_dir_name = "BINARIES-" + config.VARS.dist
+        # build the substitution loop
+        loop_cmd = "for f in $(grep -RIl"
+        for key in d_sub:
+            loop_cmd += " -e "+ key
+        loop_cmd += ' INSTALL); do\n     sed -i "\n'
+        for key in d_sub:
+            loop_cmd += "        s?" + key + "?$(pwd)/" + d_sub[key] + "?g\n"
+        loop_cmd += '            " $f\ndone'
+
+        d={}
+        d["BINARIES_DIR"] = binaries_dir_name
+        d["SUBSTITUTION_LOOP"]=loop_cmd
+        
+        # substitute the template and write it in file
+        content=src.template.substitute(installbin_template_path, d)
+        installbin_file.write(content)
+        # change the rights in order to make the file executable for everybody
+        os.chmod(filepath,
+                 stat.S_IRUSR |
+                 stat.S_IRGRP |
+                 stat.S_IROTH |
+                 stat.S_IWUSR |
+                 stat.S_IXUSR |
+                 stat.S_IXGRP |
+                 stat.S_IXOTH)
+    
+    return filepath
+
+def product_appli_creation_script(config,
+                                  logger,
+                                  file_dir,
+                                  binaries_dir_name):
+    '''Create a script that can produce an application (EDF style) in the binary
+       package.
+    
+    :param config Config: The global configuration.
+    :param logger Logger: the logging instance
+    :param file_dir str: the directory where to put the file
+    :param binaries_dir_name str: the name of the repository where the binaries
+                                  are, in the archive.
+    :return: the path of the produced script file
+    :rtype: Str
+    '''
+    template_name = "create_appli.py.for_bin_packages.template"
+    template_path = os.path.join(config.VARS.internal_dir, template_name)
+    text_to_fill = open(template_path, "r").read()
+    text_to_fill = text_to_fill.replace("TO BE FILLED 1",
+                                        '"' + binaries_dir_name + '"')
+    
+    text_to_add = ""
+    for product_name in get_SALOME_modules(config):
+        product_info = src.product.get_product_config(config, product_name)
+       
+        if src.product.product_is_smesh_plugin(product_info):
+            continue
+
+        if 'install_dir' in product_info and bool(product_info.install_dir):
+            if src.product.product_is_cpp(product_info):
+                # cpp module
+                for cpp_name in src.product.get_product_components(product_info):
+                    line_to_add = ("<module name=\"" + 
+                                   cpp_name + 
+                                   "\" gui=\"yes\" path=\"''' + "
+                                   "os.path.join(dir_bin_name, \"" + 
+                                   cpp_name + "\") + '''\"/>")
+            else:
+                # regular module
+                line_to_add = ("<module name=\"" + 
+                               product_name + 
+                               "\" gui=\"yes\" path=\"''' + "
+                               "os.path.join(dir_bin_name, \"" + 
+                               product_name + "\") + '''\"/>")
+            text_to_add += line_to_add + "\n"
+    
+    filled_text = text_to_fill.replace("TO BE FILLED 2", text_to_add)
+    
+    tmp_file_path = os.path.join(file_dir, "create_appli.py")
+    ff = open(tmp_file_path, "w")
+    ff.write(filled_text)
+    ff.close()
+    
+    # change the rights in order to make the file executable for everybody
+    os.chmod(tmp_file_path,
+             stat.S_IRUSR |
+             stat.S_IRGRP |
+             stat.S_IROTH |
+             stat.S_IWUSR |
+             stat.S_IXUSR |
+             stat.S_IXGRP |
+             stat.S_IXOTH)
+    
+    return tmp_file_path
 
 def binary_package(config, logger, options, tmp_working_dir):
     '''Prepare a dictionary that stores all the needed directories and files to
@@ -262,9 +407,21 @@ def binary_package(config, logger, options, tmp_working_dir):
     l_product_info = src.product.get_products_infos(l_products_name,
                                                     config)
     l_install_dir = []
+    l_source_dir = []
     l_not_installed = []
+    l_sources_not_present = []
     for prod_name, prod_info in l_product_info:
-        # ignore the native and fixed products
+
+        # Add the sources of the products that have the property 
+        # sources_in_package : "yes"
+        if src.get_property_in_product_cfg(prod_info,
+                                           "sources_in_package") == "yes":
+            if os.path.exists(prod_info.source_dir):
+                l_source_dir.append((prod_name, prod_info.source_dir))
+            else:
+                l_sources_not_present.append(prod_name)
+
+        # ignore the native and fixed products for install directories
         if (src.product.product_is_native(prod_info) 
                 or src.product.product_is_fixed(prod_info)
                 or not src.product.product_compiles(prod_info)):
@@ -273,7 +430,18 @@ def binary_package(config, logger, options, tmp_working_dir):
             l_install_dir.append((prod_name, prod_info.install_dir))
         else:
             l_not_installed.append(prod_name)
-    
+        
+        # Add also the cpp generated modules (if any)
+        if src.product.product_is_cpp(prod_info):
+            # cpp module
+            for name_cpp in src.product.get_product_components(prod_info):
+                install_dir = os.path.join(config.APPLICATION.workdir,
+                                           "INSTALL", name_cpp) 
+                if os.path.exists(install_dir):
+                    l_install_dir.append((name_cpp, install_dir))
+                else:
+                    l_not_installed.append(name_cpp)
+        
     # Print warning or error if there are some missing products
     if len(l_not_installed) > 0:
         text_missing_prods = ""
@@ -290,7 +458,24 @@ def binary_package(config, logger, options, tmp_working_dir):
             logger.write("%s\n%s" % (src.printcolors.printcWarning(msg),
                                      text_missing_prods),
                          1)
-    
+
+    # Do the same for sources
+    if len(l_sources_not_present) > 0:
+        text_missing_prods = ""
+        for p_name in l_sources_not_present:
+            text_missing_prods += "-" + p_name + "\n"
+        if not options.force_creation:
+            msg = _("ERROR: there are missing products sources:")
+            logger.write("%s\n%s" % (src.printcolors.printcError(msg),
+                                     text_missing_prods),
+                         1)
+            return None
+        else:
+            msg = _("WARNING: there are missing products sources:")
+            logger.write("%s\n%s" % (src.printcolors.printcWarning(msg),
+                                     text_missing_prods),
+                         1)
     # construct the name of the directory that will contain the binaries
     binaries_dir_name = "BINARIES-" + config.VARS.dist
     
@@ -299,27 +484,45 @@ def binary_package(config, logger, options, tmp_working_dir):
     d_products = {}
     for prod_name, install_dir in l_install_dir:
         path_in_archive = os.path.join(binaries_dir_name, prod_name)
-        d_products[prod_name] = (install_dir, path_in_archive)
+        d_products[prod_name + " (bin)"] = (install_dir, path_in_archive)
+        
+    for prod_name, source_dir in l_source_dir:
+        path_in_archive = os.path.join("SOURCES", prod_name)
+        d_products[prod_name + " (sources)"] = (source_dir, path_in_archive)
 
     # create the relative launcher and add it to the files to add
-    if "profile" in config.APPLICATION:
+    if ("profile" in config.APPLICATION and 
+                                       "product" in config.APPLICATION.profile):
         launcher_name = config.APPLICATION.profile.launcher_name
         launcher_package = produce_relative_launcher(config,
-                                                     logger,
-                                                     tmp_working_dir,
-                                                     launcher_name,
-                                                     binaries_dir_name)
+                                             logger,
+                                             tmp_working_dir,
+                                             launcher_name,
+                                             binaries_dir_name,
+                                             not(options.without_commercial))
     
         d_products["launcher"] = (launcher_package, launcher_name)
+        if options.sources:
+            # if we mix binaries and sources, we add a copy of the launcher, 
+            # prefixed  with "bin",in order to avoid clashes
+            d_products["launcher (copy)"] = (launcher_package, "bin"+launcher_name)
     else:
-        # No profile, it means that there has to be some environment files
-        env_file = produce_relative_env_files(config,
-                                               logger,
-                                               tmp_working_dir,
-                                               binaries_dir_name)
+        # Provide a script for the creation of an application EDF style
+        appli_script = product_appli_creation_script(config,
+                                                    logger,
+                                                    tmp_working_dir,
+                                                    binaries_dir_name)
+        
+        d_products["appli script"] = (appli_script, "create_appli.py")
 
-        d_products["environment file"] = (env_file, "env_launch.sh")
-    
+    # Put also the environment file
+    env_file = produce_relative_env_files(config,
+                                           logger,
+                                           tmp_working_dir,
+                                           binaries_dir_name)
+
+    d_products["environment file"] = (env_file, "env_launch.sh")
+      
     return d_products
 
 def source_package(sat, config, logger, options, tmp_working_dir):
@@ -381,7 +584,8 @@ def source_package(sat, config, logger, options, tmp_working_dir):
         
         d_sat["sat link"] = (tmp_satlink_path, "sat")
     
-    return src.merge_dicts(d_archives, d_archives_vcs, d_project, d_sat)
+    d_source = src.merge_dicts(d_archives, d_archives_vcs, d_project, d_sat)
+    return d_source
 
 def get_archives(config, logger):
     '''Find all the products that are get using an archive and all the products
@@ -552,10 +756,6 @@ def create_project_for_src_package(config, tmp_working_dir, with_vcs):
     lproducts_name = config.APPLICATION.products.keys()
     l_products = src.product.get_products_infos(lproducts_name, config)
     for p_name, p_info in l_products:
-        # ignore native and fixed products
-        if (src.product.product_is_native(p_info) or 
-                src.product.product_is_fixed(p_info)):
-            continue
         find_product_scripts_and_pyconf(p_name,
                                         p_info,
                                         config,
@@ -737,50 +937,106 @@ def project_package(project_file_path, tmp_working_dir):
     
     return d_project
 
-def add_readme(config, package_type, where):
+def add_readme(config, options, where):
     readme_path = os.path.join(where, "README")
-    f = open(readme_path, 'w')
-    # prepare substitution dictionary
-    d = dict()
-    if package_type == BINARY:
-        d['application'] = config.VARS.application
+    with codecs.open(readme_path, "w", 'utf-8') as f:
+
+    # templates for building the header
+        readme_header="""
+# This package was generated with sat $version
+# Date: $date
+# User: $user
+# Distribution : $dist
+
+In the following, $$ROOT represents the directory where you have installed 
+SALOME (the directory where this file is located).
+
+"""
+        readme_compilation_with_binaries="""
+
+compilation based on the binaries used as prerequisites
+=======================================================
+
+If you fail to compile the the complete application (for example because
+you are not root on your system and cannot install missing packages), you
+may try a partial compilation based on the binaries.
+For that it is necessary to copy the binaries from BINARIES to INSTALL,
+and do some substitutions on cmake and .la files (replace the build directories
+with local paths).
+The procedure to do it is:
+ 1) Remove or rename INSTALL directory if it exists
+ 2) Execute the shell script bin_install.sh:
+ > cd $ROOT
+ > ./bin_install.sh
+ 3) Use SalomeTool (as explained in Sources section) and compile only the 
+    modules you need to (with -p option)
+
+"""
+        readme_header_tpl=string.Template(readme_header)
+        readme_template_path_bin_prof = os.path.join(config.VARS.internal_dir,
+                "README_BIN.template")
+        readme_template_path_bin_noprof = os.path.join(config.VARS.internal_dir,
+                "README_BIN_NO_PROFILE.template")
+        readme_template_path_src = os.path.join(config.VARS.internal_dir,
+                "README_SRC.template")
+        readme_template_path_pro = os.path.join(config.VARS.internal_dir,
+                "README_PROJECT.template")
+        readme_template_path_sat = os.path.join(config.VARS.internal_dir,
+                "README_SAT.template")
+
+        # prepare substitution dictionary
+        d = dict()
         d['user'] = config.VARS.user
         d['date'] = datetime.datetime.now().strftime("%Y-%m-%d %H:%M")
         d['version'] = config.INTERNAL.sat_version
         d['dist'] = config.VARS.dist
-        if 'profile' in config.APPLICATION:
-            d['launcher'] = config.APPLICATION.profile.launcher_name
-        readme_template_path = os.path.join(config.VARS.internal_dir,
-                                            "README_BIN.template")
-    if package_type == SOURCE:
-        d['application'] = config.VARS.application
-        d['user'] = config.VARS.user
-        d['date'] = datetime.datetime.now().strftime("%Y-%m-%d %H:%M")
-        d['version'] = config.INTERNAL.sat_version
-        if 'profile' in config.APPLICATION:
-            d['profile'] = config.APPLICATION.profile.product
-            d['launcher'] = config.APPLICATION.profile.launcher_name
-        readme_template_path = os.path.join(config.VARS.internal_dir,
-                                    "README_SRC.template")
+        f.write(readme_header_tpl.substitute(d)) # write the general header (common)
 
-    if package_type == PROJECT:
-        d['user'] = config.VARS.user
-        d['date'] = datetime.datetime.now().strftime("%Y-%m-%d %H:%M")
-        d['version'] = config.INTERNAL.sat_version
-        readme_template_path = os.path.join(config.VARS.internal_dir,
-                                    "README_PROJECT.template")
+        if options.binaries or options.sources:
+            d['application'] = config.VARS.application
+            f.write("# Application: " + d['application'])
+            if 'profile' in config.APPLICATION:
+                d['launcher'] = config.APPLICATION.profile.launcher_name
+                d['launcher'] = config.APPLICATION.profile.launcher_name
+            else:
+                d['env_file'] = 'env_launch.sh'
 
-    if package_type == SAT:
-        d['user'] = config.VARS.user
-        d['date'] = datetime.datetime.now().strftime("%Y-%m-%d %H:%M")
-        d['version'] = config.INTERNAL.sat_version
-        readme_template_path = os.path.join(config.VARS.internal_dir,
-                                    "README_SAT.template")
-    
-    f.write(src.template.substitute(readme_template_path, d))
+        # write the specific sections
+        if options.binaries:
+            if "env_file" in d:
+                f.write(src.template.substitute(readme_template_path_bin_noprof, d))
+            else:
+                f.write(src.template.substitute(readme_template_path_bin_prof, d))
+
+        if options.sources:
+            f.write(src.template.substitute(readme_template_path_src, d))
+
+        if options.binaries and options.sources:
+            f.write(readme_compilation_with_binaries)
+
+        if options.project:
+            f.write(src.template.substitute(readme_template_path_pro, d))
+
+        if options.sat:
+            f.write(src.template.substitute(readme_template_path_sat, d))
     
     return readme_path
-        
+
+def update_config(config, prop, value):
+    '''Remove from config.APPLICATION.products the products that have the property given as input.
+    
+    :param config Config: The global config.
+    :param prop str: The property to filter
+    :param value str: The value of the property to filter
+    '''
+    src.check_config_has_application(config)
+    l_product_to_remove = []
+    for product_name in config.APPLICATION.products.keys():
+        prod_cfg = src.product.get_product_config(config, product_name)
+        if src.get_property_in_product_cfg(prod_cfg, prop) == value:
+            l_product_to_remove.append(product_name)
+    for product_name in l_product_to_remove:
+        config.APPLICATION.products.__delitem__(product_name)
 
 def description():
     '''method that is called when salomeTools is called with --help option.
@@ -789,13 +1045,13 @@ def description():
     :rtype: str
     '''
     return _("The package command creates an archive.\nThere are 4 kinds of "
-             "archive:\n  1- The binary archive. It contains all the product "
+             "archive, which can be mixed:\n  1- The binary archive. It contains all the product "
              "installation directories and a launcher,\n  2- The sources archive."
              " It contains the products archives, a project corresponding to "
              "the application and salomeTools,\n  3- The project archive. It "
              "contains a project (give the project file path as argument),\n  4-"
              " The salomeTools archive. It contains salomeTools.\n\nexample:"
-             "\nsat package SALOME-master --sources")
+             "\nsat package SALOME-master --bineries --sources")
   
 def run(args, runner, logger):
     '''method that is called when salomeTools is called with package parameter.
@@ -819,29 +1075,11 @@ def run(args, runner, logger):
         logger.write("\n", 1)
         return 1
     
-    # Check for only one option for package type
-    if all_option_types.count(True) > 1:
-        msg = _("Error: You can use only one type for the package\nUse only one"
-                " of the following options: --binaries, --sources, --project or"
-                " --sat")
-        logger.write(src.printcolors.printcError(msg), 1)
-        logger.write("\n", 1)
-        return 1
-    
-    # Get the package type
-    if options.binaries:
-        package_type = BINARY
-    if options.sources:
-        package_type = SOURCE
-    if options.project:
-        package_type = PROJECT
-    if options.sat:
-        package_type = SAT
-
     # The repository where to put the package if not Binary or Source
     package_default_path = runner.cfg.USER.workdir
     
-    if package_type in [BINARY, SOURCE]:
+    # if the package contains binaries or sources:
+    if options.binaries or options.sources:
         # Check that the command has been called with an application
         src.check_config_has_application(runner.cfg)
 
@@ -854,7 +1092,8 @@ def run(args, runner, logger):
                                             "PACKAGE")
         src.ensure_path_exists(package_default_path)
         
-    elif package_type == PROJECT:
+    # if the package contains a project:
+    if options.project:
         # check that the project is visible by SAT
         if options.project not in runner.cfg.PROJECTS.project_file_paths:
             site_path = os.path.join(runner.cfg.VARS.salometoolsway,
@@ -867,10 +1106,12 @@ def run(args, runner, logger):
             logger.write("\n", 1)
             return 1
     
-    # Print
-    src.printcolors.print_value(logger, "Package type", package_type, 2)
-
-    # get the name of the archive or construct it
+    # Remove the products that are filtered by the --without_property option
+    if options.without_property:
+        [prop, value] = options.without_property.split(":")
+        update_config(runner.cfg, prop, value)
+    
+    # get the name of the archive or build it
     if options.name:
         if os.path.basename(options.name) == options.name:
             # only a name (not a path)
@@ -887,38 +1128,37 @@ def run(args, runner, logger):
             archive_name = archive_name[:-len(".tar.gz")]
         
     else:
+        archive_name=""
         dir_name = package_default_path
-        if package_type == BINARY:
-            archive_name = (runner.cfg.APPLICATION.name +
-                            "-" +
-                            runner.cfg.VARS.dist)
+        if options.binaries or options.sources:
+            archive_name = runner.cfg.APPLICATION.name
+
+        if options.binaries:
+            archive_name += "_"+runner.cfg.VARS.dist
             
-        if package_type == SOURCE:
-            archive_name = (runner.cfg.APPLICATION.name +
-                            "-" +
-                            "SRC")
+        if options.sources:
+            archive_name += "_SRC"
             if options.with_vcs:
-                archive_name = (runner.cfg.APPLICATION.name +
-                            "-" +
-                            "SRC" +
-                            "-" +
-                            "VCS")
+                archive_name += "_VCS"
 
-        if package_type == PROJECT:
+        if options.project:
             project_name, __ = os.path.splitext(
                                             os.path.basename(options.project))
-            archive_name = ("PROJECT" +
-                            "-" +
-                            project_name)
+            archive_name += ("PROJECT_" + project_name)
  
-        if package_type == SAT:
-            archive_name = ("salomeTools" +
-                            "-" +
-                            runner.cfg.INTERNAL.sat_version)
+        if options.sat:
+            archive_name += ("salomeTools_" + runner.cfg.INTERNAL.sat_version)
+        if len(archive_name)==0: # no option worked 
+            msg = _("Error: Cannot name the archive\n"
+                    " check if at least one of the following options was "
+                    "selected : --binaries, --sources, --project or"
+                    " --salometools")
+            logger.write(src.printcolors.printcError(msg), 1)
+            logger.write("\n", 1)
+            return 1
  
     path_targz = os.path.join(dir_name, archive_name + ".tgz")
     
-    # Print the path of the package
     src.printcolors.print_value(logger, "Package path", path_targz, 2)
 
     # Create a working directory for all files that are produced during the
@@ -935,30 +1175,67 @@ def run(args, runner, logger):
     logger.write(src.printcolors.printcLabel(msg), 2)
     logger.write("\n", 2)
 
-    if package_type == BINARY:           
-        d_files_to_add = binary_package(runner.cfg,
-                                        logger,
-                                        options,
-                                        tmp_working_dir)
-        if not(d_files_to_add):
-            return 1
+    d_files_to_add={}  # content of the archive
+
+    # a dict to hold paths that will need to be substitute for users recompilations
+    d_paths_to_substitute={}  
+
+    if options.binaries:
+        d_bin_files_to_add = binary_package(runner.cfg,
+                                            logger,
+                                            options,
+                                            tmp_working_dir)
+        # for all binaries dir, store the substitution that will be required 
+        # for extra compilations
+        for key in d_bin_files_to_add:
+            if key.endswith("(bin)"):
+                source_dir = d_bin_files_to_add[key][0]
+                path_in_archive = d_bin_files_to_add[key][1].replace("BINARIES-" + runner.cfg.VARS.dist,"INSTALL")
+                if os.path.basename(source_dir)==os.path.basename(path_in_archive):
+                    # if basename is the same we will just substitute the dirname 
+                    d_paths_to_substitute[os.path.dirname(source_dir)]=\
+                        os.path.dirname(path_in_archive)
+                else:
+                    d_paths_to_substitute[source_dir]=path_in_archive
+
+        d_files_to_add.update(d_bin_files_to_add)
 
-    if package_type == SOURCE:
-        d_files_to_add = source_package(runner,
+    if options.sources:
+        d_files_to_add.update(source_package(runner,
                                         runner.cfg,
                                         logger, 
                                         options,
-                                        tmp_working_dir)          
+                                        tmp_working_dir))
+        if options.binaries:
+            # for archives with bin and sources we provide a shell script able to 
+            # install binaries for compilation
+            file_install_bin=produce_install_bin_file(runner.cfg,logger,
+                                                      tmp_working_dir,
+                                                      d_paths_to_substitute,
+                                                      "install_bin.sh")
+            d_files_to_add.update({"install_bin" : (file_install_bin, "install_bin.sh")})
+            logger.write("substitutions that need to be done later : \n", 5)
+            logger.write(str(d_paths_to_substitute), 5)
+            logger.write("\n", 5)
+    else:
+        # --salomeTool option is not considered when --sources is selected, as this option
+        # already brings salomeTool!
+        if options.sat:
+            d_files_to_add.update({"salomeTools" : (runner.cfg.VARS.salometoolsway, "")})
+        
     
-    if package_type == PROJECT:
-        d_files_to_add = project_package(options.project, tmp_working_dir)
+    if options.project:
+        d_files_to_add.update(project_package(options.project, tmp_working_dir))
+
+    if not(d_files_to_add):
+        msg = _("Error: Empty dictionnary to build the archive!\n")
+        logger.write(src.printcolors.printcError(msg), 1)
+        logger.write("\n", 1)
+        return 1
 
-    if package_type == SAT:
-        d_files_to_add = {"salomeTools" : (runner.cfg.VARS.salometoolsway, "")}
-    
     # Add the README file in the package
     local_readme_tmp_path = add_readme(runner.cfg,
-                                       package_type,
+                                       options,
                                        tmp_working_dir)
     d_files_to_add["README"] = (local_readme_tmp_path, "README")
 
@@ -980,8 +1257,12 @@ def run(args, runner, logger):
         # Creating the object tarfile
         tar = tarfile.open(path_targz, mode='w:gz')
         
+        # get the filtering function if needed
+        filter_function = None
+        filter_function = exclude_VCS_and_extensions
+
         # Add the files to the tarfile object
-        res = add_files(tar, archive_name, d_files_to_add, logger)
+        res = add_files(tar, archive_name, d_files_to_add, logger, f_exclude=filter_function)
         tar.close()
     except KeyboardInterrupt:
         logger.write(src.printcolors.printcError("\nERROR: forced interruption\n"), 1)