|
48 | 48 | import inspect |
49 | 49 | import json |
50 | 50 | import os |
| 51 | +import random |
51 | 52 | import re |
52 | 53 | import stat |
53 | 54 | import sys |
|
57 | 58 | from concurrent.futures import ThreadPoolExecutor |
58 | 59 | from datetime import datetime |
59 | 60 | from enum import Enum |
| 61 | +from string import ascii_letters |
60 | 62 | from textwrap import indent |
61 | 63 |
|
62 | 64 | import easybuild.tools.environment as env |
|
79 | 81 | from easybuild.tools.config import EASYBUILD_SOURCES_URL, EBPYTHONPREFIXES # noqa |
80 | 82 | from easybuild.tools.config import FORCE_DOWNLOAD_ALL, FORCE_DOWNLOAD_PATCHES, FORCE_DOWNLOAD_SOURCES |
81 | 83 | from easybuild.tools.config import MOD_SEARCH_PATH_HEADERS, PYTHONPATH, SEARCH_PATH_BIN_DIRS, SEARCH_PATH_LIB_DIRS |
82 | | -from easybuild.tools.config import build_option, build_path, get_log_filename, get_repository, get_repositorypath |
| 84 | +from easybuild.tools.config import build_option, build_path, get_failed_install_build_dirs_path |
| 85 | +from easybuild.tools.config import get_failed_install_logs_path, get_log_filename, get_repository, get_repositorypath |
83 | 86 | from easybuild.tools.config import install_path, log_path, package_path, source_paths |
84 | 87 | from easybuild.tools.environment import restore_env, sanitize_env |
85 | 88 | from easybuild.tools.filetools import CHECKSUM_TYPE_SHA256 |
86 | 89 | from easybuild.tools.filetools import adjust_permissions, apply_patch, back_up_file, change_dir, check_lock |
87 | | -from easybuild.tools.filetools import compute_checksum, convert_name, copy_file, create_lock, create_patch_info |
88 | | -from easybuild.tools.filetools import derive_alt_pypi_url, diff_files, dir_contains_files, download_file |
89 | | -from easybuild.tools.filetools import encode_class_name, extract_file, find_backup_name_candidate |
90 | | -from easybuild.tools.filetools import get_cwd, get_source_tarball_from_git, is_alt_pypi_url |
91 | | -from easybuild.tools.filetools import is_binary, is_sha256_checksum, mkdir, move_file, move_logs, read_file, remove_dir |
92 | | -from easybuild.tools.filetools import remove_file, remove_lock, verify_checksum, weld_paths, write_file, symlink |
| 90 | +from easybuild.tools.filetools import compute_checksum, convert_name, copy_dir, copy_file, create_lock |
| 91 | +from easybuild.tools.filetools import create_non_existing_paths, create_patch_info, derive_alt_pypi_url, diff_files |
| 92 | +from easybuild.tools.filetools import dir_contains_files, download_file, encode_class_name, extract_file |
| 93 | +from easybuild.tools.filetools import find_backup_name_candidate, get_cwd, get_source_tarball_from_git, is_alt_pypi_url |
| 94 | +from easybuild.tools.filetools import is_binary, is_parent_path, is_sha256_checksum, mkdir, move_file, move_logs |
| 95 | +from easybuild.tools.filetools import read_file, remove_dir, remove_file, remove_lock, symlink, verify_checksum |
| 96 | +from easybuild.tools.filetools import weld_paths, write_file |
93 | 97 | from easybuild.tools.hooks import ( |
94 | 98 | BUILD_STEP, CLEANUP_STEP, CONFIGURE_STEP, EXTENSIONS_STEP, EXTRACT_STEP, FETCH_STEP, INSTALL_STEP, MODULE_STEP, |
95 | 99 | MODULE_WRITE, PACKAGE_STEP, PATCH_STEP, PERMISSIONS_STEP, POSTITER_STEP, POSTPROC_STEP, PREPARE_STEP, READY_STEP, |
@@ -4438,6 +4442,54 @@ def print_dry_run_note(loc, silent=True): |
4438 | 4442 | dry_run_msg(msg, silent=silent) |
4439 | 4443 |
|
4440 | 4444 |
|
| 4445 | +def copy_build_dirs_logs_failed_install(application_log, silent, app, easyconfig): |
| 4446 | + """ |
| 4447 | + Copy build directories and log files for failed installation (if desired) |
| 4448 | + """ |
| 4449 | + logs_path = get_failed_install_logs_path(easyconfig) |
| 4450 | + build_dirs_path = get_failed_install_build_dirs_path(easyconfig) |
| 4451 | + |
| 4452 | + # there may be multiple log files, or the file name may be different due to zipping |
| 4453 | + logs = glob.glob(f"{application_log}*") |
| 4454 | + |
| 4455 | + timestamp = time.strftime('%Y%m%d-%H%M%S') |
| 4456 | + salt = ''.join(random.choices(ascii_letters, k=5)) |
| 4457 | + unique_subdir = f'{timestamp}-{salt}' |
| 4458 | + |
| 4459 | + operation_args = [] |
| 4460 | + |
| 4461 | + if logs_path and logs: |
| 4462 | + logs_path = os.path.join(logs_path, unique_subdir) |
| 4463 | + |
| 4464 | + if is_parent_path(app.builddir, logs_path): |
| 4465 | + msg = "Path to copy log files of failed installs to is subdirectory of build directory; not copying" |
| 4466 | + print_warning(msg, log=_log, silent=silent) |
| 4467 | + else: |
| 4468 | + msg = f"Log file(s) of failed installation copied to {logs_path}" |
| 4469 | + operation_args.append((copy_file, logs, logs_path, msg)) |
| 4470 | + |
| 4471 | + if build_dirs_path and os.path.isdir(app.builddir): |
| 4472 | + build_dirs_path = os.path.join(build_dirs_path, unique_subdir) |
| 4473 | + |
| 4474 | + if is_parent_path(app.builddir, build_dirs_path): |
| 4475 | + msg = "Path to copy build dirs of failed installs to is subdirectory of build directory; not copying" |
| 4476 | + print_warning(msg, log=_log, silent=silent) |
| 4477 | + else: |
| 4478 | + msg = f"Build directory of failed installation copied to {build_dirs_path}" |
| 4479 | + |
| 4480 | + def operation(src, dest): |
| 4481 | + copy_dir(src, dest, dirs_exist_ok=True) |
| 4482 | + |
| 4483 | + operation_args.append((operation, [app.builddir], build_dirs_path, msg)) |
| 4484 | + |
| 4485 | + persistence_paths = create_non_existing_paths(target_path for (_, _, target_path, _) in operation_args) |
| 4486 | + |
| 4487 | + for idx, (operation, paths, _, msg) in enumerate(operation_args): |
| 4488 | + for path in paths: |
| 4489 | + operation(path, persistence_paths[idx]) |
| 4490 | + print_msg(msg, log=_log, silent=silent) |
| 4491 | + |
| 4492 | + |
4441 | 4493 | def build_and_install_one(ecdict, init_env): |
4442 | 4494 | """ |
4443 | 4495 | Build the software |
@@ -4696,6 +4748,9 @@ def ensure_writable_log_dir(log_dir): |
4696 | 4748 | logs = glob.glob('%s*' % application_log) |
4697 | 4749 | print_msg("Results of the build can be found in the log file(s) %s" % ', '.join(logs), log=_log, silent=silent) |
4698 | 4750 |
|
| 4751 | + if not success: |
| 4752 | + copy_build_dirs_logs_failed_install(application_log, silent, app, ecdict['ec']) |
| 4753 | + |
4699 | 4754 | del app |
4700 | 4755 |
|
4701 | 4756 | return (success, application_log, error_msg, exit_code) |
|
0 commit comments