3 # Copyright (C) 2010-2012 CEA/DEN
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.
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.
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
32 ARCHIVE_DIR = "ARCHIVES"
33 PROJECT_DIR = "PROJECT"
35 PROJECT_TEMPLATE = """#!/usr/bin/env python
38 # The path to the archive root directory
39 root_path : $PWD + "/../"
41 project_path : $PWD + "/"
43 # Where to search the archives of the products
44 ARCHIVEPATH : $root_path + "ARCHIVES"
45 # Where to search the pyconf of the applications
46 APPLICATIONPATH : $project_path + "applications/"
47 # Where to search the pyconf of the products
48 PRODUCTPATH : $project_path + "products/"
49 # Where to search the pyconf of the jobs of the project
50 JOBPATH : $project_path + "jobs/"
51 # Where to search the pyconf of the machines of the project
52 MACHINEPATH : $project_path + "machines/"
55 SITE_TEMPLATE = ("""#!/usr/bin/env python
62 log_dir : $USER.workdir + "/LOGS"
65 tmp_dir_with_application : '/tmp' + $VARS.sep + $VARS.user + """
66 """$VARS.sep + $APPLICATION.name + $VARS.sep + 'test'
67 tmp_dir : '/tmp' + $VARS.sep + $VARS.user + $VARS.sep + 'test'
74 project_file_paths : [$VARS.salometoolsway + $VARS.sep + \"..\" + $VARS.sep"""
75 """ + \"""" + PROJECT_DIR + """\" + $VARS.sep + "project.pyconf"]
79 # Define all possible option for the package command : sat package <options>
80 parser = src.options.Options()
81 parser.add_option('b', 'binaries', 'boolean', 'binaries',
82 _('Optional: Produce a binary package.'), False)
83 parser.add_option('f', 'force_creation', 'boolean', 'force_creation',
84 _('Optional: Only binary package: produce the archive even if '
85 'there are some missing products.'), False)
86 parser.add_option('s', 'sources', 'boolean', 'sources',
87 _('Optional: Produce a compilable archive of the sources of the '
88 'application.'), False)
89 parser.add_option('', 'with_vcs', 'boolean', 'with_vcs',
90 _('Optional: Only source package: do not make archive of vcs products.'),
92 parser.add_option('p', 'project', 'string', 'project',
93 _('Optional: Produce an archive that contains a project.'), "")
94 parser.add_option('t', 'salometools', 'boolean', 'sat',
95 _('Optional: Produce an archive that contains salomeTools.'), False)
96 parser.add_option('n', 'name', 'string', 'name',
97 _('Optional: The name or full path of the archive.'), None)
98 parser.add_option('', 'add_files', 'list2', 'add_files',
99 _('Optional: The list of additional files to add to the archive.'), [])
101 def add_files(tar, name_archive, d_content, logger):
102 '''Create an archive containing all directories and files that are given in
103 the d_content argument.
105 :param tar tarfile: The tarfile instance used to make the archive.
106 :param name_archive str: The name of the archive to make.
107 :param d_content dict: The dictionary that contain all directories and files
108 to add in the archive.
110 (path_on_local_machine, path_in_archive)
111 :param logger Logger: the logging instance
112 :return: 0 if success, 1 if not.
115 # get the max length of the messages in order to make the display
116 max_len = len(max(d_content.keys(), key=len))
119 # loop over each directory or file stored in the d_content dictionary
120 for name in d_content.keys():
121 # display information
122 len_points = max_len - len(name)
123 logger.write(name + " " + len_points * "." + " ", 3)
124 # Get the local path and the path in archive
125 # of the directory or file to add
126 local_path, archive_path = d_content[name]
127 in_archive = os.path.join(name_archive, archive_path)
128 # Add it in the archive
130 tar.add(local_path, arcname=in_archive)
131 logger.write(src.printcolors.printcSuccess(_("OK")), 3)
132 except Exception as e:
133 logger.write(src.printcolors.printcError(_("KO ")), 3)
134 logger.write(str(e), 3)
136 logger.write("\n", 3)
139 def produce_relative_launcher(config,
144 '''Create a specific SALOME launcher for the binary package. This launcher
147 :param config Config: The global configuration.
148 :param logger Logger: the logging instance
149 :param file_dir str: the directory where to put the launcher
150 :param file_name str: The launcher name
151 :param binaries_dir_name str: the name of the repository where the binaries
153 :return: the path of the produced launcher
157 # Get the launcher template
158 profile_install_dir = os.path.join(binaries_dir_name,
159 config.APPLICATION.profile.product)
160 withProfile = src.fileEnviron.withProfile
161 withProfile = withProfile.replace(
162 "ABSOLUTE_APPLI_PATH'] = 'PROFILE_INSTALL_DIR'",
163 "ABSOLUTE_APPLI_PATH'] = out_dir_Path + '" + config.VARS.sep + profile_install_dir + "'")
164 withProfile = withProfile.replace(
165 "os.path.join( 'PROFILE_INSTALL_DIR'",
166 "os.path.join( out_dir_Path, '" + profile_install_dir + "'")
168 before, after = withProfile.split(
169 "# here your local standalone environment\n")
171 # create an environment file writer
172 writer = src.environment.FileEnvWriter(config,
177 filepath = os.path.join(file_dir, file_name)
178 # open the file and write into it
179 launch_file = open(filepath, "w")
180 launch_file.write(before)
182 writer.write_cfgForPy_file(launch_file, for_package = binaries_dir_name)
183 launch_file.write(after)
186 # Little hack to put out_dir_Path outside the strings
187 src.replace_in_file(filepath, 'r"out_dir_Path', 'out_dir_Path + r"' )
189 # change the rights in order to make the file executable for everybody
201 def produce_relative_env_files(config,
205 '''Create some specific environment files for the binary package. These
206 files use relative paths.
208 :param config Config: The global configuration.
209 :param logger Logger: the logging instance
210 :param file_dir str: the directory where to put the files
211 :param binaries_dir_name str: the name of the repository where the binaries
213 :return: the list of path of the produced environment files
216 # create an environment file writer
217 writer = src.environment.FileEnvWriter(config,
223 filepath = writer.write_env_file("env_launch.sh",
226 for_package = binaries_dir_name)
228 # Little hack to put out_dir_Path as environment variable
229 src.replace_in_file(filepath, '"out_dir_Path', '"${out_dir_Path}' )
231 # change the rights in order to make the file executable for everybody
244 def binary_package(config, logger, options, tmp_working_dir):
245 '''Prepare a dictionary that stores all the needed directories and files to
246 add in a binary package.
248 :param config Config: The global configuration.
249 :param logger Logger: the logging instance
250 :param options OptResult: the options of the launched command
251 :param tmp_working_dir str: The temporary local directory containing some
252 specific directories or files needed in the
254 :return: the dictionary that stores all the needed directories and files to
255 add in a binary package.
256 {label : (path_on_local_machine, path_in_archive)}
260 # Get the list of product installation to add to the archive
261 l_products_name = config.APPLICATION.products.keys()
262 l_product_info = src.product.get_products_infos(l_products_name,
266 for prod_name, prod_info in l_product_info:
267 # ignore the native and fixed products
268 if (src.product.product_is_native(prod_info)
269 or src.product.product_is_fixed(prod_info)
270 or not src.product.product_compiles(prod_info)):
272 if src.product.check_installation(prod_info):
273 l_install_dir.append((prod_name, prod_info.install_dir))
275 l_not_installed.append(prod_name)
277 # Print warning or error if there are some missing products
278 if len(l_not_installed) > 0:
279 text_missing_prods = ""
280 for p_name in l_not_installed:
281 text_missing_prods += "-" + p_name + "\n"
282 if not options.force_creation:
283 msg = _("ERROR: there are missing products installations:")
284 logger.write("%s\n%s" % (src.printcolors.printcError(msg),
289 msg = _("WARNING: there are missing products installations:")
290 logger.write("%s\n%s" % (src.printcolors.printcWarning(msg),
294 # construct the name of the directory that will contain the binaries
295 binaries_dir_name = "BINARIES-" + config.VARS.dist
297 # construct the correlation table between the product names, there
298 # actual install directories and there install directory in archive
300 for prod_name, install_dir in l_install_dir:
301 path_in_archive = os.path.join(binaries_dir_name, prod_name)
302 d_products[prod_name] = (install_dir, path_in_archive)
304 # create the relative launcher and add it to the files to add
305 if "profile" in config.APPLICATION:
306 launcher_name = config.APPLICATION.profile.launcher_name
307 launcher_package = produce_relative_launcher(config,
313 d_products["launcher"] = (launcher_package, launcher_name)
315 # No profile, it means that there has to be some environment files
316 env_file = produce_relative_env_files(config,
321 d_products["environment file"] = (env_file, "env_launch.sh")
325 def source_package(sat, config, logger, options, tmp_working_dir):
326 '''Prepare a dictionary that stores all the needed directories and files to
327 add in a source package.
329 :param config Config: The global configuration.
330 :param logger Logger: the logging instance
331 :param options OptResult: the options of the launched command
332 :param tmp_working_dir str: The temporary local directory containing some
333 specific directories or files needed in the
335 :return: the dictionary that stores all the needed directories and files to
336 add in a source package.
337 {label : (path_on_local_machine, path_in_archive)}
341 # Get all the products that are prepared using an archive
342 logger.write("Find archive products ... ")
343 d_archives, l_pinfo_vcs = get_archives(config, logger)
344 logger.write("Done\n")
346 if not options.with_vcs and len(l_pinfo_vcs) > 0:
347 # Make archives with the products that are not prepared using an archive
348 # (git, cvs, svn, etc)
349 logger.write("Construct archives for vcs products ... ")
350 d_archives_vcs = get_archives_vcs(l_pinfo_vcs,
355 logger.write("Done\n")
358 logger.write("Create the project ... ")
359 d_project = create_project_for_src_package(config,
362 logger.write("Done\n")
365 tmp_sat = add_salomeTools(config, tmp_working_dir)
366 d_sat = {"salomeTools" : (tmp_sat, "salomeTools")}
368 # Add a sat symbolic link if not win
369 if not src.architecture.is_windows():
370 tmp_satlink_path = os.path.join(tmp_working_dir, 'sat')
374 # In the jobs, os.getcwd() can fail
375 t = config.USER.workdir
376 os.chdir(tmp_working_dir)
377 if os.path.lexists(tmp_satlink_path):
378 os.remove(tmp_satlink_path)
379 os.symlink(os.path.join('salomeTools', 'sat'), 'sat')
382 d_sat["sat link"] = (tmp_satlink_path, "sat")
384 return src.merge_dicts(d_archives, d_archives_vcs, d_project, d_sat)
386 def get_archives(config, logger):
387 '''Find all the products that are get using an archive and all the products
388 that are get using a vcs (git, cvs, svn) repository.
390 :param config Config: The global configuration.
391 :param logger Logger: the logging instance
392 :return: the dictionary {name_product :
393 (local path of its archive, path in the package of its archive )}
394 and the list of specific configuration corresponding to the vcs
398 # Get the list of product informations
399 l_products_name = config.APPLICATION.products.keys()
400 l_product_info = src.product.get_products_infos(l_products_name,
404 for p_name, p_info in l_product_info:
405 # ignore the native and fixed products
406 if (src.product.product_is_native(p_info)
407 or src.product.product_is_fixed(p_info)):
409 if p_info.get_source == "archive":
410 archive_path = p_info.archive_info.archive_name
411 archive_name = os.path.basename(archive_path)
413 l_pinfo_vcs.append((p_name, p_info))
415 d_archives[p_name] = (archive_path,
416 os.path.join(ARCHIVE_DIR, archive_name))
417 return d_archives, l_pinfo_vcs
419 def add_salomeTools(config, tmp_working_dir):
420 '''Prepare a version of salomeTools that has a specific site.pyconf file
421 configured for a source package.
423 :param config Config: The global configuration.
424 :param tmp_working_dir str: The temporary local directory containing some
425 specific directories or files needed in the
427 :return: The path to the local salomeTools directory to add in the package
430 # Copy sat in the temporary working directory
431 sat_tmp_path = src.Path(os.path.join(tmp_working_dir, "salomeTools"))
432 sat_running_path = src.Path(config.VARS.salometoolsway)
433 sat_running_path.copy(sat_tmp_path)
435 # Update the site.pyconf file that contains the path to the project
436 site_pyconf_name = "site.pyconf"
437 site_pyconf_dir = os.path.join(tmp_working_dir, "salomeTools", "data")
438 site_pyconf_file = os.path.join(site_pyconf_dir, site_pyconf_name)
439 ff = open(site_pyconf_file, "w")
440 ff.write(SITE_TEMPLATE)
443 return sat_tmp_path.path
445 def get_archives_vcs(l_pinfo_vcs, sat, config, logger, tmp_working_dir):
446 '''For sources package that require that all products are get using an
447 archive, one has to create some archive for the vcs products.
448 So this method calls the clean and source command of sat and then create
451 :param l_pinfo_vcs List: The list of specific configuration corresponding to
453 :param sat Sat: The Sat instance that can be called to clean and source the
455 :param config Config: The global configuration.
456 :param logger Logger: the logging instance
457 :param tmp_working_dir str: The temporary local directory containing some
458 specific directories or files needed in the
460 :return: the dictionary that stores all the archives to add in the source
461 package. {label : (path_on_local_machine, path_in_archive)}
464 # clean the source directory of all the vcs products, then use the source
465 # command and thus construct an archive that will not contain the patches
466 l_prod_names = [pn for pn, __ in l_pinfo_vcs]
468 logger.write(_("clean sources\n"))
469 args_clean = config.VARS.application
470 args_clean += " --sources --products "
471 args_clean += ",".join(l_prod_names)
472 sat.clean(args_clean, batch=True, verbose=0, logger_add_link = logger)
474 logger.write(_("get sources"))
475 args_source = config.VARS.application
476 args_source += " --products "
477 args_source += ",".join(l_prod_names)
478 sat.source(args_source, batch=True, verbose=0, logger_add_link = logger)
480 # make the new archives
482 for pn, pinfo in l_pinfo_vcs:
483 path_archive = make_archive(pn, pinfo, tmp_working_dir)
484 d_archives_vcs[pn] = (path_archive,
485 os.path.join(ARCHIVE_DIR, pn + ".tgz"))
486 return d_archives_vcs
488 def make_archive(prod_name, prod_info, where):
489 '''Create an archive of a product by searching its source directory.
491 :param prod_name str: The name of the product.
492 :param prod_info Config: The specific configuration corresponding to the
494 :param where str: The path of the repository where to put the resulting
496 :return: The path of the resulting archive
499 path_targz_prod = os.path.join(where, prod_name + ".tgz")
500 tar_prod = tarfile.open(path_targz_prod, mode='w:gz')
501 local_path = prod_info.source_dir
502 tar_prod.add(local_path, arcname=prod_name)
504 return path_targz_prod
506 def create_project_for_src_package(config, tmp_working_dir, with_vcs):
507 '''Create a specific project for a source package.
509 :param config Config: The global configuration.
510 :param tmp_working_dir str: The temporary local directory containing some
511 specific directories or files needed in the
513 :param with_vcs boolean: True if the package is with vcs products (not
514 transformed into archive products)
515 :return: The dictionary
516 {"project" : (produced project, project path in the archive)}
520 # Create in the working temporary directory the full project tree
521 project_tmp_dir = os.path.join(tmp_working_dir, PROJECT_DIR)
522 products_pyconf_tmp_dir = os.path.join(project_tmp_dir,
524 compil_scripts_tmp_dir = os.path.join(project_tmp_dir,
527 env_scripts_tmp_dir = os.path.join(project_tmp_dir,
530 patches_tmp_dir = os.path.join(project_tmp_dir,
533 application_tmp_dir = os.path.join(project_tmp_dir,
535 for directory in [project_tmp_dir,
536 compil_scripts_tmp_dir,
539 application_tmp_dir]:
540 src.ensure_path_exists(directory)
542 # Create the pyconf that contains the information of the project
543 project_pyconf_name = "project.pyconf"
544 project_pyconf_file = os.path.join(project_tmp_dir, project_pyconf_name)
545 ff = open(project_pyconf_file, "w")
546 ff.write(PROJECT_TEMPLATE)
549 # Loop over the products to get there pyconf and all the scripts
550 # (compilation, environment, patches)
551 # and create the pyconf file to add to the project
552 lproducts_name = config.APPLICATION.products.keys()
553 l_products = src.product.get_products_infos(lproducts_name, config)
554 for p_name, p_info in l_products:
555 # ignore native and fixed products
556 if (src.product.product_is_native(p_info) or
557 src.product.product_is_fixed(p_info)):
559 find_product_scripts_and_pyconf(p_name,
563 compil_scripts_tmp_dir,
566 products_pyconf_tmp_dir)
568 find_application_pyconf(config, application_tmp_dir)
570 d_project = {"project" : (project_tmp_dir, PROJECT_DIR )}
573 def find_product_scripts_and_pyconf(p_name,
577 compil_scripts_tmp_dir,
580 products_pyconf_tmp_dir):
581 '''Create a specific pyconf file for a given product. Get its environment
582 script, its compilation script and patches and put it in the temporary
583 working directory. This method is used in the source package in order to
584 construct the specific project.
586 :param p_name str: The name of the product.
587 :param p_info Config: The specific configuration corresponding to the
589 :param config Config: The global configuration.
590 :param with_vcs boolean: True if the package is with vcs products (not
591 transformed into archive products)
592 :param compil_scripts_tmp_dir str: The path to the temporary compilation
593 scripts directory of the project.
594 :param env_scripts_tmp_dir str: The path to the temporary environment script
595 directory of the project.
596 :param patches_tmp_dir str: The path to the temporary patch scripts
597 directory of the project.
598 :param products_pyconf_tmp_dir str: The path to the temporary product
599 scripts directory of the project.
602 # read the pyconf of the product
603 product_pyconf_path = src.find_file_in_lpath(p_name + ".pyconf",
604 config.PATHS.PRODUCTPATH)
605 product_pyconf_cfg = src.pyconf.Config(product_pyconf_path)
607 # find the compilation script if any
608 if src.product.product_has_script(p_info):
609 compil_script_path = src.Path(p_info.compil_script)
610 compil_script_path.copy(compil_scripts_tmp_dir)
611 product_pyconf_cfg[p_info.section].compil_script = os.path.basename(
612 p_info.compil_script)
613 # find the environment script if any
614 if src.product.product_has_env_script(p_info):
615 env_script_path = src.Path(p_info.environ.env_script)
616 env_script_path.copy(env_scripts_tmp_dir)
617 product_pyconf_cfg[p_info.section].environ.env_script = os.path.basename(
618 p_info.environ.env_script)
619 # find the patches if any
620 if src.product.product_has_patches(p_info):
621 patches = src.pyconf.Sequence()
622 for patch_path in p_info.patches:
623 p_path = src.Path(patch_path)
624 p_path.copy(patches_tmp_dir)
625 patches.append(os.path.basename(patch_path), "")
627 product_pyconf_cfg[p_info.section].patches = patches
630 # put in the pyconf file the resolved values
631 for info in ["git_info", "cvs_info", "svn_info"]:
633 for key in p_info[info]:
634 product_pyconf_cfg[p_info.section][info][key] = p_info[
637 # if the product is not archive, then make it become archive.
638 if src.product.product_is_vcs(p_info):
639 product_pyconf_cfg[p_info.section].get_source = "archive"
640 if not "archive_info" in product_pyconf_cfg[p_info.section]:
641 product_pyconf_cfg[p_info.section].addMapping("archive_info",
642 src.pyconf.Mapping(product_pyconf_cfg),
644 product_pyconf_cfg[p_info.section
645 ].archive_info.archive_name = p_info.name + ".tgz"
647 # write the pyconf file to the temporary project location
648 product_tmp_pyconf_path = os.path.join(products_pyconf_tmp_dir,
650 ff = open(product_tmp_pyconf_path, 'w')
651 ff.write("#!/usr/bin/env python\n#-*- coding:utf-8 -*-\n\n")
652 product_pyconf_cfg.__save__(ff, 1)
655 def find_application_pyconf(config, application_tmp_dir):
656 '''Find the application pyconf file and put it in the specific temporary
657 directory containing the specific project of a source package.
659 :param config Config: The global configuration.
660 :param application_tmp_dir str: The path to the temporary application
661 scripts directory of the project.
663 # read the pyconf of the application
664 application_name = config.VARS.application
665 application_pyconf_path = src.find_file_in_lpath(
666 application_name + ".pyconf",
667 config.PATHS.APPLICATIONPATH)
668 application_pyconf_cfg = src.pyconf.Config(application_pyconf_path)
671 application_pyconf_cfg.APPLICATION.workdir = src.pyconf.Reference(
672 application_pyconf_cfg,
674 'VARS.salometoolsway + $VARS.sep + ".."')
676 # Prevent from compilation in base
677 application_pyconf_cfg.APPLICATION.no_base = "yes"
679 # write the pyconf file to the temporary application location
680 application_tmp_pyconf_path = os.path.join(application_tmp_dir,
681 application_name + ".pyconf")
682 ff = open(application_tmp_pyconf_path, 'w')
683 ff.write("#!/usr/bin/env python\n#-*- coding:utf-8 -*-\n\n")
684 application_pyconf_cfg.__save__(ff, 1)
687 def project_package(project_file_path, tmp_working_dir):
688 '''Prepare a dictionary that stores all the needed directories and files to
689 add in a project package.
691 :param project_file_path str: The path to the local project.
692 :param tmp_working_dir str: The temporary local directory containing some
693 specific directories or files needed in the
695 :return: the dictionary that stores all the needed directories and files to
696 add in a project package.
697 {label : (path_on_local_machine, path_in_archive)}
701 # Read the project file and get the directories to add to the package
702 project_pyconf_cfg = src.pyconf.Config(project_file_path)
703 paths = {"ARCHIVEPATH" : "archives",
704 "APPLICATIONPATH" : "applications",
705 "PRODUCTPATH" : "products",
707 "MACHINEPATH" : "machines"}
708 # Loop over the project paths and add it
710 if path not in project_pyconf_cfg:
712 # Add the directory to the files to add in the package
713 d_project[path] = (project_pyconf_cfg[path], paths[path])
714 # Modify the value of the path in the package
715 project_pyconf_cfg[path] = src.pyconf.Reference(
718 'project_path + "/' + paths[path] + '"')
721 if "project_path" not in project_pyconf_cfg:
722 project_pyconf_cfg.addMapping("project_path",
723 src.pyconf.Mapping(project_pyconf_cfg),
725 project_pyconf_cfg.project_path = src.pyconf.Reference(project_pyconf_cfg,
729 # Write the project pyconf file
730 project_file_name = os.path.basename(project_file_path)
731 project_pyconf_tmp_path = os.path.join(tmp_working_dir, project_file_name)
732 ff = open(project_pyconf_tmp_path, 'w')
733 ff.write("#!/usr/bin/env python\n#-*- coding:utf-8 -*-\n\n")
734 project_pyconf_cfg.__save__(ff, 1)
736 d_project["Project hat file"] = (project_pyconf_tmp_path, project_file_name)
740 def add_readme(config, package_type, where):
741 readme_path = os.path.join(where, "README")
742 f = open(readme_path, 'w')
743 # prepare substitution dictionary
745 if package_type == BINARY:
746 d['application'] = config.VARS.application
747 d['user'] = config.VARS.user
748 d['date'] = datetime.datetime.now().strftime("%Y-%m-%d %H:%M")
749 d['version'] = config.INTERNAL.sat_version
750 d['dist'] = config.VARS.dist
751 if 'profile' in config.APPLICATION:
752 d['launcher'] = config.APPLICATION.profile.launcher_name
753 readme_template_path = os.path.join(config.VARS.internal_dir,
754 "README_BIN.template")
756 d['env_file'] = 'env_launch.sh'
757 readme_template_path = os.path.join(config.VARS.internal_dir,
758 "README_BIN_NO_PROFILE.template")
760 if package_type == SOURCE:
761 d['application'] = config.VARS.application
762 d['user'] = config.VARS.user
763 d['date'] = datetime.datetime.now().strftime("%Y-%m-%d %H:%M")
764 d['version'] = config.INTERNAL.sat_version
765 if 'profile' in config.APPLICATION:
766 d['profile'] = config.APPLICATION.profile.product
767 d['launcher'] = config.APPLICATION.profile.launcher_name
768 readme_template_path = os.path.join(config.VARS.internal_dir,
769 "README_SRC.template")
771 if package_type == PROJECT:
772 d['user'] = config.VARS.user
773 d['date'] = datetime.datetime.now().strftime("%Y-%m-%d %H:%M")
774 d['version'] = config.INTERNAL.sat_version
775 readme_template_path = os.path.join(config.VARS.internal_dir,
776 "README_PROJECT.template")
778 if package_type == SAT:
779 d['user'] = config.VARS.user
780 d['date'] = datetime.datetime.now().strftime("%Y-%m-%d %H:%M")
781 d['version'] = config.INTERNAL.sat_version
782 readme_template_path = os.path.join(config.VARS.internal_dir,
783 "README_SAT.template")
785 f.write(src.template.substitute(readme_template_path, d))
791 '''method that is called when salomeTools is called with --help option.
793 :return: The text to display for the package command description.
796 return _("The package command creates an archive.\nThere are 4 kinds of "
797 "archive:\n 1- The binary archive. It contains all the product "
798 "installation directories and a launcher,\n 2- The sources archive."
799 " It contains the products archives, a project corresponding to "
800 "the application and salomeTools,\n 3- The project archive. It "
801 "contains a project (give the project file path as argument),\n 4-"
802 " The salomeTools archive. It contains salomeTools.\n\nexample:"
803 "\nsat package SALOME-master --sources")
805 def run(args, runner, logger):
806 '''method that is called when salomeTools is called with package parameter.
810 (options, args) = parser.parse_args(args)
812 # Check that a type of package is called, and only one
813 all_option_types = (options.binaries,
815 options.project not in ["", None],
818 # Check if no option for package type
819 if all_option_types.count(True) == 0:
820 msg = _("Error: Precise a type for the package\nUse one of the "
821 "following options: --binaries, --sources, --project or"
823 logger.write(src.printcolors.printcError(msg), 1)
824 logger.write("\n", 1)
827 # Check for only one option for package type
828 if all_option_types.count(True) > 1:
829 msg = _("Error: You can use only one type for the package\nUse only one"
830 " of the following options: --binaries, --sources, --project or"
832 logger.write(src.printcolors.printcError(msg), 1)
833 logger.write("\n", 1)
836 # Get the package type
838 package_type = BINARY
840 package_type = SOURCE
842 package_type = PROJECT
846 # The repository where to put the package if not Binary or Source
847 package_default_path = runner.cfg.USER.workdir
849 if package_type in [BINARY, SOURCE]:
850 # Check that the command has been called with an application
851 src.check_config_has_application(runner.cfg)
853 # Display information
854 logger.write(_("Packaging application %s\n") % src.printcolors.printcLabel(
855 runner.cfg.VARS.application), 1)
857 # Get the default directory where to put the packages
858 package_default_path = os.path.join(runner.cfg.APPLICATION.workdir,
860 src.ensure_path_exists(package_default_path)
862 elif package_type == PROJECT:
863 # check that the project is visible by SAT
864 if options.project not in runner.cfg.PROJECTS.project_file_paths:
865 site_path = os.path.join(runner.cfg.VARS.salometoolsway,
868 msg = _("ERROR: the project %(proj)s is not visible by salomeTools."
869 "\nPlease add it in the %(site)s file." % {
870 "proj" : options.project, "site" : site_path})
871 logger.write(src.printcolors.printcError(msg), 1)
872 logger.write("\n", 1)
876 src.printcolors.print_value(logger, "Package type", package_type, 2)
878 # get the name of the archive or construct it
880 if os.path.basename(options.name) == options.name:
881 # only a name (not a path)
882 archive_name = options.name
883 dir_name = package_default_path
885 archive_name = os.path.basename(options.name)
886 dir_name = os.path.dirname(options.name)
889 if archive_name[-len(".tgz"):] == ".tgz":
890 archive_name = archive_name[:-len(".tgz")]
891 if archive_name[-len(".tar.gz"):] == ".tar.gz":
892 archive_name = archive_name[:-len(".tar.gz")]
895 dir_name = package_default_path
896 if package_type == BINARY:
897 archive_name = (runner.cfg.APPLICATION.name +
899 runner.cfg.VARS.dist)
901 if package_type == SOURCE:
902 archive_name = (runner.cfg.APPLICATION.name +
906 archive_name = (runner.cfg.APPLICATION.name +
912 if package_type == PROJECT:
913 project_name, __ = os.path.splitext(
914 os.path.basename(options.project))
915 archive_name = ("PROJECT" +
919 if package_type == SAT:
920 archive_name = ("salomeTools" +
922 runner.cfg.INTERNAL.sat_version)
924 path_targz = os.path.join(dir_name, archive_name + ".tgz")
926 # Print the path of the package
927 src.printcolors.print_value(logger, "Package path", path_targz, 2)
929 # Create a working directory for all files that are produced during the
930 # package creation and that will be removed at the end of the command
931 tmp_working_dir = os.path.join(runner.cfg.VARS.tmp_root,
932 runner.cfg.VARS.datehour)
933 src.ensure_path_exists(tmp_working_dir)
934 logger.write("\n", 5)
935 logger.write(_("The temporary working directory: %s\n" % tmp_working_dir),5)
937 logger.write("\n", 3)
939 msg = _("Preparation of files to add to the archive")
940 logger.write(src.printcolors.printcLabel(msg), 2)
941 logger.write("\n", 2)
943 if package_type == BINARY:
944 d_files_to_add = binary_package(runner.cfg,
948 if not(d_files_to_add):
951 if package_type == SOURCE:
952 d_files_to_add = source_package(runner,
958 if package_type == PROJECT:
959 d_files_to_add = project_package(options.project, tmp_working_dir)
961 if package_type == SAT:
962 d_files_to_add = {"salomeTools" : (runner.cfg.VARS.salometoolsway, "")}
964 # Add the README file in the package
965 local_readme_tmp_path = add_readme(runner.cfg,
968 d_files_to_add["README"] = (local_readme_tmp_path, "README")
970 # Add the additional files of option add_files
971 if options.add_files:
972 for file_path in options.add_files:
973 if not os.path.exists(file_path):
974 msg = _("WARNING: the file %s is not accessible.\n" % file_path)
976 file_name = os.path.basename(file_path)
977 d_files_to_add[file_name] = (file_path, file_name)
979 logger.write("\n", 2)
981 logger.write(src.printcolors.printcLabel(_("Actually do the package")), 2)
982 logger.write("\n", 2)
985 # Creating the object tarfile
986 tar = tarfile.open(path_targz, mode='w:gz')
988 # Add the files to the tarfile object
989 res = add_files(tar, archive_name, d_files_to_add, logger)
991 except KeyboardInterrupt:
992 logger.write(src.printcolors.printcError("\nERROR: forced interruption\n"), 1)
993 logger.write(_("Removing the temporary working directory ... "), 1)
994 # remove the working directory
995 shutil.rmtree(tmp_working_dir)
996 logger.write(_("OK"), 1)
997 logger.write(_("\n"), 1)
1000 # remove the working directory
1001 shutil.rmtree(tmp_working_dir)
1003 # Print again the path of the package
1004 logger.write("\n", 2)
1005 src.printcolors.print_value(logger, "Package path", path_targz, 2)