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('', 'with_sources', 'boolean', 'with_sources',
87 _('Optional: Only binary package: produce and and a source archive in the '
88 'binary package.'), False)
89 parser.add_option('s', 'sources', 'boolean', 'sources',
90 _('Optional: Produce a compilable archive of the sources of the '
91 'application.'), False)
92 parser.add_option('', 'with_vcs', 'boolean', 'with_vcs',
93 _('Optional: Only source package: do not make archive of vcs products.'),
95 parser.add_option('p', 'project', 'string', 'project',
96 _('Optional: Produce an archive that contains a project.'), "")
97 parser.add_option('t', 'salometools', 'boolean', 'sat',
98 _('Optional: Produce an archive that contains salomeTools.'), False)
99 parser.add_option('n', 'name', 'string', 'name',
100 _('Optional: The name or full path of the archive.'), None)
102 def add_files(tar, name_archive, d_content, logger):
103 '''Create an archive containing all directories and files that are given in
104 the d_content argument.
106 :param tar tarfile: The tarfile instance used to make the archive.
107 :param name_archive str: The name of the archive to make.
108 :param d_content dict: The dictionary that contain all directories and files
109 to add in the archive.
111 (path_on_local_machine, path_in_archive)
112 :param logger Logger: the logging instance
113 :return: 0 if success, 1 if not.
116 # get the max length of the messages in order to make the display
117 max_len = len(max(d_content.keys(), key=len))
120 # loop over each directory or file stored in the d_content dictionary
121 for name in d_content.keys():
122 # display information
123 len_points = max_len - len(name)
124 logger.write(name + " " + len_points * "." + " ", 3)
125 # Get the local path and the path in archive
126 # of the directory or file to add
127 local_path, archive_path = d_content[name]
128 in_archive = os.path.join(name_archive, archive_path)
129 # Add it in the archive
131 tar.add(local_path, arcname=in_archive)
132 logger.write(src.printcolors.printcSuccess(_("OK")), 3)
133 except Exception as e:
134 logger.write(src.printcolors.printcError(_("KO ")), 3)
135 logger.write(str(e), 3)
137 logger.write("\n", 3)
140 def produce_relative_launcher(config,
145 '''Create a specific SALOME launcher for the binary package. This launcher
148 :param config Config: The global configuration.
149 :param logger Logger: the logging instance
150 :param file_dir str: the directory where to put the launcher
151 :param file_name str: The launcher name
152 :param binaries_dir_name str: the name of the repository where the binaries
154 :return: the path of the produced launcher
158 # Get the launcher template
159 profile_install_dir = os.path.join(binaries_dir_name,
160 config.APPLICATION.profile.product)
161 withProfile = src.fileEnviron.withProfile
162 withProfile = withProfile.replace(
163 "ABSOLUTE_APPLI_PATH'] = 'PROFILE_INSTALL_DIR'",
164 "ABSOLUTE_APPLI_PATH'] = out_dir_Path + '" + config.VARS.sep + profile_install_dir + "'")
165 withProfile = withProfile.replace(
166 "os.path.join( 'PROFILE_INSTALL_DIR'",
167 "os.path.join( out_dir_Path, '" + profile_install_dir + "'")
169 before, after = withProfile.split(
170 "# here your local standalone environment\n")
172 # create an environment file writer
173 writer = src.environment.FileEnvWriter(config,
178 filepath = os.path.join(file_dir, file_name)
179 # open the file and write into it
180 launch_file = open(filepath, "w")
181 launch_file.write(before)
183 writer.write_cfgForPy_file(launch_file, for_package = binaries_dir_name)
184 launch_file.write(after)
187 # Little hack to put out_dir_Path outside the strings
188 src.replace_in_file(filepath, 'r"out_dir_Path', 'out_dir_Path + r"' )
190 # change the rights in order to make the file executable for everybody
202 def binary_package(config, logger, options, tmp_working_dir):
203 '''Prepare a dictionary that stores all the needed directories and files to
204 add in a binary package.
206 :param config Config: The global configuration.
207 :param logger Logger: the logging instance
208 :param options OptResult: the options of the launched command
209 :param tmp_working_dir str: The temporary local directory containing some
210 specific directories or files needed in the
212 :return: the dictionary that stores all the needed directories and files to
213 add in a binary package.
214 {label : (path_on_local_machine, path_in_archive)}
218 # Get the list of product installation to add to the archive
219 l_products_name = config.APPLICATION.products.keys()
220 l_product_info = src.product.get_products_infos(l_products_name,
224 for prod_name, prod_info in l_product_info:
225 # ignore the native and fixed products
226 if (src.product.product_is_native(prod_info)
227 or src.product.product_is_fixed(prod_info)):
229 if src.product.check_installation(prod_info):
230 l_install_dir.append((prod_name, prod_info.install_dir))
232 l_not_installed.append(prod_name)
234 # Print warning or error if there are some missing products
235 if len(l_not_installed) > 0:
236 text_missing_prods = ""
237 for p_name in l_not_installed:
238 text_missing_prods += "-" + p_name + "\n"
239 if not options.force_creation:
240 msg = _("ERROR: there are missing products installations:")
241 logger.write("%s\n%s" % (src.printcolors.printcError(msg),
246 msg = _("WARNING: there are missing products installations:")
247 logger.write("%s\n%s" % (src.printcolors.printcWarning(msg),
251 # construct the name of the directory that will contain the binaries
252 binaries_dir_name = "BINARIES-" + config.VARS.dist
254 # construct the correlation table between the product names, there
255 # actual install directories and there install directory in archive
257 for prod_name, install_dir in l_install_dir:
258 path_in_archive = os.path.join(binaries_dir_name, prod_name)
259 d_products[prod_name] = (install_dir, path_in_archive)
261 # create the relative launcher and add it to the files to add
262 if "profile" in config.APPLICATION:
263 launcher_name = config.APPLICATION.profile.launcher_name
264 launcher_package = produce_relative_launcher(config,
270 d_products["launcher"] = (launcher_package, launcher_name)
274 def source_package(sat, config, logger, options, tmp_working_dir):
275 '''Prepare a dictionary that stores all the needed directories and files to
276 add in a source package.
278 :param config Config: The global configuration.
279 :param logger Logger: the logging instance
280 :param options OptResult: the options of the launched command
281 :param tmp_working_dir str: The temporary local directory containing some
282 specific directories or files needed in the
284 :return: the dictionary that stores all the needed directories and files to
285 add in a source package.
286 {label : (path_on_local_machine, path_in_archive)}
290 # Get all the products that are prepared using an archive
291 logger.write("Find archive products ... ")
292 d_archives, l_pinfo_vcs = get_archives(config, logger)
293 logger.write("Done\n")
295 if not options.with_vcs and len(l_pinfo_vcs) > 0:
296 # Make archives with the products that are not prepared using an archive
297 # (git, cvs, svn, etc)
298 logger.write("Construct archives for vcs products ... ")
299 d_archives_vcs = get_archives_vcs(l_pinfo_vcs,
304 logger.write("Done\n")
307 logger.write("Create the project ... ")
308 d_project = create_project_for_src_package(config,
311 logger.write("Done\n")
314 tmp_sat = add_salomeTools(config, tmp_working_dir)
315 d_sat = {"salomeTools" : (tmp_sat, "salomeTools")}
317 # Add a sat symbolic link
318 tmp_satlink_path = os.path.join(tmp_working_dir, 'sat')
320 os.chdir(tmp_working_dir)
321 if os.path.lexists(tmp_satlink_path):
322 os.remove(tmp_satlink_path)
323 os.symlink(os.path.join('salomeTools', 'sat'), 'sat')
326 d_sat["sat link"] = (tmp_satlink_path, "sat")
328 return src.merge_dicts(d_archives, d_archives_vcs, d_project, d_sat)
330 def get_archives(config, logger):
331 '''Find all the products that are get using an archive and all the products
332 that are get using a vcs (git, cvs, svn) repository.
334 :param config Config: The global configuration.
335 :param logger Logger: the logging instance
336 :return: the dictionary {name_product :
337 (local path of its archive, path in the package of its archive )}
338 and the list of specific configuration corresponding to the vcs
342 # Get the list of product informations
343 l_products_name = config.APPLICATION.products.keys()
344 l_product_info = src.product.get_products_infos(l_products_name,
348 for p_name, p_info in l_product_info:
349 # ignore the native and fixed products
350 if (src.product.product_is_native(p_info)
351 or src.product.product_is_fixed(p_info)):
353 if p_info.get_source == "archive":
354 archive_path = p_info.archive_info.archive_name
355 archive_name = os.path.basename(archive_path)
357 l_pinfo_vcs.append((p_name, p_info))
359 d_archives[p_name] = (archive_path,
360 os.path.join(ARCHIVE_DIR, archive_name))
361 return d_archives, l_pinfo_vcs
363 def add_salomeTools(config, tmp_working_dir):
364 '''Prepare a version of salomeTools that has a specific site.pyconf file
365 configured for a source package.
367 :param config Config: The global configuration.
368 :param tmp_working_dir str: The temporary local directory containing some
369 specific directories or files needed in the
371 :return: The path to the local salomeTools directory to add in the package
374 # Copy sat in the temporary working directory
375 sat_tmp_path = src.Path(os.path.join(tmp_working_dir, "salomeTools"))
376 sat_running_path = src.Path(config.VARS.salometoolsway)
377 sat_running_path.copy(sat_tmp_path)
379 # Update the site.pyconf file that contains the path to the project
380 site_pyconf_name = "site.pyconf"
381 site_pyconf_dir = os.path.join(tmp_working_dir, "salomeTools", "data")
382 site_pyconf_file = os.path.join(site_pyconf_dir, site_pyconf_name)
383 ff = open(site_pyconf_file, "w")
384 ff.write(SITE_TEMPLATE)
387 return sat_tmp_path.path
389 def get_archives_vcs(l_pinfo_vcs, sat, config, logger, tmp_working_dir):
390 '''For sources package that require that all products are get using an
391 archive, one has to create some archive for the vcs products.
392 So this method calls the clean and source command of sat and then create
395 :param l_pinfo_vcs List: The list of specific configuration corresponding to
397 :param sat Sat: The Sat instance that can be called to clean and source the
399 :param config Config: The global configuration.
400 :param logger Logger: the logging instance
401 :param tmp_working_dir str: The temporary local directory containing some
402 specific directories or files needed in the
404 :return: the dictionary that stores all the archives to add in the source
405 package. {label : (path_on_local_machine, path_in_archive)}
408 # clean the source directory of all the vcs products, then use the source
409 # command and thus construct an archive that will not contain the patches
410 l_prod_names = [pn for pn, __ in l_pinfo_vcs]
412 logger.write(_("clean sources\n"))
413 args_clean = config.VARS.application
414 args_clean += " --sources --products "
415 args_clean += ",".join(l_prod_names)
416 sat.clean(args_clean, batch=True, verbose=0, logger_add_link = logger)
418 logger.write(_("get sources"))
419 args_source = config.VARS.application
420 args_source += " --products "
421 args_source += ",".join(l_prod_names)
422 sat.source(args_source, batch=True, verbose=0, logger_add_link = logger)
424 # make the new archives
426 for pn, pinfo in l_pinfo_vcs:
427 path_archive = make_archive(pn, pinfo, tmp_working_dir)
428 d_archives_vcs[pn] = (path_archive,
429 os.path.join(ARCHIVE_DIR, pn + ".tgz"))
430 return d_archives_vcs
432 def make_archive(prod_name, prod_info, where):
433 '''Create an archive of a product by searching its source directory.
435 :param prod_name str: The name of the product.
436 :param prod_info Config: The specific configuration corresponding to the
438 :param where str: The path of the repository where to put the resulting
440 :return: The path of the resulting archive
443 path_targz_prod = os.path.join(where, prod_name + ".tgz")
444 tar_prod = tarfile.open(path_targz_prod, mode='w:gz')
445 local_path = prod_info.source_dir
446 tar_prod.add(local_path, arcname=prod_name)
448 return path_targz_prod
450 def create_project_for_src_package(config, tmp_working_dir, with_vcs):
451 '''Create a specific project for a source package.
453 :param config Config: The global configuration.
454 :param tmp_working_dir str: The temporary local directory containing some
455 specific directories or files needed in the
457 :param with_vcs boolean: True if the package is with vcs products (not
458 transformed into archive products)
459 :return: The dictionary
460 {"project" : (produced project, project path in the archive)}
464 # Create in the working temporary directory the full project tree
465 project_tmp_dir = os.path.join(tmp_working_dir, PROJECT_DIR)
466 products_pyconf_tmp_dir = os.path.join(project_tmp_dir,
468 compil_scripts_tmp_dir = os.path.join(project_tmp_dir,
471 env_scripts_tmp_dir = os.path.join(project_tmp_dir,
474 patches_tmp_dir = os.path.join(project_tmp_dir,
477 application_tmp_dir = os.path.join(project_tmp_dir,
479 for directory in [project_tmp_dir,
480 compil_scripts_tmp_dir,
483 application_tmp_dir]:
484 src.ensure_path_exists(directory)
486 # Create the pyconf that contains the information of the project
487 project_pyconf_name = "project.pyconf"
488 project_pyconf_file = os.path.join(project_tmp_dir, project_pyconf_name)
489 ff = open(project_pyconf_file, "w")
490 ff.write(PROJECT_TEMPLATE)
493 # Loop over the products to get there pyconf and all the scripts
494 # (compilation, environment, patches)
495 # and create the pyconf file to add to the project
496 lproducts_name = config.APPLICATION.products.keys()
497 l_products = src.product.get_products_infos(lproducts_name, config)
498 for p_name, p_info in l_products:
499 # ignore native and fixed products
500 if (src.product.product_is_native(p_info) or
501 src.product.product_is_fixed(p_info)):
503 find_product_scripts_and_pyconf(p_name,
507 compil_scripts_tmp_dir,
510 products_pyconf_tmp_dir)
512 find_application_pyconf(config, application_tmp_dir)
514 d_project = {"project" : (project_tmp_dir, PROJECT_DIR )}
517 def find_product_scripts_and_pyconf(p_name,
521 compil_scripts_tmp_dir,
524 products_pyconf_tmp_dir):
525 '''Create a specific pyconf file for a given product. Get its environment
526 script, its compilation script and patches and put it in the temporary
527 working directory. This method is used in the source package in order to
528 construct the specific project.
530 :param p_name str: The name of the product.
531 :param p_info Config: The specific configuration corresponding to the
533 :param config Config: The global configuration.
534 :param with_vcs boolean: True if the package is with vcs products (not
535 transformed into archive products)
536 :param compil_scripts_tmp_dir str: The path to the temporary compilation
537 scripts directory of the project.
538 :param env_scripts_tmp_dir str: The path to the temporary environment script
539 directory of the project.
540 :param patches_tmp_dir str: The path to the temporary patch scripts
541 directory of the project.
542 :param products_pyconf_tmp_dir str: The path to the temporary product
543 scripts directory of the project.
546 # read the pyconf of the product
547 product_pyconf_path = src.find_file_in_lpath(p_name + ".pyconf",
548 config.PATHS.PRODUCTPATH)
549 product_pyconf_cfg = src.pyconf.Config(product_pyconf_path)
551 # find the compilation script if any
552 if src.product.product_has_script(p_info):
553 compil_script_path = src.Path(p_info.compil_script)
554 compil_script_path.copy(compil_scripts_tmp_dir)
555 product_pyconf_cfg[p_info.section].compil_script = os.path.basename(
556 p_info.compil_script)
557 # find the environment script if any
558 if src.product.product_has_env_script(p_info):
559 env_script_path = src.Path(p_info.environ.env_script)
560 env_script_path.copy(env_scripts_tmp_dir)
561 product_pyconf_cfg[p_info.section].environ.env_script = os.path.basename(
562 p_info.environ.env_script)
563 # find the patches if any
564 if src.product.product_has_patches(p_info):
565 patches = src.pyconf.Sequence()
566 for patch_path in p_info.patches:
567 p_path = src.Path(patch_path)
568 p_path.copy(patches_tmp_dir)
569 patches.append(os.path.basename(patch_path), "")
571 product_pyconf_cfg[p_info.section].patches = patches
574 # put in the pyconf file the resolved values
575 for info in ["git_info", "cvs_info", "svn_info"]:
577 for key in p_info[info]:
578 product_pyconf_cfg[p_info.section][info][key] = p_info[
581 # if the product is not archive, then make it become archive.
582 if src.product.product_is_vcs(p_info):
583 product_pyconf_cfg[p_info.section].get_source = "archive"
584 if not "archive_info" in product_pyconf_cfg[p_info.section]:
585 product_pyconf_cfg[p_info.section].addMapping("archive_info",
586 src.pyconf.Mapping(product_pyconf_cfg),
588 product_pyconf_cfg[p_info.section
589 ].archive_info.archive_name = p_info.name + ".tgz"
591 # write the pyconf file to the temporary project location
592 product_tmp_pyconf_path = os.path.join(products_pyconf_tmp_dir,
594 ff = open(product_tmp_pyconf_path, 'w')
595 ff.write("#!/usr/bin/env python\n#-*- coding:utf-8 -*-\n\n")
596 product_pyconf_cfg.__save__(ff, 1)
599 def find_application_pyconf(config, application_tmp_dir):
600 '''Find the application pyconf file and put it in the specific temporary
601 directory containing the specific project of a source package.
603 :param config Config: The global configuration.
604 :param application_tmp_dir str: The path to the temporary application
605 scripts directory of the project.
607 # read the pyconf of the application
608 application_name = config.VARS.application
609 application_pyconf_path = src.find_file_in_lpath(
610 application_name + ".pyconf",
611 config.PATHS.APPLICATIONPATH)
612 application_pyconf_cfg = src.pyconf.Config(application_pyconf_path)
615 application_pyconf_cfg.APPLICATION.workdir = src.pyconf.Reference(
616 application_pyconf_cfg,
618 'VARS.salometoolsway + $VARS.sep + ".."')
620 # Prevent from compilation in base
621 application_pyconf_cfg.APPLICATION.no_base = "yes"
623 # write the pyconf file to the temporary application location
624 application_tmp_pyconf_path = os.path.join(application_tmp_dir,
625 application_name + ".pyconf")
626 ff = open(application_tmp_pyconf_path, 'w')
627 ff.write("#!/usr/bin/env python\n#-*- coding:utf-8 -*-\n\n")
628 application_pyconf_cfg.__save__(ff, 1)
631 def project_package(project_file_path, tmp_working_dir):
632 '''Prepare a dictionary that stores all the needed directories and files to
633 add in a project package.
635 :param project_file_path str: The path to the local project.
636 :param tmp_working_dir str: The temporary local directory containing some
637 specific directories or files needed in the
639 :return: the dictionary that stores all the needed directories and files to
640 add in a project package.
641 {label : (path_on_local_machine, path_in_archive)}
645 # Read the project file and get the directories to add to the package
646 project_pyconf_cfg = src.pyconf.Config(project_file_path)
647 paths = {"ARCHIVEPATH" : "archives",
648 "APPLICATIONPATH" : "applications",
649 "PRODUCTPATH" : "products",
651 "MACHINEPATH" : "machines"}
652 # Loop over the project paths and add it
654 if path not in project_pyconf_cfg:
656 # Add the directory to the files to add in the package
657 d_project[path] = (project_pyconf_cfg[path], paths[path])
658 # Modify the value of the path in the package
659 project_pyconf_cfg[path] = src.pyconf.Reference(
662 'project_path + "/' + paths[path] + '"')
665 if "project_path" not in project_pyconf_cfg:
666 project_pyconf_cfg.addMapping("project_path",
667 src.pyconf.Mapping(project_pyconf_cfg),
669 project_pyconf_cfg.project_path = src.pyconf.Reference(project_pyconf_cfg,
673 # Write the project pyconf file
674 project_file_name = os.path.basename(project_file_path)
675 project_pyconf_tmp_path = os.path.join(tmp_working_dir, project_file_name)
676 ff = open(project_pyconf_tmp_path, 'w')
677 ff.write("#!/usr/bin/env python\n#-*- coding:utf-8 -*-\n\n")
678 project_pyconf_cfg.__save__(ff, 1)
680 d_project["Project hat file"] = (project_pyconf_tmp_path, project_file_name)
684 def add_readme(config, package_type, where):
685 readme_path = os.path.join(where, "README")
686 f = open(readme_path, 'w')
687 # prepare substitution dictionary
689 if package_type == BINARY:
690 d['application'] = config.VARS.application
691 d['user'] = config.VARS.user
692 d['date'] = datetime.datetime.now().strftime("%Y-%m-%d %H:%M")
693 d['version'] = config.INTERNAL.sat_version
694 d['dist'] = config.VARS.dist
695 if 'profile' in config.APPLICATION:
696 d['launcher'] = config.APPLICATION.profile.launcher_name
697 readme_template_path = os.path.join(config.VARS.internal_dir,
698 "README_BIN.template")
699 if package_type == SOURCE:
700 d['application'] = config.VARS.application
701 d['user'] = config.VARS.user
702 d['date'] = datetime.datetime.now().strftime("%Y-%m-%d %H:%M")
703 d['version'] = config.INTERNAL.sat_version
704 if 'profile' in config.APPLICATION:
705 d['profile'] = config.APPLICATION.profile.product
706 d['launcher'] = config.APPLICATION.profile.launcher_name
707 readme_template_path = os.path.join(config.VARS.internal_dir,
708 "README_SRC.template")
710 if package_type == PROJECT:
711 d['user'] = config.VARS.user
712 d['date'] = datetime.datetime.now().strftime("%Y-%m-%d %H:%M")
713 d['version'] = config.INTERNAL.sat_version
714 readme_template_path = os.path.join(config.VARS.internal_dir,
715 "README_PROJECT.template")
717 if package_type == SAT:
718 d['user'] = config.VARS.user
719 d['date'] = datetime.datetime.now().strftime("%Y-%m-%d %H:%M")
720 d['version'] = config.INTERNAL.sat_version
721 readme_template_path = os.path.join(config.VARS.internal_dir,
722 "README_SAT.template")
724 f.write(src.template.substitute(readme_template_path, d))
730 '''method that is called when salomeTools is called with --help option.
732 :return: The text to display for the package command description.
735 return _("The package command creates an archive.\nThere are 4 kinds of "
736 "archive:\n 1- The binary archive. It contains all the product "
737 "installation directories and a launcher,\n 2- The sources archive."
738 " It contains the products archives, a project corresponding to "
739 "the application and salomeTools,\n 3- The project archive. It "
740 "contains a project (give the project file path as argument),\n 4-"
741 " The salomeTools archive. It contains salomeTools.\n\nexample:"
742 "\nsat package SALOME-master --sources")
744 def run(args, runner, logger):
745 '''method that is called when salomeTools is called with package parameter.
749 (options, args) = parser.parse_args(args)
751 # Check that a type of package is called, and only one
752 all_option_types = (options.binaries,
754 options.project not in ["", None],
757 # Check if no option for package type
758 if all_option_types.count(True) == 0:
759 msg = _("Error: Precise a type for the package\nUse one of the "
760 "following options: --binaries, --sources, --project or"
762 logger.write(src.printcolors.printcError(msg), 1)
763 logger.write("\n", 1)
766 # Check for only one option for package type
767 if all_option_types.count(True) > 1:
768 msg = _("Error: You can use only one type for the package\nUse only one"
769 " of the following options: --binaries, --sources, --project or"
771 logger.write(src.printcolors.printcError(msg), 1)
772 logger.write("\n", 1)
775 # Get the package type
777 package_type = BINARY
779 package_type = SOURCE
781 package_type = PROJECT
785 # The repository where to put the package if not Binary or Source
786 package_default_path = runner.cfg.USER.workdir
788 if package_type in [BINARY, SOURCE]:
789 # Check that the command has been called with an application
790 src.check_config_has_application(runner.cfg)
792 # Display information
793 logger.write(_("Packaging application %s\n") % src.printcolors.printcLabel(
794 runner.cfg.VARS.application), 1)
796 # Get the default directory where to put the packages
797 package_default_path = os.path.join(runner.cfg.APPLICATION.workdir,
799 src.ensure_path_exists(package_default_path)
801 elif package_type == PROJECT:
802 # check that the project is visible by SAT
803 if options.project not in runner.cfg.PROJECTS.project_file_paths:
804 site_path = os.path.join(runner.cfg.VARS.salometoolsway,
807 msg = _("ERROR: the project %(proj)s is not visible by salomeTools."
808 "\nPlease add it in the %(site)s file." % {
809 "proj" : options.project, "site" : site_path})
810 logger.write(src.printcolors.printcError(msg), 1)
811 logger.write("\n", 1)
815 src.printcolors.print_value(logger, "Package type", package_type, 2)
817 # get the name of the archive or construct it
819 if os.path.basename(options.name) == options.name:
820 # only a name (not a path)
821 archive_name = options.name
822 dir_name = package_default_path
824 archive_name = os.path.basename(options.name)
825 dir_name = os.path.dirname(options.name)
828 if archive_name[-len(".tgz"):] == ".tgz":
829 archive_name = archive_name[:-len(".tgz")]
830 if archive_name[-len(".tar.gz"):] == ".tar.gz":
831 archive_name = archive_name[:-len(".tar.gz")]
834 dir_name = package_default_path
835 if package_type == BINARY:
836 archive_name = (runner.cfg.APPLICATION.name +
838 runner.cfg.VARS.dist)
840 if package_type == SOURCE:
841 archive_name = (runner.cfg.APPLICATION.name +
845 archive_name = (runner.cfg.APPLICATION.name +
851 if package_type == PROJECT:
852 project_name, __ = os.path.splitext(
853 os.path.basename(options.project))
854 archive_name = ("PROJECT" +
858 if package_type == SAT:
859 archive_name = ("salomeTools" +
861 runner.cfg.INTERNAL.sat_version)
863 path_targz = os.path.join(dir_name, archive_name + ".tgz")
865 # Print the path of the package
866 src.printcolors.print_value(logger, "Package path", path_targz, 2)
868 # Create a working directory for all files that are produced during the
869 # package creation and that will be removed at the end of the command
870 tmp_working_dir = os.path.join(runner.cfg.VARS.tmp_root,
871 runner.cfg.VARS.datehour)
872 src.ensure_path_exists(tmp_working_dir)
873 logger.write("\n", 5)
874 logger.write(_("The temporary working directory: %s\n" % tmp_working_dir),5)
876 logger.write("\n", 3)
878 msg = _("Preparation of files to add to the archive")
879 logger.write(src.printcolors.printcLabel(msg), 2)
880 logger.write("\n", 2)
882 if package_type == BINARY:
883 d_files_to_add = binary_package(runner.cfg,
887 if not(d_files_to_add):
890 # Create and add the source package
891 # if the option "with_sources" is called
892 if options.with_sources:
893 logger.write(_("Create a source archive (can be long) ... "), 3)
894 tmp_pkg_src_name = runner.cfg.APPLICATION.name + "-" + "SRC.tgz"
895 tmp_pkg_src_path = os.path.join(tmp_working_dir, tmp_pkg_src_name)
896 package_options = runner.cfg.VARS.application
897 package_options += " --sources --with_vcs --name "
898 package_options += tmp_pkg_src_path
899 # sat package <package_options>
900 runner.package(package_options,
903 logger_add_link = logger)
904 d_files_to_add["SOURCES PACKAGE"] = (tmp_pkg_src_path,
906 logger.write(src.printcolors.printc("OK"), 3)
907 logger.write("\n", 3)
909 if package_type == SOURCE:
910 d_files_to_add = source_package(runner,
916 if package_type == PROJECT:
917 d_files_to_add = project_package(options.project, tmp_working_dir)
919 if package_type == SAT:
920 d_files_to_add = {"salomeTools" : (runner.cfg.VARS.salometoolsway, "")}
922 # Add the README file in the package
923 local_readme_tmp_path = add_readme(runner.cfg,
926 d_files_to_add["README"] = (local_readme_tmp_path, "README")
928 logger.write("\n", 2)
930 logger.write(src.printcolors.printcLabel(_("Actually do the package")), 2)
931 logger.write("\n", 2)
934 # Creating the object tarfile
935 tar = tarfile.open(path_targz, mode='w:gz')
937 # Add the files to the tarfile object
938 res = add_files(tar, archive_name, d_files_to_add, logger)
940 except KeyboardInterrupt:
941 logger.write(src.printcolors.printcError("\nERROR: forced interruption\n"), 1)
942 logger.write(_("Removing the temporary working directory ... "), 1)
943 # remove the working directory
944 shutil.rmtree(tmp_working_dir)
945 logger.write(_("OK"), 1)
946 logger.write(_("\n"), 1)
949 # remove the working directory
950 shutil.rmtree(tmp_working_dir)
952 # Print again the path of the package
953 logger.write("\n", 2)
954 src.printcolors.print_value(logger, "Package path", path_targz, 2)