Skip to content

Commit 2386ddd

Browse files
authored
Merge branch 'easybuilders:develop' into patch-1
2 parents 136bfd1 + b2b9c54 commit 2386ddd

File tree

11 files changed

+166
-31
lines changed

11 files changed

+166
-31
lines changed

.github/workflows/container_tests.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ jobs:
9797
# see https://docs.easybuild.io/en/latest/Containers.html
9898
curl -OL https://raw.githubusercontent.com/easybuilders/easybuild-easyconfigs/develop/easybuild/easyconfigs/b/bzip2/bzip2-1.0.8.eb
9999
export EASYBUILD_CONTAINERPATH=$PWD
100-
export EASYBUILD_CONTAINER_CONFIG='bootstrap=docker,from=ghcr.io/easybuilders/centos-7.9-python3-amd64'
100+
export EASYBUILD_CONTAINER_CONFIG='bootstrap=docker,from=ghcr.io/easybuilders/rockylinux-8.10-amd64'
101101
eb bzip2-1.0.8.eb --containerize --experimental --container-build-image
102102
singularity exec bzip2-1.0.8.sif command -v bzip2 | grep '/app/software/bzip2/1.0.8/bin/bzip2' || (echo "Path to bzip2 '$which_bzip2' is not correct" && exit 1)
103103
singularity exec bzip2-1.0.8.sif bzip2 --help

.github/workflows/container_tests_apptainer.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ jobs:
9191
# see https://docs.easybuild.io/en/latest/Containers.html
9292
curl -OL https://raw.githubusercontent.com/easybuilders/easybuild-easyconfigs/develop/easybuild/easyconfigs/b/bzip2/bzip2-1.0.8.eb
9393
export EASYBUILD_CONTAINERPATH=$PWD
94-
export EASYBUILD_CONTAINER_CONFIG='bootstrap=docker,from=ghcr.io/easybuilders/centos-7.9-python3-amd64'
94+
export EASYBUILD_CONTAINER_CONFIG='bootstrap=docker,from=ghcr.io/easybuilders/rockylinux-8.10-amd64'
9595
export EASYBUILD_CONTAINER_TYPE='apptainer'
9696
eb bzip2-1.0.8.eb --containerize --experimental --container-build-image
9797
apptainer exec bzip2-1.0.8.sif command -v bzip2 | grep '/app/software/bzip2/1.0.8/bin/bzip2' || (echo "Path to bzip2 '$which_bzip2' is not correct" && exit 1)

RELEASE_NOTES

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,62 @@ For more detailed information, please see the git log.
44
These release notes can also be consulted at https://docs.easybuild.io/release-notes .
55

66

7+
v5.1.0 (26 May 2025)
8+
--------------------
9+
10+
feature release
11+
12+
- various enhancements, including:
13+
- add support for data installations (#4474, #4873, #4874)
14+
- allow specifying location for RPATH wrapper scripts via `rpath_wrappers_dir` (#4596)
15+
- add a CUDA device code sanity check (#4692)
16+
- add support for check_readelf_rpath easyconfig parameter to optionally skip RPATH checks (#4768)
17+
- add support for using environment variables in value used in modextravars (#4855)
18+
- print summary after the build in trace output (#4861, #4875)
19+
- avoid leaking keys by mistake with `--upload-test-report` (#4877)
20+
- obtain PR/commit diff via GitHub API rather than downloading `*.diff` file via github.com (#4878)
21+
- support options for patch command (#4886)
22+
- replace full trace message for extension check command with simple pass/fail message (#4892)
23+
- various bug fixes, including:
24+
- also pass `rpath_include_dirs` when preparing build environment for extensions (#4596)
25+
- fix `check_checksums` when `nosource: True` is used (#4806)
26+
- fix help string of findPythonDeps.py script (#4821)
27+
- take into account `job-output-dir` option in Slurm job backend (#4842)
28+
- fix unbound variable in error case in `build_and_install_software` (#4843)
29+
- avoid failure when only some passed easyconfigs exist (#4847)
30+
- restore original value for non-list easyconfig parameter values that are considered for iterating over (#4848)
31+
- add '-' before 'DMKL_ILP64' in $CFLAGS (#4850)
32+
- enhance RPATH sanity check to skip anything whose absolute path resolves to outside the install dir (#4854)
33+
- use new `ModEnvVarType.STRICT_PATH_WITH_FILES` with `CMAKE_LIBRARY_PATH` environment variable (#4858)
34+
- fix `is_patch_for` for patch dicts (#4865)
35+
- update fake module for each extension installed (#4868, #4888, #4895)
36+
- implement exponential backoff in `download_file` (#4870, #4880)
37+
- use `develop` branch for PRs that target removed `5.0.x` branch in `fetch_files_from_pr` (#4879)
38+
- also ignore errors raised during test step when `--ignore-test-failure` is used (#4881)
39+
- fix download progress bar (#4885)
40+
- fix `--dep-graph` by using `graphviz` Python package (#4891)
41+
- fixes for test suite:
42+
- fix `test_github_preview_pr` which got broken because there's no more easyconfigs for bzip2 1.0.6 in easyconfigs repo (#4827)
43+
- fix tests after removal of 5.0.x branch (#4830)
44+
- fix missed message in trivial equal-asserts (#4831)
45+
- fix wrong variable name used for Python version in linting CI (#4839)
46+
- fix failing GitHub integration CI tests (#4841)
47+
- fix testsuite badge in README (#4845)
48+
- other changes:
49+
- go back to using `develop` branch rather than `5.0.x` branch in GitHub Actions workflows (#4820)
50+
- remove source tarball for Python 3.7.2 from test sources (#4828)
51+
- delete .coveragerc (#4833)
52+
- remove Python 2 constructs (#4834)
53+
- remove superflous assignment in `_sanity_check_step` (#4851)
54+
- replace deprecation warning about reproducible tarballs on Python older than 3.9 with a regular warning (#4852)
55+
- move `EasyBlock.expand_module_search_path` into `ModuleEnvironmentVariable.expand_paths` (#4859)
56+
57+
758
v5.0.0 (18 March 2025)
859
----------------------
960

61+
major release (includes breaking changes)
62+
1063
- remove support for Python 2.7 and 3.5 (#4229, #4270, #4306, #4473, #4477, #4476, #4478, #4524, #4607, #4756, #4810, #4811)
1164
- also run unit test suite with Python 3.12 + 3.13 (#4484, #4674)
1265
- changed defaults in EasyBuild configuration:

easybuild/framework/easyblock.py

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2289,11 +2289,12 @@ def fake_module_environment(self, extra_modules=None, with_build_deps=False):
22892289

22902290
fake_mod_data = self.load_fake_module(purge=True, extra_modules=extra_modules)
22912291

2292-
yield
2293-
2294-
# cleanup (unload fake module, remove fake module dir)
2295-
if fake_mod_data:
2296-
self.clean_up_fake_module(fake_mod_data)
2292+
try:
2293+
yield
2294+
finally:
2295+
# cleanup (unload fake module, remove fake module dir)
2296+
if fake_mod_data:
2297+
self.clean_up_fake_module(fake_mod_data)
22972298

22982299
def guess_start_dir(self):
22992300
"""

easybuild/tools/output.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,13 +48,19 @@
4848
pass
4949

5050

51+
COLOR_BLUE = 'blue'
52+
COLOR_CYAN = 'cyan'
5153
COLOR_GREEN = 'green'
54+
COLOR_PURPLE = 'purple'
5255
COLOR_RED = 'red'
5356
COLOR_YELLOW = 'yellow'
5457

5558
# map known colors to ANSII color codes
5659
KNOWN_COLORS = {
60+
COLOR_BLUE: '\033[0;34m',
61+
COLOR_CYAN: '\033[0;36m',
5762
COLOR_GREEN: '\033[0;32m',
63+
COLOR_PURPLE: '\033[0;35m',
5864
COLOR_RED: '\033[0;31m',
5965
COLOR_YELLOW: '\033[1;33m',
6066
}

easybuild/tools/run.py

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -424,6 +424,8 @@ def to_cmd_str(cmd):
424424
kwargs = {
425425
'interactive': interactive,
426426
'work_dir': work_dir,
427+
'fail_on_error': fail_on_error,
428+
'hidden': hidden,
427429
}
428430
hook_res = run_hook(RUN_SHELL_CMD, hooks, pre_step_hook=True, args=[cmd], kwargs=kwargs)
429431
if hook_res:
@@ -589,6 +591,19 @@ def to_cmd_str(cmd):
589591
work_dir=work_dir, out_file=cmd_out_fp, err_file=cmd_err_fp, cmd_sh=cmd_sh,
590592
thread_id=thread_id, task_id=task_id)
591593

594+
if with_hooks:
595+
run_hook_kwargs = {
596+
'exit_code': res.exit_code,
597+
'interactive': interactive,
598+
'output': res.output,
599+
'stderr': res.stderr,
600+
'work_dir': res.work_dir,
601+
'shell_cmd_result': res,
602+
'fail_on_error': fail_on_error,
603+
'hidden': hidden,
604+
}
605+
run_hook(RUN_SHELL_CMD, hooks, post_step_hook=True, args=[cmd], kwargs=run_hook_kwargs)
606+
592607
# always log command output
593608
cmd_name = cmd_str.split(' ')[0]
594609
if split_stderr:
@@ -618,16 +633,6 @@ def to_cmd_str(cmd):
618633
except OSError as err:
619634
raise EasyBuildError(f"Failed to return to {initial_work_dir} after executing command `{cmd_str}`: {err}")
620635

621-
if with_hooks:
622-
run_hook_kwargs = {
623-
'exit_code': res.exit_code,
624-
'interactive': interactive,
625-
'output': res.output,
626-
'stderr': res.stderr,
627-
'work_dir': res.work_dir,
628-
}
629-
run_hook(RUN_SHELL_CMD, hooks, post_step_hook=True, args=[cmd], kwargs=run_hook_kwargs)
630-
631636
if not hidden:
632637
time_since_start = time_str_since(start_time)
633638
trace_msg(f"command completed: exit {res.exit_code}, ran in {time_since_start}")

easybuild/tools/systemtools.py

Lines changed: 36 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -56,11 +56,20 @@
5656
# pkg_resources is provided by the setuptools Python package,
5757
# which we really want to keep as an *optional* dependency
5858
try:
59-
import pkg_resources
59+
# catch & ignore deprecation warning when importing pkg_resources produced by setuptools
60+
with warnings.catch_warnings():
61+
warnings.simplefilter("ignore", UserWarning)
62+
import pkg_resources
6063
HAVE_PKG_RESOURCES = True
6164
except ImportError:
6265
HAVE_PKG_RESOURCES = False
6366

67+
# importlib.metadata only available in Python 3.10+ (which we take into account when using it)
68+
try:
69+
import importlib.metadata
70+
except ImportError:
71+
pass
72+
6473
try:
6574
# only needed on macOS, may not be available on Linux
6675
import ctypes.macholib.dyld
@@ -1467,17 +1476,38 @@ def det_pypkg_version(pkg_name, imported_pkg, import_name=None):
14671476

14681477
version = None
14691478

1470-
if HAVE_PKG_RESOURCES:
1479+
# prefer using importlib.metadata, since pkg_resources is deprecated since setuptools v68.0.0
1480+
# and is scheduled to be removed in November 2025; see also https://github.com/pypa/setuptools/pull/5007
1481+
1482+
raised_error = None
1483+
1484+
# figure out which function to use to determine module/package version,
1485+
# and which error may be raised if the name is unknown
1486+
if check_python_version() >= (3, 10):
1487+
1488+
def _get_version(name):
1489+
return importlib.metadata.version(name)
1490+
1491+
raised_error = importlib.metadata.PackageNotFoundError
1492+
1493+
elif HAVE_PKG_RESOURCES:
1494+
1495+
def _get_version(name):
1496+
return pkg_resources.get_distribution(name).version
1497+
1498+
raised_error = pkg_resources.DistributionNotFound
1499+
1500+
if raised_error is not None:
14711501
if import_name:
14721502
try:
1473-
version = pkg_resources.get_distribution(import_name).version
1474-
except pkg_resources.DistributionNotFound as err:
1503+
version = _get_version(import_name)
1504+
except raised_error as err:
14751505
_log.debug("%s Python package not found: %s", import_name, err)
14761506

14771507
if version is None:
14781508
try:
1479-
version = pkg_resources.get_distribution(pkg_name).version
1480-
except pkg_resources.DistributionNotFound as err:
1509+
version = _get_version(pkg_name)
1510+
except raised_error as err:
14811511
_log.debug("%s Python package not found: %s", pkg_name, err)
14821512

14831513
if version is None:

easybuild/tools/version.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@
4545
# recent setuptools versions will *TRANSFORM* something like 'X.Y.Zdev' into 'X.Y.Z.dev0', with a warning like
4646
# UserWarning: Normalizing '2.4.0dev' to '2.4.0.dev0'
4747
# This causes problems further up the dependency chain...
48-
VERSION = LooseVersion('5.0.1.dev0')
48+
VERSION = LooseVersion('5.1.1.dev0')
4949
UNKNOWN = 'UNKNOWN'
5050
UNKNOWN_EASYBLOCKS_VERSION = '0.0.UNKNOWN.EASYBLOCKS'
5151

test/framework/output.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -130,10 +130,13 @@ def test_colorize(self):
130130
Test colorize function
131131
"""
132132
if HAVE_RICH:
133-
for color in ('green', 'red', 'yellow'):
133+
for color in ('blue', 'cyan', 'green', 'purple', 'red', 'yellow'):
134134
self.assertEqual(colorize('test', color), '[bold %s]test[/bold %s]' % (color, color))
135135
else:
136+
self.assertEqual(colorize('test', 'blue'), '\x1b[0;34mtest\x1b[0m')
137+
self.assertEqual(colorize('test', 'cyan'), '\x1b[0;36mtest\x1b[0m')
136138
self.assertEqual(colorize('test', 'green'), '\x1b[0;32mtest\x1b[0m')
139+
self.assertEqual(colorize('test', 'purple'), '\x1b[0;35mtest\x1b[0m')
137140
self.assertEqual(colorize('test', 'red'), '\x1b[0;31mtest\x1b[0m')
138141
self.assertEqual(colorize('test', 'yellow'), '\x1b[1;33mtest\x1b[0m')
139142

test/framework/run.py

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2068,7 +2068,9 @@ def pre_run_shell_cmd_hook(cmd, *args, **kwargs):
20682068
print("pre-run hook '%s' in %s" % (cmd, work_dir))
20692069
import sys
20702070
sys.stderr.write('pre-run hook done\\n')
2071-
if not cmd.startswith('echo'):
2071+
print("command is allowed to fail: %s" % kwargs.get('fail_on_error', 'NOT AVAILABLE'))
2072+
print("command is hidden: %s" % kwargs.get('hidden', 'NOT AVAILABLE'))
2073+
if cmd != 'false' and not cmd.startswith('echo'):
20722074
cmds = cmd.split(';')
20732075
return '; '.join(cmds[:-1] + ["echo " + cmds[-1].lstrip()])
20742076
@@ -2081,6 +2083,8 @@ def post_run_shell_cmd_hook(cmd, *args, **kwargs):
20812083
else:
20822084
msg = "post-run hook '%s'" % cmd
20832085
msg += " (exit code: %s, output: '%s')" % (exit_code, output)
2086+
msg += "\\ncommand was allowed to fail: %s" % kwargs.get('fail_on_error', 'NOT AVAILABLE')
2087+
msg += "\\ncommand was hidden: %s" % kwargs.get('hidden', 'NOT AVAILABLE')
20842088
print(msg)
20852089
""")
20862090
write_file(hooks_file, hooks_file_txt)
@@ -2095,7 +2099,11 @@ def post_run_shell_cmd_hook(cmd, *args, **kwargs):
20952099

20962100
expected_stdout = '\n'.join([
20972101
f"pre-run hook 'make' in {cwd}",
2102+
"command is allowed to fail: True",
2103+
"command is hidden: False",
20982104
"post-run hook 'echo make' (exit code: 0, output: 'make\n')",
2105+
"command was allowed to fail: True",
2106+
"command was hidden: False",
20992107
'',
21002108
])
21012109
self.assertEqual(stdout, expected_stdout)
@@ -2109,6 +2117,8 @@ def post_run_shell_cmd_hook(cmd, *args, **kwargs):
21092117

21102118
expected_stdout = '\n'.join([
21112119
"pre-run hook 'make' in %s" % cwd,
2120+
"command is allowed to fail: True",
2121+
"command is hidden: False",
21122122
' running shell command "echo make"',
21132123
' (in %s)' % cwd,
21142124
'',
@@ -2126,6 +2136,24 @@ def post_run_shell_cmd_hook(cmd, *args, **kwargs):
21262136
regex = re.compile('>> running shell command:\n\techo make', re.M)
21272137
self.assertTrue(regex.search(stdout), "Pattern '%s' found in: %s" % (regex.pattern, stdout))
21282138

2139+
with self.mocked_stdout_stderr():
2140+
# run_shell_cmd will raise RunShellCmdError which we don't care about here,
2141+
# we just want to verify that the post_run_shell_cmd_hook has run
2142+
try:
2143+
run_shell_cmd("false")
2144+
except RunShellCmdError:
2145+
pass
2146+
stdout = self.get_stdout()
2147+
2148+
expected_end = '\n'.join([
2149+
'',
2150+
"post-run hook 'false' (exit code: 1, output: '')",
2151+
"command was allowed to fail: True",
2152+
"command was hidden: False",
2153+
'',
2154+
])
2155+
self.assertTrue(stdout.endswith(expected_end), f"Stdout should end with '{expected_end}': {stdout}")
2156+
21292157
def test_run_shell_cmd_delete_cwd(self):
21302158
"""
21312159
Test commands that destroy directories inside initial working directory

0 commit comments

Comments
 (0)