Skip to content

Commit 4b9d41d

Browse files
authored
Merge branch 'easybuilders:develop' into optarch-map
2 parents 66832be + d4098ba commit 4b9d41d

File tree

7 files changed

+134
-15
lines changed

7 files changed

+134
-15
lines changed

RELEASE_NOTES

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,28 @@ For more detailed information, please see the git log.
44
These release notes can also be consulted at https://easybuild.readthedocs.io/en/latest/Release_notes.html.
55

66

7+
v4.9.2 (12 June 2024)
8+
---------------------
9+
10+
update/bugfix release
11+
12+
- various enhancements, including:
13+
- improve behavior when using extension which has 'nosource' enabled (#4506)
14+
- enhance 'get_software_libdir' to return 'lib' or 'lib64' if only one of them contains library files (#4513)
15+
- implement versions checks to avoid mixing major versions across the EasyBuild components (#4520, #4553)
16+
- add support for easyconfig parameter 'module_only' (#4537)
17+
- various bug fixes, including:
18+
- fix typo in patch_step logging (#4505)
19+
- consider both 'easybuild-framework*.tar.gz' and 'easybuild_framework*.tar.gz' in CI workflows (#4507)
20+
- don't delete existing environment module files when using '--dump-env-script' with '--force' or '--rebuild' (#4512)
21+
- fix resolved (template) values in case of failure (#4532)
22+
- also consider '$CRAY_PE_LIBSCI_PREFIX_DIR' to determine installation prefix for cray-libsci (#4551)
23+
- symlink downloaded repo at specified commit when using '--from-commit' so easyconfigs for dependencies are found (#4552)
24+
- other changes:
25+
- code cleanup in 'easyblock.py' (#4519)
26+
- stop running unit tests on Python 3.5 (#4530)
27+
28+
729
v4.9.1 (5 April 2024)
830
---------------------
931

easybuild/toolchains/linalg/libsci.py

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -65,13 +65,20 @@ def _get_software_root(self, name, required=True):
6565
"""Get install prefix for specified software name; special treatment for Cray modules."""
6666
if name == 'cray-libsci':
6767
# Cray-provided LibSci module
68-
env_var = 'CRAY_LIBSCI_PREFIX_DIR'
69-
root = os.getenv(env_var, None)
68+
root = None
69+
# consider both $CRAY_LIBSCI_PREFIX_DIR and $CRAY_PE_LIBSCI_PREFIX_DIR,
70+
# cfr. https://github.com/easybuilders/easybuild-framework/issues/4536
71+
env_vars = ('CRAY_LIBSCI_PREFIX_DIR', 'CRAY_PE_LIBSCI_PREFIX_DIR')
72+
for env_var in env_vars:
73+
root = os.getenv(env_var, None)
74+
if root is not None:
75+
self.log.debug("Obtained install prefix for %s via $%s: %s", name, env_var, root)
76+
break
77+
7078
if root is None:
7179
if required:
72-
raise EasyBuildError("Failed to determine install prefix for %s via $%s", name, env_var)
73-
else:
74-
self.log.debug("Obtained install prefix for %s via $%s: %s", name, env_var, root)
80+
env_vars_str = ', '.join('$' + e for e in env_vars)
81+
raise EasyBuildError("Failed to determine install prefix for %s via $%s", name, env_vars_str)
7582
else:
7683
root = super(LibSci, self)._get_software_root(name, required=required)
7784

easybuild/tools/github.py

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -589,13 +589,19 @@ def fetch_files_from_pr(pr, path=None, github_user=None, github_account=None, gi
589589
raise EasyBuildError("Couldn't find path to patched file %s", full_path)
590590

591591
if github_repo == GITHUB_EASYCONFIGS_REPO:
592-
ver = _get_version_for_repo(os.path.join(final_path, 'setup.py'))
592+
ver_file = os.path.join(final_path, 'setup.py')
593593
elif github_repo == GITHUB_EASYBLOCKS_REPO:
594-
ver = _get_version_for_repo(os.path.join(final_path, 'easybuild', 'easyblocks', '__init__.py'))
594+
ver_file = os.path.join(final_path, 'easybuild', 'easyblocks', '__init__.py')
595+
else:
596+
raise EasyBuildError("Don't know how to determine version for repo %s", github_repo)
595597

596-
if different_major_versions(FRAMEWORK_VERSION, ver):
597-
raise EasyBuildError("Framework (%s) is a different major version than used in %s/%s PR #%s (%s)",
598-
FRAMEWORK_VERSION, github_account, github_repo, pr, ver)
598+
# take into account that the file we need to determine repo version may not be available,
599+
# for example when a closed PR is used (since then we only download files patched by the PR)
600+
if os.path.exists(ver_file):
601+
ver = _get_version_for_repo(ver_file)
602+
if different_major_versions(FRAMEWORK_VERSION, ver):
603+
raise EasyBuildError("Framework (%s) is a different major version than used in %s/%s PR #%s (%s)",
604+
FRAMEWORK_VERSION, github_account, github_repo, pr, ver)
599605

600606
return files
601607

@@ -643,6 +649,13 @@ def fetch_files_from_commit(commit, files=None, path=None, github_account=None,
643649
if github_repo is None:
644650
github_repo = GITHUB_EASYCONFIGS_REPO
645651

652+
if github_repo == GITHUB_EASYCONFIGS_REPO:
653+
easybuild_subdir = os.path.join('easybuild', 'easyconfigs')
654+
elif github_repo == GITHUB_EASYBLOCKS_REPO:
655+
easybuild_subdir = os.path.join('easybuild', 'easyblocks')
656+
else:
657+
raise EasyBuildError("Unknown repo: %s", github_repo)
658+
646659
if path is None:
647660
if github_repo == GITHUB_EASYCONFIGS_REPO:
648661
extra_ec_paths = build_option('extra_ec_paths')
@@ -686,6 +699,12 @@ def fetch_files_from_commit(commit, files=None, path=None, github_account=None,
686699
else:
687700
raise EasyBuildError("Unknown repo: %s" % github_repo)
688701

702+
# symlink subdirectories of 'easybuild/easy{blocks,configs}' into path that gets added to robot search path
703+
mkdir(path, parents=True)
704+
dirpath = os.path.join(repo_commit, easybuild_subdir)
705+
for subdir in os.listdir(dirpath):
706+
symlink(os.path.join(dirpath, subdir), os.path.join(path, subdir))
707+
689708
# copy specified files to directory where they're expected to be found
690709
file_paths = []
691710
for file in files:

easybuild/tools/modules.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
* Jens Timmerman (Ghent University)
3838
* David Brown (Pacific Northwest National Laboratory)
3939
"""
40+
import glob
4041
import os
4142
import re
4243
import shlex
@@ -52,6 +53,7 @@
5253
from easybuild.tools.module_naming_scheme.mns import DEVEL_MODULE_SUFFIX
5354
from easybuild.tools.py2vs3 import subprocess_popen_text
5455
from easybuild.tools.run import run_cmd
56+
from easybuild.tools.systemtools import get_shared_lib_ext
5557
from easybuild.tools.utilities import get_subclasses, nub
5658

5759
# software root/version environment variable name prefixes
@@ -1671,6 +1673,7 @@ def get_software_libdir(name, only_one=True, fs=None):
16711673
16721674
Returns the library subdirectory, relative to software root.
16731675
It fails if multiple library subdirs are found, unless only_one is False which yields a list of all library subdirs.
1676+
If only_one is True and fs is None, select the one subdirectory with shared or static libraries, if possible.
16741677
16751678
:param name: name of the software package
16761679
:param only_one: indicates whether only one lib path is expected to be found
@@ -1703,6 +1706,16 @@ def get_software_libdir(name, only_one=True, fs=None):
17031706
if len(res) == 1:
17041707
res = res[0]
17051708
else:
1709+
if fs is None and len(res) == 2:
1710+
# if both lib and lib64 were found, check if only one (exactly) has libraries;
1711+
# this is needed for software with library archives in lib64 but other files/directories in lib
1712+
lib_glob = ['*.%s' % ext for ext in ['a', get_shared_lib_ext()]]
1713+
has_libs = [any(glob.glob(os.path.join(root, subdir, f)) for f in lib_glob) for subdir in res]
1714+
if has_libs[0] and not has_libs[1]:
1715+
return res[0]
1716+
elif has_libs[1] and not has_libs[0]:
1717+
return res[1]
1718+
17061719
raise EasyBuildError("Multiple library subdirectories found for %s in %s: %s",
17071720
name, root, ', '.join(res))
17081721
return res

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('4.9.2.dev0')
48+
VERSION = LooseVersion('4.9.3.dev0')
4949
UNKNOWN = 'UNKNOWN'
5050
UNKNOWN_EASYBLOCKS_VERSION = '0.0.UNKNOWN.EASYBLOCKS'
5151

test/framework/modules.py

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@
5151
from easybuild.tools.modules import curr_module_paths, get_software_libdir, get_software_root, get_software_version
5252
from easybuild.tools.modules import invalidate_module_caches_for, modules_tool, reset_module_caches
5353
from easybuild.tools.run import run_cmd
54+
from easybuild.tools.systemtools import get_shared_lib_ext
5455

5556

5657
# number of modules included for testing purposes
@@ -674,10 +675,23 @@ def test_get_software_root_version_libdir(self):
674675
os.environ.pop('EBROOT%s' % env_var_name)
675676
os.environ.pop('EBVERSION%s' % env_var_name)
676677

677-
# check expected result of get_software_libdir with multiple lib subdirs
678+
# if only 'lib' has a library archive, use it
678679
root = os.path.join(tmpdir, name)
679680
mkdir(os.path.join(root, 'lib64'))
680681
os.environ['EBROOT%s' % env_var_name] = root
682+
write_file(os.path.join(root, 'lib', 'libfoo.a'), 'foo')
683+
self.assertEqual(get_software_libdir(name), 'lib')
684+
685+
remove_file(os.path.join(root, 'lib', 'libfoo.a'))
686+
687+
# also check vice versa with *shared* library in lib64
688+
shlib_ext = get_shared_lib_ext()
689+
write_file(os.path.join(root, 'lib64', 'libfoo.' + shlib_ext), 'foo')
690+
self.assertEqual(get_software_libdir(name), 'lib64')
691+
692+
remove_file(os.path.join(root, 'lib64', 'libfoo.' + shlib_ext))
693+
694+
# check expected result of get_software_libdir with multiple lib subdirs
681695
self.assertErrorRegex(EasyBuildError, "Multiple library subdirectories found.*", get_software_libdir, name)
682696
self.assertEqual(get_software_libdir(name, only_one=False), ['lib', 'lib64'])
683697

test/framework/options.py

Lines changed: 47 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1927,7 +1927,7 @@ def test_github_from_pr(self):
19271927

19281928
# make sure that *only* these modules are listed, no others
19291929
regex = re.compile(r"^ \* \[.\] .*/(?P<filepath>.*) \(module: (?P<module>.*)\)$", re.M)
1930-
self.assertTrue(sorted(regex.findall(outtxt)), sorted(modules))
1930+
self.assertEqual(sorted(x[1] for x in regex.findall(outtxt)), sorted(x[1] for x in modules))
19311931

19321932
pr_tmpdir = os.path.join(tmpdir, r'eb-\S{6,8}', 'files_pr6424')
19331933
regex = re.compile(r"Extended list of robot search paths with \['%s'\]:" % pr_tmpdir, re.M)
@@ -1962,12 +1962,12 @@ def test_github_from_pr(self):
19621962

19631963
# make sure that *only* these modules are listed, no others
19641964
regex = re.compile(r"^ \* \[.\] .*/(?P<filepath>.*) \(module: (?P<module>.*)\)$", re.M)
1965-
self.assertTrue(sorted(regex.findall(outtxt)), sorted(modules))
1965+
self.assertEqual(sorted(x[1] for x in regex.findall(outtxt)), sorted(x[1] for x in modules))
19661966

19671967
for pr in ('12150', '12366'):
19681968
pr_tmpdir = os.path.join(tmpdir, r'eb-\S{6,8}', 'files_pr%s' % pr)
19691969
regex = re.compile(r"Extended list of robot search paths with .*%s.*:" % pr_tmpdir, re.M)
1970-
self.assertTrue(regex.search(outtxt), "Found pattern %s in %s" % (regex.pattern, outtxt))
1970+
self.assertTrue(regex.search(outtxt), "Found pattern '%s' in: %s" % (regex.pattern, outtxt))
19711971

19721972
except URLError as err:
19731973
print("Ignoring URLError '%s' in test_from_pr" % err)
@@ -2144,6 +2144,50 @@ def test_from_commit(self):
21442144
print("Ignoring URLError '%s' in test_from_commit" % err)
21452145
shutil.rmtree(tmpdir)
21462146

2147+
easyblock_template = '\n'.join([
2148+
"from easybuild.framework.easyblock import EasyBlock",
2149+
"class %s(EasyBlock):",
2150+
" pass",
2151+
])
2152+
2153+
# create fake custom easyblock for CMake that is required by easyconfig used in test below
2154+
easyblock_file = os.path.join(self.test_prefix, 'easyblocks', 'cmake.py')
2155+
write_file(easyblock_file, easyblock_template % 'EB_CMake')
2156+
2157+
# also test with an easyconfig that requires additional easyconfigs to resolve dependencies,
2158+
# cfr. https://github.com/easybuilders/easybuild-framework/issues/4540;
2159+
# using commit that adds CMake-3.18.4.eb (which requires ncurses-6.2.eb),
2160+
# see https://github.com/easybuilders/easybuild-easyconfigs/pull/13156
2161+
test_commit = '41eee3fe2e5102f52319481ca8dde16204dab590'
2162+
args = [
2163+
'--from-commit=%s' % test_commit,
2164+
'--dry-run',
2165+
'--tmpdir=%s' % tmpdir,
2166+
'--include-easyblocks=' + os.path.join(self.test_prefix, 'easyblocks', '*.py'),
2167+
]
2168+
try:
2169+
outtxt = self.eb_main(args, logfile=dummylogfn, raise_error=True)
2170+
modules = [
2171+
(tmpdir, 'ncurses/6.2'),
2172+
(tmpdir, 'CMake/3.18.4'),
2173+
]
2174+
for path_prefix, module in modules:
2175+
ec_fn = "%s.eb" % '-'.join(module.split('/'))
2176+
path = '.*%s' % os.path.dirname(path_prefix)
2177+
regex = re.compile(r"^ \* \[.\] %s.*%s \(module: %s\)$" % (path, ec_fn, module), re.M)
2178+
self.assertTrue(regex.search(outtxt), "Found pattern %s in %s" % (regex.pattern, outtxt))
2179+
2180+
# make sure that *only* these modules are listed, no others
2181+
regex = re.compile(r"^ \* \[.\] .*/(?P<filepath>.*) \(module: (?P<module>.*)\)$", re.M)
2182+
self.assertEqual(sorted(x[1] for x in regex.findall(outtxt)), sorted(x[1] for x in modules))
2183+
2184+
pr_tmpdir = os.path.join(tmpdir, r'eb-\S{6,8}', 'files_commit_%s' % test_commit)
2185+
regex = re.compile(r"Extended list of robot search paths with \['%s'\]:" % pr_tmpdir, re.M)
2186+
self.assertTrue(regex.search(outtxt), "Found pattern %s in %s" % (regex.pattern, outtxt))
2187+
except URLError as err:
2188+
print("Ignoring URLError '%s' in test_from_commit" % err)
2189+
shutil.rmtree(tmpdir)
2190+
21472191
# must be run after test for --list-easyblocks, hence the '_xxx_'
21482192
# cleaning up the imported easyblocks is quite difficult...
21492193
def test_xxx_include_easyblocks_from_commit(self):

0 commit comments

Comments
 (0)